author_engine 0.1.0 → 0.3.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 (40) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -2
  3. data/API.md +20 -0
  4. data/Gemfile.lock +13 -2
  5. data/README.md +8 -4
  6. data/author_engine.gemspec +2 -1
  7. data/bin/author_engine +3 -1
  8. data/lib/author_engine/button.rb +1 -1
  9. data/lib/author_engine/cli.rb +21 -0
  10. data/lib/author_engine/collision_detection/collision_detection.rb +188 -0
  11. data/lib/author_engine/containers/loader.rb +8 -1
  12. data/lib/author_engine/game/common/parts/collision_detection.rb +33 -0
  13. data/lib/author_engine/game/game.rb +28 -2
  14. data/lib/author_engine/game/{parts → gosu/parts}/colors.rb +0 -0
  15. data/lib/author_engine/game/{parts → gosu/parts}/common.rb +0 -0
  16. data/lib/author_engine/game/{parts → gosu/parts}/graphics.rb +19 -1
  17. data/lib/author_engine/game/{parts → gosu/parts}/input.rb +0 -0
  18. data/lib/author_engine/game/opal/exporter.rb +157 -0
  19. data/lib/author_engine/game/opal/game_runner.rb +158 -0
  20. data/lib/author_engine/game/opal/parts/colors.rb +64 -0
  21. data/lib/author_engine/game/opal/parts/common.rb +13 -0
  22. data/lib/author_engine/game/opal/parts/graphics.rb +69 -0
  23. data/lib/author_engine/game/opal/parts/input.rb +30 -0
  24. data/lib/author_engine/image.rb +1 -0
  25. data/lib/author_engine/level_picker.rb +92 -0
  26. data/lib/author_engine/opal.rb +15 -0
  27. data/lib/author_engine/save_file.rb +49 -15
  28. data/lib/author_engine/sprite.rb +1 -2
  29. data/lib/author_engine/sprite_picker.rb +10 -3
  30. data/lib/author_engine/text.rb +2 -2
  31. data/lib/author_engine/version.rb +1 -1
  32. data/lib/author_engine/views/level_editor.rb +161 -0
  33. data/lib/author_engine/views/play_viewer.rb +1 -0
  34. data/lib/author_engine.rb +9 -4
  35. data/screenshots/code_editor.png +0 -0
  36. data/screenshots/play.png +0 -0
  37. data/screenshots/sprite_editor.png +0 -0
  38. metadata +36 -9
  39. data/test_3.authorengine +0 -519
  40. data/testing.authorengine +0 -578
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: aa9450a11aa87c07b6af55a87d7ebf3a68feaff0c671662e6662a14ebf45a004
4
- data.tar.gz: 52c74e684c1d5c402083b5dfa7a630ad99d445ec5cd786db9fc3a3d324f7c9a4
3
+ metadata.gz: 0ac3f16a1dc192379088c8f74dde1e6dab90e5edeefa35e1bcb810c7017b6833
4
+ data.tar.gz: '0860cdd4a930f02a6654fbde557148d8e460bb3666e8e87c10a64ba81dffcf6e'
5
5
  SHA512:
6
- metadata.gz: 5b0173f8357c12aadd3d0ac99e0a7b2c78d862d93bca6940d3f383be701e51d00dfd5c63ea7873fb7289778389846bbce2cdb5129c5e5bb6b8801895d0f5f018
7
- data.tar.gz: a59df8c02965376c9824385f756516a5af44a4c88854c748a8246bf6f2929a63048e6c1f040214cbd193b5837d91f1ca24ab0161d3d9a9e8984a16fd8aafec61
6
+ metadata.gz: 91dc4eace8dcb2c8f3edae461cef1a515e5616a915dd19f7598df02e0fd6f0bab0e45f75713b40869aefa803b9db6cda0f48b0279d9f91cb6cf4a5fa16c4caad
7
+ data.tar.gz: 6ff618da871039a3786b1bdab78977914d41c7c10e45101ac19865aaee3c7ab3f771af7caec2577bcfb35c03372b1dbf9dfdf0a0af669b45a9ec5a8b77af33b9
data/.gitignore CHANGED
@@ -7,5 +7,6 @@
7
7
  /spec/reports/
8
8
  /tmp/
9
9
 
