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.
- checksums.yaml +4 -4
- data/.gitignore +3 -2
- data/API.md +20 -0
- data/Gemfile.lock +13 -2
- data/README.md +8 -4
- data/author_engine.gemspec +2 -1
- data/bin/author_engine +3 -1
- data/lib/author_engine/button.rb +1 -1
- data/lib/author_engine/cli.rb +21 -0
- data/lib/author_engine/collision_detection/collision_detection.rb +188 -0
- data/lib/author_engine/containers/loader.rb +8 -1
- data/lib/author_engine/game/common/parts/collision_detection.rb +33 -0
- data/lib/author_engine/game/game.rb +28 -2
- data/lib/author_engine/game/{parts → gosu/parts}/colors.rb +0 -0
- data/lib/author_engine/game/{parts → gosu/parts}/common.rb +0 -0
- data/lib/author_engine/game/{parts → gosu/parts}/graphics.rb +19 -1
- data/lib/author_engine/game/{parts → gosu/parts}/input.rb +0 -0
- data/lib/author_engine/game/opal/exporter.rb +157 -0
- data/lib/author_engine/game/opal/game_runner.rb +158 -0
- data/lib/author_engine/game/opal/parts/colors.rb +64 -0
- data/lib/author_engine/game/opal/parts/common.rb +13 -0
- data/lib/author_engine/game/opal/parts/graphics.rb +69 -0
- data/lib/author_engine/game/opal/parts/input.rb +30 -0
- data/lib/author_engine/image.rb +1 -0
- data/lib/author_engine/level_picker.rb +92 -0
- data/lib/author_engine/opal.rb +15 -0
- data/lib/author_engine/save_file.rb +49 -15
- data/lib/author_engine/sprite.rb +1 -2
- data/lib/author_engine/sprite_picker.rb +10 -3
- data/lib/author_engine/text.rb +2 -2
- data/lib/author_engine/version.rb +1 -1
- data/lib/author_engine/views/level_editor.rb +161 -0
- data/lib/author_engine/views/play_viewer.rb +1 -0
- data/lib/author_engine.rb +9 -4
- data/screenshots/code_editor.png +0 -0
- data/screenshots/play.png +0 -0
- data/screenshots/sprite_editor.png +0 -0
- metadata +36 -9
- data/test_3.authorengine +0 -519
- data/testing.authorengine +0 -578
@@ -0,0 +1,158 @@
|
|
1
|
+
class AuthorEngine
|
2
|
+
class GameRunner
|
3
|
+
def self.instance
|
4
|
+
@instance
|
5
|
+
end
|
6
|
+
def self.instance=(klass)
|
7
|
+
@instance = klass
|
8
|
+
end
|
9
|
+
|
10
|
+
attr_reader :save_file, :spritesheet, :sprites, :levels, :fps
|
11
|
+
attr_reader :game
|
12
|
+
def initialize(project_string)
|
13
|
+
AuthorEngine::GameRunner.instance=(self)
|
14
|
+
|
15
|
+
@save_file = AuthorEngine::SaveFile.new(nil)
|
16
|
+
@save_file.load(false, project_string)
|
17
|
+
|
18
|
+
size = 16
|
19
|
+
|
20
|
+
@levels = @save_file.levels
|
21
|
+
@levels.each {|level| level.each {|sprite| sprite.x = sprite.x * size; sprite.y = sprite.y * size}}
|
22
|
+
|
23
|
+
@sprites = []
|
24
|
+
@spritesheet = nil
|
25
|
+
@spritesheet_width = @save_file.sprites.columns
|
26
|
+
@spritesheet_height = @save_file.sprites.rows
|
27
|
+
@sprite_size = 16
|
28
|
+
|
29
|
+
@fps = 0
|
30
|
+
@counted_frames = 0
|
31
|
+
@frame_count_stated_at = 0
|
32
|
+
|
33
|
+
@game = Game.new(code: @save_file.code)
|
34
|
+
build_spritesheet_and_sprites_list
|
35
|
+
resize_canvas
|
36
|
+
|
37
|
+
@collision_detection = AuthorEngine::CollisionDetection.new(@sprites, @levels)
|
38
|
+
@game.collision_detection = @collision_detection
|
39
|
+
|
40
|
+
@levels.each {|level| @collision_detection.add_level(level) }
|
41
|
+
|
42
|
+
@game.init
|
43
|
+
|
44
|
+
return self
|
45
|
+
end
|
46
|
+
|
47
|
+
def draw
|
48
|
+
@game.draw_background
|
49
|
+
@game.draw
|
50
|
+
return nil
|
51
|
+
end
|
52
|
+
|
53
|
+
def update
|
54
|
+
@game.update
|
55
|
+
return nil
|
56
|
+
end
|
57
|
+
|
58
|
+
def run_game
|
59
|
+
`window.requestAnimationFrame(function() {#{run_game}})` # placed here to ensure next frame is called even if draw or update throw an error
|
60
|
+
|
61
|
+
@counted_frames+=1
|
62
|
+
|
63
|
+
if @game.milliseconds - @frame_count_stated_at >= 1000.0
|
64
|
+
@fps = @counted_frames
|
65
|
+
@frame_count_stated_at = @game.milliseconds
|
66
|
+
@counted_frames = 0
|
67
|
+
end
|
68
|
+
|
69
|
+
|
70
|
+
if @sprites.size == (@spritesheet_width/@sprite_size)*(@spritesheet_height/@sprite_size)
|
71
|
+
draw
|
72
|
+
update
|
73
|
+
else
|
74
|
+
@game.draw_background
|
75
|
+
@game.text("Loading sprite #{@sprites.size}/#{(@spritesheet_width/@sprite_size)*(@spritesheet_height/@sprite_size)}.", 0, @game.height/2, 8)
|
76
|
+
end
|
77
|
+
|
78
|
+
return nil
|
79
|
+
end
|
80
|
+
|
81
|
+
def resize_canvas
|
82
|
+
width = `window.innerWidth`
|
83
|
+
height = `window.innerHeight`
|
84
|
+
|
85
|
+
if width < height
|
86
|
+
@game.scale = `window.innerWidth / 128.0`
|
87
|
+
else
|
88
|
+
@game.scale = `window.innerHeight / 128.0`
|
89
|
+
end
|
90
|
+
|
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}`
|
95
|
+
|
96
|
+
`#{@game.canvas_context}.scale(#{@game.scale}, #{@game.scale})`
|
97
|
+
`#{@game.canvas_context}.imageSmoothingEnabled = false`
|
98
|
+
return nil
|
99
|
+
end
|
100
|
+
|
101
|
+
def build_spritesheet_and_sprites_list
|
102
|
+
spritesheet_data = @save_file.sprites
|
103
|
+
width = spritesheet_data.columns
|
104
|
+
height= spritesheet_data.rows
|
105
|
+
size = 16
|
106
|
+
|
107
|
+
temp_canvas = `document.createElement('canvas')`
|
108
|
+
temp_canvas_context = `#{temp_canvas}.getContext('2d')`
|
109
|
+
`#{temp_canvas}.width = #{spritesheet_data.columns}`
|
110
|
+
`#{temp_canvas}.height = #{spritesheet_data.rows}`
|
111
|
+
|
112
|
+
buffer = `new Uint8ClampedArray(#{spritesheet_data.to_blob})`
|
113
|
+
image_data = `new ImageData(#{buffer}, #{width})`
|
114
|
+
`#{temp_canvas_context}.putImageData(#{image_data}, 0, 0)`
|
115
|
+
|
116
|
+
@spritesheet = `new Image()`
|
117
|
+
`#{@spritesheet}.onload = function() { #{load_sprites} }`
|
118
|
+
`#{@spritesheet}.src = #{temp_canvas}.toDataURL()`
|
119
|
+
|
120
|
+
end
|
121
|
+
|
122
|
+
def load_sprites
|
123
|
+
spritesheet_data = @save_file.sprites
|
124
|
+
width = spritesheet_data.columns
|
125
|
+
height= spritesheet_data.rows
|
126
|
+
size = 16
|
127
|
+
|
128
|
+
temp_canvas = `document.createElement('canvas')`
|
129
|
+
temp_canvas_context = `#{temp_canvas}.getContext('2d')`
|
130
|
+
`#{temp_canvas}.width = #{size}`
|
131
|
+
`#{temp_canvas}.height = #{size}`
|
132
|
+
|
133
|
+
(height/size).times do |y|
|
134
|
+
(width/size).times do |x|
|
135
|
+
`#{temp_canvas_context}.clearRect(0,0, #{size}, #{size})`
|
136
|
+
`#{temp_canvas_context}.drawImage(#{@spritesheet}, #{x * size}, #{y * size}, #{size}, #{size}, 0, 0, #{size}, #{size})`
|
137
|
+
@collision_detection.add_sprite(`#{temp_canvas_context}.getImageData(0,0, #{size}, #{size}).data`)
|
138
|
+
|
139
|
+
`createImageBitmap(#{@spritesheet}, #{x * size}, #{y * size}, #{size}, #{size}).then(sprite => { #{@sprites.push(`sprite`)} })`
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
return nil
|
144
|
+
end
|
145
|
+
|
146
|
+
def show(update_interval = (1000.0 / 60))
|
147
|
+
return unless RUBY_ENGINE == "opal"
|
148
|
+
|
149
|
+
`window.addEventListener('resize', () => { #{resize_canvas} })`
|
150
|
+
`document.addEventListener('keydown', (event) => { #{AuthorEngine::Part::Input::KEY_STATES[`event.key`] = true} })`
|
151
|
+
`document.addEventListener('keyup', (event) => { #{AuthorEngine::Part::Input::KEY_STATES[`event.key`] = false} })`
|
152
|
+
|
153
|
+
`document.getElementById('loading').style.display = "none"`
|
154
|
+
`window.requestAnimationFrame(function() {#{run_game}})`
|
155
|
+
return nil
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
class AuthorEngine
|
2
|
+
class Part
|
3
|
+
module Colors
|
4
|
+
Color = Struct.new(:red, :green, :blue)
|
5
|
+
COLORS = {
|
6
|
+
0 => Color.new(0,0,0),
|
7
|
+
1 => Color.new(29, 43, 83),
|
8
|
+
2 => Color.new(126, 37, 83),
|
9
|
+
3 => Color.new(0, 135, 81),
|
10
|
+
|
11
|
+
4 => Color.new(171, 82, 54),
|
12
|
+
5 => Color.new(95, 87, 79),
|
13
|
+
6 => Color.new(194, 195, 199),
|
14
|
+
7 => Color.new(255, 241, 232),
|
15
|
+
|
16
|
+
8 => Color.new(255, 0, 77),
|
17
|
+
9 => Color.new(255, 163, 0),
|
18
|
+
10 => Color.new(225, 236, 39),
|
19
|
+
11 => Color.new(0, 228, 54),
|
20
|
+
|
21
|
+
12 => Color.new(41, 173, 255),
|
22
|
+
13 => Color.new(131, 118, 156),
|
23
|
+
14 => Color.new(225, 119, 168),
|
24
|
+
15 => Color.new(255, 204, 170)
|
25
|
+
}
|
26
|
+
|
27
|
+
def black; rgb(COLORS.dig(0)); end
|
28
|
+
def dark_blue; rgb(COLORS.dig(1)); end
|
29
|
+
def dark_purple; rgb(COLORS.dig(2)); end
|
30
|
+
def dark_green; rgb(COLORS.dig(3)); end
|
31
|
+
|
32
|
+
def brown; rgb(COLORS.dig(4)); end
|
33
|
+
def dark_gray; rgb(COLORS.dig(5)); end
|
34
|
+
def light_gray; rgb(COLORS.dig(6)); end
|
35
|
+
def white; rgb(COLORS.dig(7)); end
|
36
|
+
|
37
|
+
def red; rgb(COLORS.dig(8)); end
|
38
|
+
def orange; rgb(COLORS.dig(9)); end
|
39
|
+
def yellow; rgb(COLORS.dig(10)); end
|
40
|
+
def green; rgb(COLORS.dig(11)); end
|
41
|
+
|
42
|
+
def blue; rgb(COLORS.dig(12)); end
|
43
|
+
def indigo; rgb(COLORS.dig(13)); end
|
44
|
+
def pink; rgb(COLORS.dig(14)); end
|
45
|
+
def peach; rgb(COLORS.dig(15)); end
|
46
|
+
|
47
|
+
def rgb(color)
|
48
|
+
return "rgb(#{color.red}, #{color.green}, #{color.blue})"
|
49
|
+
end
|
50
|
+
|
51
|
+
def xml_color(color)
|
52
|
+
red = color.red.to_s(16)
|
53
|
+
green = color.green.to_s(16)
|
54
|
+
blue = color.blue.to_s(16)
|
55
|
+
|
56
|
+
red = "0#{red}" if color.red < 10
|
57
|
+
green = "0#{green}" if color.green < 10
|
58
|
+
blue = "0#{blue}" if color.blue < 10
|
59
|
+
|
60
|
+
return "#{red}#{green}#{blue}"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class AuthorEngine
|
2
|
+
class Part
|
3
|
+
module Common
|
4
|
+
def width; 128; end
|
5
|
+
def height; 128; end
|
6
|
+
def fps; AuthorEngine::GameRunner.instance.fps; end
|
7
|
+
def milliseconds
|
8
|
+
@__initial_milliseconds ||= `performance.now()`
|
9
|
+
(`performance.now()` - @__initial_milliseconds).round(3)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
class AuthorEngine
|
2
|
+
class Part
|
3
|
+
module Graphics
|
4
|
+
def rect(x = 0, y = 0, width = 1, height = 1, color = "white", z = 0)
|
5
|
+
`#{@canvas_context}.fillStyle = #{color}`
|
6
|
+
`#{@canvas_context}.fillRect(#{x}, #{y}, #{width}, #{height})`
|
7
|
+
return nil
|
8
|
+
end
|
9
|
+
|
10
|
+
def sprite(sprite_sheet_index, x = 0, y = 0, z = 0, alpha = 255)
|
11
|
+
size = 16 # sprite size
|
12
|
+
sprites = AuthorEngine::GameRunner.instance.sprites
|
13
|
+
|
14
|
+
`#{@canvas_context}.save()`
|
15
|
+
if alpha <= 0
|
16
|
+
alpha = 0
|
17
|
+
else
|
18
|
+
alpha = (alpha / 255.0)
|
19
|
+
end
|
20
|
+
`#{@canvas_context}.globalAlpha = #{alpha}`
|
21
|
+
|
22
|
+
`#{@canvas_context}.drawImage(#{sprites[sprite_sheet_index]}, #{x}, #{y})`
|
23
|
+
|
24
|
+
`#{@canvas_context}.restore()`
|
25
|
+
end
|
26
|
+
|
27
|
+
def text(string, x = 0, y = 0, size = 4, z = 0, color = "white")
|
28
|
+
font = "#{size}px Connection, Consolas"
|
29
|
+
`#{@canvas_context}.font = #{font}`
|
30
|
+
`#{@canvas_context}.fillStyle = #{color}`
|
31
|
+
`#{@canvas_context}.textBaseline = "top"`
|
32
|
+
`#{@canvas_context}.fillText(#{string}, #{x}, #{y})`
|
33
|
+
end
|
34
|
+
|
35
|
+
def level(index, z = 0)
|
36
|
+
_level = AuthorEngine::GameRunner.instance.levels[index]
|
37
|
+
raise "No level at '#{index}'!" unless _level
|
38
|
+
|
39
|
+
_level.each do |sprite|
|
40
|
+
sprite(sprite.sprite, sprite.x, sprite.y, z)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def swap(level, current_sprite, replacement_sprite)
|
45
|
+
_level = AuthorEngine::GameRunner.instance.levels[level]
|
46
|
+
raise "No level at '#{index}'!" unless _level
|
47
|
+
raise "No sprite at '#{current_sprite}'!" unless AuthorEngine::GameRunner.instance.sprites[current_sprite]
|
48
|
+
raise "No sprite at '#{current_sprite}'!" unless AuthorEngine::GameRunner.instance.sprites[replacement_sprite]
|
49
|
+
|
50
|
+
_level.each {|sprite| sprite.sprite = replacement_sprite if sprite.sprite == current_sprite}
|
51
|
+
end
|
52
|
+
|
53
|
+
def translate(x, y, &block)
|
54
|
+
`#{@canvas_context}.save()`
|
55
|
+
`#{@canvas_context}.translate(#{x}, #{y})`
|
56
|
+
block.call if block
|
57
|
+
`#{@canvas_context}.restore()`
|
58
|
+
end
|
59
|
+
|
60
|
+
def rotate(angle, x = 0, y = 0, &block)
|
61
|
+
`#{@canvas_context}.save()`
|
62
|
+
`#{@canvas_context}.translate(#{x}, #{y})`
|
63
|
+
`#{@canvas_context}.rotate(#{angle})`
|
64
|
+
block.call if block
|
65
|
+
`#{@canvas_context}.restore()`
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
class AuthorEngine
|
2
|
+
class Part
|
3
|
+
module Input
|
4
|
+
BUTTONS = {
|
5
|
+
"left" => "ArrowLeft",
|
6
|
+
"right" => "ArrowRight",
|
7
|
+
"up" => "ArrowUp",
|
8
|
+
"down" => "ArrowDown",
|
9
|
+
"x" => "x",
|
10
|
+
"y" => "c",
|
11
|
+
}
|
12
|
+
|
13
|
+
# Store keys state
|
14
|
+
KEY_STATES = {
|
15
|
+
}
|
16
|
+
|
17
|
+
def button?(name)
|
18
|
+
down = false
|
19
|
+
|
20
|
+
if BUTTONS.dig(name)
|
21
|
+
down = KEY_STATES.dig(BUTTONS.dig(name)) # dig returns false if key not found
|
22
|
+
else
|
23
|
+
raise "Button '#{name}' not found!"
|
24
|
+
end
|
25
|
+
|
26
|
+
return down
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/lib/author_engine/image.rb
CHANGED
@@ -0,0 +1,92 @@
|
|
1
|
+
class AuthorEngine
|
2
|
+
class LevelPicker
|
3
|
+
include Support
|
4
|
+
|
5
|
+
attr_reader :x, :y, :z, :width, :height, :offset
|
6
|
+
attr_reader :active_level, :active_layer
|
7
|
+
def initialize(x: nil, y: nil, z: 15)
|
8
|
+
@x, @y, @z = x, y, z
|
9
|
+
|
10
|
+
@offset = 1 * window.square_scale
|
11
|
+
@width = window.width - @offset * 4
|
12
|
+
@height = (window.sprite_size * window.square_scale) + @offset * 2
|
13
|
+
|
14
|
+
@x = window.width / 2 - self.width / 2
|
15
|
+
|
16
|
+
@current_level = AuthorEngine::Text.new(y: @y + @offset*2, z: @z + 1)
|
17
|
+
|
18
|
+
@active_level = 0
|
19
|
+
@active_layer = 0
|
20
|
+
|
21
|
+
@max_layers = 16
|
22
|
+
|
23
|
+
@buttons = []
|
24
|
+
|
25
|
+
@buttons << Button.new(label: "-", color: Gosu::Color::GRAY, x: (window.width / 2) - @offset*8, y: @y + @offset*2, z: 18, tooltip: "↓ Decrease Layer") do
|
26
|
+
@active_layer-=1 unless @active_layer < 1
|
27
|
+
end
|
28
|
+
@buttons << Button.new(label: "+", color: Gosu::Color::GRAY, x: (@buttons.last.x + @buttons.last.width) + @offset*2, y: @y + @offset*2, z: 18, tooltip: "↑ Increase Layer") do
|
29
|
+
@active_layer+=1 if @active_layer < @max_layers
|
30
|
+
end
|
31
|
+
|
32
|
+
@buttons << Button.new(label: "<", x: (@x + @width) - @width/3, y: @y + @offset*2, z: 18, tooltip: "← Previous Level", color: Gosu::Color::GRAY) do
|
33
|
+
@active_level-=1
|
34
|
+
@active_level = LevelEditor.instance.levels.size - 1 if @active_level < 0
|
35
|
+
end
|
36
|
+
|
37
|
+
@buttons << Button.new(label: "-", x: @buttons.last.x + @buttons.last.width + @offset, y: @y + @offset*2, z: 18, tooltip: "Destroy Level (Non-recoverable)", color: Gosu::Color::RED) do
|
38
|
+
if LevelEditor.instance.levels[@active_level].is_a?(Array)
|
39
|
+
LevelEditor.instance.levels.delete_at(@active_level)
|
40
|
+
@active_level-=1
|
41
|
+
end
|
42
|
+
|
43
|
+
if LevelEditor.instance.levels.size == 0
|
44
|
+
LevelEditor.instance.levels.push([])
|
45
|
+
@active_level = LevelEditor.instance.levels.size - 1
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
@buttons << Button.new(label: "+", x: @buttons.last.x + @buttons.last.width + @offset, y: @y + @offset*2, z: 18, tooltip: "Add Level", color: Gosu::Color::GREEN) do
|
50
|
+
LevelEditor.instance.levels.push([])
|
51
|
+
@active_level = LevelEditor.instance.levels.size - 1
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
@buttons << Button.new(label: ">", x: @buttons.last.x + @buttons.last.width + @offset, y: @y + @offset*2, z: 18, tooltip: "→ Next Level", color: Gosu::Color::GRAY) do
|
56
|
+
@active_level+=1
|
57
|
+
@active_level = 0 if @active_level >= LevelEditor.instance.levels.size - 1
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def draw
|
62
|
+
Gosu.draw_rect(@x, @y, @width, @height, Gosu::Color.rgba(255,255,255,220), @z)
|
63
|
+
Gosu.draw_rect(@x+4, @y+4, @width-8, @height-8, Gosu::Color.rgba(10, 10, 10,200), @z)
|
64
|
+
|
65
|
+
@buttons.each(&:draw)
|
66
|
+
|
67
|
+
@current_level.message = "Level: #{@active_level}\nLayer: #{@active_layer}/#{@max_layers}"
|
68
|
+
@current_level.x = @x + @offset*2
|
69
|
+
@current_level.draw
|
70
|
+
end
|
71
|
+
|
72
|
+
def button_up(id)
|
73
|
+
@buttons.each {|b| b.button_up(id) }
|
74
|
+
|
75
|
+
case id
|
76
|
+
when Gosu::KbUp
|
77
|
+
@active_layer+=1 if @active_layer < @max_layers
|
78
|
+
|
79
|
+
when Gosu::KbDown
|
80
|
+
@active_layer-=1 unless @active_layer < 1
|
81
|
+
|
82
|
+
when Gosu::KbLeft
|
83
|
+
@active_level -= 1
|
84
|
+
@active_level = LevelEditor.instance.levels.size - 1 if @active_level < 0
|
85
|
+
|
86
|
+
when Gosu::KbRight
|
87
|
+
@active_level += 1
|
88
|
+
@active_level = 0 unless @active_level < LevelEditor.instance.levels.size
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
raise "Only require \"author_engine/opal\" with Opal!" unless RUBY_ENGINE == "opal"
|
2
|
+
|
3
|
+
require_relative "game/common/parts/collision_detection"
|
4
|
+
|
5
|
+
require_relative "game/opal/parts/common"
|
6
|
+
require_relative "game/opal/parts/colors"
|
7
|
+
require_relative "game/opal/parts/graphics"
|
8
|
+
require_relative "game/opal/parts/input"
|
9
|
+
|
10
|
+
require_relative "collision_detection/collision_detection"
|
11
|
+
require_relative "sprite"
|
12
|
+
|
13
|
+
require_relative "game/game"
|
14
|
+
require_relative "save_file"
|
15
|
+
require_relative "game/opal/game_runner"
|
@@ -23,7 +23,7 @@ class AuthorEngine
|
|
23
23
|
|
24
24
|
@code, @sprites, @levels = nil, nil, nil
|
25
25
|
|
26
|
-
load
|
26
|
+
load unless RUBY_ENGINE == "opal"
|
27
27
|
end
|
28
28
|
|
29
29
|
def save
|
@@ -64,23 +64,29 @@ class AuthorEngine
|
|
64
64
|
|
65
65
|
def save_levels
|
66
66
|
@buffer+= "___LEVELS___\n"
|
67
|
-
|
68
|
-
|
67
|
+
LevelEditor.instance.levels.each do |level|
|
68
|
+
@buffer+= "#{level.map {|s| "#{s.sprite},#{s.x},#{s.y},#{s.z}"}.join(",")}\n"
|
69
|
+
end
|
70
|
+
@buffer.strip # Level is the last element saved
|
69
71
|
end
|
70
72
|
|
71
|
-
def load
|
72
|
-
|
73
|
-
|
73
|
+
def load(from_file = true, data = nil)
|
74
|
+
string = ""
|
75
|
+
if from_file
|
76
|
+
File.open(@file, "r") {|f| string = f.read}
|
77
|
+
else
|
78
|
+
string = data
|
79
|
+
end
|
74
80
|
|
75
|
-
load_code(
|
76
|
-
load_spritesheet(
|
77
|
-
load_levels(
|
81
|
+
load_code(string)
|
82
|
+
load_spritesheet(string)
|
83
|
+
load_levels(string)
|
78
84
|
end
|
79
85
|
|
80
|
-
def load_code(
|
86
|
+
def load_code(string)
|
81
87
|
buffer = ""
|
82
88
|
in_code= false
|
83
|
-
|
89
|
+
string.each_line do |line|
|
84
90
|
if line.start_with?("___CODE___")
|
85
91
|
in_code = true
|
86
92
|
next
|
@@ -95,13 +101,13 @@ class AuthorEngine
|
|
95
101
|
@code = buffer
|
96
102
|
end
|
97
103
|
|
98
|
-
def load_spritesheet(
|
104
|
+
def load_spritesheet(string)
|
99
105
|
buffer = ""
|
100
106
|
width = 0
|
101
107
|
height = 0
|
102
108
|
in_sprites = false
|
103
109
|
|
104
|
-
|
110
|
+
string.each_line do |line|
|
105
111
|
if line.strip.start_with?("___SPRITES___")
|
106
112
|
in_sprites = true
|
107
113
|
next
|
@@ -123,12 +129,40 @@ class AuthorEngine
|
|
123
129
|
buffer += line.strip
|
124
130
|
end
|
125
131
|
|
126
|
-
stream =
|
132
|
+
stream = nil
|
133
|
+
if RUBY_ENGINE != "opal"
|
134
|
+
stream = buffer.scan(/../).map { |x| x.hex }.pack('c*')
|
135
|
+
else
|
136
|
+
stream = buffer.scan(/../).map { |x| Integer(x.hex) }
|
137
|
+
end
|
127
138
|
|
128
139
|
@sprites = SpriteSheetData.new(width, height, stream)
|
129
140
|
end
|
130
141
|
|
131
|
-
def load_levels(
|
142
|
+
def load_levels(string)
|
143
|
+
levels = []
|
144
|
+
in_level = false
|
145
|
+
|
146
|
+
string.each_line do |line|
|
147
|
+
if line.start_with?("___LEVELS___")
|
148
|
+
in_level = true
|
149
|
+
next
|
150
|
+
end
|
151
|
+
if line.start_with?("___") && in_level
|
152
|
+
break
|
153
|
+
end
|
154
|
+
|
155
|
+
if in_level
|
156
|
+
level = []
|
157
|
+
# 0 - Sprite, 1 - X, 2 - Y, 3 - Z
|
158
|
+
line.strip.split(",").each_slice(4) do |sprite|
|
159
|
+
level << Sprite.new(Integer(sprite[0]), Integer(sprite[1]), Integer(sprite[2]), Integer(sprite[3]))
|
160
|
+
end
|
161
|
+
levels << level
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
@levels = levels
|
132
166
|
end
|
133
167
|
end
|
134
168
|
end
|
data/lib/author_engine/sprite.rb
CHANGED
@@ -4,7 +4,7 @@ class AuthorEngine
|
|
4
4
|
|
5
5
|
attr_reader :active_sprite
|
6
6
|
attr_reader :x, :y, :width, :height
|
7
|
-
attr_reader :rows, :columns
|
7
|
+
attr_reader :rows, :columns, :offset
|
8
8
|
def initialize(x: nil, y:, width: nil, height: nil)
|
9
9
|
@x, @y, @width, @height = x, y, width, height
|
10
10
|
@sprite_size = window.sprite_size
|
@@ -21,19 +21,26 @@ class AuthorEngine
|
|
21
21
|
|
22
22
|
@offset = 1 * window.square_scale
|
23
23
|
@tooltip = AuthorEngine::Text.new(message: "", z: 100)
|
24
|
-
@current_page = AuthorEngine::Text.new(message: "Page 0", size: 20, x: window.width/2,
|
24
|
+
@current_page = AuthorEngine::Text.new(message: "Page 0", size: 20, x: window.width/2, z: 100)
|
25
25
|
|
26
26
|
@page = 0
|
27
27
|
end
|
28
28
|
|
29
|
+
def y=(n)
|
30
|
+
@y = n
|
31
|
+
end
|
32
|
+
|
29
33
|
def draw
|
30
|
-
|
34
|
+
@current_page.y = @y - 24
|
35
|
+
|
36
|
+
Gosu.draw_rect(@x-@offset, @y-@offset, @width+(@offset*2), @height+(@offset*2), Gosu::Color.rgba(255,255,255,220), 15)
|
31
37
|
Gosu.draw_rect(@x, @y, @width, @height, Gosu::Color.rgba(10, 10, 10, 200), 15)
|
32
38
|
draw_grid
|
33
39
|
draw_sprites
|
34
40
|
|
35
41
|
draw_and_update_tooltip
|
36
42
|
@current_page.message = "Page #{@page}"
|
43
|
+
@current_page.x = @width/2 - @current_page.width/2
|
37
44
|
@current_page.draw
|
38
45
|
end
|
39
46
|
|
data/lib/author_engine/text.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
class AuthorEngine
|
2
2
|
class Text
|
3
3
|
include Support
|
4
|
-
FONT_DEFAULT
|
5
|
-
FONT_DEFAULT_BOLD = "assets/fonts/ConnectionBold.otf"
|
4
|
+
FONT_DEFAULT = "#{File.expand_path("../../../", __FILE__)}/assets/fonts/Connection.otf"
|
5
|
+
FONT_DEFAULT_BOLD = "#{File.expand_path("../../../", __FILE__)}/assets/fonts/ConnectionBold.otf"
|
6
6
|
|
7
7
|
attr_accessor :message, :x, :y, :z, :color
|
8
8
|
attr_reader :size, :font
|