dxopal 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +25 -0
  3. data/DEVELOPMENT.md +3 -1
  4. data/Gemfile.lock +14 -6
  5. data/README.md +2 -2
  6. data/Rakefile +12 -11
  7. data/TODO.md +2 -2
  8. data/build/dxopal.js +35121 -29081
  9. data/build/dxopal.min.js +1 -1
  10. data/config.ru +6 -5
  11. data/doc/api/DXOpal.html +4 -4
  12. data/doc/api/DXOpal/Font.html +30 -19
  13. data/doc/api/DXOpal/Image.html +417 -242
  14. data/doc/api/DXOpal/Input.html +402 -102
  15. data/doc/api/DXOpal/Input/MouseCodes.html +3 -3
  16. data/doc/api/DXOpal/RemoteResource.html +29 -27
  17. data/doc/api/DXOpal/Sound.html +3 -3
  18. data/doc/api/DXOpal/SoundEffect.html +14 -10
  19. data/doc/api/DXOpal/SoundEffect/WaveTypes.html +3 -3
  20. data/doc/api/DXOpal/Sprite.html +3 -3
  21. data/doc/api/DXOpal/Window.html +238 -132
  22. data/doc/api/_index.html +4 -7
  23. data/doc/api/css/style.css +7 -0
  24. data/doc/api/file.README.html +6 -36
  25. data/doc/api/file_list.html +0 -5
  26. data/doc/api/frames.html +1 -1
  27. data/doc/api/index.html +6 -36
  28. data/doc/api/method_list.html +113 -57
  29. data/doc/api/top-level-namespace.html +3 -3
  30. data/doc/en/index.html +12 -0
  31. data/doc/ja/index.html +9 -0
  32. data/dxopal.gemspec +3 -2
  33. data/exe/dxopal +4 -2
  34. data/index.html +2 -0
  35. data/opal/dxopal.rb +42 -0
  36. data/opal/dxopal/font.rb +2 -0
  37. data/opal/dxopal/image.rb +30 -3
  38. data/opal/dxopal/input/key_codes.rb +0 -3
  39. data/opal/dxopal/remote_resource.rb +2 -0
  40. data/opal/dxopal/sound_effect.rb +3 -0
  41. data/opal/dxopal/sprite/collision_check.rb +27 -7
  42. data/opal/dxopal/sprite/collision_checker.rb +2 -0
  43. data/opal/dxopal/sprite/physics.rb +6 -2
  44. data/opal/dxopal/version.rb +1 -1
  45. data/opal/dxopal/window.rb +13 -4
  46. data/template/index.html +4 -1
  47. metadata +20 -6
@@ -6,7 +6,7 @@
6
6
  <title>
7
7
  Top Level Namespace
8
8
 
9
- &mdash; Documentation by YARD 0.9.9
9
+ &mdash; Documentation by YARD 0.9.12
10
10
 
11
11
  </title>
12
12
 
@@ -100,9 +100,9 @@
100
100
  </div>
101
101
 
102
102
  <div id="footer">
103
- Generated on Tue Oct 17 13:56:27 2017 by
103
+ Generated on Mon Feb 5 16:56:40 2018 by
104
104
  <a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
105
- 0.9.9 (ruby-2.4.2).
105
+ 0.9.12 (ruby-2.4.2).
106
106
  </div>
107
107
 
108
108
  </div>
@@ -83,6 +83,18 @@ $ dxopal server</code></pre>
83
83
  </li>
84
84
  </ul>
85
85
 
86
+ <h2>FAQ</h2>
87
+ <h3>Why is dxopal.js so big?</h3>
88
+ <p>
89
+ Because it contains the whole opal processor, so that you will
90
+ not be bothered by how to compile your game files into JS.
91
+ </p>
92
+ <p>
93
+ Technically you can reduce the file size by commenting out
94
+ <code>require "opal-parser"</code> in opal/dxopal.rb and
95
+ building your own .js (including your game).
96
+ </p>
97
+
86
98
  </section>
87
99
  <footer>
88
100
  <p><small>Hosted on <a href="https://pages.github.com">GitHub Pages</a> using the <a href='https://github.com/pages-themes/dinky'>Dinky theme</a></small></p>
@@ -82,6 +82,15 @@ $ dxopal server</code></pre>
82
82
  </li>
83
83
  </ul>
84
84
 