10
- _*.rb
11
- *.authorengine
10
+ **/_*.rb
11
+ **/*.authorengine
12
+ **/*.html
data/API.md CHANGED
@@ -38,10 +38,30 @@ end
38
38
  ### milliseconds
39
39
  Milliseconds since game started
40
40
 
41
+ # CollisionDetection
42
+ ### bounding_box(sprite_index)
43
+ returns the bounding_box for sprite
44
+ ### sprite_vs_sprite(sprite_index, sprite_x, sprite_y, target_sprite_index, target_x, target_y)
45
+ determine whether 2 sprites are colliding
46
+ ### sprite_vs_level(sprite_index, sprite_x, sprite_y, level)
47
+ returns an array of level tiles that sprite is colliding with. returns an empty array if non are colliding.
48
+ ### colliding_edge(sprite_index, sprite_x, sprite_y, target_sprite_index, target_x, target_y)
49
+ determine the edge of which sprite is colliding with with target
50
+ ### draw_sprite_box(sprite_index, sprite_x, sprite_y)
51
+ draws sprites bounding box
52
+ ### draw_level_boxes(level_index)
53
+ draws bounding boxes around each tile of level
54
+ ### render_bounding_box(sprite_index, box, sprite_x, sprite_y, edges = {}, z = Float::INFINITY)
55
+ draw bounding box around sprite with optional edges from colliding_edges to show colliding edges
56
+
41
57
  # Graphics
42
58
  ### rect(x = 0, y = 0, width = 1, height = 1, color = white, z = 0)
43
59
  ### sprite(sprite_sheet_index, x = 0, y = 0, z = 0, color = white)
44
60
  ### text(string, x = 0, y = 0, size = 4, z = 0, color = white)
61
+ ### level(level_index, z = 0)
62
+
63
+ ### swap(level_index, current_sprite, replacement_sprite)
64
+ Swap level's current_sprite with replacement_sprite
45
65
 
46
66
  ### translate(x, y, &block)
47
67
  Translate the contents of block by x and y
data/Gemfile.lock CHANGED
@@ -1,17 +1,28 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- author_engine (0.1.0)
4
+ author_engine (0.3.0)
5
5
  coderay (~> 1.1.2)
6
6
  gosu (~> 0.14.4)
7
+ opal (~> 0.11.4)
7
8
 
8
9
  GEM
9
10
  remote: https://rubygems.org/
10
11
  specs:
12
+ ast (2.4.0)
11
13
  coderay (1.1.2)
12
14
  gosu (0.14.4)
15
+ hike (1.2.3)
13
16
  minitest (5.11.3)
17
+ opal (0.11.4)
18
+ ast (>= 2.3.0)
19
+ hike (~> 1.2)
20
+ parser (= 2.3.3.1)
21
+ sourcemap (~> 0.1.0)
22
+ parser (2.3.3.1)
23
+ ast (~> 2.2)
14
24
  rake (10.5.0)
25
+ sourcemap (0.1.1)
15
26
 
16
27
  PLATFORMS
17
28
  ruby
@@ -23,4 +34,4 @@ DEPENDENCIES
23
34
  rake (~> 10.0)
24
35
 
25
36
  BUNDLED WITH
26
- 1.16.3
37
+ 1.17.2
data/README.md CHANGED
@@ -8,19 +8,23 @@ A virtual console¹ that you code in Ruby.
8
8
  `gem install author_engine`
9
9
 
10
10
  ## Run
