dxopal 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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