85
+ <h2>FAQ</h2>
86
+ <h3>dxopal.jsのサイズがけっこう大きいのはなぜ?</h3>
87
+ <p>
88
+ Opal処理系がまるごと入っているからです。その代わり、作ったゲームをJavaScriptに変換する手順を気にしなくて済むというメリットがあります。
89
+ </p>
90
+ <p>
91
+ 技術的には、opal/dxopal.rbの<code>require "opal-parser"</code>をコメントアウトして、作ったゲームと一緒に.jsに変換すればより小さいサイズで済むはずです。
92
+ </p>
93
+
85
94
  </section>
86
95
  <footer>
87
96
  <p><small>Hosted on <a href="https://pages.github.com">GitHub Pages</a> using the <a href='https://github.com/pages-themes/dinky'>Dinky theme</a></small></p>
@@ -20,10 +20,11 @@ Gem::Specification.new do |spec|
20
20
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
21
21
  spec.require_paths = ["lib"]
22
22
 
23
- spec.add_runtime_dependency "opal", "~> 0.10.5"
23
+ spec.add_runtime_dependency "opal", "~> 0.11.0"
24
24
  spec.add_runtime_dependency "thor", "~> 0.19.1"
25
25
  spec.add_runtime_dependency "rack", "~> 2.0"
26
26
  spec.add_development_dependency "bundler", "~> 1.14"
27
27
  spec.add_development_dependency "rake", "~> 10.0"
28
- spec.add_development_dependency "yard", "~> 0.9.9"
28
+ spec.add_development_dependency "yard", "~> 0.9.12"
29
+ spec.add_development_dependency "opal-sprockets", "~> 0.4.1"
29
30
  end
data/exe/dxopal CHANGED
@@ -31,14 +31,16 @@ module DXOpal
31
31
  end
32
32
 
33
33
  desc "server", "Start local server"
34
+ option "port", aliases: :p, type: :numeric, default: 7521
34
35
  def server
35
36
  puts "Starting DXOpal Server"
36
- puts "(Open http://localhost:7521/index.html in browser)"
37
+ puts "(Open http://localhost:#{options[:port]}/index.html in the browser)"
37
38
  puts "---"
38
39
  app = Rack::Directory.new(Dir.pwd)
39
- Rack::Server.start(app: app, Port: 7521)
40
+ Rack::Server.start(app: app, Port: options[:port])
40
41
  end
41
42
  end
42
43
  end
43
44
 
45
+ puts "DXOpal v#{DXOpal::VERSION}"
44
46
  DXOpal::Cli.start
data/index.html CHANGED
@@ -23,6 +23,7 @@
23
23
  <canvas id="dxopal-canvas" style='float: left'></canvas>
24
24
  <div id="editor" style='width: 350px; height: 300px; position: relative'></div>
25
25
  <input type='button' style='float: right' id='run' value='Run'>
26
+ <div id="dxopal-errors"></div>
26
27
  </section>
27
28
  </div>
28
29
 
@@ -42,6 +43,7 @@
42
43
  editor.setValue(rb, -1); // -1: set cursor to document start
43
44
  });