11
- `author_engine`
11
+ `author_engine [filename] [options]`
12
+ - Run AuthorEngine editor with optional filename argument to open project.
13
+
14
+ `author_engine export filename`
15
+ - Export project to web using [Opal](https://opalrb.com).
12
16
  ### Options
13
17
  `--native` Open AuthorEngine in fullscreen and maximized.
14
18
 
15
19
  # Interface
16
20
  ## Play
17
- ![play_view](#)
21
+ ![play_view](https://raw.githubusercontent.com/cyberarm/author_engineV2/master/screenshots/play.png)
18
22
  ## Sprite Editor
19
- ![sprite_editor_view](#)
23
+ ![sprite_editor_view](https://raw.githubusercontent.com/cyberarm/author_engineV2/master/screenshots/sprite_editor.png)
20
24
  ## Level Editor
21
25
  ![level_editor_view](#)
22
26
  ## Code Editor
23
- ![code_editor_view](#)
27
+ ![code_editor_view](https://raw.githubusercontent.com/cyberarm/author_engineV2/master/screenshots/code_editor.png)
24
28
 
25
29
 
26
30
  ¹: Does not directly run any kind of assembly
@@ -30,10 +30,11 @@ Gem::Specification.new do |spec|
30
30
  end
31
31
  spec.bindir = "bin"
32
32
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
33
- spec.require_paths = ["lib"]
33
+ spec.require_paths = ["lib", "assets"]
34
34
 
35
35
  spec.add_dependency "gosu", "~> 0.14.4"
36
36
  spec.add_dependency "coderay", "~> 1.1.2"
37
+ spec.add_dependency "opal", "~> 0.11.4"
37
38
 
38
39
  spec.add_development_dependency "bundler", "~> 1.16"
39
40
  spec.add_development_dependency "rake", "~> 10.0"
data/bin/author_engine CHANGED
@@ -1,4 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  require "author_engine"
4
- AuthorEngine::Window.new.show
4
+ require "author_engine/cli"
5
+
6
+ AuthorEngine::CLI.new
@@ -111,7 +111,7 @@ class AuthorEngine
111
111
  @image.draw(@x+@x_padding, @y+@y_padding, @z, (1 * window.square_scale), (1 * window.square_scale))
112
112
 
113
113
  else
114
- raise "Nothing to draw! (text and image were nil or invalid types)"
114
+ raise "Nothing to draw! (label and image were nil or invalid types)"
115
115
  end
116
116
  end
117
117
 
@@ -0,0 +1,21 @@
1
+ class AuthorEngine
2
+ class CLI
3
+ def initialize
4
+ if ARGV[0] && ARGV[0] == "export"
5
+ if ARGV[1] && ARGV[1].end_with?(".authorengine")
6
+ require "author_engine/game/opal/exporter"
7
+
8
+ AuthorEngine::OpalExporter.new(project_file: ARGV[1])
9
+ else
10
+ puts "author_engine export project [exported_name]"
11
+ end
12
+
13
+ elsif ARGV[0] && ARGV[0].end_with?(".authorengine")
14
+ # The Loader Container handles loading projects
15
+ AuthorEngine::Window.new.show
16
+ else
17
+ AuthorEngine::Window.new.show
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,188 @@
1
+ class AuthorEngine
2
+ class CollisionDetection
3
+ Color = Struct.new(:red, :green, :blue, :alpha)
4
+ BoundingBox = Struct.new(:x, :y, :width, :height)
5
+
6
+ def initialize(game_sprites, game_levels)
7
+ @game_sprites = game_sprites
8
+ @game_levels = game_levels
9
+
10
+ @sprites= []
11
+ @levels = []
12
+
13
+ @known_collisions = []
14
+ end
15
+
16
+ def clear
17
+ @known_collisions.clear
18
+ end
19
+
20
+ def add_sprite(image_or_blob)
21
+ blob = nil
22
+ if RUBY_ENGINE != "opal"
23
+ blob = image_or_blob.to_blob
24
+ else
25
+ blob = []
26
+ `#{image_or_blob}.forEach(function(value) {#{blob << `value`}})`#.each {|n| blob << n}
27
+ end
28
+
29
+ @sprites << {blob: blob, box: bounding_box(blob)}
30
+ end
31
+
32
+ def add_level(level_array)
33
+ @levels << level_array # TODO: Put level's into an optimized structure for fast quadrant look-ups
34
+ end
35
+
36
+ def box(sprite_index)
37
+ @sprites[sprite_index][:box]
38
+ end
39
+
40
+ def sprite_vs_sprite(sprite_index, sprite_x, sprite_y, target_sprite_index, target_x, target_y)
41
+ bounding_boxes_intersect?(box(sprite_index), sprite_x, sprite_y, box(target_sprite_index), target_x, target_y)
42
+ end
43
+
44
+ def sprite_vs_level(sprite_index, sprite_x, sprite_y, level)
45
+ detected = []
46
+
47
+ collider = box(sprite_index)
48
+ @levels[level].each do |sprite|
49
+ if bounding_boxes_intersect?(collider, sprite_x, sprite_y, box(sprite.sprite), sprite.x, sprite.y)
50
+ detected << sprite
51
+ end
52
+ end
53
+
54
+ return detected
55
+ end
56
+
57
+ def colliding_edge(sprite_index, sprite_x, sprite_y, target_sprite_index, target_x, target_y)
58
+ sprite_box = box(sprite_index)
59
+ target_box = box(target_sprite_index)
60
+
61
+ edges = {top: false, left: false, right: false, bottom: false}
62
+
63
+ # https://gamedev.stackexchange.com/a/24091
64
+ wy = (sprite_box.width + target_box.width) * ((sprite_y - sprite_box.height) - (target_y - target_box.height/2));
65
+ hx = (sprite_box.height + target_box.height) * ((sprite_x - sprite_box.width) - (target_x - target_box.height/2));
66
+
67
+ if (wy > hx)
68
+ if (wy > -hx)
69
+ edges[:bottom] = true
70
+ else
71
+ edges[:left] = true
72
+ end
73
+ else
74
+ if (wy > -hx)
75
+ edges[:right] = true
76
+ else
77
+ edges[:top] = true
78
+ end
79
+ end
80
+
81
+ return edges
82
+ end
83
+
84
+ def debug_draw_sprite(sprite_index, sprite_x, sprite_y)
85
+ render_bounding_box(sprite_index, box(sprite_index), sprite_x, sprite_y)
86
+ end
87
+
88
+ def debug_draw_level(level_index)
89
+ @levels[level_index].each do |sprite|
90
+ render_bounding_box(sprite.sprite, box(sprite.sprite), sprite.x, sprite.y)
91
+ end
92
+ end
93
+
94
+ def render_bounding_box(sprite_index, box, sprite_x, sprite_y, edges = {}, z = Float::INFINITY, color = 0xc800ff00, collision_color = 0xc8ff00ff)
95
+ if RUBY_ENGINE == "opal"
96
+ color = "green"
97
+ collision_color = "red"
98
+ end
99
+ paint_color = color
100
+ # EDGE: TOP
101
+ # TOP LEFT TO TOP RIGHT
102
+ if edges[:top] then paint_color = collision_color; else paint_color = color; end
103
+ draw_line(
104
+ box.x + sprite_x, box.y + sprite_y,
105
+ box.x + sprite_x + box.width, box.y + sprite_y,
106
+ paint_color, z
107
+ )
108
+
109
+ # EDGE: RIGHT
110
+ # TOP RIGHT TO BOTTOM RIGHT
111
+ if edges[:right] then paint_color = collision_color; else paint_color = color; end
112
+ draw_line(
113
+ box.x + sprite_x + box.width, box.y + sprite_y,
114
+ box.x + sprite_x + box.width, box.y + sprite_y + box.height,
115
+ paint_color, z
116
+ )
117
+
118
+ # EDGE: BOTTOM
119
+ # BOTTOM RIGHT to BOTTOM LEFT
120
+ if edges[:bottom] then paint_color = collision_color; else paint_color = color; end
121
+ draw_line(
122
+ box.x + sprite_x + box.width, box.y + sprite_y + box.height,
123
+ box.x + sprite_x, box.y + sprite_y + box.height,
124
+ paint_color, z
125
+ )
126
+
127
+ # EDGE: LEFT
128
+ # BOTTOM LEFT TO TOP LEFT
129
+ if edges[:left] then paint_color = collision_color; else paint_color = color; end
130
+ draw_line(
131
+ box.x + sprite_x, box.y + sprite_y + box.height,
132
+ box.x + sprite_x, box.y + sprite_y,
133
+ paint_color, z
134
+ )
135
+ end
136
+
137
+ private
138
+ def bounding_boxes_intersect?(a, a_x, a_y, b, b_x, b_y)
139
+ (a.x + a_x) <= (b.x + b_x + b.width) && (a.x + a_x + a.width) >= (b.x + b_x) &&
140
+ (a.y + a_y) <= (b.y + b_y + b.height) && (a.y + a_y + a.height) >= (b.y + b_y)
141
+ end
142
+
143
+ def draw_line(x, y, x2, y2, color, z = 0)
144
+ if RUBY_ENGINE == "opal"
145
+ `#{AuthorEngine::GameRunner.instance.game.canvas_context}.strokeStyle = #{color}`
146
+ `#{AuthorEngine::GameRunner.instance.game.canvas_context}.lineWidth = 1`
147
+
148
+ `#{AuthorEngine::GameRunner.instance.game.canvas_context}.beginPath()`
149
+ `#{AuthorEngine::GameRunner.instance.game.canvas_context}.moveTo(#{x}, #{y})`
150
+ `#{AuthorEngine::GameRunner.instance.game.canvas_context}.lineTo(#{x2}, #{y2})`
151
+ `#{AuthorEngine::GameRunner.instance.game.canvas_context}.stroke()`
152
+ else
153
+ Gosu.draw_line(x, y, color, x2, y2, color, z)
154
+ end
155
+ end
156
+
157
+ # returns alpha value of pixel at x and y
158
+ def solid_at?(blob, x, y)
159
+ width = 16
160
+
161
+ blob[(y * width + x) * 4 + 3].ord
162
+ end
163
+
164
+ def bounding_box(blob, size = 16)
165
+ box = BoundingBox.new(size, size, 0, 0)
166
+ size.times do |y|
167
+ size.times do |x|
168
+ if solid_at?(blob, x, y) > 0
169
+ box.x = x if x < box.x
170
+ box.y = y if y < box.y
171
+ box.width = x if x > box.width
172
+ box.height = y if y > box.height
173
+ end
174
+ end
175
+ end
176
+
177
+ # Correct width/height
178
+ box.width -= box.x
179
+ box.height -= box.y
180
+
181
+ # Correct off-by-1
182
+ box.width += 1
183
+ box.height += 1
184
+
185
+ return box
186
+ end
187
+ end
188
+ end
@@ -26,6 +26,14 @@ class AuthorEngine
26
26
  @entering_name = true
27
27
  end
28
28
  @new_button.x = window.width - @new_button.width
29
+
30
+ if ARGV[0] && File.exists?(ARGV[0])
31
+ if ARGV[0].end_with?(".authorengine")
32
+ load(ARGV[0])
33
+ else
34
+ puts "AuthorEngine: #{ARGV[0]} is not a compatible file."
35
+ end
36
+ end
29
37
  end
30
38
 
31
39
  def load(filename)
@@ -54,7 +62,6 @@ class AuthorEngine
54
62
  Gosu.draw_rect(0, @new_button.y, window.width, @new_button.height, @header_color)
55
63
  @font.draw_text("AuthorEngine", 1*window.square_scale,@font.height/2,0)
56
64
  @new_button.draw
57
- @font.draw_text(@list[@index].name, 0, 0, 0) if @list[@index]
58
65
 
59
66
  Gosu.clip_to(0, @font.height*2, window.width, window.height-(@font.height*4)) do
60
67
  y = (window.height/2-@font.height) - (@height/2)
@@ -0,0 +1,33 @@
1
+ class AuthorEngine
2
+ class Part
3
+ module CollisionDetection
4
+ def bounding_box(sprite_index)
5
+ @collision_detection.box(sprite_index)
6
+ end
7
+
8
+ def colliding_edge(sprite_index, sprite_x, sprite_y, target_sprite_index, target_x, target_y)
9
+ @collision_detection.colliding_edge(sprite_index, sprite_x, sprite_y, target_sprite_index, target_x, target_y)
10
+ end
11
+
12
+ def sprite_vs_sprite(sprite_index, sprite_x, sprite_y, target_sprite_index, target_x, target_y)
13
+ @collision_detection.sprite_vs_sprite(sprite_index, sprite_x, sprite_y, target_sprite_index, target_x, target_y)
14
+ end
15
+
16
+ def sprite_vs_level(sprite_index, sprite_x, sprite_y, level)
17
+ @collision_detection.sprite_vs_level(sprite_index, sprite_x, sprite_y, level)
18
+ end
19
+
20
+ def draw_sprite_box(sprite_index, sprite_x, sprite_y)
21
+ @collision_detection.debug_draw_sprite(sprite_index, sprite_x, sprite_y)
22
+ end
23
+
24
+ def draw_level_boxes(level_index)
25
+ @collision_detection.debug_draw_level(level_index)
26
+ end
27
+
28
+ def render_bounding_box(sprite_index, box, sprite_x, sprite_y, edges = {}, z = Float::INFINITY)
29
+ @collision_detection.render_bounding_box(sprite_index, box, sprite_x, sprite_y, edges, z, nil, nil)
30
+ end
31
+ end
32
+ end
33
+ end
@@ -1,17 +1,43 @@
1
1
  class AuthorEngine
2
2
  class Game
3
3
  include AuthorEngine::Part::Common
4
+ include AuthorEngine::Part::CollisionDetection
4
5
  include AuthorEngine::Part::Colors
5
6
  include AuthorEngine::Part::Graphics
6
7
  include AuthorEngine::Part::Input
7
8
 
9
+ attr_accessor :scale, :canvas, :canvas_context
10
+ attr_accessor :collision_detection
8
11
  def initialize(code:)
9
- @background_color = Gosu::Color::BLACK
12
+ if RUBY_ENGINE == "opal"
13
+ @scale = 1.0
14
+ @canvas = `document.getElementById('canvas')`
15
+ @canvas_context = `#{@canvas}.getContext('2d')`
16
+ end
17
+
18
+ if RUBY_ENGINE != "opal"
19
+ @sprites = SpriteEditor.instance.sprites
20
+
21
+ @levels = []
22
+ # Create a "Deep Copy" to allow for swapping of a level's sprites without corrupting LevelEditor's version
23
+ LevelEditor.instance.levels.each do |level|
24
+ @levels << level.sort_by {|sprite| sprite.z}.map {|sprite| sprite.dup}
25
+ end
26
+ size = 16
27
+ @levels.each {|level| level.each {|sprite| sprite.x = sprite.x * size; sprite.y = sprite.y * size}}
28
+
29
+ @collision_detection = CollisionDetection.new(@sprites, @levels)
30
+
31
+ @sprites.each {|sprite| @collision_detection.add_sprite(sprite) }
32
+ @levels.each {|level| @collision_detection.add_level(level) }
33
+ end
34
+
35
+ @background_color = black
10
36
  self.instance_eval(code)
11
37
  end
12
38
 
13
39
  def draw_background
14
- Gosu.draw_rect(0, 0, Window::VIEW_WIDTH, Window::VIEW_HEIGHT, @background_color)
40
+ rect(0, 0, width, height, @background_color)
15
41
  end
16
42
 
17
43
  def init
@@ -20,11 +20,29 @@ class AuthorEngine
20
20
  end
21
21
 
22
22
  def sprite(index, x = 0, y = 0, z = 0, alpha = 255)
23
- image = SpriteEditor.instance.sprites[index]
23
+ image = @sprites[index]
24
24
  raise "No sprite at '#{index}'!" unless image
25
25
  image.draw(x, y, z, 1,1, Gosu::Color.rgba(255,255,255, alpha))
26
26
  end
27
27
 
28
+ def level(index, z = 0)
29
+ _level = @levels[index]
30
+ raise "No level at '#{index}'!" unless _level
31
+
32
+ _level.each do |sprite|
33
+ sprite(sprite.sprite, sprite.x, sprite.y, z)
34
+ end
35
+ end
36
+
37
+ def swap(level, current_sprite, replacement_sprite)
38
+ _level = @levels[level]
39
+ raise "No level at '#{index}'!" unless _level
40
+ raise "No sprite at '#{current_sprite}'!" unless @sprites[current_sprite]
41
+ raise "No sprite at '#{current_sprite}'!" unless @sprites[replacement_sprite]
42
+
43
+ _level.each {|sprite| sprite.sprite = replacement_sprite if sprite.sprite == current_sprite}
44
+ end
45
+
28
46
  def translate(x, y, &block)
29
47
  Gosu.translate(x, y) do
30
48
  block.call if block
@@ -0,0 +1,157 @@
1
+ require "opal"
2
+ require "fileutils"
3
+
4
+ class AuthorEngine
5
+ class OpalExporter
6
+ def initialize(project_file:)
7
+ @project_file = project_file
8
+
9
+ save(export)
10
+ end
11
+
12
+ def project_name
13
+ name = File.basename(@project_file, ".authorengine")
14
+ return name.split("_").map {|n| n.capitalize}.join(" ")
15
+ end
16
+
17
+ def stylesheet
18
+ %{
19
+ @font-face { font-family: Connection; src: url('fonts/Connection.otf'); }
20
+ @font-face { font-family: ConnectionBold; src: url('fonts/ConnectionBold.otf'); }
21
+
22
+ body {
23
+ margin: 0;
24
+ padding: 0;
25
+ background: #222;
26
+ }
27
+ #canvas {
28
+ display: block;
29
+ margin: 0 auto;
30
+ cursor: none;
31
+ }
32
+ #loading {
33
+ font-family: Connection, sans serif;
34
+ color: white;
35
+ text-align: center;
36
+
37
+ position: absolute;
38
+ top: 0;
39
+ bottom: 0;
40
+ left: 0;
41
+ right: 0;
42
+ width: 50%;
43
+ height: 30%;
44
+ margin: auto;
45
+ }
46
+ }
47
+ end
48
+
49
+ def project
50
+ %{
51
+ var projectString = `#{File.open(@project_file).read}`;
52
+ }
53
+ end
54
+
55
+ def game_runtime
56
+ program = %{
57
+ require "opal"
58
+ require "opal-parser"
59
+ require "author_engine/opal"
60
+
61
+ `var callback = function(){
62
+ \#{AuthorEngine::GameRunner.new(`projectString`).show}
63
+ };
64
+
65
+ if (
66
+ document.readyState === "complete" ||
67
+ (document.readyState !== "loading" && !document.documentElement.doScroll)
68
+ ) {
69
+ callback();
70
+ } else {
71
+ document.addEventListener("DOMContentLoaded", callback);
72
+ }`
73
+ }
74
+
75
+ builder = Opal::Builder.new
76
+ base_path = File.expand_path("../../../..", __FILE__)
77
+ builder.append_paths("#{base_path}")
78
+
79
+ puts "Transpiling to JavaScript using Opal..."
80
+
81
+
82
+ builder.build("opal")
83
+ builder.build("opal-parser")
84
+ builder.build_require("author_engine/opal")
85
+
86
+ builder.build_str(program, "(inline)").to_s
87
+ end
88
+
89
+ def template
90
+ %{
91
+ <!doctype html5>
92
+ <html>
93
+ <head>
94
+ <meta charset="utf-8" />
95
+ <title>#{project_name} | AuthorEngine</title>
96
+ </head>
97
+ <style>
98
+ #{stylesheet}
99
+ </style>
100
+ <body>
101
+ <h1 id="loading">Loading...</h1>
102
+ <canvas id="canvas">
103
+ <h1>Your Browser Does Not Support HTML5 Canvas!</h1>
104
+ </canvas>
105
+
106
+ <script>
107
+ // Add a small delay before loading application in order to finish loading page and show "Loading..."
108
+ window.setTimeout(function() {
109
+ var script = document.createElement('script');
110
+ script.src = "application.js";
111
+
112
+ document.head.appendChild(script);
113
+ }, 500);
114
+ </script>
115
+ </body>
116
+ </html>
117
+ }
118
+ end
119
+
120
+ def export
121
+ template
122
+ end
123
+
124
+ def save(string)
125
+ filename = File.basename(@project_file)
126
+ directory = File.expand_path(@project_file.sub(filename, ''))
127
+ name = filename.sub(".authorengine", "")
128
+
129
+ export_path = "#{directory}/#{name}"
130
+ unless File.exists?(export_path)
131
+ Dir.mkdir(export_path)
132
+ unless File.exists?("#{export_path}/fonts")
133
+ Dir.mkdir("#{export_path}/fonts")
134
+ end
135
+ end
136
+
137
+ puts "Saving to \"#{export_path}\""
138
+ File.open("#{export_path}/#{name}.html", "w") do |file|
139
+ file.write(string)
140
+ end
141
+
142
+ File.open("#{export_path}/application.js", "w") do |file|
143
+ file.write(project)
144
+ file.write("\n\n\n")
145
+ file.write(game_runtime)
146
+ end
147
+
148
+ fonts_path = "#{File.expand_path("../../../../../", __FILE__)}/assets/fonts"
149
+ font_files = Dir.glob("#{fonts_path}/*")
150
+ font_files.each do |file|
151
+ FileUtils.cp(file, "#{export_path}/fonts/#{File.basename(file)}")
152
+ end
153
+
154
+ puts "Saved."
155
+ end
156
+ end
157
+ end