dxopal 1.0.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 (64) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +5 -0
  3. data/.ignore +5 -0
  4. data/.nojekyll +4 -0
  5. data/CHANGELOG.md +90 -0
  6. data/DEVELOPMENT.md +57 -0
  7. data/Gemfile +2 -0
  8. data/Gemfile.lock +39 -0
  9. data/README.md +22 -0
  10. data/Rakefile +66 -0
  11. data/TODO.md +278 -0
  12. data/build/dxopal.js +46590 -0
  13. data/build/dxopal.min.js +1 -0
  14. data/config.ru +39 -0
  15. data/doc/api/DXOpal.html +129 -0
  16. data/doc/api/DXOpal/Font.html +485 -0
  17. data/doc/api/DXOpal/Image.html +2533 -0
  18. data/doc/api/DXOpal/Input.html +1086 -0
  19. data/doc/api/DXOpal/Input/MouseCodes.html +146 -0
  20. data/doc/api/DXOpal/RemoteResource.html +641 -0
  21. data/doc/api/DXOpal/Sound.html +568 -0
  22. data/doc/api/DXOpal/SoundEffect.html +444 -0
  23. data/doc/api/DXOpal/SoundEffect/WaveTypes.html +130 -0
  24. data/doc/api/DXOpal/Sprite.html +1419 -0
  25. data/doc/api/DXOpal/Window.html +1915 -0
  26. data/doc/api/_index.html +228 -0
  27. data/doc/api/class_list.html +51 -0
  28. data/doc/api/css/common.css +1 -0
  29. data/doc/api/css/full_list.css +58 -0
  30. data/doc/api/css/style.css +492 -0
  31. data/doc/api/file.CHANGELOG.html +162 -0
  32. data/doc/api/file.README.html +124 -0
  33. data/doc/api/file_list.html +61 -0
  34. data/doc/api/frames.html +17 -0
  35. data/doc/api/index.html +124 -0
  36. data/doc/api/js/app.js +248 -0
  37. data/doc/api/js/full_list.js +216 -0
  38. data/doc/api/js/jquery.js +4 -0
  39. data/doc/api/method_list.html +939 -0
  40. data/doc/api/top-level-namespace.html +110 -0
  41. data/doc/en/index.html +93 -0
  42. data/doc/ja/index.html +92 -0
  43. data/dxopal.gemspec +29 -0
  44. data/exe/dxopal +44 -0
  45. data/index.html +56 -0
  46. data/opal/dxopal.rb +54 -0
  47. data/opal/dxopal/constants/colors.rb +16 -0
  48. data/opal/dxopal/font.rb +20 -0
  49. data/opal/dxopal/image.rb +301 -0
  50. data/opal/dxopal/input.rb +170 -0
  51. data/opal/dxopal/input/key_codes.rb +168 -0
  52. data/opal/dxopal/remote_resource.rb +65 -0
  53. data/opal/dxopal/sound.rb +53 -0
  54. data/opal/dxopal/sound_effect.rb +84 -0
  55. data/opal/dxopal/sprite.rb +94 -0
  56. data/opal/dxopal/sprite/collision_area.rb +288 -0
  57. data/opal/dxopal/sprite/collision_check.rb +106 -0
  58. data/opal/dxopal/sprite/collision_checker.rb +169 -0
  59. data/opal/dxopal/sprite/physics.rb +82 -0
  60. data/opal/dxopal/version.rb +3 -0
  61. data/opal/dxopal/window.rb +173 -0
  62. data/template/index.html +13 -0
  63. data/template/main.rb +9 -0
  64. metadata +191 -0