44
45
  $('#run').on("click", function() {
46
+ $('#dxopal-errors').empty();
45
47
  try {
46
48
  eval(Opal.compile(editor.getValue()));
47
49
  }
@@ -14,6 +14,8 @@ require 'dxopal/version'
14
14
  # Enable runtime compilation of Opal code (so that you can make games
15
15
  # without even install Ruby)
16
16
  require 'opal-parser'
17
+
18
+ # Patch to opal-parser
17
19
  def require_remote(url)
18
20
  %x{
19
21
  var r = new XMLHttpRequest();
@@ -33,6 +35,29 @@ module DXOpal
33
35
  include DXOpal::Input::MouseCodes
34
36
  include DXOpal::SoundEffect::WaveTypes
35
37
 
38
+ # Call block and dump backtrace if an exception is raised.
39
+ # Nothing is shown if a tag with `id='dxopal-errors'` does not exist
40
+ def self.dump_error(&block)
41
+ block.call
42
+ rescue Exception => ex
43
+ div = `document.getElementById('dxopal-errors')`
44
+ if `div && !ex.DXOpalPrinted`
45
+ %x{
46
+ div.textContent = "ERROR: " + #{ex.class.name};
47
+ var ul = document.createElement('ul');
48
+ // Note: ex.backtrace may be an Array or a String
49
+ #{Array(ex.backtrace)}.forEach(function(line){
50
+ var li = document.createElement('li');
51
+ li.textContent = line;
52
+ ul.appendChild(li);
53
+ });
54
+ div.appendChild(ul);
55
+ ex.DXOpalPrinted = true;
56
+ }
57
+ end
58
+ raise ex
59
+ end
60
+
36
61
  # Like `Kernel.p`, but prints only limited times for each `key`
37
62
  # This is useful for debugging your game without flooding the
38
63
  # developer console.
@@ -49,6 +74,23 @@ module DXOpal
49
74
  end
50
75
  end
51
76
 
77
+ %x{
78
+ // Like `console.log`, but prints only limited times.
79
+ // Example:
80
+ // Opal.DXOpal.p_("player", player)
81
+ (function(){
82
+ var P_CT = {};
83
+ Opal.DXOpal.p_ = function(key, obj, n) {
84
+ n = (n || 10);
85
+ P_CT[key] = (P_CT[key] || 0);
86
+ if (P_CT[key] < n) {
87
+ console.log(key, obj);
88
+ P_CT[key] += 1;
89
+ }
90
+ };
91
+ })();
92
+ }
93
+
52
94
  # `require 'dxopal'` will automatically import names like `Window` to the
53
95
  # toplevel (as `require 'dxruby'` does)
54
96
  include DXOpal
@@ -1,4 +1,6 @@
1
1
  module DXOpal
2
+ # Represents a font
3
+ # Used by Window.draw_font, etc.
2
4
  class Font
3
5
  def self.default; @@default ||= Font.new(24); end
4
6
  def self.default=(f); @@default = f; end
@@ -1,6 +1,8 @@
1
1
  require 'dxopal/remote_resource'
2
2
 
3
3
  module DXOpal
4
+ # Represents an image
5
+ # Each instance of Image has its own off-screen canvas.
4
6
  class Image < RemoteResource
5
7
  RemoteResource.add_class(Image)
6
8
 
@@ -53,6 +55,14 @@ module DXOpal
53
55
  return self
54
56
  end
55
57
 
58
+ # Draw an Image on this image with scaling
59
+ # - scale_x, scale_y: scaling factor (eg. 1.5)
60
+ # - center_x, center_y: scaling center (in other words, the point
61
+ # which does not move by this scaling. Default: image center)
62
+ def draw_scale(x, y, image, scale_x, scale_y, center_x=nil, center_y=nil)
63
+ draw_ex(x, y, image, scale_x: scale_x, scale_y: scale_y, center_x: center_x, center_y: center_y)
64
+ end
65
+
56
66
  # Draw an Image on this image with rotation
57
67
  # - angle: Rotation angle (radian)
58
68
  # - center_x, center_y: Rotation center in the `image` (default: center of the `image`)
@@ -231,7 +241,7 @@ module DXOpal
231
241
  def slice(x, y, width, height)
232
242
  newimg = Image.new(width, height)
233
243
  data = _image_data(x, y, width, height)
234
- newimg._put_image_data(data, 0, 0)
244
+ newimg._put_image_data(data)
235
245
  return newimg
236
246
  end
237
247
 
@@ -246,10 +256,27 @@ module DXOpal
246
256
  }
247
257
  end
248
258
 
259
+ # Set alpha of the pixels of the given color to 0
260
+ # - color : RGB color (If ARGV color is given, A is just ignored)
261
+ def set_color_key(color)
262
+ r, g, b, _ = _rgba_ary(color)
263
+ data = _image_data()
264
+ %x{
265
+ var buf = data.data;
266
+
267
+ for(var i = 0; i < buf.length; i += 4){
268
+ if (buf[i] == r && buf[i+1] == g && buf[i+2] == b) {
269
+ buf[i+3] = 0
270
+ }
271
+ }
272
+ }
273
+ _put_image_data(data)
274
+ end
275
+
249
276
  # Copy an <img> onto this image
250
277
  def _draw_raw_image(x, y, raw_img)
251
278
  %x{
252
- #{@ctx}.drawImage(#{raw_img}, x, y)
279
+ #{@ctx}.drawImage(#{raw_img}, x, y);
253
280
  }
254
281
  end
255
282
 
@@ -259,7 +286,7 @@ module DXOpal
259
286
  end
260
287
 
261
288
  # Call .putImageData
262
- def _put_image_data(image_data, x, y)
289
+ def _put_image_data(image_data, x=0, y=0)
263
290
  `#{@ctx}.putImageData(image_data, x, y)`
264
291
  end
265
292
 
@@ -1,9 +1,6 @@
1
1
  module DXOpal
2
2
  module Input
