author_engine 0.4.0 → 0.5.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 694fa108a1f195431f1a2e19a9c27f23b26b1749d671f564f8cbbf4a5763b6a7
4
- data.tar.gz: 0b366a28a323cd1dbc2fff3854ee6785fd35561ec0c0f6cf2d175dcddf5eba7d
3
+ metadata.gz: 240a86f7ca8210f55b1000684999a28d178bb8aee05816924c09987279930acb
4
+ data.tar.gz: b020c530b4e217ff3b2c6fa8f956eae3a7faef8c3e07de8226fdbd239a0adec9
5
5
  SHA512:
6
- metadata.gz: 5516f268ab834bc8ea4b78e81a12ece30471e9dfd8a88a79bd21265067a161345bc923825572917afb17a2222cec2214b7d02768b9ec1fe4836346f007914769
7
- data.tar.gz: f047c5ca5837b0ccac07690fb9ce939e22705bb90357837e66ca8d35bb3570ac1de98b22bbbeeb774b4cd07462334833cfb3d691054e56e1c197c20a44bb1b19
6
+ metadata.gz: 979bd0fc59a1767dede59ca38f1ac63965beb8c538c95c25fd824d7d5c0b4449508d83f4dec6bc2e4b0d8c046f37f35c1995da4f2460e4d9562534d59b4e41fd
7
+ data.tar.gz: d105fe0793a73d82bb36c69623a031ad0a45ffd0dfbae4027a55e4a77e05bcd75be360fc9fa8427080a2ab1dc4f993f87065a63b0fdbb7e1ec89c99dbc2649d6
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- author_engine (0.4.0)
4
+ author_engine (0.5.0)
5
5
  coderay (~> 1.1.2)
6
6
  gosu (~> 0.14.4)
7
7
  opal (~> 0.11.4)
@@ -14,6 +14,21 @@ class AuthorEngine
14
14
  return name.split("_").map {|n| n.capitalize}.join(" ")
15
15
  end
16
16
 
17
+ # Rebuild opal runtime of it doesn't exist or if its out of date
18
+ def build_opal?
19
+ opal_runtime = "#{export_directory}/js/runtime.js"
20
+
21
+ if File.exists?(opal_runtime)
22
+ file = File.open(opal_runtime)
23
+ version = file.first.gsub("/", "").strip
24
+ file.close
25
+
26
+ Opal::VERSION != version
27
+ else
28
+ true
29
+ end
30
+ end
31
+
17
32
  def stylesheet