@@ -0,0 +1,168 @@
1
+ module DXOpal
2
+ module Input
3
+ module KeyCodes
4
+ K_SPACE = " "
5
+ K_X = "x"
6
+
7
+ K_ESCAPE = 27
8
+ # K_1 1
9
+ # K_2 2
10
+ # K_3 3
11
+ # K_4 4
12
+ # K_5 5
13
+ # K_6 6
14
+ # K_7 7
15
+ # K_8 8
16
+ # K_9 9
17
+ # K_0 0
18
+ K_MINUS = 189
19
+ #K_EQUALS = "="
20
+ K_BACK = 8 # Backspace
21
+ K_TAB = 9
22
+ K_Q = 81
23
+ K_W = 87
24
+ K_E = 69
25
+ K_R = 82
26
+ K_T = 84
27
+ K_Y = 89
28
+ K_U = 85
29
+ K_I = 73
30
+ K_O = 79
31
+ K_P = 80
32
+ K_LBRACKET = 219
33
+ K_RBRACKET = 221
34
+ K_RETURN = 13
35
+ #K_LCONTROL Ctrl
36
+ K_A = 65
37
+ K_S = 83
38
+ K_D = 68
39
+ K_F = 70
40
+ K_G = 71
41
+ K_H = 72
42
+ K_J = 74
43
+ K_K = 75
44
+ K_L = 76
45
+ K_SEMICOLON = 186
46
+ #K_APOSTROPHE = "'"
47
+ #K_GRAVE = "`"
48
+ #K_LSHIFT Shift
49
+ K_BACKSLASH = 0
50
+ K_Z = 90
51
+ K_X = 88
52
+ K_C = 67
53
+ K_V = 86
54
+ K_B = 66
55
+ K_N = 78
56
+ K_M = 77
57
+ K_COMMA = 188
58
+ K_PERIOD = 190
59
+ K_SLASH = 191
60
+ #K_RSHIFT Shift
61
+ #K_MULTIPLY = "*"
62
+ #K_LMENU Alt
63
+ K_SPACE = 32
64
+ #K_CAPITAL Caps Lock
65
+ K_F1 = 112
66
+ K_F2 = 113
67
+ K_F3 = 114
68
+ K_F4 = 115
69
+ K_F5 = 116
70
+ K_F6 = 117
71
+ K_F7 = 118
72
+ K_F8 = 119
73
+ K_F9 = 120
74
+ K_F10 = 121
75
+ #K_NUMLOCK = "NumLock"
76
+ #K_SCROLL = "ScrollLock"
77
+ #K_NUMPAD7 7 *3
78
+ #K_NUMPAD8 8 *3
79
+ #K_NUMPAD9 9 *3
80
+ #K_SUBTRACT - *3
81
+ #K_NUMPAD4 4 *3
82
+ #K_NUMPAD5 5 *3
83
+ #K_NUMPAD6 6 *3
84
+ #K_ADD + *3
85
+ #K_NUMPAD1 1 *3
86
+ #K_NUMPAD2 2 *3
87
+ #K_NUMPAD3 3 *3
88
+ #K_NUMPAD0 0 *3
89
+ #K_DECIMAL . *3
90
+ #K_OEM_102
91
+ K_F11 = 122
92
+ K_F12 = 123
93
+ K_F13 = 124
94
+ K_F14 = 125
95
+ K_F15 = 126
96
+ #K_KANA
97
+ #K_ABNT_C1
98
+ #K_CONVERT
99
+ #K_NOCONVERT
100
+ #K_YEN
101
+ #K_ABNT_C2
102
+ #K_NUMPADEQUALS = *3 *1
103
+ K_PREVTRACK = 187 # ^
104
+ K_AT = 219 # @
105
+ K_COLON = 186
106
+ K_UNDERLINE = 189 # _
107
+ #K_KANJI
108
+ #K_STOP
109
+ #K_AX
110
+ #K_UNLABELED
111
+ #K_NEXTTRACK
112
+ #K_NUMPADENTER Enter *3
113
+ #K_RCONTROL Ctrl
114
+ #K_MUTE
115
+ #K_CALCULATOR
116
+ #K_PLAYPAUSE
117
+ #K_MEDIASTOP
118
+ #K_VOLUMEDOWN
119
+ #K_VOLUMEUP
120
+ #K_WEBHOME
121
+ #K_NUMPADCOMMA , *3 *1
122
+ #K_DIVIDE / *3
123
+ #K_SYSRQ
124
+ #K_RMENU Alt
125
+ #K_PAUSE = "Pause"
126
+ #K_HOME "Home"
127
+ K_UP = 38
128
+ #K_PRIOR
129
+ K_LEFT = 37
130
+ K_RIGHT = 39
131
+ #K_END = "End"
132
+ K_DOWN = 40
133
+ #K_NEXT
134
+ #K_INSERT = "Insert"
135
+ #K_DELETE = "Delete"
136
+ #K_LWIN Windows
137
+ #K_RWIN Windows
138
+ #K_APPS
139
+ #K_POWER
140
+ #K_SLEEP
141
+ #K_WAKE
142
+ #K_WEBSEARCH
143
+ #K_WEBFAVORITES
144
+ #K_WEBREFRESH
145
+ #K_WEBSTOP
146
+ #K_WEBFORWARD
147
+ #K_WEBBACK
148
+ #K_MYCOMPUTER
149
+ #K_MAIL
150
+ #K_MEDIASELECT
151
+ K_BACKSPACE = 8
152
+ #K_NUMPADSTAR * *3
153
+ #K_LALT Alt
154
+ #K_CAPSLOCK CapsLock
155
+ #K_NUMPADMINUS - *3
156
+ #K_NUMPADPLUS + *3
157
+ #K_NUMPADPERIOD . *3
158
+ #K_NUMPADSLASH / *3
159
+ #K_RALT Alt
160
+ K_UPARROW = 38
161
+ #K_PGUP = "PageUp"
162
+ K_LEFTARROW = 37
163
+ K_RIGHTARROW = 39
164
+ K_DOWNARROW = 40
165
+ #K_PGDN = "PageDown"
166
+ end
167
+ end
168
+ end
@@ -0,0 +1,65 @@
1
+ module DXOpal
2
+ # A base class for resources acquired through JS Promises.
3
+ # Provides `<klass>.register` and `<klass>[name]`.
4
+ # A subclass must impelment `<klass>._load`.
5
+ class RemoteResource
6
+ # List of registered resources (Contains path_or_url)
7
+ @@resources = Hash.new{|h,k| h[k] = {}}
8
+ # Contains promises
9
+ @@promises = Hash.new{|h,k| h[k] = {}}
10
+ # Contains instances of Image, Sound
11
+ @@instances = Hash.new{|h,k| h[k] = {}}
12
+
13
+ # Subclasses of RemoteResource
14
+ @@klasses = {}
15
+ def self.add_class(subklass)
16
+ @@klasses[subklass._klass_name] = subklass
17
+ end
18
+
19
+ # Reserve instance generation
20
+ def self.register(name, *args, &block)
21
+ @@resources[_klass_name] ||= {}
22
+ @@resources[_klass_name][name] = [block, args]
23
+ end
24
+
25
+ # Return instance of loaded resource (call on subclasses)
26
+ def self.[](name)
27
+ if (ret = @@instances[_klass_name][name])
28
+ return ret
29
+ else
30
+ raise "#{_klass_name} #{name.inspect} is not registered"
31
+ end
32
+ end
33
+
34
+ # Called from Window.load_resources
35
+ def self._load_resources(&block)
36
+ @@resources.each do |klass_name, items|
37
+ klass = @@klasses[klass_name]
38
+ items.each do |name, (block, args)|
39
+ if !@@promises[klass_name][name]
40
+ instance, promise = klass._load(*args, &block)
41
+ @@instances[klass_name][name] = instance
42
+ @@promises[klass_name][name] = promise
43
+ end
44
+ end
45
+ end
46
+ promises = @@promises.values.flat_map(&:values)
47
+ %x{
48
+ Promise.all(#{promises}).then(function() {
49
+ #{block.call}
50
+ });
51
+ }
52
+ end
53
+
54
+ # Load actual content (defined on subclasses)
55
+ # Return `[instance, promise]`
56
+ def self._load(*args)
57
+ raise "override me"
58
+ end
59
+
60
+ # Return a string like "Image" or "Sound"
61
+ def self._klass_name
62
+ return self.name.split(/::/).last
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,53 @@
1
+ require 'dxopal/remote_resource'
2
+
3
+ module DXOpal
4
+ class Sound < RemoteResource
5
+ RemoteResource.add_class(Sound)
6
+
7
+ # Return AudioContext
8
+ def self.audio_context
9
+ @@audio_context ||= %x{
10
+ new (window.AudioContext||window.webkitAudioContext)
11
+ }
12
+ end
13
+
14
+ # Load remote sound (called via Window.load_resources)
15
+ def self._load(path_or_url)
16
+ snd = new(path_or_url)
17
+ snd_promise = %x{
18
+ new Promise(function(resolve, reject) {
19
+ var request = new XMLHttpRequest();
20
+ request.open('GET', #{path_or_url}, true);
21
+ request.responseType = 'arraybuffer';
22
+ request.onload = function() {
23
+ var audioData = request.response;
24
+ var context = #{Sound.audio_context};
25
+ context.decodeAudioData(audioData, function(decoded) {
26
+ snd['$decoded='](decoded);
27
+ resolve();
28
+ });
29
+ };
30
+ request.send();
31
+ });
32
+ }
33
+ return snd, snd_promise
34
+ end
35
+
36
+ def initialize(path_or_url)
37
+ @path_or_url = path_or_url # Used in error message
38
+ end
39
+ attr_accessor :decoded
40
+
41
+ # Play this sound once
42
+ def play
43
+ raise "Sound #{path_or_url} is not loaded yet" unless @decoded
44
+ %x{
45
+ var context = #{Sound.audio_context};
46
+ var source = context.createBufferSource();
47
+ source.buffer = #{@decoded};
48
+ source.connect(context.destination);
49
+ source.start(0);
50
+ }
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,84 @@
1
+ module DXOpal
2
+ # User-generated sound
3
+ #
4
+ # Example:
5
+ # v = 80
6
+ # SoundEffect.register(:sound1, 4000, WAVE_RECT, 5000) do
7
+ # v = v - 0.03
8
+ # [rand(300), v]
9
+ # end
10
+ class SoundEffect < Sound
11
+ RemoteResource.add_class(SoundEffect)
12
+
13
+ module WaveTypes
14
+ WAVE_SIN = :sine
15
+ WAVE_SAW = :sawtooth
16
+ WAVE_TRI = :triangle
17
+ WAVE_RECT = :square
18
+ end
19
+
20
+ # time : Total number of ticks
21
+ # When resolution=1000(default), `time` is equivalent to the
22
+ # total length of the sound in milliseconds.
23
+ # wave_type : Type of wave form
24
+ # resolution : Number of ticks per second
25
+ # block : Should return [freq(0~44100), volume(0~255)]
26
+ def self._load(time, wave_type=WAVE_RECT, resolution=1000, &block)
27
+ snd = new("(soundeffect)")
28
+ snd_promise = %x{
29
+ new Promise(function(resolve, reject){
30
+ var n_channels = 1;
31
+ var context = #{Sound.audio_context};
32
+ var n_ticks = #{time};
33
+ var totalSeconds = #{time / resolution};
34
+ var valuesPerSecond = context.sampleRate;
35
+ var n_values = totalSeconds * valuesPerSecond;
36
+ var myArrayBuffer = context.createBuffer(n_channels, n_values, valuesPerSecond);
37
+ var values = myArrayBuffer.getChannelData(0);
38
+ var n = 0;
39
+ for (var i = 0; i < n_ticks; i++) {
40
+ var ret = #{block.call};
41
+ var freq = ret[0], volume = ret[1];
42
+ if (freq < 0) freq = 0;
43
+ if (freq > 44100) freq = 44100;
44
+ if (volume < 0) volume = 0;
45
+ if (volume > 255) volume = 255;
46
+ var vol = volume / 255; // 0.0~1.0
47
+
48
+ var period = valuesPerSecond * 1 / freq;
49
+ for (; n < ((i+1) / n_ticks * n_values); n++) {
50
+ var phase = (n % period) / period; // 0.0~1.0
51
+ var value; // -1.0~1.0
52
+ switch(#{wave_type}) {
53
+ case "sine":
54
+ value = Math.sin(2 * Math.PI * phase) * 2 - 1;
55
+ break;
56
+ case "sawtooth":
57
+ value = phase * 2 - 1;
58
+ break;
59
+ case "triangle":
60
+ value = phase < 0.25 ? 0+phase*4 :
61
+ phase < 0.5 ? 1-(phase-0.25)*4 :
62
+ phase < 0.75 ? 0-(phase-0.5)*4 :
63
+ -1+(phase-0.75)*4;
64
+ break;
65
+ case "square":
66
+ value = (phase < 0.5 ? 1 : -1);
67
+ break;
68
+ default:
69
+ #{raise "unknown wave_type: " + wave_type.inspect};
70
+ }
71
+ values[n] = value * vol;
72
+ }
73
+ }
74
+ snd['$decoded='](myArrayBuffer);
75
+ resolve();
76
+ });
77
+ }
78
+ return snd, snd_promise
79
+ end
80
+
81
+ def add(wave_type=WAVE_RECT, resolution=1000)
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,94 @@
1
+ require 'dxopal/sprite/collision_check'
2
+ require 'dxopal/sprite/physics'
3
+
4
+ module DXOpal
5
+ class Sprite
6
+ extend DXOpal::Sprite::CollisionCheck::ClassMethods
7
+ include DXOpal::Sprite::CollisionCheck
8
+ include DXOpal::Sprite::Physics
9
+
10
+ # Call #update on each sprite (unless it is vanished or do not have #update)
11
+ def self.update(sprites)
12
+ sprites.each do |sprite|
13
+ next if !sprite.respond_to?(:update)
14
+ next if sprite.respond_to?(:vanished?) && sprite.vanished?
15
+ sprite.update
16
+ end
17
+ end
18
+
19
+ # Remove vanished sprites (and nils) from the array, destructively
20
+ def self.clean(sprites)
21
+ sprites.reject!{|sprite|
22
+ sprite.nil? || sprite.vanished?
23
+ }
24
+ end
25
+
26
+ # Draw each of the given sprites (unless it is vanished)
27
+ def self.draw(sprites)
28
+ sprites.flatten.sort_by(&:z).each do |sprite|
29
+ next if sprite.respond_to?(:vanished?) && sprite.vanished?
30
+ sprite.draw
31
+ end
32
+ end
33
+
34
+ def initialize(x=0, y=0, image=nil)
35
+ @x, @y, @image = x, y, image
36
+ @z = 0
37
+ @angle = 0
38
+ @scale_x = @scale_y = 1.0
39
+ if image
40
+ @center_x = image.width / 2
41
+ @center_y = image.height / 2
42
+ end
43
+
44
+ @visible = true
45
+ @vanished = false
46
+ _init_collision_info(@image)
47
+ end
48
+ attr_accessor :z, :visible
49
+
50
+ # Set angle (0~360, default: 0)
51
+ attr_accessor :angle
52
+ # Set horizontal/vertical scale (default: 1.0)
53
+ attr_accessor :scale_x, :scale_y
54
+ # Set rotation center (default: center of `image`)
55
+ attr_accessor :center_x, :center_y
56
+
57
+ attr_reader :x, :y
58
+
59
+ def x=(newx)
60
+ @x = newx
61
+ _move_matter_body if @_matter_body
62
+ end
63
+
64
+ def y=(newy)
65
+ @y = newy
66
+ _move_matter_body if @_matter_body
67
+ end
68
+
69
+ def image; @image; end
70
+ def image=(img)
71
+ @image = img
72
+ if @collision.nil?
73
+ self.collision = [0, 0, img.width-1, img.height-1]
74
+ end
75
+ if @center_x.nil?
76
+ @center_x = img.width / 2
77
+ @center_y = img.height / 2
78
+ end
79
+ end
80
+
81
+ def vanish; @vanished = true; end
82
+ def vanished?; @vanished; end
83
+
84
+ # Draw this sprite to Window
85
+ def draw
86
+ raise "image not set to Sprite" if @image.nil?
87
+ return if !@visible
88
+
89
+ Window.draw_ex(@x, @y, @image,
90
+ scale_x: @scale_x, scale_y: @scale_y,
91
+ angle: @angle, center_x: @center_x, center_y: @center_y)
92
+ end
93
+ end
94
+ end