3
3
  module KeyCodes
4
- K_SPACE = " "
5
- K_X = "x"
6
-
7
4
  K_ESCAPE = 27
8
5
  # K_1 1
9
6
  # K_2 2
@@ -2,6 +2,8 @@ module DXOpal
2
2
  # A base class for resources acquired through JS Promises.
3
3
  # Provides `<klass>.register` and `<klass>[name]`.
4
4
  # A subclass must impelment `<klass>._load`.
5
+ #
6
+ # TODO: better name? (SoundEffect is not actually 'remote')
5
7
  class RemoteResource
6
8
  # List of registered resources (Contains path_or_url)
7
9
  @@resources = Hash.new{|h,k| h[k] = {}}
@@ -7,6 +7,8 @@ module DXOpal
7
7
  # v = v - 0.03
8
8
  # [rand(300), v]
9
9
  # end
10
+ #
11
+ # This will generate a sound with WebAudio.
10
12
  class SoundEffect < Sound
11
13
  RemoteResource.add_class(SoundEffect)
12
14
 
@@ -79,6 +81,7 @@ module DXOpal
79
81
  end
80
82
 
81
83
  def add(wave_type=WAVE_RECT, resolution=1000)
84
+ TODO
82
85
  end
83
86
  end
84
87
  end
@@ -5,8 +5,28 @@ module DXOpal
5
5
  # Methods of Sprite related to collision checking
6
6
  module CollisionCheck
7
7
  module ClassMethods
8
- # TODO: implement arguments `shot` and `hit`
8
+ # Run collision checking for set of sprites
9
+ # - offences: Sprite or [Sprite]
10
+ # - defences: Sprite or [Sprite]
11
+ # - shot: method name
12
+ # - hit: method name
13
+ #
14
+ # This method has two modes.
15
+ # - If `offences` and `defences` are the same, collision check will
16
+ # be performed on each pair from the array. Method `hit` is called
17
+ # on the each sprite, with the other sprite as an argument.
18
+ # - Otherwise, collision check will be performed on each pair
19
+ # of offence sprite and defence sprite. In this case,
20
+ # method `shot` is called on the offence sprite and
21
+ # method `hit` is called on the defence sprite, with the
22
+ # other sprite as an argument.
23
+ #
24
+ # TODO: return true if any collition is detected
25
+ # TODO: skip collision checking if shot/hit returned `:discard`
9
26
  def check(offences, defences, shot=:shot, hit=:hit)
27
+ offences = Array(offences)
28
+ defences = Array(defences)
29
+ i = j = 0 # trick to use i, j in the `#{}`
10
30
  if offences.equal?(defences)
11
31
  # any-vs-any mode
12
32
  sprites = offences.select{|x| x.is_a?(Sprite)}