18
33
  %{
19
34
  @font-face { font-family: Connection; src: url('fonts/Connection.otf'); }
@@ -27,7 +42,7 @@ body {
27
42
  #canvas {
28
43
  display: block;
29
44
  margin: 0 auto;
30
- cursor: none;
45
+ // cursor: none;
31
46
  }
32
47
  #loading {
33
48
  font-family: Connection, sans serif;
@@ -54,8 +69,8 @@ var projectString = `#{File.open(@project_file).read}`;
54
69
 
55
70
  def game_runtime
56
71
  program = %{
57
- require "opal"
58
- require "opal-parser"
72
+ # require "opal"
73
+ # require "opal-parser"
59
74
  require "author_engine/opal"
60
75
 
61
76
  `var callback = function(){
@@ -72,18 +87,34 @@ if (
72
87
  }`
73
88
  }
74
89
 
75
- builder = Opal::Builder.new
90
+ puts "Transpiling to JavaScript using Opal..."
91
+
92
+ opal_builder = nil
93
+ if build_opal?
94
+ puts " Building Opal runtime..."
95
+
96
+ opal_builder = Opal::Builder.new
97
+ opal_builder.build("opal")
98
+ opal_builder.build("opal-parser")
99
+ else
100
+ puts " Skipping Opal runtime. Already exists as v#{Opal::VERSION}..."
101
+ end
102
+
103
+ puts " Building AuthorEngine runtime with project..."
104
+ game_builder = Opal::Builder.new
76
105
  base_path = File.expand_path("../../../..", __FILE__)
77
- builder.append_paths("#{base_path}")
106
+ game_builder.append_paths("#{base_path}")
78
107
 
79
- puts "Transpiling to JavaScript using Opal..."
108
+ game_builder.build_require("author_engine/opal")
80
109
 
110
+ opal_builder_js = nil
111
+ if opal_builder
112
+ opal_runtime_js = opal_builder.build_str("", "(inline)").to_s
113
+ end
81
114
 
82
- builder.build("opal")
83
- builder.build("opal-parser")
84
- builder.build_require("author_engine/opal")
115
+ author_engine_js = game_builder.build_str(program, "(inline)").to_s
85
116
 
86
- builder.build_str(program, "(inline)").to_s
117
+ return {opal_runtime: opal_runtime_js, author_engine_runtime: author_engine_js}
87
118
  end
88
119
 
89
120
  def template
@@ -103,13 +134,23 @@ if (
103
134
  <h1>Your Browser Does Not Support HTML5 Canvas!</h1>
104
135
  </canvas>
105
136
 
137
+ <script src="game.js"></script>
106
138
  <script>
107
139
  // Add a small delay before loading application in order to finish loading page and show "Loading..."
108
140
  window.setTimeout(function() {
109
- var script = document.createElement('script');
110
- script.src = "application.js";
141
+ console.log("Loading Opal runtime...");
142
+
143
+ var opal_runtime = document.createElement('script');
144
+ opal_runtime.onload = function() {
145
+ console.log("Loading AuthorEngine runtime...");
111
146
 
112
- document.head.appendChild(script);
147
+ var author_engine_runtime = document.createElement('script');
148
+ author_engine_runtime.src = "js/author_engine.js";
149
+ document.head.appendChild(author_engine_runtime);
150
+ }
151
+ opal_runtime.src = "js/runtime.js";
152
+
153
+ document.head.appendChild(opal_runtime);
113
154
  }, 500);
114
155
  </script>
115
156
  </body>
@@ -121,17 +162,28 @@ if (
121
162
  template
122
163
  end
123
164
 
124
- def save(string)
165
+ def export_directory
125
166
  filename = File.basename(@project_file)
126
167
  directory = File.expand_path(@project_file.sub(filename, ''))
127
168
  name = filename.sub(".authorengine", "")
128
169
 
170
+ return "#{directory}/#{name}"
171
+ end
172
+
173
+ def save(string)
174
+ filename = File.basename(@project_file)
175
+ directory = File.expand_path(@project_file.sub(filename, ''))
176
+ name = filename.sub(".authorengine", "")
129
177
  export_path = "#{directory}/#{name}"
178
+
130
179
  unless File.exists?(export_path)
131
180
  Dir.mkdir(export_path)
132
- unless File.exists?("#{export_path}/fonts")
133
- Dir.mkdir("#{export_path}/fonts")
134
- end
181
+ end
182
+ unless File.exists?("#{export_path}/fonts")
183
+ Dir.mkdir("#{export_path}/fonts")
184
+ end
185
+ unless File.exists?("#{export_path}/js")
186
+ Dir.mkdir("#{export_path}/js")
135
187
  end
136
188
 
137
189
  puts "Saving to \"#{export_path}\""
@@ -139,10 +191,20 @@ if (
139
191
  file.write(string)
140
192
  end
141
193
 
142
- File.open("#{export_path}/application.js", "w") do |file|
194
+ hash = game_runtime
195
+ if hash[:opal_runtime]
196
+ File.open("#{export_path}/js/runtime.js", "w") do |file|
197
+ file.write("// #{Opal::VERSION}\n")
198
+ file.write(hash[:opal_runtime])
199
+ end
200
+ end
201
+
202
+ File.open("#{export_path}/game.js", "w") do |file|
143
203
  file.write(project)
144
- file.write("\n\n\n")
145
- file.write(game_runtime)
204
+ end
205
+
206
+ File.open("#{export_path}/js/author_engine.js", "w") do |file|
207
+ file.write(hash[:author_engine_runtime])
146
208
  end
147
209
 
148
210
  fonts_path = "#{File.expand_path("../../../../../", __FILE__)}/assets/fonts"
@@ -7,6 +7,8 @@ class AuthorEngine
7
7
  @instance = klass
8
8
  end
9
9
 
10
+ include TouchHandler
11
+
10
12
  attr_reader :save_file, :spritesheet, :sprites, :levels, :fps
11
13
  attr_reader :game
12
14
  def initialize(project_string)
@@ -41,6 +43,41 @@ class AuthorEngine
41
43
 
42
44
  @game.init
43
45
 
46
+ @show_touch_controls = false
47
+ @touch_buttons = []
48
+ buttons = AuthorEngine::Part::OpalInput::BUTTONS
49
+ key_states = AuthorEngine::Part::OpalInput::KEY_STATES
50
+ @touch_buttons.push(
51
+ TouchButton.new(
52
+ label: "Up", color: @game.dark_gray, x: 137, y: `window.innerHeight/2 - #{125}`, width: 50, height: 50, side: :left,
53
+ contact_proc: proc { key_states[buttons["up"]] = true}, no_contact_proc: proc { key_states[buttons["up"]] = false}
54
+ ),
55
+ TouchButton.new(
56
+ label: "Down", color: @game.dark_gray, x: 137, y: `window.innerHeight/2 + 25`, width: 50, height: 50, side: :left,
57
+ contact_proc: proc { key_states[buttons["down"]] = true}, no_contact_proc: proc { key_states[buttons["down"]] = false}
58
+ ),
59
+
60
+ TouchButton.new(
61
+ label: "Left", color: @game.black, x: 175, width: 50, height: 50, side: :left,
62
+ contact_proc: proc { key_states[buttons["left"]] = true}, no_contact_proc: proc { key_states[buttons["left"]] = false}
63
+ ),
64
+ TouchButton.new(
65
+ label: "Right", color: @game.black, x: 100, width: 50, height: 50, side: :left,
66
+ contact_proc: proc { key_states[buttons["right"]] = true}, no_contact_proc: proc { key_states[buttons["right"]] = false}
67
+ ),
68
+
69
+
70
+ TouchButton.new(
71
+ label: "X", color: @game.red, x: 50, width: 50, height: 50, side: :right,
72
+ contact_proc: proc { key_states[buttons["x"]] = true}, no_contact_proc: proc { key_states[buttons["x"]] = false}
73
+ ),
74
+ TouchButton.new(
75
+ label: "Y", color: @game.yellow, x: 125, width: 50, height: 50, side: :right,
76
+ contact_proc: proc { key_states[buttons["y"]] = true}, no_contact_proc: proc { key_states[buttons["y"]] = false}
77
+ )
78
+ )
79
+ touch_handler_setup
80
+
44
81
  return self
45
82
  end
46
83
 
@@ -57,6 +94,7 @@ class AuthorEngine
57
94
 
58
95
  def run_game
59
96
  `window.requestAnimationFrame(function() {#{run_game}})` # placed here to ensure next frame is called even if draw or update throw an error
97
+ `#{@game.canvas_context}.clearRect(0,0, window.innerWidth, window.innerHeight)`
60
98
 
61
99
  @counted_frames+=1
62
100
 
@@ -68,8 +106,30 @@ class AuthorEngine
68
106
 
69
107
 
70
108
  if @sprites.size == (@spritesheet_width/@sprite_size)*(@spritesheet_height/@sprite_size)
109
+ width = 128 * @game.scale
110
+
111
+ # `#{@canvas_context}.setTransform(1, 0, 0, 1, 0, 0)`
112
+ `#{@game.canvas_context}.save()`
113
+ `#{@game.canvas_context}.translate(window.innerWidth/2 - #{width/2}, 0)`
114
+ `#{@game.canvas_context}.scale(#{@game.scale}, #{@game.scale})`
115
+ `#{@game.canvas_context}.save()`
116
+
117
+ region = `new Path2D()`
118
+ `#{region}.rect(0, 0, 128, 128)`
119
+ `#{@game.canvas_context}.clip(#{region})`
120
+ `#{@game.canvas_context}.save()`
71
121
  draw
122
+
123
+ `#{@game.canvas_context}.restore()`
124
+ `#{@game.canvas_context}.restore()`
125
+ `#{@game.canvas_context}.restore()`
126
+
72
127
  update
128
+
129
+ if @show_touch_controls
130
+ draw_touch_controls
131
+ update_touch_controls
132
+ end
73
133
  else
74
134
  @game.draw_background
75
135
  @game.text("Loading sprite #{@sprites.size}/#{(@spritesheet_width/@sprite_size)*(@spritesheet_height/@sprite_size)}.", 0, @game.height/2, 8)
@@ -78,6 +138,25 @@ class AuthorEngine
78
138
  return nil
79
139
  end
80
140
 
141
+ def draw_touch_controls
142
+ @touch_buttons.each(&:draw)
143
+ end
144
+
145
+ def update_touch_controls
146
+ active_buttons = []
147
+
148
+ @touch_buttons.each do |button|
149
+ @current_touches.each do |id, touch|
150
+ if touch.x.between?(button.x, button.x+button.width) && touch.y.between?(button.y, button.y+button.height)
151
+ active_buttons << button
152
+ button.active
153
+ end
154
+ end
155
+ end
156
+
157
+ (@touch_buttons - active_buttons).each(&:inactive)
158
+ end
159
+
81
160
  def resize_canvas
82
161
  width = `window.innerWidth`
83
162
  height = `window.innerHeight`
@@ -88,12 +167,11 @@ class AuthorEngine
88
167
  @game.scale = `window.innerHeight / 128.0`
89
168
  end
90
169
 
91
- `#{@game.canvas}.width = 128 * #{@game.scale}`
92
- `#{@game.canvas}.height = 128 * #{@game.scale}`
93
- `#{@game.canvas}.style.width = 128 * #{@game.scale}`
94
- `#{@game.canvas}.style.height = 128 * #{@game.scale}`
170
+ `#{@game.canvas}.width = #{width}`
171
+ `#{@game.canvas}.height = #{height}`
172
+ `#{@game.canvas}.style.width = #{width}`
173
+ `#{@game.canvas}.style.height = #{height}`
95
174
 
96
- `#{@game.canvas_context}.scale(#{@game.scale}, #{@game.scale})`
97
175
  `#{@game.canvas_context}.imageSmoothingEnabled = false`
98
176
  return nil
99
177
  end
@@ -150,6 +228,11 @@ class AuthorEngine
150
228
  `document.addEventListener('keydown', (event) => { #{AuthorEngine::Part::OpalInput::KEY_STATES[`event.key`] = true} })`
151
229
  `document.addEventListener('keyup', (event) => { #{AuthorEngine::Part::OpalInput::KEY_STATES[`event.key`] = false} })`
152
230
 
231
+ `#{@game.canvas}.addEventListener('touchstart', (event) => { #{@show_touch_controls = true; handle_touch_start(`event`); puts "Touch started..."} })`
232
+ `#{@game.canvas}.addEventListener('touchmove', (event) => { #{handle_touch_move(`event`); puts "Touch moved..."} })`
233
+ `#{@game.canvas}.addEventListener('touchcancel', (event) => { #{handle_touch_cancel(`event`); puts "Touch canceled."} })`
234
+ `#{@game.canvas}.addEventListener('touchend', (event) => { #{handle_touch_end(`event`); puts "Touch Ended."} })`
235
+
153
236
  `document.getElementById('loading').style.display = "none"`
154
237
  `window.requestAnimationFrame(function() {#{run_game}})`
155
238
  return nil
@@ -10,7 +10,7 @@ class AuthorEngine
10
10
  "y" => "c",
11
11
  }
12
12
 
13
- # Store keys state
13
+ # Store key states
14
14
  KEY_STATES = {
15
15
  }
16
16
 
@@ -0,0 +1,36 @@
1
+ class AuthorEngine
2
+ class TouchButton
3
+ attr_reader :x, :y, :width, :height
4
+ def initialize(label:, color:, x:, y: nil, width:, height:, side:, contact_proc:, no_contact_proc:)
5
+ @label, @color, @x, @y, @width, @height = label, color, x, y, width, height
6
+ @side, @contact_proc, @no_contact_proc = side, contact_proc, no_contact_proc
7
+
8
+ @game = AuthorEngine::GameRunner.instance.game
9
+ @game_width = 128 * @game.scale
10
+ @game_x = `window.innerWidth/2 - #{@game_width/2}`
11
+
12
+ if @side == :left
13
+ @x = @game_x-@x
14
+ elsif @side == :right
15
+ @x = @game_x+@game_width+@x
16
+ else
17
+ raise "side must be :left or :right"
18
+ end
19
+
20
+ @y = `window.innerHeight/2 - #{height}` unless @y.is_a?(Numeric)
21
+ end
22
+
23
+ def draw
24
+ `#{@game.canvas_context}.fillStyle = #{@color}`
25
+ `#{@game.canvas_context}.fillRect(#{@x}, #{@y}, #{width}, #{width})`
26
+ end
27
+
28
+ def active
29
+ @contact_proc.call
30
+ end
31
+
32
+ def inactive
33
+ @no_contact_proc.call
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,49 @@
1
+ class AuthorEngine
2
+ module TouchHandler
3
+ Touch = Struct.new(:x, :y)
4
+ def touch_handler_setup
5
+ @current_touches = {}
6
+ end
7
+
8
+ def copy_touch(touch)
9
+ Touch.new(`touch.pageX`, `touch.pageY`)
10
+ end
11
+
12
+ def handle_touch_start(event)
13
+ `#{event}.preventDefault()`
14
+
15
+ touches = `#{event}.changedTouches`
16
+ `for (var i = 0; i < #{touches}.length; i++) {
17
+ #{@current_touches[`touches[i].identifier`] = copy_touch(`touches[i]`)}
18
+ }`
19
+
20
+ return nil
21
+ end
22
+
23
+ def handle_touch_move(event)
24
+ `#{event}.preventDefault()`
25
+
26
+ touches = `#{event}.changedTouches`
27
+ `for (var i = 0; i < #{touches}.length; i++) {
28
+ #{@current_touches[`touches[i].identifier`] = copy_touch(`touches[i]`)}
29
+ }`
30
+
31
+ return nil
32
+ end
33
+
34
+ def handle_touch_cancel(event)
35
+ handle_touch_end(event)
36
+ end
37
+
38
+ def handle_touch_end(event)
39
+ `#{event}.preventDefault()`
40
+
41
+ touches = `#{event}.changedTouches`
42
+ `for (var i = 0; i < #{touches}.length; i++) {
43
+ #{@current_touches.delete(`touches[i].identifier`)}
44
+ }`
45
+
46
+ return nil
47
+ end
48
+ end
49
+ end
@@ -12,4 +12,6 @@ require_relative "sprite"
12
12
 
13
13
  require_relative "game/game"
14
14
  require_relative "save_file"
15
+ require_relative "game/opal/touch_handler"
16
+ require_relative "game/opal/touch_button"
15
17
  require_relative "game/opal/game_runner"
@@ -1,3 +1,3 @@
1
1
  class AuthorEngine
2
- VERSION = "0.4.0"
2
+ VERSION = "0.5.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: author_engine
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cyberarm
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-12-22 00:00:00.000000000 Z
11
+ date: 2018-12-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: gosu
@@ -146,6 +146,8 @@ files:
146
146
  - lib/author_engine/game/opal/game_runner.rb
147
147
  - lib/author_engine/game/opal/parts/graphics.rb
148
148
  - lib/author_engine/game/opal/parts/input.rb
149
+ - lib/author_engine/game/opal/touch_button.rb
150
+ - lib/author_engine/game/opal/touch_handler.rb
149
151
  - lib/author_engine/image.rb
150
152
  - lib/author_engine/level_picker.rb
151
153
  - lib/author_engine/opal.rb