dxopal 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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>