@@ -14,9 +34,9 @@ module DXOpal
14
34
  %x{
15
35
  for (var i=0; i<n; i++) {
16
36
  for (var j=i+1; j<n; j++) {
17
- if (sprites[i]['$==='](sprites[j])) {
18
- sprites[i]['$hit']();
19
- sprites[j]['$hit']();
37
+ if (#{sprites[i] === sprites[j]}) {
38
+ #{sprites[i].__send__(hit)};
39
+ #{sprites[j].__send__(hit)};
20
40
  }
21
41
  }
22
42
  }
@@ -26,9 +46,9 @@ module DXOpal
26
46
  %x{
27
47
  for (var i=0; i<offences.length; i++) {
28
48
  for (var j=0; j<defences.length; j++) {
29
- if (offences[i]['$==='](defences[j])) {
30
- offences[i]['$shot'](defences[j]);
31
- defences[j]['$hit'](offences[i]);
49
+ if (#{offences[i] === defences[j]}) {
50
+ #{offences[i].__send__(shot, defences[j])};
51
+ #{defences[j].__send__(hit, offences[i])};
32
52
  }
33
53
  }
34
54
  }
@@ -1,4 +1,6 @@
1
1
  # vim: set ft=javascript:
2
+ # Collision checking algorithm, implemented in JavaScript.
3
+ # Available as `Opal.DXOpal.CollisionChecker` in the runtime.
2
4
  %x{ (function(){
3
5
 
4
6
  var intersect = function(x1, y1, x2, y2, x3, y3, x4, y4){
@@ -1,6 +1,8 @@
1
1
  module DXOpal
2
2
  class Sprite
3
- # Physics engine powered by Matter.js
3
+ # Experimental Matter.js (physics engine) support
4
+ #
5
+ # You need to load matter.js in advance to using these features.
4
6
  module Physics
5
7
  # Create Matter Body and register it to the World
6
8
  # - type: :rectangle, etc.
@@ -56,7 +58,9 @@ module DXOpal
56
58
 
57
59
  # Return true if `physical_body=` is ever called
58
60
  def self.matter_enabled?
59
- `!!#{@matter_engine}`
61
+ # Note: we cannot use `!!` here because @matter_engine may be a JS object,
62
+ # which does not have Ruby's `!@` method
63
+ @matter_engine ? true : false
60
64
  end
61
65
 
62
66
  # Call Matter.Runner.tick
@@ -1,3 +1,3 @@
1
1
  module DXOpal
2
- VERSION = "1.0.0"
2
+ VERSION = "1.1.0"
3
3
  end
@@ -14,7 +14,9 @@ module DXOpal
14
14
  # Load resources specified with Image.register or Sound.register
15
15
  # Call block when loaded
16
16
  def self.load_resources(&block)
17
- RemoteResource._load_resources(&block)
17
+ RemoteResource._load_resources do
18
+ DXOpal.dump_error(&block)
19
+ end
18
20
  end
19
21
 
20
22
  # Start main loop
@@ -22,8 +24,9 @@ module DXOpal
22
24
  # When called twice, previous loop is stopped (this is useful
23
25
  # when implementing interactive game editor, etc.)
24
26
  def self.loop(&block)
27
+ already_running = !!@@block
25
28
  @@block = block
26
- `window`.JS.requestAnimationFrame{|time| _loop(time) }
29
+ _loop unless already_running
27
30
  end
28
31
 
29
32
  # (DXOpal original) Pause & resume
@@ -43,7 +46,7 @@ module DXOpal
43
46
  end
44
47
 
45
48
  # (internal) call @@block periodically
46
- def self._loop(time)
49
+ def self._loop(time=0)
47
50
  @@img ||= _init(@@width, @@height)
48
51
  t0 = Time.now
49
52
 
@@ -67,7 +70,7 @@ module DXOpal
67
70
  if @@paused
68
71
  Window.draw_pause_screen
69
72
  else
70
- @@block.call
73
+ DXOpal.dump_error(&@@block)
71
74
  end
72
75
 
73
76
  # Draw
@@ -77,6 +80,7 @@ module DXOpal
77
80
  case item[2]
78
81
  when :image then @@img.draw(*item.drop(3))
79
82
  when :image_rot then @@img.draw_rot(*item.drop(3))
83
+ when :image_scale then @@img.draw_scale(*item.drop(3))
80
84
  when :draw_ex then @@img.draw_ex(*item.drop(3))
81
85
  when :font then @@img.draw_font(*item.drop(3))
82
86
  when :pixel then @@img.[]=(*item.drop(3))
@@ -120,6 +124,10 @@ module DXOpal
120
124
  enqueue_draw(z, :image, x, y, image)
121
125
  end
122
126
 
127
+ def self.draw_scale(x, y, image, scale_x, scale_y, center_x=nil, center_y=nil, z=0)
128
+ enqueue_draw(z, :image_scale, x, y, image, scale_x, scale_y, center_x, center_y)
129
+ end
130
+
123
131
  def self.draw_rot(x, y, image, angle, center_x=nil, center_y=nil, z=0)
124
132
  enqueue_draw(z, :image_rot, x, y, image, angle, center_x, center_y)
125
133
  end
@@ -166,6 +174,7 @@ module DXOpal
166
174
  enqueue_draw(z, :triangle_fill, x1, y1, x2, y2, x3, y3, color)
167
175
  end
168
176
 
177
+ # (internal)
169
178
  def self.enqueue_draw(z, *args)
170
179
  @@draw_queue.push([z, @@draw_queue.length, *args])
171
180
  end
@@ -4,10 +4,13 @@
4
4
  <meta charset= "utf-8" />
5
5
  <title>DXOpal game</title>
6
6
  <script type="text/javascript" src="dxopal.min.js"></script>
7
- <script type="text/ruby" src="main.rb"></script>
7
+ <script type="text/ruby">
8
+ DXOpal.dump_error{ require_remote 'main.rb' }
9
+ </script>
8
10
  </head>
9
11
 
10
12
  <body>
11
13
  <canvas id="dxopal-canvas"></canvas>
14
+ <div id="dxopal-errors"></div>
12
15
  </body>
13
16
  </html>