summaryrefslogtreecommitdiffhomepage
path: root/samples
diff options
context:
space:
mode:
authorAmir Rajan <[email protected]>2021-12-10 00:09:48 -0600
committerAmir Rajan <[email protected]>2021-12-10 00:09:48 -0600
commiteaa29e72939f5edf61735ccbb73c36ee89369f65 (patch)
treec310fac2e39bd799bf7fc1f73d35c12bcc5187b7 /samples
parent33dfdde9ae03e3218b4796f3595d3b727f626587 (diff)
downloaddragonruby-game-toolkit-contrib-eaa29e72939f5edf61735ccbb73c36ee89369f65.tar.gz
dragonruby-game-toolkit-contrib-eaa29e72939f5edf61735ccbb73c36ee89369f65.zip
Synced with DragonRuby Game Toolkit v3.2.
Diffstat (limited to 'samples')
-rw-r--r--samples/02_input_basics/01_moving_a_sprite/replay.txt73
-rw-r--r--samples/04_physics_and_collisions/06_box_collision_3/app/main.rb12
-rw-r--r--samples/04_physics_and_collisions/07_jump_physics/app/main.rb10
-rw-r--r--samples/05_mouse/01_mouse_click/app/main.rb16
-rw-r--r--samples/05_mouse/02_mouse_move/app/main.rb2
-rw-r--r--samples/05_mouse/04_coordinate_systems/app/main.rb4
-rw-r--r--samples/07_advanced_audio/01_audio_mixer/app/main.rb5
-rw-r--r--samples/07_advanced_audio/01_audio_mixer/sounds/drum.mp3bin0 -> 55090 bytes
-rw-r--r--samples/07_advanced_rendering/00_labels_with_wrapped_text/app/main.rb88
-rw-r--r--samples/07_advanced_rendering/00_labels_with_wrapped_text/replay.txt93
-rw-r--r--samples/07_advanced_rendering/00_rotating_label/app/main.rb32
-rw-r--r--samples/07_advanced_rendering/08_splitscreen_camera/app/main.rb35
-rw-r--r--samples/09_performance/03_sprites_as_struct/app/main.rb82
-rw-r--r--samples/09_performance/03_sprites_as_struct/license-for-sample.txt9
-rw-r--r--samples/09_performance/03_sprites_as_struct/sprites/tiny-star.pngbin0 -> 112 bytes
-rw-r--r--samples/09_performance/04_sprites_as_strict_entities/app/main.rb72
-rw-r--r--samples/09_performance/04_sprites_as_strict_entities/license-for-sample.txt9
-rw-r--r--samples/09_performance/04_sprites_as_strict_entities/sprites/tiny-star.pngbin0 -> 112 bytes
-rw-r--r--samples/09_performance/05_sprites_as_classes/app/main.rb55
-rw-r--r--samples/09_performance/05_sprites_as_classes/license-for-sample.txt9
-rw-r--r--samples/09_performance/05_sprites_as_classes/sprites/tiny-star.pngbin0 -> 112 bytes
-rw-r--r--samples/09_performance/06_static_sprites_as_classes/app/main.rb56
-rw-r--r--samples/09_performance/06_static_sprites_as_classes/license-for-sample.txt9
-rw-r--r--samples/09_performance/06_static_sprites_as_classes/sprites/tiny-star.pngbin0 -> 112 bytes
-rw-r--r--samples/09_performance/07_static_sprites_as_classes_with_custom_drawing/app/main.rb88
-rw-r--r--samples/09_performance/07_static_sprites_as_classes_with_custom_drawing/license-for-sample.txt9
-rw-r--r--samples/09_performance/07_static_sprites_as_classes_with_custom_drawing/sprites/tiny-star.pngbin0 -> 112 bytes
-rw-r--r--samples/09_performance/08_collision_limits/app/main.rb55
-rw-r--r--samples/09_performance/08_collision_limits/license-for-sample.txt9
-rw-r--r--samples/10_advanced_debugging/00_logging/app/main.rb19
-rw-r--r--samples/11_http/01_retrieve_images/app/main.rb4
-rw-r--r--samples/11_http/02_in_game_web_server_http_get/app/main.rb28
-rw-r--r--samples/11_http/02_in_game_web_server_http_get/license-for-sample.txt9
-rw-r--r--samples/11_http/03_in_game_web_server_http_post/app/main.rb72
-rw-r--r--samples/11_http/03_in_game_web_server_http_post/replay.txt415
-rw-r--r--samples/12_c_extensions/.gitignore2
-rw-r--r--samples/12_c_extensions/01_basics/native/ext-bindings.c37
-rw-r--r--samples/12_c_extensions/02_intermediate/native/re-bindings.c67
-rw-r--r--samples/12_c_extensions/03_native_pixel_arrays/native/ext-bindings.c37
-rw-r--r--samples/13_path_finding_algorithms/01_breadth_first_search/replay.txt203
-rw-r--r--samples/13_path_finding_algorithms/02_detailed_breadth_first_search/replay.txt241
-rw-r--r--samples/13_path_finding_algorithms/03_breadcrumbs/app/main.rb136
-rw-r--r--samples/13_path_finding_algorithms/03_breadcrumbs/replay.txt365
-rw-r--r--samples/13_path_finding_algorithms/04_early_exit/app/main.rb204
-rw-r--r--samples/13_path_finding_algorithms/04_early_exit/replay.txt364
-rw-r--r--samples/13_path_finding_algorithms/05_dijkstra/app/main.rb218
-rw-r--r--samples/13_path_finding_algorithms/05_dijkstra/replay.txt686
-rw-r--r--samples/13_path_finding_algorithms/06_heuristic/app/main.rb2
-rw-r--r--samples/13_path_finding_algorithms/06_heuristic/replay.txt719
-rw-r--r--samples/13_path_finding_algorithms/07_heuristic_with_walls/app/main.rb2
-rw-r--r--samples/13_path_finding_algorithms/07_heuristic_with_walls/replay.txt352
-rw-r--r--samples/13_path_finding_algorithms/08_a_star/app/main.rb258
-rw-r--r--samples/13_path_finding_algorithms/08_a_star/replay.txt434
-rw-r--r--samples/99_genre_3d/02_wireframe/replay.txt242
-rw-r--r--samples/99_genre_3d/03_yaw_pitch_roll/app/main.rb351
-rw-r--r--samples/99_genre_3d/03_yaw_pitch_roll/replay.txt361
-rw-r--r--samples/99_genre_arcade/bullet_hell/replay.txt126
-rw-r--r--samples/99_genre_arcade/flappy_dragon/app/main.rb97
-rw-r--r--samples/99_genre_arcade/twinstick/replay.txt174
-rw-r--r--samples/99_genre_crafting/farming_game_starting_point/replay.txt170
-rw-r--r--samples/99_genre_crafting/replay.txt170
-rw-r--r--samples/99_genre_dungeon_crawl/classics_jam/replay.txt197
-rw-r--r--samples/99_genre_mario/01_jumping/app/main.rb78
-rw-r--r--samples/99_genre_mario/01_jumping/replay.txt52
-rw-r--r--samples/99_genre_mario/01_jumping/sprites/square/red.pngbin0 -> 335 bytes
-rw-r--r--samples/99_genre_mario/02_jumping_and_collisions/app/main.rb281
-rw-r--r--samples/99_genre_mario/02_jumping_and_collisions/replay.txt159
-rw-r--r--samples/99_genre_mario/02_jumping_and_collisions/sprites/square/red.pngbin0 -> 335 bytes
-rw-r--r--samples/99_genre_mario/02_jumping_and_collisions/sprites/square/white.pngbin0 -> 325 bytes
-rw-r--r--samples/99_genre_platformer/clepto_frog/app/main.rb171
-rw-r--r--samples/99_genre_platformer/clepto_frog/app/map.rb5
-rw-r--r--samples/99_genre_platformer/clepto_frog/replay.txt249
-rw-r--r--samples/99_genre_platformer/the_little_probe/app/main.rb10
-rw-r--r--samples/99_genre_platformer/the_little_probe/bug-replay.txt205
-rw-r--r--samples/99_genre_rpg_roguelike/01_roguelike_starting_point/replay.txt196
-rw-r--r--samples/99_genre_rpg_topdown/topdown_casino/app/main.rb139
-rw-r--r--samples/99_genre_rpg_topdown/topdown_casino/license-for-sample.txt9
-rw-r--r--samples/99_genre_rpg_topdown/topdown_casino/replay.txt123
-rw-r--r--samples/99_genre_rpg_topdown/topdown_casino/sprites/fire.pngbin0 -> 893 bytes
-rw-r--r--samples/99_genre_rpg_topdown/topdown_casino/sprites/gem200.pngbin0 -> 916 bytes
-rw-r--r--samples/99_genre_rpg_topdown/topdown_casino/sprites/gem400.pngbin0 -> 920 bytes
-rw-r--r--samples/99_genre_rpg_topdown/topdown_casino/sprites/herodown100.pngbin0 -> 3600 bytes
-rw-r--r--samples/99_genre_rpg_topdown/topdown_casino/sprites/herodown200.pngbin0 -> 3600 bytes
-rw-r--r--samples/99_genre_rpg_topdown/topdown_casino/sprites/heroleft100.pngbin0 -> 3600 bytes
-rw-r--r--samples/99_genre_rpg_topdown/topdown_casino/sprites/heroleft200.pngbin0 -> 3600 bytes
-rw-r--r--samples/99_genre_rpg_topdown/topdown_casino/sprites/heroright100.pngbin0 -> 3600 bytes
-rw-r--r--samples/99_genre_rpg_topdown/topdown_casino/sprites/heroright200.pngbin0 -> 3600 bytes
-rw-r--r--samples/99_genre_rpg_topdown/topdown_casino/sprites/heroup100.pngbin0 -> 3600 bytes
-rw-r--r--samples/99_genre_rpg_topdown/topdown_casino/sprites/heroup200.pngbin0 -> 3600 bytes
-rw-r--r--samples/99_genre_rpg_topdown/topdown_casino/sprites/oldman.pngbin0 -> 967 bytes
-rw-r--r--samples/99_genre_teenytiny/teenytiny_starting_point/app/main.rb162
-rw-r--r--samples/99_genre_teenytiny/teenytiny_starting_point/license.txt9
-rw-r--r--samples/99_genre_teenytiny/teenytiny_starting_point/sprites/square-green.pngbin0 -> 283 bytes
-rw-r--r--samples/99_genre_teenytiny/teenytiny_starting_point/sprites/square-red.pngbin0 -> 274 bytes
94 files changed, 8809 insertions, 633 deletions
diff --git a/samples/02_input_basics/01_moving_a_sprite/replay.txt b/samples/02_input_basics/01_moving_a_sprite/replay.txt
new file mode 100644
index 0000000..1ec5f3a
--- /dev/null
+++ b/samples/02_input_basics/01_moving_a_sprite/replay.txt
@@ -0,0 +1,73 @@
+replay_version 2.0
+stopped_at 442
+seed 100
+recorded_at 2021-11-20 11:06:58 -0600
+[:mouse_button_up, 1, 0, 1, 1, 5]
+[:key_down_raw, 1073741903, 0, 2, 2, 147]
+[:key_down_raw, 1073741903, 0, 2, 3, 162]
+[:key_down_raw, 1073741903, 0, 2, 4, 164]
+[:key_down_raw, 1073741903, 0, 2, 5, 166]
+[:key_down_raw, 1073741903, 0, 2, 6, 168]
+[:key_down_raw, 1073741903, 0, 2, 7, 170]
+[:key_down_raw, 1073741903, 0, 2, 8, 172]
+[:key_down_raw, 1073741906, 0, 2, 9, 172]
+[:key_down_raw, 1073741905, 0, 2, 10, 182]
+[:key_up_raw, 1073741903, 0, 2, 11, 185]
+[:key_up_raw, 1073741906, 0, 2, 12, 188]
+[:key_down_raw, 1073741904, 0, 2, 13, 195]
+[:key_up_raw, 1073741905, 0, 2, 14, 202]
+[:key_up_raw, 1073741904, 0, 2, 15, 208]
+[:key_down_raw, 1073741903, 0, 2, 16, 210]
+[:key_down_raw, 1073741903, 0, 2, 17, 225]
+[:key_down_raw, 1073741903, 0, 2, 18, 227]
+[:key_down_raw, 1073741903, 0, 2, 19, 229]
+[:key_down_raw, 1073741903, 0, 2, 20, 231]
+[:key_down_raw, 1073741903, 0, 2, 21, 233]
+[:key_down_raw, 1073741903, 0, 2, 22, 235]
+[:key_down_raw, 1073741903, 0, 2, 23, 237]
+[:key_down_raw, 1073741903, 0, 2, 24, 239]
+[:key_down_raw, 1073741903, 0, 2, 25, 241]
+[:key_down_raw, 1073741903, 0, 2, 26, 243]
+[:key_down_raw, 1073741903, 0, 2, 27, 245]
+[:key_down_raw, 1073741903, 0, 2, 28, 247]
+[:key_down_raw, 1073741903, 0, 2, 29, 249]
+[:key_down_raw, 1073741903, 0, 2, 30, 251]
+[:key_down_raw, 1073741903, 0, 2, 31, 253]
+[:key_down_raw, 1073741903, 0, 2, 32, 255]
+[:key_down_raw, 1073741903, 0, 2, 33, 257]
+[:key_down_raw, 1073741903, 0, 2, 34, 259]
+[:key_down_raw, 1073741903, 0, 2, 35, 261]
+[:key_down_raw, 1073741903, 0, 2, 36, 263]
+[:key_down_raw, 1073741903, 0, 2, 37, 265]
+[:key_down_raw, 1073741903, 0, 2, 38, 267]
+[:key_down_raw, 1073741903, 0, 2, 39, 269]
+[:key_down_raw, 1073741903, 0, 2, 40, 271]
+[:key_down_raw, 1073741906, 0, 2, 41, 271]
+[:key_up_raw, 1073741903, 0, 2, 42, 282]
+[:key_down_raw, 1073741906, 0, 2, 43, 286]
+[:key_down_raw, 1073741906, 0, 2, 44, 288]
+[:key_down_raw, 1073741906, 0, 2, 45, 290]
+[:key_down_raw, 1073741906, 0, 2, 46, 292]
+[:key_down_raw, 1073741906, 0, 2, 47, 294]
+[:key_down_raw, 1073741906, 0, 2, 48, 296]
+[:key_down_raw, 1073741906, 0, 2, 49, 298]
+[:key_down_raw, 1073741906, 0, 2, 50, 301]
+[:key_down_raw, 1073741905, 0, 2, 51, 302]
+[:key_up_raw, 1073741906, 0, 2, 52, 313]
+[:key_down_raw, 1073741904, 0, 2, 53, 315]
+[:key_up_raw, 1073741905, 0, 2, 54, 322]
+[:key_down_raw, 1073741904, 0, 2, 55, 330]
+[:key_down_raw, 1073741904, 0, 2, 56, 332]
+[:key_down_raw, 1073741904, 0, 2, 57, 334]
+[:key_down_raw, 1073741904, 0, 2, 58, 336]
+[:key_down_raw, 1073741904, 0, 2, 59, 338]
+[:key_down_raw, 1073741904, 0, 2, 60, 340]
+[:key_down_raw, 1073741904, 0, 2, 61, 342]
+[:key_down_raw, 1073741904, 0, 2, 62, 344]
+[:key_down_raw, 1073741904, 0, 2, 63, 346]
+[:key_down_raw, 1073741904, 0, 2, 64, 348]
+[:key_down_raw, 1073741904, 0, 2, 65, 350]
+[:key_up_raw, 1073741904, 0, 2, 66, 351]
+[:key_down_raw, 96, 0, 2, 67, 359]
+[:key_up_raw, 96, 0, 2, 68, 364]
+[:key_down_raw, 13, 0, 2, 69, 442]
diff --git a/samples/04_physics_and_collisions/06_box_collision_3/app/main.rb b/samples/04_physics_and_collisions/06_box_collision_3/app/main.rb
index ae447fd..e2210c2 100644
--- a/samples/04_physics_and_collisions/06_box_collision_3/app/main.rb
+++ b/samples/04_physics_and_collisions/06_box_collision_3/app/main.rb
@@ -152,17 +152,17 @@ class Game
end
def calc_player_dx
- player.y += player.dy
- player.dy += state.gravity
- player.dy += player.dy * state.drag ** 2 * -1
- end
-
- def calc_player_dy
player.dx = player.dx.clamp(-5, 5)
player.dx *= 0.9
player.x += player.dx
end
+ def calc_player_dy
+ player.y += player.dy
+ player.dy += state.gravity
+ player.dy += player.dy * state.drag ** 2 * -1
+ end
+
def reset_player
player.x = 100
player.y = 720
diff --git a/samples/04_physics_and_collisions/07_jump_physics/app/main.rb b/samples/04_physics_and_collisions/07_jump_physics/app/main.rb
index 3fcb9e9..8db98be 100644
--- a/samples/04_physics_and_collisions/07_jump_physics/app/main.rb
+++ b/samples/04_physics_and_collisions/07_jump_physics/app/main.rb
@@ -45,8 +45,7 @@ class VerticalPlatformer
input
end
- # Sets default values
- def defaults
+ def init_game
s.platforms ||= [ # initializes platforms collection with two platforms using hashes
new_platform(x: 0, y: 0, w: 700, h: 32, dx: 1, speed: 0, rect: nil),
new_platform(x: 0, y: 300, w: 700, h: 32, dx: 1, speed: 0, rect: nil), # 300 pixels higher
@@ -69,6 +68,11 @@ class VerticalPlatformer
s.camera ||= { y: -100 } # shows view on screen (as the player moves upward, the camera does too)
end
+ # Sets default values
+ def defaults
+ init_game
+ end
+
# Outputs objects onto the screen
def render
outputs.solids << s.platforms.map do |p| # outputs platforms onto screen
@@ -156,7 +160,9 @@ class VerticalPlatformer
rect: nil)
end
else
+ # game over
s.as_hash.clear # otherwise clear the hash (no new platform is necessary)
+ init_game
end
end
diff --git a/samples/05_mouse/01_mouse_click/app/main.rb b/samples/05_mouse/01_mouse_click/app/main.rb
index 8969a6e..e37a753 100644
--- a/samples/05_mouse/01_mouse_click/app/main.rb
+++ b/samples/05_mouse/01_mouse_click/app/main.rb
@@ -49,12 +49,23 @@ class TicTacToe
# Starts the game with player x's turn and creates an array (to_a) for space combinations.
# Calls methods necessary for the game to run properly.
def tick
- state.current_turn ||= :x
- state.space_combinations = [-1, 0, 1].product([-1, 0, 1]).to_a
+ init_new_game
render_board
input_board
end
+ def init_new_game
+ state.current_turn ||= :x
+ state.space_combinations ||= [-1, 0, 1].product([-1, 0, 1]).to_a
+
+ state.spaces ||= {}
+
+ state.space_combinations.each do |x, y|
+ state.spaces[x] ||= {}
+ state.spaces[x][y] ||= state.new_entity(:space)
+ end
+ end
+
# Uses borders to create grid squares for the game's board. Also outputs the game pieces using labels.
def render_board
square_size = 80
@@ -130,6 +141,7 @@ class TicTacToe
def input_restart_game
return unless state.game_over
gtk.reset
+ init_new_game
end
# Checks if x or o won the game.
diff --git a/samples/05_mouse/02_mouse_move/app/main.rb b/samples/05_mouse/02_mouse_move/app/main.rb
index 97edbe7..d9387dc 100644
--- a/samples/05_mouse/02_mouse_move/app/main.rb
+++ b/samples/05_mouse/02_mouse_move/app/main.rb
@@ -196,7 +196,7 @@ class ProtectThePuppiesFromTheZombies
def calc_kill_zombie
# Find all zombies that intersect with the player. They are considered killed.
- killed_this_frame = state.zombies.find_all { |z| z.sprite.intersect_rect? state.player_sprite }
+ killed_this_frame = state.zombies.find_all { |z| z.sprite && (z.sprite.intersect_rect? state.player_sprite) }
state.zombies = state.zombies - killed_this_frame # remove newly killed zombies from zombies collection
state.killed_zombies += killed_this_frame # add newly killed zombies to killed zombies
diff --git a/samples/05_mouse/04_coordinate_systems/app/main.rb b/samples/05_mouse/04_coordinate_systems/app/main.rb
index cbf3329..fcfa090 100644
--- a/samples/05_mouse/04_coordinate_systems/app/main.rb
+++ b/samples/05_mouse/04_coordinate_systems/app/main.rb
@@ -2,7 +2,7 @@
APIs listing that haven't been encountered in previous sample apps:
- - args.inputs.mouse.position: Coordinates of the mouse's position on the screen.
+ - args.inputs.mouse.click.position: Coordinates of the mouse's position on the screen.
Unlike args.inputs.mouse.click.point, the mouse does not need to be pressed down for
position to know the mouse's coordinates.
For more information about the mouse, go to mygame/documentation/07-mouse.md.
@@ -43,7 +43,7 @@ def tick args
# ensure that the outputs don't overlap each other. Try removing them and see what happens.
pos = args.inputs.mouse.position # stores coordinates of mouse's position
args.outputs.labels << [pos.x + 10, pos.y + 10, "#{pos}"] # outputs label of coordinates
- args.outputs.solids << [pos.x - 2, pos.y - 2, 5, 5] # outputs small black box placed where mouse is hovering
+ args.outputs.solids << [pos.x - 2, pos.y - 2, 5, 5] # outputs small blackk box placed where mouse is hovering
button = [0, 0, 370, 50] # sets definition of toggle button
args.outputs.borders << button # outputs button as border (not filled in)
diff --git a/samples/07_advanced_audio/01_audio_mixer/app/main.rb b/samples/07_advanced_audio/01_audio_mixer/app/main.rb
index 3a85d47..9cdc62f 100644
--- a/samples/07_advanced_audio/01_audio_mixer/app/main.rb
+++ b/samples/07_advanced_audio/01_audio_mixer/app/main.rb
@@ -71,6 +71,7 @@ def render_sources args
end
def playtime_str t
+ return "" unless t
minutes = (t / 60.0).floor
seconds = t - (minutes * 60.0).to_f
return minutes.to_s + ':' + seconds.floor.to_s + ((seconds - seconds.floor).to_s + "000")[1..3]
@@ -183,7 +184,7 @@ def panel_primitives args, audio_entry
results.playtime_slider_rect = progress_bar(args: args,
row: 2.5,
col: 2,
- percentage: audio_entry.playtime / audio_entry.length_,
+ percentage: (audio_entry.playtime || 1) / (audio_entry.length_ || 1),
text: "#{playtime_str(audio_entry.playtime)} / #{playtime_str(audio_entry.length_)}")
results.primitives << results.playtime_slider_rect.primitives
@@ -320,7 +321,7 @@ def defaults args
args.state.sound_files ||= [
{ name: :tada, path: "sounds/tada.wav" },
{ name: :splash, path: "sounds/splash.wav" },
- { name: :drum, path: "sounds/drum.wav" },
+ { name: :drum, path: "sounds/drum.mp3" },
{ name: :spring, path: "sounds/spring.wav" },
{ name: :music, path: "sounds/music.ogg" }
]
diff --git a/samples/07_advanced_audio/01_audio_mixer/sounds/drum.mp3 b/samples/07_advanced_audio/01_audio_mixer/sounds/drum.mp3
new file mode 100644
index 0000000..e41e671
--- /dev/null
+++ b/samples/07_advanced_audio/01_audio_mixer/sounds/drum.mp3
Binary files differ
diff --git a/samples/07_advanced_rendering/00_labels_with_wrapped_text/app/main.rb b/samples/07_advanced_rendering/00_labels_with_wrapped_text/app/main.rb
new file mode 100644
index 0000000..71eefa9
--- /dev/null
+++ b/samples/07_advanced_rendering/00_labels_with_wrapped_text/app/main.rb
@@ -0,0 +1,88 @@
+def tick args
+ # defaults
+ args.state.scroll_location ||= 0
+ args.state.textbox.messages ||= []
+ args.state.textbox.scroll ||= 0
+
+ # render
+ args.outputs.background_color = [0, 0, 0, 255]
+ render_messages args
+ render_instructions args
+
+ # inputs
+ if args.inputs.keyboard.key_down.one
+ queue_message args, "Hello there neighbour! my name is mark, how is your day today?"
+ end
+
+ if args.inputs.keyboard.key_down.two
+ queue_message args, "I'm doing great sir, actually I'm having a picnic today"
+ end
+
+ if args.inputs.keyboard.key_down.three
+ queue_message args, "Well that sounds wonderful!"
+ end
+
+ if args.inputs.keyboard.key_down.home
+ args.state.scroll_location = 1
+ end
+
+ if args.inputs.keyboard.key_down.delete
+ clear_message_queue args
+ end
+end
+
+def queue_message args, msg
+ args.state.textbox.messages.concat msg.wrapped_lines 50
+end
+
+def clear_message_queue args
+ args.state.textbox.messages = nil
+ args.state.textbox.scroll = 0
+end
+
+def render_messages args
+ args.outputs[:textbox].w = 400
+ args.outputs[:textbox].h = 720
+
+ args.outputs.primitives << args.state.textbox.messages.each_with_index.map do |s, idx|
+ {
+ x: 0,
+ y: 20 * (args.state.textbox.messages.size - idx) + args.state.textbox.scroll * 20,
+ text: s,
+ size_enum: -3,
+ alignment_enum: 0,
+ r: 255, g:255, b: 255, a: 255
+ }
+ end
+
+ args.outputs[:textbox].labels << args.state.textbox.messages.each_with_index.map do |s, idx|
+ {
+ x: 0,
+ y: 20 * (args.state.textbox.messages.size - idx) + args.state.textbox.scroll * 20,
+ text: s,
+ size_enum: -3,
+ alignment_enum: 0,
+ r: 255, g:255, b: 255, a: 255
+ }
+ end
+
+ args.outputs[:textbox].borders << [0, 0, args.outputs[:textbox].w, 720]
+
+ args.state.textbox.scroll += args.inputs.mouse.wheel.y unless args.inputs.mouse.wheel.nil?
+
+ if args.state.scroll_location > 0
+ args.state.textbox.scroll = 0
+ args.state.scroll_location = 0
+ end
+
+ args.outputs.sprites << [900, 0, args.outputs[:textbox].w, 720, :textbox]
+end
+
+def render_instructions args
+ args.outputs.labels << [30,
+ 30.from_top,
+ "press 1, 2, 3 to display messages, MOUSE WHEEL to scroll, HOME to go to top, BACKSPACE to delete.",
+ 0, 255, 255]
+
+ args.outputs.primitives << [0, 55.from_top, 1280, 30, :pixel, 0, 255, 0, 0, 0].sprite
+end
diff --git a/samples/07_advanced_rendering/00_labels_with_wrapped_text/replay.txt b/samples/07_advanced_rendering/00_labels_with_wrapped_text/replay.txt
new file mode 100644
index 0000000..8153881
--- /dev/null
+++ b/samples/07_advanced_rendering/00_labels_with_wrapped_text/replay.txt
@@ -0,0 +1,93 @@
+replay_version 2.0
+stopped_at 461
+seed 100
+recorded_at 2021-11-20 11:11:30 -0600
+[:mouse_button_up, 1, 0, 1, 1, 5]
+[:mouse_move, 789, 84, 2, 2, 33]
+[:mouse_move, 790, 84, 2, 3, 35]
+[:mouse_move, 791, 84, 2, 4, 37]
+[:key_down_raw, 49, 0, 2, 5, 72]
+[:key_up_raw, 49, 0, 2, 6, 78]
+[:key_down_raw, 50, 0, 2, 7, 90]
+[:key_up_raw, 50, 0, 2, 8, 97]
+[:mouse_move, 789, 85, 2, 9, 108]
+[:mouse_move, 784, 86, 2, 10, 109]
+[:mouse_move, 780, 88, 2, 11, 110]
+[:mouse_move, 780, 89, 2, 12, 112]
+[:mouse_move, 780, 90, 2, 13, 114]
+[:mouse_move, 780, 91, 2, 14, 115]
+[:key_down_raw, 49, 0, 2, 15, 123]
+[:key_up_raw, 49, 0, 2, 16, 131]
+[:key_down_raw, 49, 0, 2, 17, 150]
+[:key_up_raw, 49, 0, 2, 18, 157]
+[:key_down_raw, 50, 0, 2, 19, 161]
+[:key_up_raw, 50, 0, 2, 20, 169]
+[:key_down_raw, 51, 0, 2, 21, 179]
+[:key_up_raw, 51, 0, 2, 22, 186]
+[:mouse_move, 780, 92, 2, 23, 186]
+[:mouse_move, 781, 92, 2, 24, 187]
+[:mouse_move, 777, 92, 2, 25, 225]
+[:mouse_move, 769, 94, 2, 26, 226]
+[:mouse_move, 761, 96, 2, 27, 227]
+[:mouse_move, 759, 97, 2, 28, 228]
+[:mouse_move, 760, 99, 2, 29, 231]
+[:mouse_move, 762, 101, 2, 30, 232]
+[:mouse_move, 768, 112, 2, 31, 233]
+[:mouse_move, 769, 112, 2, 32, 234]
+[:mouse_wheel, 0, 1, 2, 33, 234]
+[:mouse_move, 769, 113, 2, 34, 234]
+[:mouse_wheel, 0, 2, 2, 35, 235]
+[:mouse_move, 770, 114, 2, 36, 235]
+[:mouse_wheel, 0, 4, 2, 37, 236]
+[:mouse_move, 771, 115, 2, 38, 237]
+[:mouse_wheel, 0, 6, 2, 39, 237]
+[:mouse_move, 771, 116, 2, 40, 239]
+[:mouse_wheel, 0, 7, 2, 41, 239]
+[:mouse_move, 772, 119, 2, 42, 240]
+[:mouse_move, 773, 120, 2, 43, 241]
+[:mouse_move, 773, 121, 2, 44, 242]
+[:mouse_move, 774, 121, 2, 45, 243]
+[:mouse_move, 774, 122, 2, 46, 244]
+[:mouse_move, 775, 124, 2, 47, 246]
+[:mouse_move, 780, 132, 2, 48, 247]
+[:mouse_move, 784, 142, 2, 49, 248]
+[:mouse_move, 788, 149, 2, 50, 249]
+[:mouse_move, 789, 150, 2, 51, 250]
+[:mouse_move, 789, 151, 2, 52, 251]
+[:mouse_move, 790, 151, 2, 53, 252]
+[:mouse_move, 790, 152, 2, 54, 262]
+[:mouse_wheel, 0, 1, 2, 55, 273]
+[:mouse_wheel, 0, 1, 2, 56, 274]
+[:mouse_wheel, 0, 4, 2, 57, 275]
+[:mouse_wheel, 0, 6, 2, 58, 277]
+[:mouse_move, 790, 151, 2, 59, 288]
+[:mouse_wheel, 0, -1, 2, 60, 297]
+[:mouse_wheel, 0, -1, 2, 61, 299]
+[:mouse_wheel, 0, -4, 2, 62, 300]
+[:mouse_wheel, 0, -6, 2, 63, 301]
+[:mouse_wheel, 0, -1, 2, 64, 317]
+[:mouse_wheel, 0, -1, 2, 65, 318]
+[:mouse_wheel, 0, -4, 2, 66, 319]
+[:mouse_wheel, 0, -6, 2, 67, 320]
+[:mouse_wheel, 0, -7, 2, 68, 321]
+[:mouse_move, 791, 151, 2, 69, 322]
+[:key_down_raw, 49, 0, 2, 70, 339]
+[:key_up_raw, 49, 0, 2, 71, 343]
+[:mouse_move, 791, 150, 2, 72, 343]
+[:key_down_raw, 49, 0, 2, 73, 348]
+[:key_up_raw, 49, 0, 2, 74, 351]
+[:key_down_raw, 49, 0, 2, 75, 356]
+[:key_up_raw, 49, 0, 2, 76, 361]
+[:key_down_raw, 96, 0, 2, 77, 388]
+[:mouse_move, 792, 150, 2, 78, 389]
+[:key_up_raw, 96, 0, 2, 79, 392]
+[:mouse_move, 792, 149, 2, 80, 394]
+[:mouse_move, 787, 157, 2, 81, 418]
+[:mouse_move, 776, 165, 2, 82, 419]
+[:mouse_move, 768, 168, 2, 83, 420]
+[:mouse_move, 766, 168, 2, 84, 421]
+[:mouse_move, 767, 168, 2, 85, 424]
+[:mouse_move, 772, 168, 2, 86, 425]
+[:mouse_move, 777, 168, 2, 87, 426]
+[:mouse_move, 778, 168, 2, 88, 427]
+[:key_down_raw, 13, 0, 2, 89, 461]
diff --git a/samples/07_advanced_rendering/00_rotating_label/app/main.rb b/samples/07_advanced_rendering/00_rotating_label/app/main.rb
new file mode 100644
index 0000000..8b21fb8
--- /dev/null
+++ b/samples/07_advanced_rendering/00_rotating_label/app/main.rb
@@ -0,0 +1,32 @@
+def tick args
+ # set the render target width and height to match the label
+ args.outputs[:scene].w = 220
+ args.outputs[:scene].h = 30
+
+
+ # make the background transparent
+ args.outputs[:scene].background_color = [255, 255, 255, 0]
+
+ # set the blendmode of the label to 0 (no blending)
+ # center it inside of the scene
+ # set the vertical_alignment_enum to 1 (center)
+ args.outputs[:scene].labels << { x: 0,
+ y: 15,
+ text: "label in render target",
+ blendmode_enum: 0,
+ vertical_alignment_enum: 1 }
+
+ # add a border to the render target
+ args.outputs[:scene].borders << { x: 0,
+ y: 0,
+ w: args.outputs[:scene].w,
+ h: args.outputs[:scene].h }
+
+ # add the rendertarget to the main output as a sprite
+ args.outputs.sprites << { x: 640 - args.outputs[:scene].w.half,
+ y: 360 - args.outputs[:scene].h.half,
+ w: args.outputs[:scene].w,
+ h: args.outputs[:scene].h,
+ angle: args.state.tick_count,
+ path: :scene }
+end
diff --git a/samples/07_advanced_rendering/08_splitscreen_camera/app/main.rb b/samples/07_advanced_rendering/08_splitscreen_camera/app/main.rb
index 9b08e1e..9d22918 100644
--- a/samples/07_advanced_rendering/08_splitscreen_camera/app/main.rb
+++ b/samples/07_advanced_rendering/08_splitscreen_camera/app/main.rb
@@ -6,7 +6,7 @@ class CameraMovement
def serialize
{state: state, inputs: inputs, outputs: outputs, grid: grid }
end
-
+
def inspect
serialize.to_s
end
@@ -76,12 +76,12 @@ class CameraMovement
default_player(0, 0, 64, 64,
"sprites/player/player_#{state.player_cyan.orientation}_standing.png")
end
-
+
def new_player_magenta
default_player(64, 0, 64, 64,
"sprites/player/player_#{state.player_magenta.orientation}_standing.png")
end
-
+
def new_camera_magenta
default_camera(0,0,720,720)
end
@@ -93,7 +93,8 @@ class CameraMovement
def new_camera_center
default_camera(0,0,1280,720)
end
-
+
+
def new_room
default_floor_tile(0,0,1024,1024,'sprites/rooms/camera_room.png')
end
@@ -118,7 +119,7 @@ class CameraMovement
state.player_cyan.x += state.player_cyan.dx
state.player_cyan.y += state.player_cyan.dy
end
-
+
def calc_player_magenta
state.player_magenta.x += state.player_magenta.dx
state.player_magenta.y += state.player_magenta.dy
@@ -133,7 +134,7 @@ class CameraMovement
state.camera_center.x += (targetX - state.camera_center.x) * 0.1 * timeScale
state.camera_center.y += (targetY - state.camera_center.y) * 0.1 * timeScale
end
-
+
def calc_camera_magenta
timeScale = 1
@@ -170,7 +171,7 @@ class CameraMovement
def calc_trauma_decay
state.trauma = state.trauma * 0.9
end
-
+
def calc_random_float_range(min, max)
rand * (max-min) + min
end
@@ -198,7 +199,7 @@ class CameraMovement
g: 255,
b: 255}
end
-
+
def render_player_magenta
outputs[:scene].sprites << {x: state.player_magenta.x,
y: state.player_magenta.y,
@@ -244,16 +245,16 @@ class CameraMovement
render_camera_magenta_scene
render_camera_cyan_scene
- angle = Math.atan((state.player_magenta.y - state.player_cyan.y)/(state.player_magenta.x- state.player_cyan.x)) * 180/Math::PI
+ angle = Math.atan((state.player_magenta.y - state.player_cyan.y)/(state.player_magenta.x- state.player_cyan.x)) * 180/Math::PI
output_split_camera angle
-
+
end
def render_camera_magenta_scene
zoomFactor = 1
offsetX = 32
offsetY = 32
-
+
outputs[:scene_magenta].sprites << {x: (-state.camera_magenta.x*2),
y: (-state.camera_magenta.y),
w: outputs[:scene].width*2,
@@ -279,7 +280,7 @@ class CameraMovement
outputs.labels << [128,64,"#{quadrant}",8,2,255,0,255,255]
if quadrant == 1
set_camera_attributes(w: 640, h: 720, m_x: 640, m_y: 0, c_x: 0, c_y: 0)
-
+
elsif quadrant == 2
set_camera_attributes(w: 1280, h: 360, m_x: 0, m_y: 360, c_x: 0, c_y: 0)
@@ -297,7 +298,7 @@ class CameraMovement
state.camera_cyan.h = h + 64
outputs[:scene_cyan].width = (w) * 2
outputs[:scene_cyan].height = h
-
+
state.camera_magenta.w = w + 64
state.camera_magenta.h = h + 64
outputs[:scene_magenta].width = (w) * 2
@@ -309,7 +310,7 @@ class CameraMovement
path: :scene_magenta}
outputs.sprites << {x: c_x,
y: c_y,
- w: w,
+ w: w,
h: h,
path: :scene_cyan}
end
@@ -317,7 +318,7 @@ class CameraMovement
def add_trauma amount
state.trauma = [state.trauma + amount, 1.0].min
end
-
+
def remove_trauma amount
state.trauma = [state.trauma - amount, 0.0].max
end
@@ -357,7 +358,7 @@ class CameraMovement
outputs.labels << [128,512,"#{state.player_cyan.x.round()}",8,2,0,255,255,255]
outputs.labels << [128,480,"#{state.player_cyan.y.round()}",8,2,0,255,255,255]
end
-
+
def input_move_magenta
if inputs.keyboard.key_held.w
state.player_magenta.dy = 5
@@ -391,5 +392,5 @@ def tick args
$camera_movement.outputs = args.outputs
$camera_movement.state = args.state
$camera_movement.grid = args.grid
- $camera_movement.tick
+ $camera_movement.tick
end
diff --git a/samples/09_performance/03_sprites_as_struct/app/main.rb b/samples/09_performance/03_sprites_as_struct/app/main.rb
new file mode 100644
index 0000000..7b738b7
--- /dev/null
+++ b/samples/09_performance/03_sprites_as_struct/app/main.rb
@@ -0,0 +1,82 @@
+# create a Struct variant that allows for named parameters on construction.
+class NamedStruct < Struct
+ def initialize **opts
+ super(*members.map { |k| opts[k] })
+ end
+end
+
+# create a Star NamedStruct
+Star = NamedStruct.new(:x, :y, :w, :h, :path, :s,
+ :angle, :angle_anchor_x, :angle_anchor_y,
+ :r, :g, :b, :a,
+ :tile_x, :tile_y,
+ :tile_w, :tile_h,
+ :source_x, :source_y,
+ :source_w, :source_h,
+ :flip_horizontally, :flip_vertically,
+ :blendmode_enum)
+
+# Sprites represented as Structs. They require a little bit more code than Hashes,
+# but are the a little faster to render too.
+def random_x args
+ (args.grid.w.randomize :ratio) * -1
+end
+
+def random_y args
+ (args.grid.h.randomize :ratio) * -1
+end
+
+def random_speed
+ 1 + (4.randomize :ratio)
+end
+
+def new_star args
+ Star.new x: (random_x args),
+ y: (random_y args),
+ w: 4, h: 4,
+ path: 'sprites/tiny-star.png',
+ s: random_speed
+end
+
+def move_star args, star
+ star.x += star[:s]
+ star.y += star[:s]
+ if star.x > args.grid.w || star.y > args.grid.h
+ star.x = (random_x args)
+ star.y = (random_y args)
+ star[:s] = random_speed
+ end
+end
+
+def tick args
+ args.state.star_count ||= 0
+
+ # sets console command when sample app initially opens
+ if Kernel.global_tick_count == 0
+ puts ""
+ puts ""
+ puts "========================================================="
+ puts "* INFO: Sprites, Structs"
+ puts "* INFO: Please specify the number of sprites to render."
+ args.gtk.console.set_command "reset_with count: 100"
+ end
+
+ # init
+ if args.state.tick_count == 0
+ args.state.stars = args.state.star_count.map { |i| new_star args }
+ end
+
+ # update
+ args.state.stars.each { |s| move_star args, s }
+
+ # render
+ args.outputs.sprites << args.state.stars
+ args.outputs.background_color = [0, 0, 0]
+ args.outputs.primitives << args.gtk.current_framerate_primitives
+end
+
+# resets game, and assigns star count given by user
+def reset_with count: count
+ $gtk.reset
+ $gtk.args.state.star_count = count
+end
diff --git a/samples/09_performance/03_sprites_as_struct/license-for-sample.txt b/samples/09_performance/03_sprites_as_struct/license-for-sample.txt
new file mode 100644
index 0000000..175ac25
--- /dev/null
+++ b/samples/09_performance/03_sprites_as_struct/license-for-sample.txt
@@ -0,0 +1,9 @@
+Copyright 2021 DragonRuby LLC
+
+MIT License
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/samples/09_performance/03_sprites_as_struct/sprites/tiny-star.png b/samples/09_performance/03_sprites_as_struct/sprites/tiny-star.png
new file mode 100644
index 0000000..e04786a
--- /dev/null
+++ b/samples/09_performance/03_sprites_as_struct/sprites/tiny-star.png
Binary files differ
diff --git a/samples/09_performance/04_sprites_as_strict_entities/app/main.rb b/samples/09_performance/04_sprites_as_strict_entities/app/main.rb
new file mode 100644
index 0000000..a2688c2
--- /dev/null
+++ b/samples/09_performance/04_sprites_as_strict_entities/app/main.rb
@@ -0,0 +1,72 @@
+# Sprites represented as StrictEntities using the queue ~args.outputs.sprites~
+# yields apis access similar to Entities, but all properties that can be set on the
+# entity must be predefined with a default value. Strict entities do not support the
+# addition of new properties after the fact. They are more performant than OpenEntities
+# because of this constraint.
+def random_x args
+ (args.grid.w.randomize :ratio) * -1
+end
+
+def random_y args
+ (args.grid.h.randomize :ratio) * -1
+end
+
+def random_speed
+ 1 + (4.randomize :ratio)
+end
+
+def new_star args
+ args.state.new_entity_strict(:star,
+ x: (random_x args),
+ y: (random_y args),
+ w: 4, h: 4,
+ path: 'sprites/tiny-star.png',
+ s: random_speed) do |entity|
+ # invoke attr_sprite so that it responds to
+ # all properties that are required to render a sprite
+ entity.attr_sprite
+ end
+end
+
+def move_star args, star
+ star.x += star.s
+ star.y += star.s
+ if star.x > args.grid.w || star.y > args.grid.h
+ star.x = (random_x args)
+ star.y = (random_y args)
+ star.s = random_speed
+ end
+end
+
+def tick args
+ args.state.star_count ||= 0
+
+ # sets console command when sample app initially opens
+ if Kernel.global_tick_count == 0
+ puts ""
+ puts ""
+ puts "========================================================="
+ puts "* INFO: Sprites, Strict Entities"
+ puts "* INFO: Please specify the number of sprites to render."
+ args.gtk.console.set_command "reset_with count: 100"
+ end
+
+ # init
+ if args.state.tick_count == 0
+ args.state.stars = args.state.star_count.map { |i| new_star args }
+ end
+
+ # update
+ args.state.stars.each { |s| move_star args, s }
+
+ # render
+ args.outputs.sprites << args.state.stars
+ args.outputs.background_color = [0, 0, 0]
+ args.outputs.primitives << args.gtk.current_framerate_primitives
+end
+
+# resets game, and assigns star count given by user
+def reset_with count: count
+ $gtk.reset
+ $gtk.args.state.star_count = count
+end
diff --git a/samples/09_performance/04_sprites_as_strict_entities/license-for-sample.txt b/samples/09_performance/04_sprites_as_strict_entities/license-for-sample.txt
new file mode 100644
index 0000000..100dcec
--- /dev/null
+++ b/samples/09_performance/04_sprites_as_strict_entities/license-for-sample.txt
@@ -0,0 +1,9 @@
+Copyright 2019 DragonRuby LLC
+
+MIT License
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/samples/09_performance/04_sprites_as_strict_entities/sprites/tiny-star.png b/samples/09_performance/04_sprites_as_strict_entities/sprites/tiny-star.png
new file mode 100644
index 0000000..e04786a
--- /dev/null
+++ b/samples/09_performance/04_sprites_as_strict_entities/sprites/tiny-star.png
Binary files differ
diff --git a/samples/09_performance/05_sprites_as_classes/app/main.rb b/samples/09_performance/05_sprites_as_classes/app/main.rb
new file mode 100644
index 0000000..67cde79
--- /dev/null
+++ b/samples/09_performance/05_sprites_as_classes/app/main.rb
@@ -0,0 +1,55 @@
+# Sprites represented as Classes using the queue ~args.outputs.sprites~.
+# gives you full control of property declaration and method invocation.
+# They are more performant than OpenEntities and StrictEntities, but more code upfront.
+class Star
+ attr_sprite
+
+ def initialize grid
+ @grid = grid
+ @x = (rand @grid.w) * -1
+ @y = (rand @grid.h) * -1
+ @w = 4
+ @h = 4
+ @s = 1 + (4.randomize :ratio)
+ @path = 'sprites/tiny-star.png'
+ end
+
+ def move
+ @x += @s
+ @y += @s
+ @x = (rand @grid.w) * -1 if @x > @grid.right
+ @y = (rand @grid.h) * -1 if @y > @grid.top
+ end
+end
+
+# calls methods needed for game to run properly
+def tick args
+ # sets console command when sample app initially opens
+ if Kernel.global_tick_count == 0
+ puts ""
+ puts ""
+ puts "========================================================="
+ puts "* INFO: Sprites, Classes"
+ puts "* INFO: Please specify the number of sprites to render."
+ args.gtk.console.set_command "reset_with count: 100"
+ end
+
+ # init
+ if args.state.tick_count == 0
+ args.state.stars = args.state.star_count.map { |i| Star.new args.grid }
+ end
+
+ # update
+ args.state.stars.each(&:move)
+
+ # render
+ args.outputs.sprites << args.state.stars
+ args.outputs.background_color = [0, 0, 0]
+ args.outputs.primitives << args.gtk.current_framerate_primitives
+end
+
+# resets game, and assigns star count given by user
+def reset_with count: count
+ $gtk.reset
+ $gtk.args.state.star_count = count
+end
diff --git a/samples/09_performance/05_sprites_as_classes/license-for-sample.txt b/samples/09_performance/05_sprites_as_classes/license-for-sample.txt
new file mode 100644
index 0000000..100dcec
--- /dev/null
+++ b/samples/09_performance/05_sprites_as_classes/license-for-sample.txt
@@ -0,0 +1,9 @@
+Copyright 2019 DragonRuby LLC
+
+MIT License
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/samples/09_performance/05_sprites_as_classes/sprites/tiny-star.png b/samples/09_performance/05_sprites_as_classes/sprites/tiny-star.png
new file mode 100644
index 0000000..e04786a
--- /dev/null
+++ b/samples/09_performance/05_sprites_as_classes/sprites/tiny-star.png
Binary files differ
diff --git a/samples/09_performance/06_static_sprites_as_classes/app/main.rb b/samples/09_performance/06_static_sprites_as_classes/app/main.rb
new file mode 100644
index 0000000..db5bf8e
--- /dev/null
+++ b/samples/09_performance/06_static_sprites_as_classes/app/main.rb
@@ -0,0 +1,56 @@
+# Sprites represented as Classes using the queue ~args.outputs.static_sprites~.
+# bypasses the queue behavior of ~args.outputs.sprites~. All instances are held
+# by reference. You get better performance, but you are mutating state of held objects
+# which is less functional/data oriented.
+class Star
+ attr_sprite
+
+ def initialize grid
+ @grid = grid
+ @x = (rand @grid.w) * -1
+ @y = (rand @grid.h) * -1
+ @w = 4
+ @h = 4
+ @s = 1 + (4.randomize :ratio)
+ @path = 'sprites/tiny-star.png'
+ end
+
+ def move
+ @x += @s
+ @y += @s
+ @x = (rand @grid.w) * -1 if @x > @grid.right
+ @y = (rand @grid.h) * -1 if @y > @grid.top
+ end
+end
+
+# calls methods needed for game to run properly
+def tick args
+ # sets console command when sample app initially opens
+ if Kernel.global_tick_count == 0
+ puts ""
+ puts ""
+ puts "========================================================="
+ puts "* INFO: Static Sprites, Classes"
+ puts "* INFO: Please specify the number of sprites to render."
+ args.gtk.console.set_command "reset_with count: 100"
+ end
+
+ # init
+ if args.state.tick_count == 0
+ args.state.stars = args.state.star_count.map { |i| Star.new args.grid }
+ args.outputs.static_sprites << args.state.stars
+ end
+
+ # update
+ args.state.stars.each(&:move)
+
+ # render
+ args.outputs.background_color = [0, 0, 0]
+ args.outputs.primitives << args.gtk.current_framerate_primitives
+end
+
+# resets game, and assigns star count given by user
+def reset_with count: count
+ $gtk.reset
+ $gtk.args.state.star_count = count
+end
diff --git a/samples/09_performance/06_static_sprites_as_classes/license-for-sample.txt b/samples/09_performance/06_static_sprites_as_classes/license-for-sample.txt
new file mode 100644
index 0000000..100dcec
--- /dev/null
+++ b/samples/09_performance/06_static_sprites_as_classes/license-for-sample.txt
@@ -0,0 +1,9 @@
+Copyright 2019 DragonRuby LLC
+
+MIT License
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/samples/09_performance/06_static_sprites_as_classes/sprites/tiny-star.png b/samples/09_performance/06_static_sprites_as_classes/sprites/tiny-star.png
new file mode 100644
index 0000000..e04786a
--- /dev/null
+++ b/samples/09_performance/06_static_sprites_as_classes/sprites/tiny-star.png
Binary files differ
diff --git a/samples/09_performance/07_static_sprites_as_classes_with_custom_drawing/app/main.rb b/samples/09_performance/07_static_sprites_as_classes_with_custom_drawing/app/main.rb
new file mode 100644
index 0000000..3291f5e
--- /dev/null
+++ b/samples/09_performance/07_static_sprites_as_classes_with_custom_drawing/app/main.rb
@@ -0,0 +1,88 @@
+# Sprites represented as Classes, with a draw_override method, and using the queue ~args.outputs.static_sprites~.
+# is the fastest approach. This is comparable to what other game engines set as the default behavior.
+# There are tradeoffs for all this speed if the creation of a full blown class, and bypassing
+# functional/data-oriented practices.
+class Star
+ def initialize grid
+ @grid = grid
+ @x = (rand @grid.w) * -1
+ @y = (rand @grid.h) * -1
+ @w = 4
+ @h = 4
+ @s = 1 + (4.randomize :ratio)
+ @path = 'sprites/tiny-star.png'
+ end
+
+ def move
+ @x += @s
+ @y += @s
+ @x = (rand @grid.w) * -1 if @x > @grid.right
+ @y = (rand @grid.h) * -1 if @y > @grid.top
+ end
+
+ # if the object that is in args.outputs.sprites (or static_sprites)
+ # respond_to? :draw_override, then the method is invoked giving you
+ # access to the class used to draw to the canvas.
+ def draw_override ffi_draw
+ # first move then draw
+ move
+
+ # The argument order for ffi.draw_sprite is:
+ # x, y, w, h, path
+ ffi_draw.draw_sprite @x, @y, @w, @h, @path
+
+ # The argument order for ffi_draw.draw_sprite_2 is (pass in nil for default value):
+ # x, y, w, h, path,
+ # angle, alpha
+
+ # The argument order for ffi_draw.draw_sprite_3 is:
+ # x, y, w, h,
+ # path,
+ # angle,
+ # alpha, red_saturation, green_saturation, blue_saturation
+ # tile_x, tile_y, tile_w, tile_h,
+ # flip_horizontally, flip_vertically,
+ # angle_anchor_x, angle_anchor_y,
+ # source_x, source_y, source_w, source_h
+
+ # The argument order for ffi_draw.draw_sprite_4 is:
+ # x, y, w, h,
+ # path,
+ # angle,
+ # alpha, red_saturation, green_saturation, blue_saturation
+ # tile_x, tile_y, tile_w, tile_h,
+ # flip_horizontally, flip_vertically,
+ # angle_anchor_x, angle_anchor_y,
+ # source_x, source_y, source_w, source_h,
+ # blendmode_enum
+ end
+end
+
+# calls methods needed for game to run properly
+def tick args
+ # sets console command when sample app initially opens
+ if Kernel.global_tick_count == 0
+ puts ""
+ puts ""
+ puts "========================================================="
+ puts "* INFO: Static Sprites, Classes, Draw Override"
+ puts "* INFO: Please specify the number of sprites to render."
+ args.gtk.console.set_command "reset_with count: 100"
+ end
+
+ # init
+ if args.state.tick_count == 0
+ args.state.stars = args.state.star_count.map { |i| Star.new args.grid }
+ args.outputs.static_sprites << args.state.stars
+ end
+
+ # render framerate
+ args.outputs.background_color = [0, 0, 0]
+ args.outputs.primitives << args.gtk.current_framerate_primitives
+end
+
+# resets game, and assigns star count given by user
+def reset_with count: count
+ $gtk.reset
+ $gtk.args.state.star_count = count
+end
diff --git a/samples/09_performance/07_static_sprites_as_classes_with_custom_drawing/license-for-sample.txt b/samples/09_performance/07_static_sprites_as_classes_with_custom_drawing/license-for-sample.txt
new file mode 100644
index 0000000..100dcec
--- /dev/null
+++ b/samples/09_performance/07_static_sprites_as_classes_with_custom_drawing/license-for-sample.txt
@@ -0,0 +1,9 @@
+Copyright 2019 DragonRuby LLC
+
+MIT License
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/samples/09_performance/07_static_sprites_as_classes_with_custom_drawing/sprites/tiny-star.png b/samples/09_performance/07_static_sprites_as_classes_with_custom_drawing/sprites/tiny-star.png
new file mode 100644
index 0000000..e04786a
--- /dev/null
+++ b/samples/09_performance/07_static_sprites_as_classes_with_custom_drawing/sprites/tiny-star.png
Binary files differ
diff --git a/samples/09_performance/08_collision_limits/app/main.rb b/samples/09_performance/08_collision_limits/app/main.rb
new file mode 100644
index 0000000..01ad308
--- /dev/null
+++ b/samples/09_performance/08_collision_limits/app/main.rb
@@ -0,0 +1,55 @@
+=begin
+
+ Reminders:
+ - find_all: Finds all elements of a collection that meet certain requirements.
+ In this sample app, we're finding all bodies that intersect with the center body.
+
+ - args.outputs.solids: An array. The values generate a solid.
+ The parameters are [X, Y, WIDTH, HEIGHT, RED, GREEN, BLUE]
+ For more information about solids, go to mygame/documentation/03-solids-and-borders.md.
+
+ - args.outputs.labels: An array. The values generate a label.
+ The parameters are [X, Y, TEXT, SIZE, ALIGNMENT, RED, GREEN, BLUE, ALPHA, FONT STYLE]
+ For more information about labels, go to mygame/documentation/02-labels.md.
+
+ - ARRAY#intersect_rect?: Returns true or false depending on if two rectangles intersect.
+
+=end
+
+# This code demonstrates moving objects that loop around once they exceed the scope of the screen,
+# which has dimensions of 1280 by 720, and also detects collisions between objects called "bodies".
+
+def body_count num
+ $gtk.args.state.other_bodies = num.map { [1280 * rand, 720 * rand, 10, 10] } # other_bodies set using num collection
+end
+
+def tick args
+
+ # Center body's values are set using an array
+ # Map is used to set values of 2000 other bodies
+ # All bodies that intersect with center body are stored in collisions collection
+ args.state.center_body ||= [640 - 100, 360 - 100, 200, 200] # calculations done to place body in center
+ args.state.other_bodies ||= 2000.map { [1280 * rand, 720 * rand, 10, 10] } # 2000 bodies given random position on screen
+
+ # finds all bodies that intersect with center body, stores them in collisions
+ collisions = args.state.other_bodies.find_all { |b| b.intersect_rect? args.state.center_body }
+
+ args.borders << args.state.center_body # outputs center body as a black border
+
+ # transparency changes based on number of collisions; the more collisions, the redder (more transparent) the box becomes
+ args.solids << [args.state.center_body, 255, 0, 0, collisions.length * 5] # center body is red solid
+ args.solids << args.state.other_bodies # other bodies are output as (black) solids, as well
+
+ args.labels << [10, 30, args.gtk.current_framerate] # outputs frame rate in bottom left corner
+
+ # Bodies are returned to bottom left corner if positions exceed scope of screen
+ args.state.other_bodies.each do |b| # for each body in the other_bodies collection
+ b.x += 5 # x and y are both incremented by 5
+ b.y += 5
+ b.x = 0 if b.x > 1280 # x becomes 0 if star exceeds scope of screen (goes too far right)
+ b.y = 0 if b.y > 720 # y becomes 0 if star exceeds scope of screen (goes too far up)
+ end
+end
+
+# Resets the game.
+$gtk.reset
diff --git a/samples/09_performance/08_collision_limits/license-for-sample.txt b/samples/09_performance/08_collision_limits/license-for-sample.txt
new file mode 100644
index 0000000..100dcec
--- /dev/null
+++ b/samples/09_performance/08_collision_limits/license-for-sample.txt
@@ -0,0 +1,9 @@
+Copyright 2019 DragonRuby LLC
+
+MIT License
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/samples/10_advanced_debugging/00_logging/app/main.rb b/samples/10_advanced_debugging/00_logging/app/main.rb
new file mode 100644
index 0000000..f97b9d8
--- /dev/null
+++ b/samples/10_advanced_debugging/00_logging/app/main.rb
@@ -0,0 +1,19 @@
+def tick args
+ args.outputs.background_color = [255, 255, 255, 0]
+ if args.state.tick_count == 0
+ args.gtk.log_spam "log level spam"
+ args.gtk.log_debug "log level debug"
+ args.gtk.log_info "log level info"
+ args.gtk.log_warn "log level warn"
+ args.gtk.log_error "log level error"
+ args.gtk.log_unfiltered "log level unfiltered"
+ puts "This is a puts call"
+ args.gtk.console.show
+ end
+
+ if args.state.tick_count == 60
+ puts "This is a puts call on tick 60"
+ elsif args.state.tick_count == 120
+ puts "This is a puts call on tick 120"
+ end
+end
diff --git a/samples/11_http/01_retrieve_images/app/main.rb b/samples/11_http/01_retrieve_images/app/main.rb
index 53ece84..2a6a294 100644
--- a/samples/11_http/01_retrieve_images/app/main.rb
+++ b/samples/11_http/01_retrieve_images/app/main.rb
@@ -1,8 +1,10 @@
+$gtk.register_cvar 'app.warn_seconds', "seconds to wait before starting", :uint, 11
+
def tick args
args.outputs.background_color = [0, 0, 0]
# Show a warning at the start.
- args.state.warning_debounce ||= 11 * 60
+ args.state.warning_debounce ||= args.cvars['app.warn_seconds'].value * 60
if args.state.warning_debounce > 0
args.state.warning_debounce -= 1
args.outputs.labels << [640, 600, "This app shows random images from the Internet.", 10, 1, 255, 255, 255]
diff --git a/samples/11_http/02_in_game_web_server_http_get/app/main.rb b/samples/11_http/02_in_game_web_server_http_get/app/main.rb
new file mode 100644
index 0000000..7fd67f7
--- /dev/null
+++ b/samples/11_http/02_in_game_web_server_http_get/app/main.rb
@@ -0,0 +1,28 @@
+def tick args
+ args.state.port ||= 3000
+ args.state.reqnum ||= 0
+ # by default the embedded webserver runs on port 9001 (the port number is over 9000) and is disabled in a production build
+ # to enable the http server in a production build, you need to manually start
+ # the server up:
+ args.gtk.start_server! port: args.state.port, enable_in_prod: true
+ args.outputs.background_color = [0, 0, 0]
+ args.outputs.labels << [640, 600, "Point your web browser at http://localhost:#{args.state.port}/", 10, 1, 255, 255, 255]
+
+ args.inputs.http_requests.each { |req|
+ puts("METHOD: #{req.method}");
+ puts("URI: #{req.uri}");
+ puts("HEADERS:");
+ req.headers.each { |k,v| puts(" #{k}: #{v}") }
+
+ if (req.uri == '/')
+ # headers and body can be nil if you don't care about them.
+ # If you don't set the Content-Type, it will default to
+ # "text/html; charset=utf-8".
+ # Don't set Content-Length; we'll ignore it and calculate it for you
+ args.state.reqnum += 1
+ req.respond 200, "<html><head><title>hello</title></head><body><h1>This #{req.method} was request number #{args.state.reqnum}!</h1></body></html>\n", { 'X-DRGTK-header' => 'Powered by DragonRuby!' }
+ else
+ req.reject
+ end
+ }
+end
diff --git a/samples/11_http/02_in_game_web_server_http_get/license-for-sample.txt b/samples/11_http/02_in_game_web_server_http_get/license-for-sample.txt
new file mode 100644
index 0000000..175ac25
--- /dev/null
+++ b/samples/11_http/02_in_game_web_server_http_get/license-for-sample.txt
@@ -0,0 +1,9 @@
+Copyright 2021 DragonRuby LLC
+
+MIT License
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/samples/11_http/03_in_game_web_server_http_post/app/main.rb b/samples/11_http/03_in_game_web_server_http_post/app/main.rb
new file mode 100644
index 0000000..8116358
--- /dev/null
+++ b/samples/11_http/03_in_game_web_server_http_post/app/main.rb
@@ -0,0 +1,72 @@
+def tick args
+ # defaults
+ args.state.post_button = args.layout.rect(row: 0, col: 0, w: 5, h: 1).merge(text: "execute http_post")
+ args.state.post_body_button = args.layout.rect(row: 1, col: 0, w: 5, h: 1).merge(text: "execute http_post_body")
+ args.state.request_to_s ||= ""
+ args.state.request_body ||= ""
+
+ # render
+ args.state.post_button.yield_self do |b|
+ args.outputs.borders << b
+ args.outputs.labels << b.merge(text: b.text,
+ y: b.y + 30,
+ x: b.x + 10)
+ end
+
+ args.state.post_body_button.yield_self do |b|
+ args.outputs.borders << b
+ args.outputs.labels << b.merge(text: b.text,
+ y: b.y + 30,
+ x: b.x + 10)
+ end
+
+ draw_label args, 0, 6, "Request:", args.state.request_to_s
+ draw_label args, 0, 14, "Request Body Unaltered:", args.state.request_body
+
+ # input
+ if args.inputs.mouse.click
+ # ============= HTTP_POST =============
+ if (args.inputs.mouse.inside_rect? args.state.post_button)
+ # ========= DATA TO SEND ===========
+ form_fields = { "userId" => "#{Time.now.to_i}" }
+ # ==================================
+
+ args.gtk.http_post "http://localhost:9001/testing",
+ form_fields,
+ ["Content-Type: application/x-www-form-urlencoded"]
+
+ args.gtk.notify! "http_post"
+ end
+
+ # ============= HTTP_POST_BODY =============
+ if (args.inputs.mouse.inside_rect? args.state.post_body_button)
+ # =========== DATA TO SEND ==============
+ json = "{ \"userId\": \"#{Time.now.to_i}\"}"
+ # ==================================
+
+ args.gtk.http_post_body "http://localhost:9001/testing",
+ json,
+ ["Content-Type: application/json", "Content-Length: #{json.length}"]
+
+ args.gtk.notify! "http_post_body"
+ end
+ end
+
+ # calc
+ args.inputs.http_requests.each do |r|
+ puts "#{r}"
+ if r.uri == "/testing"
+ puts r
+ args.state.request_to_s = "#{r}"
+ args.state.request_body = r.raw_body
+ r.respond 200, "ok"
+ end
+ end
+end
+
+def draw_label args, row, col, header, text
+ label_pos = args.layout.rect(row: row, col: col, w: 0, h: 0)
+ args.outputs.labels << "#{header}\n\n#{text}".wrapped_lines(80).map_with_index do |l, i|
+ { x: label_pos.x, y: label_pos.y - (i * 15), text: l, size_enum: -2 }
+ end
+end
diff --git a/samples/11_http/03_in_game_web_server_http_post/replay.txt b/samples/11_http/03_in_game_web_server_http_post/replay.txt
new file mode 100644
index 0000000..527f46d
--- /dev/null
+++ b/samples/11_http/03_in_game_web_server_http_post/replay.txt
@@ -0,0 +1,415 @@
+replay_version 2.0
+stopped_at 680
+seed 100
+recorded_at 2021-11-20 11:16:26 -0600
+[:mouse_button_up, 1, 0, 1, 1, 3]
+[:mouse_move, 782, 90, 2, 2, 12]
+[:mouse_move, 780, 90, 2, 3, 13]
+[:mouse_move, 771, 90, 2, 4, 14]
+[:mouse_move, 759, 90, 2, 5, 15]
+[:mouse_move, 739, 90, 2, 6, 16]
+[:mouse_move, 703, 90, 2, 7, 17]
+[:mouse_move, 681, 94, 2, 8, 18]
+[:mouse_move, 657, 95, 2, 9, 19]
+[:mouse_move, 631, 99, 2, 10, 20]
+[:mouse_move, 599, 99, 2, 11, 21]
+[:mouse_move, 560, 99, 2, 12, 22]
+[:mouse_move, 518, 97, 2, 13, 23]
+[:mouse_move, 476, 92, 2, 14, 24]
+[:mouse_move, 435, 90, 2, 15, 25]
+[:mouse_move, 391, 90, 2, 16, 26]
+[:mouse_move, 345, 90, 2, 17, 27]
+[:mouse_move, 304, 90, 2, 18, 28]
+[:mouse_move, 254, 90, 2, 19, 29]
+[:mouse_move, 230, 90, 2, 20, 30]
+[:mouse_move, 213, 90, 2, 21, 31]
+[:mouse_move, 207, 90, 2, 22, 32]
+[:mouse_move, 207, 89, 2, 23, 34]
+[:mouse_move, 207, 87, 2, 24, 35]
+[:mouse_move, 209, 84, 2, 25, 36]
+[:mouse_move, 210, 82, 2, 26, 37]
+[:mouse_move, 211, 82, 2, 27, 38]
+[:mouse_move, 211, 81, 2, 28, 40]
+[:mouse_move, 212, 80, 2, 29, 41]
+[:mouse_move, 212, 79, 2, 30, 42]
+[:mouse_button_pressed, 1, 0, 1, 31, 89]
+[:mouse_button_up, 1, 0, 1, 32, 93]
+[:mouse_move, 212, 83, 2, 33, 151]
+[:mouse_move, 216, 104, 2, 34, 152]
+[:mouse_move, 229, 135, 2, 35, 153]
+[:mouse_move, 242, 168, 2, 36, 154]
+[:mouse_move, 250, 197, 2, 37, 155]
+[:mouse_move, 254, 218, 2, 38, 156]
+[:mouse_move, 264, 240, 2, 39, 157]
+[:mouse_move, 274, 266, 2, 40, 158]
+[:mouse_move, 285, 293, 2, 41, 159]
+[:mouse_move, 295, 316, 2, 42, 160]
+[:mouse_move, 304, 345, 2, 43, 161]
+[:mouse_move, 308, 358, 2, 44, 162]
+[:mouse_move, 316, 381, 2, 45, 163]
+[:mouse_move, 328, 408, 2, 46, 164]
+[:mouse_move, 333, 431, 2, 47, 165]
+[:mouse_move, 336, 447, 2, 48, 166]
+[:mouse_move, 337, 455, 2, 49, 167]
+[:mouse_move, 337, 459, 2, 50, 168]
+[:mouse_move, 336, 459, 2, 51, 175]
+[:mouse_move, 336, 460, 2, 52, 177]
+[:mouse_move, 336, 461, 2, 53, 178]
+[:mouse_move, 334, 462, 2, 54, 179]
+[:mouse_move, 331, 462, 2, 55, 180]
+[:mouse_move, 328, 462, 2, 56, 181]
+[:mouse_move, 323, 462, 2, 57, 182]
+[:mouse_move, 318, 455, 2, 58, 183]
+[:mouse_move, 310, 438, 2, 59, 184]
+[:mouse_move, 306, 414, 2, 60, 185]
+[:mouse_move, 306, 405, 2, 61, 186]
+[:mouse_move, 307, 402, 2, 62, 187]
+[:mouse_move, 310, 395, 2, 63, 188]
+[:mouse_move, 318, 384, 2, 64, 189]
+[:mouse_move, 327, 374, 2, 65, 190]
+[:mouse_move, 338, 364, 2, 66, 191]
+[:mouse_move, 351, 355, 2, 67, 192]
+[:mouse_move, 367, 347, 2, 68, 193]
+[:mouse_move, 385, 340, 2, 69, 194]
+[:mouse_move, 406, 335, 2, 70, 195]
+[:mouse_move, 431, 330, 2, 71, 196]
+[:mouse_move, 471, 330, 2, 72, 197]
+[:mouse_move, 491, 335, 2, 73, 198]
+[:mouse_move, 505, 339, 2, 74, 199]
+[:mouse_move, 514, 342, 2, 75, 200]
+[:mouse_move, 520, 346, 2, 76, 201]
+[:mouse_move, 526, 352, 2, 77, 202]
+[:mouse_move, 530, 363, 2, 78, 203]
+[:mouse_move, 530, 378, 2, 79, 204]
+[:mouse_move, 530, 396, 2, 80, 205]
+[:mouse_move, 530, 415, 2, 81, 206]
+[:mouse_move, 524, 434, 2, 82, 207]
+[:mouse_move, 517, 446, 2, 83, 208]
+[:mouse_move, 509, 458, 2, 84, 209]
+[:mouse_move, 503, 466, 2, 85, 210]
+[:mouse_move, 499, 472, 2, 86, 211]
+[:mouse_move, 496, 478, 2, 87, 212]
+[:mouse_move, 493, 486, 2, 88, 213]
+[:mouse_move, 488, 493, 2, 89, 214]
+[:mouse_move, 476, 501, 2, 90, 215]
+[:mouse_move, 465, 509, 2, 91, 216]
+[:mouse_move, 453, 515, 2, 92, 217]
+[:mouse_move, 441, 521, 2, 93, 218]
+[:mouse_move, 426, 524, 2, 94, 219]
+[:mouse_move, 410, 524, 2, 95, 220]
+[:mouse_move, 391, 527, 2, 96, 221]
+[:mouse_move, 379, 527, 2, 97, 222]
+[:mouse_move, 368, 527, 2, 98, 223]
+[:mouse_move, 360, 528, 2, 99, 224]
+[:mouse_move, 359, 528, 2, 100, 225]
+[:mouse_move, 358, 528, 2, 101, 226]
+[:mouse_move, 364, 529, 2, 102, 232]
+[:mouse_move, 387, 533, 2, 103, 233]
+[:mouse_move, 410, 535, 2, 104, 234]
+[:mouse_move, 434, 535, 2, 105, 235]
+[:mouse_move, 468, 535, 2, 106, 236]
+[:mouse_move, 506, 535, 2, 107, 237]
+[:mouse_move, 546, 535, 2, 108, 238]
+[:mouse_move, 582, 535, 2, 109, 239]
+[:mouse_move, 614, 531, 2, 110, 240]
+[:mouse_move, 647, 521, 2, 111, 241]
+[:mouse_move, 679, 510, 2, 112, 242]
+[:mouse_move, 705, 496, 2, 113, 243]
+[:mouse_move, 722, 479, 2, 114, 244]
+[:mouse_move, 727, 447, 2, 115, 245]
+[:mouse_move, 715, 426, 2, 116, 246]
+[:mouse_move, 692, 401, 2, 117, 247]
+[:mouse_move, 665, 382, 2, 118, 248]
+[:mouse_move, 641, 371, 2, 119, 249]
+[:mouse_move, 601, 361, 2, 120, 250]
+[:mouse_move, 582, 358, 2, 121, 251]
+[:mouse_move, 510, 350, 2, 122, 252]
+[:mouse_move, 486, 350, 2, 123, 253]
+[:mouse_move, 439, 350, 2, 124, 254]
+[:mouse_move, 395, 350, 2, 125, 255]
+[:mouse_move, 362, 355, 2, 126, 256]
+[:mouse_move, 322, 370, 2, 127, 257]
+[:mouse_move, 306, 380, 2, 128, 258]
+[:mouse_move, 298, 395, 2, 129, 259]
+[:mouse_move, 296, 420, 2, 130, 260]
+[:mouse_move, 303, 439, 2, 131, 261]
+[:mouse_move, 310, 450, 2, 132, 262]
+[:mouse_move, 345, 476, 2, 133, 263]
+[:mouse_move, 376, 489, 2, 134, 264]
+[:mouse_move, 408, 495, 2, 135, 265]
+[:mouse_move, 447, 498, 2, 136, 266]
+[:mouse_move, 487, 498, 2, 137, 267]
+[:mouse_move, 526, 492, 2, 138, 268]
+[:mouse_move, 588, 476, 2, 139, 269]
+[:mouse_move, 630, 455, 2, 140, 270]
+[:mouse_move, 682, 424, 2, 141, 271]
+[:mouse_move, 733, 384, 2, 142, 272]
+[:mouse_move, 774, 341, 2, 143, 273]
+[:mouse_move, 811, 302, 2, 144, 274]
+[:mouse_move, 825, 270, 2, 145, 275]
+[:mouse_move, 828, 240, 2, 146, 276]
+[:mouse_move, 824, 211, 2, 147, 277]
+[:mouse_move, 810, 185, 2, 148, 278]
+[:mouse_move, 799, 170, 2, 149, 279]
+[:mouse_move, 793, 165, 2, 150, 280]
+[:mouse_move, 787, 162, 2, 151, 281]
+[:mouse_move, 779, 158, 2, 152, 282]
+[:mouse_move, 768, 154, 2, 153, 283]
+[:mouse_move, 759, 151, 2, 154, 284]
+[:mouse_move, 757, 150, 2, 155, 285]
+[:mouse_move, 757, 151, 2, 156, 288]
+[:mouse_move, 765, 159, 2, 157, 289]
+[:mouse_move, 775, 168, 2, 158, 290]
+[:mouse_move, 790, 172, 2, 159, 291]
+[:mouse_move, 812, 177, 2, 160, 292]
+[:mouse_move, 859, 180, 2, 161, 293]
+[:mouse_move, 902, 180, 2, 162, 294]
+[:mouse_move, 944, 178, 2, 163, 295]
+[:mouse_move, 985, 172, 2, 164, 296]
+[:mouse_move, 1025, 163, 2, 165, 297]
+[:mouse_move, 1053, 152, 2, 166, 298]
+[:mouse_move, 1075, 142, 2, 167, 299]
+[:mouse_move, 1090, 131, 2, 168, 300]
+[:mouse_move, 1096, 121, 2, 169, 301]
+[:mouse_move, 1096, 110, 2, 170, 302]
+[:mouse_move, 1088, 96, 2, 171, 303]
+[:mouse_move, 1065, 77, 2, 172, 304]
+[:mouse_move, 1030, 58, 2, 173, 305]
+[:mouse_move, 1014, 54, 2, 174, 306]
+[:mouse_move, 999, 50, 2, 175, 307]
+[:mouse_move, 978, 45, 2, 176, 308]
+[:mouse_move, 951, 41, 2, 177, 309]
+[:mouse_move, 912, 36, 2, 178, 310]
+[:mouse_move, 870, 33, 2, 179, 311]
+[:mouse_move, 833, 33, 2, 180, 312]
+[:mouse_move, 809, 39, 2, 181, 313]
+[:mouse_move, 793, 45, 2, 182, 314]
+[:mouse_move, 782, 51, 2, 183, 315]
+[:mouse_move, 777, 55, 2, 184, 316]
+[:mouse_move, 776, 70, 2, 185, 317]
+[:mouse_move, 784, 90, 2, 186, 318]
+[:mouse_move, 802, 114, 2, 187, 319]
+[:mouse_move, 827, 138, 2, 188, 320]
+[:mouse_move, 865, 156, 2, 189, 321]
+[:mouse_move, 905, 168, 2, 190, 322]
+[:mouse_move, 942, 171, 2, 191, 323]
+[:mouse_move, 972, 171, 2, 192, 324]
+[:mouse_move, 992, 167, 2, 193, 325]
+[:mouse_move, 1000, 157, 2, 194, 326]
+[:mouse_move, 1000, 140, 2, 195, 327]
+[:mouse_move, 982, 117, 2, 196, 328]
+[:mouse_move, 958, 99, 2, 197, 329]
+[:mouse_move, 903, 81, 2, 198, 330]
+[:mouse_move, 880, 75, 2, 199, 331]
+[:mouse_move, 763, 60, 2, 200, 332]
+[:mouse_move, 716, 58, 2, 201, 333]
+[:mouse_move, 604, 58, 2, 202, 334]
+[:mouse_move, 440, 65, 2, 203, 335]
+[:mouse_move, 355, 82, 2, 204, 336]
+[:mouse_move, 282, 95, 2, 205, 337]
+[:mouse_move, 221, 103, 2, 206, 338]
+[:mouse_move, 179, 109, 2, 207, 339]
+[:mouse_move, 146, 109, 2, 208, 340]
+[:mouse_move, 128, 109, 2, 209, 341]
+[:mouse_move, 116, 109, 2, 210, 342]
+[:mouse_move, 112, 108, 2, 211, 343]
+[:mouse_move, 115, 111, 2, 212, 349]
+[:mouse_move, 117, 113, 2, 213, 350]
+[:mouse_move, 118, 115, 2, 214, 351]
+[:mouse_move, 118, 116, 2, 215, 352]
+[:mouse_move, 119, 117, 2, 216, 353]
+[:mouse_move, 123, 119, 2, 217, 354]
+[:mouse_move, 127, 120, 2, 218, 355]
+[:mouse_move, 128, 120, 2, 219, 356]
+[:mouse_button_pressed, 1, 0, 1, 220, 369]
+[:mouse_button_up, 1, 0, 1, 221, 372]
+[:mouse_move, 131, 121, 2, 222, 399]
+[:mouse_move, 147, 128, 2, 223, 400]
+[:mouse_move, 165, 133, 2, 224, 401]
+[:mouse_move, 186, 138, 2, 225, 402]
+[:mouse_move, 210, 145, 2, 226, 403]
+[:mouse_move, 231, 151, 2, 227, 404]
+[:mouse_move, 252, 160, 2, 228, 405]
+[:mouse_move, 276, 176, 2, 229, 406]
+[:mouse_move, 304, 197, 2, 230, 407]
+[:mouse_move, 332, 224, 2, 231, 408]
+[:mouse_move, 352, 261, 2, 232, 409]
+[:mouse_move, 360, 293, 2, 233, 410]
+[:mouse_move, 365, 322, 2, 234, 411]
+[:mouse_move, 366, 351, 2, 235, 412]
+[:mouse_move, 358, 385, 2, 236, 413]
+[:mouse_move, 344, 403, 2, 237, 414]
+[:mouse_move, 331, 412, 2, 238, 415]
+[:mouse_move, 318, 417, 2, 239, 416]
+[:mouse_move, 307, 420, 2, 240, 417]
+[:mouse_move, 303, 422, 2, 241, 418]
+[:mouse_move, 302, 422, 2, 242, 419]
+[:mouse_move, 301, 422, 2, 243, 421]
+[:mouse_move, 298, 418, 2, 244, 422]
+[:mouse_move, 295, 410, 2, 245, 423]
+[:mouse_move, 295, 407, 2, 246, 424]
+[:mouse_move, 293, 403, 2, 247, 425]
+[:mouse_move, 293, 399, 2, 248, 426]
+[:mouse_move, 293, 396, 2, 249, 427]
+[:mouse_move, 294, 391, 2, 250, 428]
+[:mouse_move, 300, 380, 2, 251, 429]
+[:mouse_move, 306, 370, 2, 252, 430]
+[:mouse_move, 315, 361, 2, 253, 431]
+[:mouse_move, 318, 360, 2, 254, 432]
+[:mouse_move, 319, 360, 2, 255, 433]
+[:mouse_move, 321, 362, 2, 256, 434]
+[:mouse_move, 321, 363, 2, 257, 435]
+[:mouse_move, 322, 364, 2, 258, 439]
+[:mouse_move, 333, 367, 2, 259, 440]
+[:mouse_move, 357, 372, 2, 260, 441]
+[:mouse_move, 387, 375, 2, 261, 442]
+[:mouse_move, 426, 380, 2, 262, 443]
+[:mouse_move, 468, 387, 2, 263, 444]
+[:mouse_move, 506, 389, 2, 264, 445]
+[:mouse_move, 539, 389, 2, 265, 446]
+[:mouse_move, 570, 387, 2, 266, 447]
+[:mouse_move, 593, 381, 2, 267, 448]
+[:mouse_move, 614, 376, 2, 268, 449]
+[:mouse_move, 622, 376, 2, 269, 450]
+[:mouse_move, 626, 377, 2, 270, 451]
+[:mouse_move, 628, 379, 2, 271, 452]
+[:mouse_move, 628, 382, 2, 272, 453]
+[:mouse_move, 627, 388, 2, 273, 454]
+[:mouse_move, 621, 400, 2, 274, 455]
+[:mouse_move, 609, 411, 2, 275, 456]
+[:mouse_move, 594, 422, 2, 276, 457]
+[:mouse_move, 573, 429, 2, 277, 458]
+[:mouse_move, 551, 433, 2, 278, 459]
+[:mouse_move, 523, 437, 2, 279, 460]
+[:mouse_move, 481, 440, 2, 280, 461]
+[:mouse_move, 453, 439, 2, 281, 462]
+[:mouse_move, 425, 432, 2, 282, 463]
+[:mouse_move, 393, 423, 2, 283, 464]
+[:mouse_move, 368, 416, 2, 284, 465]
+[:mouse_move, 353, 415, 2, 285, 466]
+[:mouse_move, 343, 413, 2, 286, 467]
+[:mouse_move, 337, 409, 2, 287, 468]
+[:mouse_move, 332, 405, 2, 288, 469]
+[:mouse_move, 327, 395, 2, 289, 470]
+[:mouse_move, 324, 382, 2, 290, 471]
+[:mouse_move, 324, 375, 2, 291, 472]
+[:mouse_move, 336, 367, 2, 292, 473]
+[:mouse_move, 351, 361, 2, 293, 474]
+[:mouse_move, 369, 357, 2, 294, 475]
+[:mouse_move, 388, 356, 2, 295, 476]
+[:mouse_move, 405, 353, 2, 296, 477]
+[:mouse_move, 423, 352, 2, 297, 478]
+[:mouse_move, 441, 355, 2, 298, 479]
+[:mouse_move, 464, 367, 2, 299, 480]
+[:mouse_move, 482, 380, 2, 300, 481]
+[:mouse_move, 494, 395, 2, 301, 482]
+[:mouse_move, 496, 405, 2, 302, 483]
+[:mouse_move, 491, 413, 2, 303, 484]
+[:mouse_move, 467, 428, 2, 304, 485]
+[:mouse_move, 447, 439, 2, 305, 486]
+[:mouse_move, 427, 447, 2, 306, 487]
+[:mouse_move, 407, 450, 2, 307, 488]
+[:mouse_move, 385, 450, 2, 308, 489]
+[:mouse_move, 361, 449, 2, 309, 490]
+[:mouse_move, 345, 447, 2, 310, 491]
+[:mouse_move, 332, 441, 2, 311, 492]
+[:mouse_move, 321, 434, 2, 312, 493]
+[:mouse_move, 312, 424, 2, 313, 494]
+[:mouse_move, 307, 412, 2, 314, 495]
+[:mouse_move, 306, 401, 2, 315, 496]
+[:mouse_move, 310, 384, 2, 316, 497]
+[:mouse_move, 322, 369, 2, 317, 498]
+[:mouse_move, 346, 357, 2, 318, 499]
+[:mouse_move, 388, 346, 2, 319, 500]
+[:mouse_move, 434, 332, 2, 320, 501]
+[:mouse_move, 500, 314, 2, 321, 502]
+[:mouse_move, 564, 295, 2, 322, 503]
+[:mouse_move, 630, 276, 2, 323, 504]
+[:mouse_move, 676, 262, 2, 324, 505]
+[:mouse_move, 716, 248, 2, 325, 506]
+[:mouse_move, 753, 232, 2, 326, 507]
+[:mouse_move, 785, 217, 2, 327, 508]
+[:mouse_move, 820, 194, 2, 328, 509]
+[:mouse_move, 831, 186, 2, 329, 510]
+[:mouse_move, 832, 185, 2, 330, 511]
+[:mouse_move, 833, 184, 2, 331, 512]
+[:mouse_move, 834, 186, 2, 332, 518]
+[:mouse_move, 835, 189, 2, 333, 519]
+[:mouse_move, 833, 190, 2, 334, 521]
+[:mouse_move, 821, 188, 2, 335, 522]
+[:mouse_move, 793, 174, 2, 336, 523]
+[:mouse_move, 753, 152, 2, 337, 524]
+[:mouse_move, 725, 132, 2, 338, 525]
+[:mouse_move, 715, 117, 2, 339, 526]
+[:mouse_move, 710, 93, 2, 340, 527]
+[:mouse_move, 709, 69, 2, 341, 528]
+[:mouse_move, 713, 47, 2, 342, 529]
+[:mouse_move, 730, 29, 2, 343, 530]
+[:mouse_move, 763, 18, 2, 344, 531]
+[:mouse_move, 812, 16, 2, 345, 532]
+[:mouse_move, 894, 24, 2, 346, 533]
+[:mouse_move, 965, 43, 2, 347, 534]
+[:mouse_move, 1015, 64, 2, 348, 535]
+[:mouse_move, 1049, 80, 2, 349, 536]
+[:mouse_move, 1070, 97, 2, 350, 537]
+[:mouse_move, 1079, 114, 2, 351, 538]
+[:mouse_move, 1079, 126, 2, 352, 539]
+[:mouse_move, 1071, 139, 2, 353, 540]
+[:mouse_move, 1052, 147, 2, 354, 541]
+[:mouse_move, 1026, 151, 2, 355, 542]
+[:mouse_move, 986, 152, 2, 356, 543]
+[:mouse_move, 937, 152, 2, 357, 544]
+[:mouse_move, 835, 143, 2, 358, 545]
+[:mouse_move, 768, 125, 2, 359, 546]
+[:mouse_move, 711, 105, 2, 360, 547]
+[:mouse_move, 667, 86, 2, 361, 548]
+[:mouse_move, 639, 74, 2, 362, 549]
+[:mouse_move, 630, 69, 2, 363, 550]
+[:mouse_move, 630, 64, 2, 364, 551]
+[:mouse_move, 638, 53, 2, 365, 552]
+[:mouse_move, 659, 41, 2, 366, 553]
+[:mouse_move, 688, 33, 2, 367, 554]
+[:mouse_move, 723, 23, 2, 368, 555]
+[:mouse_move, 759, 19, 2, 369, 556]
+[:mouse_move, 810, 19, 2, 370, 557]
+[:mouse_move, 840, 25, 2, 371, 558]
+[:mouse_move, 866, 37, 2, 372, 559]
+[:mouse_move, 878, 47, 2, 373, 560]
+[:mouse_move, 878, 57, 2, 374, 561]
+[:mouse_move, 866, 69, 2, 375, 562]
+[:mouse_move, 835, 76, 2, 376, 563]
+[:mouse_move, 783, 77, 2, 377, 564]
+[:mouse_move, 722, 77, 2, 378, 565]
+[:mouse_move, 652, 77, 2, 379, 566]
+[:mouse_move, 559, 67, 2, 380, 567]
+[:mouse_move, 445, 36, 2, 381, 568]
+[:mouse_move, 274, 0, 2, 382, 569]
+[:mouse_move, 110, 0, 2, 383, 598]
+[:mouse_move, 131, 5, 2, 384, 599]
+[:mouse_move, 162, 14, 2, 385, 600]
+[:mouse_move, 201, 24, 2, 386, 601]
+[:mouse_move, 244, 32, 2, 387, 602]
+[:key_down_raw, 96, 0, 2, 388, 602]
+[:mouse_move, 288, 38, 2, 389, 603]
+[:mouse_move, 338, 46, 2, 390, 604]
+[:mouse_move, 422, 70, 2, 391, 605]
+[:mouse_move, 490, 90, 2, 392, 606]
+[:mouse_move, 553, 113, 2, 393, 607]
+[:key_up_raw, 96, 0, 2, 394, 608]
+[:mouse_move, 600, 129, 2, 395, 608]
+[:mouse_move, 638, 146, 2, 396, 609]
+[:mouse_move, 663, 159, 2, 397, 610]
+[:mouse_move, 686, 168, 2, 398, 611]
+[:mouse_move, 708, 177, 2, 399, 612]
+[:mouse_move, 725, 184, 2, 400, 613]
+[:mouse_move, 733, 189, 2, 401, 614]
+[:mouse_move, 735, 189, 2, 402, 615]
+[:mouse_move, 729, 189, 2, 403, 616]
+[:mouse_move, 704, 185, 2, 404, 617]
+[:mouse_move, 721, 189, 2, 405, 628]
+[:mouse_move, 744, 191, 2, 406, 629]
+[:mouse_move, 745, 191, 2, 407, 630]
+[:mouse_move, 744, 191, 2, 408, 637]
+[:mouse_move, 743, 191, 2, 409, 638]
+[:mouse_move, 744, 191, 2, 410, 665]
+[:key_down_raw, 13, 0, 2, 411, 680]
diff --git a/samples/12_c_extensions/.gitignore b/samples/12_c_extensions/.gitignore
new file mode 100644
index 0000000..a90a836
--- /dev/null
+++ b/samples/12_c_extensions/.gitignore
@@ -0,0 +1,2 @@
+ext.dylib
+
diff --git a/samples/12_c_extensions/01_basics/native/ext-bindings.c b/samples/12_c_extensions/01_basics/native/ext-bindings.c
index c805961..86b7090 100644
--- a/samples/12_c_extensions/01_basics/native/ext-bindings.c
+++ b/samples/12_c_extensions/01_basics/native/ext-bindings.c
@@ -14,7 +14,13 @@
#undef mrb_int
#endif
+void *(*drb_symbol_lookup)(const char *sym) = NULL;
+
static void (*drb_free_foreign_object_f)(mrb_state *, void *);
+static void (*drb_typecheck_float_f)(mrb_state *, mrb_value);
+static void (*drb_typecheck_int_f)(mrb_state *, mrb_value);
+static void (*drb_typecheck_bool_f)(mrb_state *, mrb_value);
+static void (*drb_typecheck_aggregate_f)(mrb_state *, mrb_value, struct RClass *, mrb_data_type *);
static struct RClass *(*mrb_module_get_f)(mrb_state *, const char *);
static mrb_int (*mrb_get_args_f)(mrb_state *, mrb_args_format, ...);
static struct RClass *(*mrb_module_get_under_f)(mrb_state *, struct RClass *, const char *);
@@ -27,7 +33,13 @@ static void (*mrb_define_class_method_f)(mrb_state *, struct RClass *, const cha
static struct RData *(*mrb_data_object_alloc_f)(mrb_state *, struct RClass *, void *, const mrb_data_type *);
static mrb_value (*mrb_str_new_cstr_f)(mrb_state *, const char *);
static void (*mrb_raise_f)(mrb_state *, struct RClass *, const char *);
+static mrb_value (*drb_float_value_f)(mrb_state *, mrb_float);
+static struct RClass *(*drb_getruntime_error_f)(mrb_state *);
+static void drb_free_foreign_object_indirect(mrb_state *state, void *pointer) {
+ drb_free_foreign_object_f(state, pointer);
+}
static int drb_ffi__ZTSi_FromRuby(mrb_state *state, mrb_value self) {
+ drb_typecheck_int_f(state, self);
return mrb_fixnum(self);
}
static mrb_value drb_ffi__ZTSi_ToRuby(mrb_state *state, int value) {
@@ -51,18 +63,25 @@ void drb_register_c_extensions(void *(*lookup)(const char *), mrb_state *state,
mrb_define_module_function_f(state, module, "square", drb_ffi_square_Binding, MRB_ARGS_REQ(1));
}
static int drb_ffi_init_indirect_functions(void *(*lookup)(const char *fnname)) {
- if (!(mrb_raise_f = (void (*)(mrb_state *, struct RClass *, const char *)) lookup("mrb_raise"))) return -1;
- if (!(mrb_module_get_f = (struct RClass *(*)(mrb_state *, const char *)) lookup("mrb_module_get"))) return -1;
- if (!(mrb_class_get_under_f = (struct RClass *(*)(mrb_state *, struct RClass *, const char *)) lookup("mrb_class_get_under"))) return -1;
- if (!(mrb_get_args_f = (mrb_int (*)(mrb_state *, mrb_args_format, ...)) lookup("mrb_get_args"))) return -1;
+ drb_symbol_lookup = lookup;
+ if (!(drb_float_value_f = (mrb_value (*)(mrb_state *, mrb_float)) lookup("drb_float_value"))) return -1;
if (!(drb_free_foreign_object_f = (void (*)(mrb_state *, void *)) lookup("drb_free_foreign_object"))) return -1;
- if (!(mrb_define_module_under_f = (struct RClass *(*)(mrb_state *, struct RClass *, const char *)) lookup("mrb_define_module_under"))) return -1;
- if (!(mrb_str_new_cstr_f = (mrb_value (*)(mrb_state *, const char *)) lookup("mrb_str_new_cstr"))) return -1;
+ if (!(drb_getruntime_error_f = (struct RClass *(*)(mrb_state *)) lookup("drb_getruntime_error"))) return -1;
+ if (!(drb_typecheck_aggregate_f = (void (*)(mrb_state *, mrb_value, struct RClass *, mrb_data_type *)) lookup("drb_typecheck_aggregate"))) return -1;
+ if (!(drb_typecheck_bool_f = (void (*)(mrb_state *, mrb_value)) lookup("drb_typecheck_bool"))) return -1;
+ if (!(drb_typecheck_float_f = (void (*)(mrb_state *, mrb_value)) lookup("drb_typecheck_float"))) return -1;
+ if (!(drb_typecheck_int_f = (void (*)(mrb_state *, mrb_value)) lookup("drb_typecheck_int"))) return -1;
+ if (!(mrb_class_get_under_f = (struct RClass *(*)(mrb_state *, struct RClass *, const char *)) lookup("mrb_class_get_under"))) return -1;
+ if (!(mrb_data_object_alloc_f = (struct RData *(*)(mrb_state *, struct RClass *, void *, const mrb_data_type *)) lookup("mrb_data_object_alloc"))) return -1;
+ if (!(mrb_define_class_method_f = (void (*)(mrb_state *, struct RClass *, const char *, mrb_func_t, mrb_aspec)) lookup("mrb_define_class_method"))) return -1;
if (!(mrb_define_class_under_f = (struct RClass *(*)(mrb_state *, struct RClass *, const char *, struct RClass *)) lookup("mrb_define_class_under"))) return -1;
+ if (!(mrb_define_method_f = (void (*)(mrb_state *, struct RClass *, const char *, mrb_func_t, mrb_aspec)) lookup("mrb_define_method"))) return -1;
if (!(mrb_define_module_function_f = (void (*)(mrb_state *, struct RClass *, const char *, mrb_func_t, mrb_aspec)) lookup("mrb_define_module_function"))) return -1;
- if (!(mrb_data_object_alloc_f = (struct RData *(*)(mrb_state *, struct RClass *, void *, const mrb_data_type *)) lookup("mrb_data_object_alloc"))) return -1;
+ if (!(mrb_define_module_under_f = (struct RClass *(*)(mrb_state *, struct RClass *, const char *)) lookup("mrb_define_module_under"))) return -1;
+ if (!(mrb_get_args_f = (mrb_int (*)(mrb_state *, mrb_args_format, ...)) lookup("mrb_get_args"))) return -1;
+ if (!(mrb_module_get_f = (struct RClass *(*)(mrb_state *, const char *)) lookup("mrb_module_get"))) return -1;
if (!(mrb_module_get_under_f = (struct RClass *(*)(mrb_state *, struct RClass *, const char *)) lookup("mrb_module_get_under"))) return -1;
- if (!(mrb_define_method_f = (void (*)(mrb_state *, struct RClass *, const char *, mrb_func_t, mrb_aspec)) lookup("mrb_define_method"))) return -1;
- if (!(mrb_define_class_method_f = (void (*)(mrb_state *, struct RClass *, const char *, mrb_func_t, mrb_aspec)) lookup("mrb_define_class_method"))) return -1;
+ if (!(mrb_raise_f = (void (*)(mrb_state *, struct RClass *, const char *)) lookup("mrb_raise"))) return -1;
+ if (!(mrb_str_new_cstr_f = (mrb_value (*)(mrb_state *, const char *)) lookup("mrb_str_new_cstr"))) return -1;
return 0;
}
diff --git a/samples/12_c_extensions/02_intermediate/native/re-bindings.c b/samples/12_c_extensions/02_intermediate/native/re-bindings.c
index 6aa5630..6bd9869 100644
--- a/samples/12_c_extensions/02_intermediate/native/re-bindings.c
+++ b/samples/12_c_extensions/02_intermediate/native/re-bindings.c
@@ -14,7 +14,13 @@
#undef mrb_int
#endif
+void *(*drb_symbol_lookup)(const char *sym) = NULL;
+
static void (*drb_free_foreign_object_f)(mrb_state *, void *);
+static void (*drb_typecheck_float_f)(mrb_state *, mrb_value);
+static void (*drb_typecheck_int_f)(mrb_state *, mrb_value);
+static void (*drb_typecheck_bool_f)(mrb_state *, mrb_value);
+static void (*drb_typecheck_aggregate_f)(mrb_state *, mrb_value, struct RClass *, mrb_data_type *);
static struct RClass *(*mrb_module_get_f)(mrb_state *, const char *);
static mrb_int (*mrb_get_args_f)(mrb_state *, mrb_args_format, ...);
static struct RClass *(*mrb_module_get_under_f)(mrb_state *, struct RClass *, const char *);
@@ -27,10 +33,18 @@ static void (*mrb_define_class_method_f)(mrb_state *, struct RClass *, const cha
static struct RData *(*mrb_data_object_alloc_f)(mrb_state *, struct RClass *, void *, const mrb_data_type *);
static mrb_value (*mrb_str_new_cstr_f)(mrb_state *, const char *);
static void (*mrb_raise_f)(mrb_state *, struct RClass *, const char *);
-static struct RClass *(*mrb_exc_get_f)(mrb_state *, const char *);
+static mrb_value (*drb_float_value_f)(mrb_state *, mrb_float);
+static struct RClass *(*drb_getruntime_error_f)(mrb_state *);
static void drb_free_foreign_object_indirect(mrb_state *state, void *pointer) {
drb_free_foreign_object_f(state, pointer);
}
+static int drb_ffi__ZTSi_FromRuby(mrb_state *state, mrb_value self) {
+ drb_typecheck_int_f(state, self);
+ return mrb_fixnum(self);
+}
+static mrb_value drb_ffi__ZTSi_ToRuby(mrb_state *state, int value) {
+ return mrb_fixnum_value(value);
+}
struct drb_foreign_object_ZTSP7regex_t {
drb_foreign_object_kind kind;
struct regex_t *value;
@@ -40,6 +54,10 @@ static mrb_data_type ForeignObjectType_ZTSP7regex_t = {"regex_t*", drb_free_fore
static struct regex_t *drb_ffi__ZTSP7regex_t_FromRuby(mrb_state *state, mrb_value self) {
if (mrb_nil_p(self))
return 0;
+ struct RClass *FFI = mrb_module_get_f(state, "FFI");
+ struct RClass *module = mrb_module_get_under_f(state, FFI, "RE");
+ struct RClass *klass = mrb_class_get_under_f(state, module, "Regex_tPointer");
+ drb_typecheck_aggregate_f(state, self, klass, &ForeignObjectType_ZTSP7regex_t);
return ((struct drb_foreign_object_ZTSP7regex_t *)DATA_PTR(self))->value;
}
static mrb_value drb_ffi__ZTSP7regex_t_ToRuby(mrb_state *state, struct regex_t *value) {
@@ -63,6 +81,10 @@ static char *drb_ffi__ZTSPc_FromRuby(mrb_state *state, mrb_value self) {
return 0;
if (mrb_type(self) == MRB_TT_STRING)
return RSTRING_PTR(self);
+ struct RClass *FFI = mrb_module_get_f(state, "FFI");
+ struct RClass *module = mrb_module_get_under_f(state, FFI, "RE");
+ struct RClass *klass = mrb_class_get_under_f(state, module, "CharPointer");
+ drb_typecheck_aggregate_f(state, self, klass, &ForeignObjectType_ZTSPc);
return ((struct drb_foreign_object_ZTSPc *)DATA_PTR(self))->value;
}
static mrb_value drb_ffi__ZTSPc_ToRuby(mrb_state *state, char *value) {
@@ -75,12 +97,6 @@ static mrb_value drb_ffi__ZTSPc_ToRuby(mrb_state *state, char *value) {
struct RData *rdata = mrb_data_object_alloc_f(state, klass, ptr, &ForeignObjectType_ZTSPc);
return mrb_obj_value(rdata);
}
-static int drb_ffi__ZTSi_FromRuby(mrb_state *state, mrb_value self) {
- return mrb_fixnum(self);
-}
-static mrb_value drb_ffi__ZTSi_ToRuby(mrb_state *state, int value) {
- return mrb_fixnum_value(value);
-}
struct drb_foreign_object_ZTSPi {
drb_foreign_object_kind kind;
int *value;
@@ -90,6 +106,10 @@ static mrb_data_type ForeignObjectType_ZTSPi = {"int*", drb_free_foreign_object_
static int *drb_ffi__ZTSPi_FromRuby(mrb_state *state, mrb_value self) {
if (mrb_nil_p(self))
return 0;
+ struct RClass *FFI = mrb_module_get_f(state, "FFI");
+ struct RClass *module = mrb_module_get_under_f(state, FFI, "RE");
+ struct RClass *klass = mrb_class_get_under_f(state, module, "IntPointer");
+ drb_typecheck_aggregate_f(state, self, klass, &ForeignObjectType_ZTSPi);
return ((struct drb_foreign_object_ZTSPi *)DATA_PTR(self))->value;
}
static mrb_value drb_ffi__ZTSPi_ToRuby(mrb_state *state, int *value) {
@@ -103,17 +123,18 @@ static mrb_value drb_ffi__ZTSPi_ToRuby(mrb_state *state, int *value) {
return mrb_obj_value(rdata);
}
static char drb_ffi__ZTSc_FromRuby(mrb_state *state, mrb_value self) {
+ drb_typecheck_int_f(state, self);
return mrb_fixnum(self);
}
static mrb_value drb_ffi__ZTSc_ToRuby(mrb_state *state, char value) {
return mrb_fixnum_value(value);
}
static mrb_value drb_ffi__ZTSP7regex_t_New(mrb_state *mrb, mrb_value self) {
- mrb_raise_f(mrb, mrb_exc_get_f(mrb, "RuntimeError"), "Cannot allocate pointer of incomplete type");
+ mrb_raise_f(mrb, drb_getruntime_error_f(mrb), "Cannot allocate pointer of incomplete type");
return mrb_nil_value();
}
static mrb_value drb_ffi__ZTSP7regex_t_GetValue(mrb_state *mrb, mrb_value value) {
- mrb_raise_f(mrb, mrb_exc_get_f(mrb, "RuntimeError"), "Cannot access value of incomplete type");
+ mrb_raise_f(mrb, drb_getruntime_error_f(mrb), "Cannot access value of incomplete type");
return mrb_nil_value();
}
static mrb_value drb_ffi__ZTSP7regex_t_IsNil(mrb_state *state, mrb_value self) {
@@ -123,11 +144,11 @@ static mrb_value drb_ffi__ZTSP7regex_t_IsNil(mrb_state *state, mrb_value self) {
return mrb_false_value();
}
static mrb_value drb_ffi__ZTSP7regex_t_GetAt(mrb_state *mrb, mrb_value self) {
- mrb_raise_f(mrb, mrb_exc_get_f(mrb, "RuntimeError"), "Cannot access value of incomplete type");
+ mrb_raise_f(mrb, drb_getruntime_error_f(mrb), "Cannot access value of incomplete type");
return mrb_nil_value();
}
static mrb_value drb_ffi__ZTSP7regex_t_SetAt(mrb_state *mrb, mrb_value self) {
- mrb_raise_f(mrb, mrb_exc_get_f(mrb, "RuntimeError"), "Cannot change value of incomplete type");
+ mrb_raise_f(mrb, drb_getruntime_error_f(mrb), "Cannot change value of incomplete type");
return mrb_nil_value();
}
static mrb_value drb_ffi__ZTSPc_New(mrb_state *mrb, mrb_value self) {
@@ -264,19 +285,25 @@ void drb_register_c_extensions(void *(*lookup)(const char *), mrb_state *state,
mrb_define_method_f(state, IntPointerClass, "nil?", drb_ffi__ZTSPi_IsNil, MRB_ARGS_REQ(0));
}
static int drb_ffi_init_indirect_functions(void *(*lookup)(const char *fnname)) {
- if (!(mrb_raise_f = (void (*)(mrb_state *, struct RClass *, const char *)) lookup("mrb_raise"))) return -1;
- if (!(mrb_str_new_cstr_f = (mrb_value (*)(mrb_state *, const char *)) lookup("mrb_str_new_cstr"))) return -1;
- if (!(mrb_define_class_under_f = (struct RClass *(*)(mrb_state *, struct RClass *, const char *, struct RClass *)) lookup("mrb_define_class_under"))) return -1;
- if (!(mrb_define_class_method_f = (void (*)(mrb_state *, struct RClass *, const char *, mrb_func_t, mrb_aspec)) lookup("mrb_define_class_method"))) return -1;
- if (!(mrb_class_get_under_f = (struct RClass *(*)(mrb_state *, struct RClass *, const char *)) lookup("mrb_class_get_under"))) return -1;
- if (!(mrb_module_get_under_f = (struct RClass *(*)(mrb_state *, struct RClass *, const char *)) lookup("mrb_module_get_under"))) return -1;
+ drb_symbol_lookup = lookup;
+ if (!(drb_float_value_f = (mrb_value (*)(mrb_state *, mrb_float)) lookup("drb_float_value"))) return -1;
if (!(drb_free_foreign_object_f = (void (*)(mrb_state *, void *)) lookup("drb_free_foreign_object"))) return -1;
+ if (!(drb_getruntime_error_f = (struct RClass *(*)(mrb_state *)) lookup("drb_getruntime_error"))) return -1;
+ if (!(drb_typecheck_aggregate_f = (void (*)(mrb_state *, mrb_value, struct RClass *, mrb_data_type *)) lookup("drb_typecheck_aggregate"))) return -1;
+ if (!(drb_typecheck_bool_f = (void (*)(mrb_state *, mrb_value)) lookup("drb_typecheck_bool"))) return -1;
+ if (!(drb_typecheck_float_f = (void (*)(mrb_state *, mrb_value)) lookup("drb_typecheck_float"))) return -1;
+ if (!(drb_typecheck_int_f = (void (*)(mrb_state *, mrb_value)) lookup("drb_typecheck_int"))) return -1;
+ if (!(mrb_class_get_under_f = (struct RClass *(*)(mrb_state *, struct RClass *, const char *)) lookup("mrb_class_get_under"))) return -1;
if (!(mrb_data_object_alloc_f = (struct RData *(*)(mrb_state *, struct RClass *, void *, const mrb_data_type *)) lookup("mrb_data_object_alloc"))) return -1;
- if (!(mrb_get_args_f = (mrb_int (*)(mrb_state *, mrb_args_format, ...)) lookup("mrb_get_args"))) return -1;
- if (!(mrb_module_get_f = (struct RClass *(*)(mrb_state *, const char *)) lookup("mrb_module_get"))) return -1;
+ if (!(mrb_define_class_method_f = (void (*)(mrb_state *, struct RClass *, const char *, mrb_func_t, mrb_aspec)) lookup("mrb_define_class_method"))) return -1;
+ if (!(mrb_define_class_under_f = (struct RClass *(*)(mrb_state *, struct RClass *, const char *, struct RClass *)) lookup("mrb_define_class_under"))) return -1;
if (!(mrb_define_method_f = (void (*)(mrb_state *, struct RClass *, const char *, mrb_func_t, mrb_aspec)) lookup("mrb_define_method"))) return -1;
- if (!(mrb_exc_get_f = (struct RClass *(*)(mrb_state *, const char *)) lookup("mrb_exc_get"))) return -1;
if (!(mrb_define_module_function_f = (void (*)(mrb_state *, struct RClass *, const char *, mrb_func_t, mrb_aspec)) lookup("mrb_define_module_function"))) return -1;
if (!(mrb_define_module_under_f = (struct RClass *(*)(mrb_state *, struct RClass *, const char *)) lookup("mrb_define_module_under"))) return -1;
+ if (!(mrb_get_args_f = (mrb_int (*)(mrb_state *, mrb_args_format, ...)) lookup("mrb_get_args"))) return -1;
+ if (!(mrb_module_get_f = (struct RClass *(*)(mrb_state *, const char *)) lookup("mrb_module_get"))) return -1;
+ if (!(mrb_module_get_under_f = (struct RClass *(*)(mrb_state *, struct RClass *, const char *)) lookup("mrb_module_get_under"))) return -1;
+ if (!(mrb_raise_f = (void (*)(mrb_state *, struct RClass *, const char *)) lookup("mrb_raise"))) return -1;
+ if (!(mrb_str_new_cstr_f = (mrb_value (*)(mrb_state *, const char *)) lookup("mrb_str_new_cstr"))) return -1;
return 0;
}
diff --git a/samples/12_c_extensions/03_native_pixel_arrays/native/ext-bindings.c b/samples/12_c_extensions/03_native_pixel_arrays/native/ext-bindings.c
index c0a923c..bdba6e7 100644
--- a/samples/12_c_extensions/03_native_pixel_arrays/native/ext-bindings.c
+++ b/samples/12_c_extensions/03_native_pixel_arrays/native/ext-bindings.c
@@ -17,6 +17,10 @@
void *(*drb_symbol_lookup)(const char *sym) = NULL;
static void (*drb_free_foreign_object_f)(mrb_state *, void *);
+static void (*drb_typecheck_float_f)(mrb_state *, mrb_value);
+static void (*drb_typecheck_int_f)(mrb_state *, mrb_value);
+static void (*drb_typecheck_bool_f)(mrb_state *, mrb_value);
+static void (*drb_typecheck_aggregate_f)(mrb_state *, mrb_value, struct RClass *, mrb_data_type *);
static struct RClass *(*mrb_module_get_f)(mrb_state *, const char *);
static mrb_int (*mrb_get_args_f)(mrb_state *, mrb_args_format, ...);
static struct RClass *(*mrb_module_get_under_f)(mrb_state *, struct RClass *, const char *);
@@ -29,10 +33,18 @@ static void (*mrb_define_class_method_f)(mrb_state *, struct RClass *, const cha
static struct RData *(*mrb_data_object_alloc_f)(mrb_state *, struct RClass *, void *, const mrb_data_type *);
static mrb_value (*mrb_str_new_cstr_f)(mrb_state *, const char *);
static void (*mrb_raise_f)(mrb_state *, struct RClass *, const char *);
-static struct RClass *(*mrb_exc_get_f)(mrb_state *, const char *);
+static mrb_value (*drb_float_value_f)(mrb_state *, mrb_float);
+static struct RClass *(*drb_getruntime_error_f)(mrb_state *);
static void drb_free_foreign_object_indirect(mrb_state *state, void *pointer) {
drb_free_foreign_object_f(state, pointer);
}
+static int drb_ffi__ZTSi_FromRuby(mrb_state *state, mrb_value self) {
+ drb_typecheck_int_f(state, self);
+ return mrb_fixnum(self);
+}
+static mrb_value drb_ffi__ZTSi_ToRuby(mrb_state *state, int value) {
+ return mrb_fixnum_value(value);
+}
static mrb_value drb_ffi_update_scanner_texture_Binding(mrb_state *state, mrb_value value) {
update_scanner_texture();
return mrb_nil_value();
@@ -48,19 +60,24 @@ void drb_register_c_extensions(void *(*lookup)(const char *), mrb_state *state,
}
static int drb_ffi_init_indirect_functions(void *(*lookup)(const char *fnname)) {
drb_symbol_lookup = lookup;
- if (!(mrb_exc_get_f = (struct RClass *(*)(mrb_state *, const char *)) lookup("mrb_exc_get"))) return -1;
- if (!(mrb_raise_f = (void (*)(mrb_state *, struct RClass *, const char *)) lookup("mrb_raise"))) return -1;
- if (!(mrb_class_get_under_f = (struct RClass *(*)(mrb_state *, struct RClass *, const char *)) lookup("mrb_class_get_under"))) return -1;
- if (!(mrb_module_get_under_f = (struct RClass *(*)(mrb_state *, struct RClass *, const char *)) lookup("mrb_module_get_under"))) return -1;
+ if (!(drb_float_value_f = (mrb_value (*)(mrb_state *, mrb_float)) lookup("drb_float_value"))) return -1;
if (!(drb_free_foreign_object_f = (void (*)(mrb_state *, void *)) lookup("drb_free_foreign_object"))) return -1;
- if (!(mrb_module_get_f = (struct RClass *(*)(mrb_state *, const char *)) lookup("mrb_module_get"))) return -1;
- if (!(mrb_define_module_under_f = (struct RClass *(*)(mrb_state *, struct RClass *, const char *)) lookup("mrb_define_module_under"))) return -1;
+ if (!(drb_getruntime_error_f = (struct RClass *(*)(mrb_state *)) lookup("drb_getruntime_error"))) return -1;
+ if (!(drb_typecheck_aggregate_f = (void (*)(mrb_state *, mrb_value, struct RClass *, mrb_data_type *)) lookup("drb_typecheck_aggregate"))) return -1;
+ if (!(drb_typecheck_bool_f = (void (*)(mrb_state *, mrb_value)) lookup("drb_typecheck_bool"))) return -1;
+ if (!(drb_typecheck_float_f = (void (*)(mrb_state *, mrb_value)) lookup("drb_typecheck_float"))) return -1;
+ if (!(drb_typecheck_int_f = (void (*)(mrb_state *, mrb_value)) lookup("drb_typecheck_int"))) return -1;
+ if (!(mrb_class_get_under_f = (struct RClass *(*)(mrb_state *, struct RClass *, const char *)) lookup("mrb_class_get_under"))) return -1;
if (!(mrb_data_object_alloc_f = (struct RData *(*)(mrb_state *, struct RClass *, void *, const mrb_data_type *)) lookup("mrb_data_object_alloc"))) return -1;
+ if (!(mrb_define_class_method_f = (void (*)(mrb_state *, struct RClass *, const char *, mrb_func_t, mrb_aspec)) lookup("mrb_define_class_method"))) return -1;
+ if (!(mrb_define_class_under_f = (struct RClass *(*)(mrb_state *, struct RClass *, const char *, struct RClass *)) lookup("mrb_define_class_under"))) return -1;
+ if (!(mrb_define_method_f = (void (*)(mrb_state *, struct RClass *, const char *, mrb_func_t, mrb_aspec)) lookup("mrb_define_method"))) return -1;
if (!(mrb_define_module_function_f = (void (*)(mrb_state *, struct RClass *, const char *, mrb_func_t, mrb_aspec)) lookup("mrb_define_module_function"))) return -1;
+ if (!(mrb_define_module_under_f = (struct RClass *(*)(mrb_state *, struct RClass *, const char *)) lookup("mrb_define_module_under"))) return -1;
if (!(mrb_get_args_f = (mrb_int (*)(mrb_state *, mrb_args_format, ...)) lookup("mrb_get_args"))) return -1;
- if (!(mrb_define_method_f = (void (*)(mrb_state *, struct RClass *, const char *, mrb_func_t, mrb_aspec)) lookup("mrb_define_method"))) return -1;
- if (!(mrb_define_class_method_f = (void (*)(mrb_state *, struct RClass *, const char *, mrb_func_t, mrb_aspec)) lookup("mrb_define_class_method"))) return -1;
+ if (!(mrb_module_get_f = (struct RClass *(*)(mrb_state *, const char *)) lookup("mrb_module_get"))) return -1;
+ if (!(mrb_module_get_under_f = (struct RClass *(*)(mrb_state *, struct RClass *, const char *)) lookup("mrb_module_get_under"))) return -1;
+ if (!(mrb_raise_f = (void (*)(mrb_state *, struct RClass *, const char *)) lookup("mrb_raise"))) return -1;
if (!(mrb_str_new_cstr_f = (mrb_value (*)(mrb_state *, const char *)) lookup("mrb_str_new_cstr"))) return -1;
- if (!(mrb_define_class_under_f = (struct RClass *(*)(mrb_state *, struct RClass *, const char *, struct RClass *)) lookup("mrb_define_class_under"))) return -1;
return 0;
}
diff --git a/samples/13_path_finding_algorithms/01_breadth_first_search/replay.txt b/samples/13_path_finding_algorithms/01_breadth_first_search/replay.txt
new file mode 100644
index 0000000..62f4aca
--- /dev/null
+++ b/samples/13_path_finding_algorithms/01_breadth_first_search/replay.txt
@@ -0,0 +1,203 @@
+replay_version 2.0
+stopped_at 213
+seed 100
+recorded_at 2021-11-20 11:17:21 -0600
+[:mouse_button_up, 1, 0, 1, 1, 4]
+[:mouse_move, 780, 95, 2, 2, 11]
+[:mouse_move, 781, 95, 2, 3, 12]
+[:mouse_move, 782, 95, 2, 4, 13]
+[:mouse_move, 783, 95, 2, 5, 14]
+[:mouse_move, 771, 95, 2, 6, 32]
+[:mouse_move, 752, 95, 2, 7, 32]
+[:mouse_move, 718, 95, 2, 8, 34]
+[:mouse_move, 652, 95, 2, 9, 34]
+[:mouse_move, 549, 95, 2, 10, 35]
+[:mouse_move, 462, 101, 2, 11, 36]
+[:mouse_move, 425, 106, 2, 12, 37]
+[:mouse_move, 405, 108, 2, 13, 38]
+[:mouse_move, 406, 109, 2, 14, 39]
+[:mouse_move, 412, 111, 2, 15, 40]
+[:mouse_move, 429, 111, 2, 16, 41]
+[:mouse_move, 450, 109, 2, 17, 42]
+[:mouse_move, 460, 107, 2, 18, 42]
+[:mouse_move, 460, 106, 2, 19, 43]
+[:mouse_move, 460, 105, 2, 20, 45]
+[:mouse_move, 460, 104, 2, 21, 46]
+[:mouse_move, 456, 104, 2, 22, 47]
+[:mouse_move, 469, 104, 2, 23, 49]
+[:mouse_move, 489, 103, 2, 24, 50]
+[:mouse_move, 512, 100, 2, 25, 51]
+[:mouse_move, 536, 96, 2, 26, 52]
+[:mouse_move, 565, 92, 2, 27, 52]
+[:mouse_move, 587, 92, 2, 28, 53]
+[:mouse_move, 597, 92, 2, 29, 54]
+[:mouse_move, 599, 92, 2, 30, 55]
+[:mouse_button_pressed, 1, 0, 1, 31, 59]
+[:mouse_button_up, 1, 0, 1, 32, 62]
+[:mouse_move, 599, 91, 2, 33, 65]
+[:mouse_move, 590, 86, 2, 34, 65]
+[:mouse_move, 570, 78, 2, 35, 66]
+[:mouse_move, 543, 70, 2, 36, 66]
+[:mouse_move, 516, 65, 2, 37, 67]
+[:mouse_move, 481, 61, 2, 38, 68]
+[:mouse_move, 449, 59, 2, 39, 69]
+[:mouse_move, 429, 57, 2, 40, 69]
+[:mouse_move, 424, 56, 2, 41, 70]
+[:mouse_move, 426, 56, 2, 42, 74]
+[:mouse_move, 429, 56, 2, 43, 75]
+[:mouse_move, 431, 56, 2, 44, 75]
+[:mouse_move, 433, 56, 2, 45, 76]
+[:mouse_move, 435, 55, 2, 46, 77]
+[:mouse_move, 437, 55, 2, 47, 78]
+[:mouse_move, 440, 55, 2, 48, 78]
+[:mouse_move, 444, 55, 2, 49, 79]
+[:mouse_move, 445, 54, 2, 50, 79]
+[:mouse_move, 444, 53, 2, 51, 81]
+[:mouse_move, 444, 52, 2, 52, 82]
+[:mouse_move, 443, 51, 2, 53, 89]
+[:mouse_button_pressed, 1, 0, 1, 54, 89]
+[:mouse_move, 442, 51, 2, 55, 89]
+[:mouse_move, 436, 51, 2, 56, 90]
+[:mouse_move, 432, 49, 2, 57, 91]
+[:mouse_move, 431, 49, 2, 58, 91]
+[:mouse_move, 429, 49, 2, 59, 92]
+[:mouse_move, 428, 49, 2, 60, 93]
+[:mouse_move, 426, 49, 2, 61, 94]
+[:mouse_move, 425, 49, 2, 62, 94]
+[:mouse_move, 424, 49, 2, 63, 95]
+[:mouse_move, 423, 49, 2, 64, 96]
+[:mouse_move, 422, 49, 2, 65, 98]
+[:mouse_move, 421, 49, 2, 66, 99]
+[:mouse_move, 420, 49, 2, 67, 99]
+[:mouse_move, 419, 49, 2, 68, 100]
+[:mouse_move, 417, 49, 2, 69, 100]
+[:mouse_move, 415, 49, 2, 70, 101]
+[:mouse_move, 414, 49, 2, 71, 102]
+[:mouse_move, 413, 49, 2, 72, 108]
+[:mouse_move, 415, 49, 2, 73, 124]
+[:mouse_move, 416, 49, 2, 74, 125]
+[:mouse_move, 420, 49, 2, 75, 126]
+[:mouse_move, 424, 49, 2, 76, 127]
+[:mouse_move, 429, 49, 2, 77, 128]
+[:mouse_move, 433, 49, 2, 78, 128]
+[:mouse_move, 441, 49, 2, 79, 129]
+[:mouse_move, 450, 49, 2, 80, 129]
+[:mouse_move, 460, 49, 2, 81, 130]
+[:mouse_move, 472, 49, 2, 82, 131]
+[:mouse_move, 480, 49, 2, 83, 131]
+[:mouse_move, 486, 49, 2, 84, 132]
+[:mouse_move, 488, 49, 2, 85, 132]
+[:mouse_move, 492, 49, 2, 86, 132]
+[:mouse_move, 498, 49, 2, 87, 133]
+[:mouse_move, 507, 49, 2, 88, 133]
+[:mouse_move, 513, 48, 2, 89, 134]
+[:mouse_move, 518, 47, 2, 90, 134]
+[:mouse_move, 523, 47, 2, 91, 134]
+[:mouse_move, 529, 46, 2, 92, 135]
+[:mouse_move, 533, 46, 2, 93, 135]
+[:mouse_move, 538, 46, 2, 94, 135]
+[:mouse_move, 543, 46, 2, 95, 136]
+[:mouse_move, 545, 46, 2, 96, 136]
+[:mouse_move, 546, 46, 2, 97, 136]
+[:mouse_move, 551, 46, 2, 98, 137]
+[:mouse_move, 558, 46, 2, 99, 137]
+[:mouse_move, 567, 46, 2, 100, 138]
+[:mouse_move, 573, 46, 2, 101, 138]
+[:mouse_move, 576, 45, 2, 102, 138]
+[:mouse_move, 579, 45, 2, 103, 138]
+[:mouse_move, 581, 45, 2, 104, 138]
+[:mouse_move, 584, 45, 2, 105, 139]
+[:mouse_move, 590, 45, 2, 106, 139]
+[:mouse_move, 597, 45, 2, 107, 139]
+[:mouse_move, 602, 45, 2, 108, 140]
+[:mouse_move, 606, 45, 2, 109, 140]
+[:mouse_move, 611, 45, 2, 110, 140]
+[:mouse_move, 617, 45, 2, 111, 140]
+[:mouse_move, 625, 45, 2, 112, 140]
+[:mouse_move, 632, 45, 2, 113, 140]
+[:mouse_move, 638, 45, 2, 114, 141]
+[:mouse_move, 643, 45, 2, 115, 141]
+[:mouse_move, 644, 44, 2, 116, 141]
+[:mouse_move, 646, 44, 2, 117, 141]
+[:mouse_move, 647, 44, 2, 118, 142]
+[:mouse_move, 650, 44, 2, 119, 142]
+[:mouse_move, 653, 44, 2, 120, 142]
+[:mouse_move, 656, 44, 2, 121, 142]
+[:mouse_move, 658, 43, 2, 122, 142]
+[:mouse_move, 659, 43, 2, 123, 143]
+[:mouse_move, 663, 43, 2, 124, 143]
+[:mouse_move, 665, 43, 2, 125, 143]
+[:mouse_move, 667, 43, 2, 126, 143]
+[:mouse_move, 669, 43, 2, 127, 143]
+[:mouse_move, 670, 43, 2, 128, 143]
+[:mouse_move, 671, 43, 2, 129, 143]
+[:mouse_move, 672, 43, 2, 130, 144]
+[:mouse_move, 674, 43, 2, 131, 144]
+[:mouse_move, 677, 43, 2, 132, 144]
+[:mouse_move, 679, 43, 2, 133, 144]
+[:mouse_move, 680, 43, 2, 134, 144]
+[:mouse_move, 681, 43, 2, 135, 144]
+[:mouse_move, 683, 43, 2, 136, 145]
+[:mouse_move, 684, 43, 2, 137, 145]
+[:mouse_move, 685, 43, 2, 138, 145]
+[:mouse_move, 686, 43, 2, 139, 145]
+[:mouse_move, 687, 43, 2, 140, 145]
+[:mouse_move, 688, 43, 2, 141, 146]
+[:mouse_button_up, 1, 0, 1, 142, 150]
+[:mouse_move, 688, 44, 2, 143, 150]
+[:mouse_move, 685, 45, 2, 144, 150]
+[:mouse_move, 674, 47, 2, 145, 150]
+[:mouse_move, 657, 52, 2, 146, 150]
+[:mouse_move, 621, 57, 2, 147, 151]
+[:mouse_move, 593, 62, 2, 148, 151]
+[:mouse_move, 568, 65, 2, 149, 151]
+[:mouse_move, 550, 68, 2, 150, 151]
+[:mouse_move, 542, 69, 2, 151, 152]
+[:mouse_move, 539, 69, 2, 152, 152]
+[:mouse_move, 536, 70, 2, 153, 152]
+[:mouse_move, 534, 70, 2, 154, 153]
+[:mouse_move, 531, 72, 2, 155, 153]
+[:mouse_move, 528, 73, 2, 156, 153]
+[:mouse_move, 522, 75, 2, 157, 154]
+[:mouse_move, 515, 80, 2, 158, 154]
+[:mouse_move, 514, 81, 2, 159, 154]
+[:mouse_move, 513, 81, 2, 160, 154]
+[:mouse_move, 509, 84, 2, 161, 156]
+[:mouse_move, 502, 88, 2, 162, 156]
+[:mouse_move, 491, 93, 2, 163, 156]
+[:mouse_move, 487, 97, 2, 164, 156]
+[:mouse_move, 486, 97, 2, 165, 156]
+[:mouse_move, 487, 96, 2, 166, 157]
+[:mouse_button_pressed, 1, 0, 1, 167, 159]
+[:mouse_button_up, 1, 0, 1, 168, 160]
+[:mouse_button_pressed, 1, 0, 1, 169, 161]
+[:mouse_move, 488, 96, 2, 170, 161]
+[:mouse_button_up, 1, 0, 1, 171, 161]
+[:mouse_move, 488, 97, 2, 172, 166]
+[:mouse_move, 487, 97, 2, 173, 166]
+[:mouse_move, 486, 97, 2, 174, 167]
+[:mouse_move, 485, 97, 2, 175, 167]
+[:mouse_move, 484, 97, 2, 176, 168]
+[:mouse_button_pressed, 1, 0, 1, 177, 172]
+[:mouse_button_up, 1, 0, 1, 178, 173]
+[:mouse_move, 485, 97, 2, 179, 185]
+[:key_down_raw, 96, 0, 2, 180, 191]
+[:mouse_move, 486, 96, 2, 181, 192]
+[:mouse_move, 488, 96, 2, 182, 192]
+[:mouse_move, 495, 94, 2, 183, 192]
+[:key_up_raw, 96, 0, 2, 184, 192]
+[:mouse_move, 503, 93, 2, 185, 193]
+[:mouse_move, 514, 92, 2, 186, 193]
+[:mouse_move, 544, 92, 2, 187, 193]
+[:mouse_move, 573, 92, 2, 188, 194]
+[:mouse_move, 607, 92, 2, 189, 194]
+[:mouse_move, 641, 89, 2, 190, 194]
+[:mouse_move, 674, 89, 2, 191, 194]
+[:mouse_move, 705, 89, 2, 192, 194]
+[:mouse_move, 735, 89, 2, 193, 195]
+[:mouse_move, 759, 89, 2, 194, 195]
+[:mouse_move, 776, 89, 2, 195, 195]
+[:mouse_move, 784, 89, 2, 196, 195]
+[:mouse_move, 786, 89, 2, 197, 196]
+[:mouse_move, 786, 90, 2, 198, 204]
+[:key_down_raw, 13, 0, 2, 199, 213]
diff --git a/samples/13_path_finding_algorithms/02_detailed_breadth_first_search/replay.txt b/samples/13_path_finding_algorithms/02_detailed_breadth_first_search/replay.txt
new file mode 100644
index 0000000..aa8719b
--- /dev/null
+++ b/samples/13_path_finding_algorithms/02_detailed_breadth_first_search/replay.txt
@@ -0,0 +1,241 @@
+replay_version 2.0
+stopped_at 435
+seed 100
+recorded_at 2021-11-20 11:18:03 -0600
+[:mouse_button_up, 1, 0, 1, 1, 4]
+[:mouse_move, 789, 89, 2, 2, 27]
+[:mouse_move, 785, 90, 2, 3, 28]
+[:mouse_move, 768, 94, 2, 4, 29]
+[:mouse_move, 752, 99, 2, 5, 30]
+[:mouse_move, 737, 104, 2, 6, 31]
+[:mouse_move, 729, 104, 2, 7, 32]
+[:mouse_move, 724, 104, 2, 8, 33]
+[:mouse_move, 720, 103, 2, 9, 34]
+[:mouse_move, 711, 103, 2, 10, 35]
+[:mouse_move, 702, 103, 2, 11, 36]
+[:mouse_move, 698, 103, 2, 12, 37]
+[:mouse_move, 697, 103, 2, 13, 38]
+[:mouse_move, 696, 103, 2, 14, 40]
+[:mouse_move, 694, 104, 2, 15, 41]
+[:mouse_move, 684, 104, 2, 16, 42]
+[:mouse_move, 666, 104, 2, 17, 43]
+[:mouse_move, 645, 105, 2, 18, 44]
+[:mouse_move, 626, 106, 2, 19, 45]
+[:mouse_move, 615, 106, 2, 20, 46]
+[:mouse_move, 609, 106, 2, 21, 47]
+[:mouse_move, 606, 106, 2, 22, 48]
+[:mouse_move, 605, 106, 2, 23, 49]
+[:mouse_move, 600, 104, 2, 24, 50]
+[:mouse_move, 590, 100, 2, 25, 51]
+[:mouse_move, 579, 97, 2, 26, 52]
+[:mouse_move, 575, 96, 2, 27, 53]
+[:mouse_move, 581, 96, 2, 28, 58]
+[:mouse_move, 596, 98, 2, 29, 59]
+[:mouse_move, 614, 98, 2, 30, 60]
+[:mouse_move, 635, 97, 2, 31, 61]
+[:mouse_move, 652, 94, 2, 32, 62]
+[:mouse_move, 657, 93, 2, 33, 63]
+[:mouse_move, 658, 92, 2, 34, 64]
+[:mouse_button_pressed, 1, 0, 1, 35, 70]
+[:mouse_move, 659, 92, 2, 36, 70]
+[:mouse_button_up, 1, 0, 1, 37, 74]
+[:mouse_move, 660, 92, 2, 38, 87]
+[:mouse_button_pressed, 1, 0, 1, 39, 92]
+[:mouse_button_up, 1, 0, 1, 40, 98]
+[:mouse_move, 661, 92, 2, 41, 101]
+[:mouse_button_pressed, 1, 0, 1, 42, 103]
+[:mouse_button_up, 1, 0, 1, 43, 108]
+[:mouse_move, 662, 92, 2, 44, 112]
+[:mouse_button_pressed, 1, 0, 1, 45, 113]
+[:mouse_button_up, 1, 0, 1, 46, 119]
+[:mouse_move, 657, 92, 2, 47, 125]
+[:mouse_move, 641, 92, 2, 48, 126]
+[:mouse_move, 623, 93, 2, 49, 127]
+[:mouse_move, 610, 95, 2, 50, 128]
+[:mouse_move, 599, 97, 2, 51, 129]
+[:mouse_move, 588, 98, 2, 52, 130]
+[:mouse_move, 584, 99, 2, 53, 131]
+[:mouse_move, 581, 99, 2, 54, 132]
+[:mouse_move, 580, 99, 2, 55, 133]
+[:mouse_move, 575, 99, 2, 56, 134]
+[:mouse_move, 572, 99, 2, 57, 135]
+[:mouse_move, 570, 99, 2, 58, 136]
+[:mouse_move, 564, 101, 2, 59, 137]
+[:mouse_move, 559, 101, 2, 60, 138]
+[:mouse_move, 557, 101, 2, 61, 139]
+[:mouse_move, 555, 102, 2, 62, 140]
+[:mouse_move, 554, 102, 2, 63, 141]
+[:mouse_button_pressed, 1, 0, 1, 64, 145]
+[:mouse_button_up, 1, 0, 1, 65, 149]
+[:mouse_button_pressed, 1, 0, 1, 66, 154]
+[:mouse_move, 555, 102, 2, 67, 154]
+[:mouse_button_up, 1, 0, 1, 68, 159]
+[:mouse_button_pressed, 1, 0, 1, 69, 163]
+[:mouse_button_up, 1, 0, 1, 70, 168]
+[:mouse_move, 555, 103, 2, 71, 168]
+[:mouse_move, 539, 103, 2, 72, 169]
+[:mouse_move, 519, 100, 2, 73, 170]
+[:mouse_move, 498, 95, 2, 74, 171]
+[:mouse_move, 488, 90, 2, 75, 172]
+[:mouse_move, 484, 88, 2, 76, 173]
+[:mouse_move, 475, 81, 2, 77, 174]
+[:mouse_move, 460, 73, 2, 78, 175]
+[:mouse_move, 441, 64, 2, 79, 176]
+[:mouse_move, 424, 57, 2, 80, 177]
+[:mouse_move, 413, 53, 2, 81, 178]
+[:mouse_move, 408, 50, 2, 82, 179]
+[:mouse_move, 407, 49, 2, 83, 182]
+[:mouse_move, 405, 47, 2, 84, 183]
+[:mouse_move, 404, 46, 2, 85, 184]
+[:mouse_move, 404, 45, 2, 86, 185]
+[:mouse_move, 403, 45, 2, 87, 186]
+[:mouse_button_pressed, 1, 0, 1, 88, 195]
+[:mouse_move, 406, 45, 2, 89, 197]
+[:mouse_move, 413, 45, 2, 90, 198]
+[:mouse_move, 423, 45, 2, 91, 199]
+[:mouse_move, 434, 45, 2, 92, 200]
+[:mouse_move, 446, 45, 2, 93, 201]
+[:mouse_move, 461, 45, 2, 94, 202]
+[:mouse_move, 472, 45, 2, 95, 203]
+[:mouse_move, 480, 45, 2, 96, 204]
+[:mouse_move, 486, 45, 2, 97, 205]
+[:mouse_move, 492, 45, 2, 98, 206]
+[:mouse_move, 495, 45, 2, 99, 207]
+[:mouse_move, 496, 45, 2, 100, 208]
+[:mouse_move, 497, 45, 2, 101, 209]
+[:mouse_move, 498, 45, 2, 102, 210]
+[:mouse_move, 501, 45, 2, 103, 211]
+[:mouse_move, 507, 45, 2, 104, 212]
+[:mouse_move, 512, 45, 2, 105, 213]
+[:mouse_move, 516, 45, 2, 106, 214]
+[:mouse_move, 518, 45, 2, 107, 215]
+[:mouse_move, 519, 45, 2, 108, 216]
+[:mouse_move, 520, 45, 2, 109, 217]
+[:mouse_move, 522, 45, 2, 110, 218]
+[:mouse_move, 525, 45, 2, 111, 219]
+[:mouse_move, 533, 45, 2, 112, 220]
+[:mouse_move, 537, 45, 2, 113, 221]
+[:mouse_move, 541, 45, 2, 114, 222]
+[:mouse_move, 545, 45, 2, 115, 223]
+[:mouse_move, 546, 45, 2, 116, 224]
+[:mouse_move, 547, 45, 2, 117, 226]
+[:mouse_move, 549, 45, 2, 118, 227]
+[:mouse_move, 554, 45, 2, 119, 228]
+[:mouse_move, 556, 45, 2, 120, 229]
+[:mouse_move, 560, 45, 2, 121, 230]
+[:mouse_move, 566, 45, 2, 122, 231]
+[:mouse_move, 570, 45, 2, 123, 232]
+[:mouse_move, 577, 45, 2, 124, 233]
+[:mouse_move, 585, 45, 2, 125, 234]
+[:mouse_move, 593, 46, 2, 126, 235]
+[:mouse_move, 602, 48, 2, 127, 236]
+[:mouse_move, 609, 48, 2, 128, 237]
+[:mouse_move, 614, 48, 2, 129, 238]
+[:mouse_move, 619, 48, 2, 130, 239]
+[:mouse_move, 625, 49, 2, 131, 240]
+[:mouse_move, 633, 49, 2, 132, 241]
+[:mouse_move, 643, 49, 2, 133, 242]
+[:mouse_move, 651, 49, 2, 134, 243]
+[:mouse_move, 658, 49, 2, 135, 243]
+[:mouse_move, 664, 49, 2, 136, 244]
+[:mouse_move, 669, 49, 2, 137, 245]
+[:mouse_move, 675, 49, 2, 138, 246]
+[:mouse_move, 679, 49, 2, 139, 247]
+[:mouse_move, 682, 49, 2, 140, 248]
+[:mouse_move, 686, 49, 2, 141, 249]
+[:mouse_move, 689, 49, 2, 142, 250]
+[:mouse_move, 691, 49, 2, 143, 251]
+[:mouse_move, 697, 49, 2, 144, 252]
+[:mouse_move, 706, 49, 2, 145, 253]
+[:mouse_move, 715, 49, 2, 146, 254]
+[:mouse_move, 723, 49, 2, 147, 255]
+[:mouse_move, 730, 49, 2, 148, 256]
+[:mouse_move, 733, 49, 2, 149, 256]
+[:mouse_move, 734, 49, 2, 150, 257]
+[:mouse_move, 737, 49, 2, 151, 258]
+[:mouse_move, 742, 49, 2, 152, 259]
+[:mouse_move, 749, 49, 2, 153, 260]
+[:mouse_move, 755, 49, 2, 154, 261]
+[:mouse_move, 758, 49, 2, 155, 262]
+[:mouse_move, 760, 49, 2, 156, 263]
+[:mouse_move, 761, 49, 2, 157, 264]
+[:mouse_move, 762, 49, 2, 158, 266]
+[:mouse_move, 763, 49, 2, 159, 268]
+[:mouse_move, 763, 48, 2, 160, 269]
+[:mouse_move, 757, 48, 2, 161, 290]
+[:mouse_move, 746, 48, 2, 162, 291]
+[:mouse_move, 732, 48, 2, 163, 291]
+[:mouse_move, 716, 48, 2, 164, 292]
+[:mouse_move, 698, 48, 2, 165, 293]
+[:mouse_move, 684, 47, 2, 166, 294]
+[:mouse_move, 673, 46, 2, 167, 295]
+[:mouse_move, 665, 44, 2, 168, 296]
+[:mouse_move, 660, 44, 2, 169, 297]
+[:mouse_move, 656, 44, 2, 170, 297]
+[:mouse_move, 652, 44, 2, 171, 298]
+[:mouse_move, 648, 44, 2, 172, 299]
+[:mouse_move, 637, 44, 2, 173, 300]
+[:mouse_move, 628, 44, 2, 174, 301]
+[:mouse_move, 618, 44, 2, 175, 302]
+[:mouse_move, 609, 44, 2, 176, 303]
+[:mouse_move, 602, 44, 2, 177, 304]
+[:mouse_move, 598, 43, 2, 178, 305]
+[:mouse_move, 596, 43, 2, 179, 306]
+[:mouse_move, 595, 43, 2, 180, 307]
+[:mouse_move, 594, 42, 2, 181, 308]
+[:mouse_move, 593, 42, 2, 182, 308]
+[:mouse_move, 591, 42, 2, 183, 309]
+[:mouse_move, 588, 42, 2, 184, 310]
+[:mouse_move, 586, 42, 2, 185, 311]
+[:mouse_move, 584, 42, 2, 186, 312]
+[:mouse_move, 582, 42, 2, 187, 313]
+[:mouse_move, 576, 42, 2, 188, 314]
+[:mouse_move, 570, 42, 2, 189, 315]
+[:mouse_move, 562, 42, 2, 190, 316]
+[:mouse_move, 554, 42, 2, 191, 317]
+[:mouse_move, 547, 42, 2, 192, 318]
+[:mouse_move, 537, 42, 2, 193, 319]
+[:mouse_move, 532, 42, 2, 194, 320]
+[:mouse_move, 528, 42, 2, 195, 321]
+[:mouse_move, 527, 42, 2, 196, 322]
+[:mouse_move, 526, 42, 2, 197, 323]
+[:mouse_move, 525, 42, 2, 198, 324]
+[:mouse_move, 524, 42, 2, 199, 325]
+[:mouse_move, 522, 42, 2, 200, 326]
+[:mouse_move, 521, 42, 2, 201, 327]
+[:mouse_move, 520, 42, 2, 202, 328]
+[:mouse_move, 519, 42, 2, 203, 329]
+[:mouse_move, 516, 42, 2, 204, 330]
+[:mouse_move, 513, 42, 2, 205, 331]
+[:mouse_move, 512, 42, 2, 206, 332]
+[:mouse_move, 509, 42, 2, 207, 333]
+[:mouse_move, 497, 42, 2, 208, 334]
+[:mouse_move, 490, 42, 2, 209, 335]
+[:mouse_move, 486, 42, 2, 210, 336]
+[:mouse_move, 483, 42, 2, 211, 337]
+[:mouse_move, 482, 42, 2, 212, 338]
+[:mouse_move, 481, 42, 2, 213, 339]
+[:mouse_button_up, 1, 0, 1, 214, 354]
+[:mouse_move, 484, 43, 2, 215, 361]
+[:mouse_move, 497, 47, 2, 216, 362]
+[:mouse_move, 513, 51, 2, 217, 363]
+[:mouse_move, 530, 55, 2, 218, 364]
+[:mouse_move, 544, 58, 2, 219, 365]
+[:mouse_move, 562, 63, 2, 220, 366]
+[:mouse_move, 589, 71, 2, 221, 367]
+[:mouse_move, 623, 81, 2, 222, 368]
+[:mouse_move, 656, 91, 2, 223, 369]
+[:mouse_move, 687, 95, 2, 224, 370]
+[:mouse_move, 731, 102, 2, 225, 371]
+[:mouse_move, 762, 110, 2, 226, 372]
+[:mouse_move, 792, 117, 2, 227, 373]
+[:mouse_move, 819, 123, 2, 228, 374]
+[:key_down_raw, 96, 0, 2, 229, 375]
+[:mouse_move, 842, 125, 2, 230, 375]
+[:mouse_move, 859, 128, 2, 231, 376]
+[:mouse_move, 871, 130, 2, 232, 377]
+[:mouse_move, 878, 131, 2, 233, 378]
+[:mouse_move, 879, 131, 2, 234, 379]
+[:key_up_raw, 96, 0, 2, 235, 379]
+[:mouse_move, 878, 131, 2, 236, 411]
+[:key_down_raw, 13, 0, 2, 237, 435]
diff --git a/samples/13_path_finding_algorithms/03_breadcrumbs/app/main.rb b/samples/13_path_finding_algorithms/03_breadcrumbs/app/main.rb
index 648805a..533a962 100644
--- a/samples/13_path_finding_algorithms/03_breadcrumbs/app/main.rb
+++ b/samples/13_path_finding_algorithms/03_breadcrumbs/app/main.rb
@@ -12,8 +12,8 @@ class Breadcrumbs
calc
# Calc Path
end
- render
- input
+ render
+ input
end
def defaults
@@ -90,7 +90,7 @@ class Breadcrumbs
[24, 9] => true,
[25, 8] => true,
[25, 9] => true,
- }
+ }
# Variables that are used by the breadth first search
# Storing cells that the search has visited, prevents unnecessary steps
@@ -109,36 +109,36 @@ class Breadcrumbs
# We store this value, because we want to remember the value even when
# the user's cursor is no longer over what they're interacting with, but
# they are still clicking down on the mouse.
- state.current_input ||= :none
+ state.current_input ||= :none
end
def calc
# Setup the search to start from the star
- search.frontier << grid.star
+ search.frontier << grid.star
search.came_from[grid.star] = nil
# Until there are no more cells to expand from
- until search.frontier.empty?
+ until search.frontier.empty?
# Takes the next frontier cell
- new_frontier = search.frontier.shift
+ new_frontier = search.frontier.shift
# For each of its neighbors
- adjacent_neighbors(new_frontier).each do |neighbor|
+ adjacent_neighbors(new_frontier).each do |neighbor|
# That have not been visited and are not walls
- unless search.came_from.has_key?(neighbor) || grid.walls.has_key?(neighbor)
+ unless search.came_from.has_key?(neighbor) || grid.walls.has_key?(neighbor)
# Add them to the frontier and mark them as visited in the first grid
# Unless the target has been visited
# Add the neighbor to the frontier and remember which cell it came from
- search.frontier << neighbor
+ search.frontier << neighbor
search.came_from[neighbor] = new_frontier
end
end
end
end
-
+
# Draws everything onto the screen
def render
- render_background
+ render_background
# render_heat_map
render_walls
# render_path
@@ -157,7 +157,7 @@ class Breadcrumbs
if current_cell && parent_cell
outputs.lines << [(current_cell.x + 0.5) * grid.cell_size, (current_cell.y + 0.5) * grid.cell_size,
(parent_cell.x + 0.5) * grid.cell_size, (parent_cell.y + 0.5) * grid.cell_size, purple]
-
+
end
render_trail(parent_cell)
end
@@ -183,8 +183,8 @@ class Breadcrumbs
# Draws what the grid looks like with nothing on it
def render_background
- render_unvisited
- render_grid_lines
+ render_unvisited
+ render_grid_lines
end
# Draws both grids
@@ -199,7 +199,7 @@ class Breadcrumbs
end
for y in 0..grid.height
- outputs.lines << horizontal_line(y)
+ outputs.lines << horizontal_line(y)
end
end
@@ -215,7 +215,7 @@ class Breadcrumbs
# Draws the walls on both grids
def render_walls
- grid.walls.each_key do |wall|
+ grid.walls.each_key do |wall|
outputs.solids << [scale_up(wall), wall_color]
end
end
@@ -223,12 +223,12 @@ class Breadcrumbs
# Renders the star on both grids
def render_star
outputs.sprites << [scale_up(grid.star), 'star.png']
- end
+ end
# Renders the target on both grids
def render_target
outputs.sprites << [scale_up(grid.target), 'target.png']
- end
+ end
# Labels the grids
def render_labels
@@ -288,14 +288,14 @@ class Breadcrumbs
# The program has to remember that the user is dragging an object
# even when the mouse is no longer over that object
# So detecting input and processing input is separate
- # detect_input
- # process_input
+ # detect_input
+ # process_input
if inputs.mouse.up
state.current_input = :none
elsif star_clicked?
state.current_input = :star
end
-
+
if mouse_inside_grid?
unless grid.target == cell_closest_to_mouse
grid.target = cell_closest_to_mouse
@@ -313,33 +313,33 @@ class Breadcrumbs
# mouse left click is held
def detect_input
# When the mouse is up, nothing is being edited
- if inputs.mouse.up
- state.current_input = :none
+ if inputs.mouse.up
+ state.current_input = :none
# When the star in the no second grid is clicked
- elsif star_clicked?
- state.current_input = :star
+ elsif star_clicked?
+ state.current_input = :star
# When the target in the no second grid is clicked
- elsif target_clicked?
- state.current_input = :target
+ elsif target_clicked?
+ state.current_input = :target
# When a wall in the first grid is clicked
- elsif wall_clicked?
- state.current_input = :remove_wall
+ elsif wall_clicked?
+ state.current_input = :remove_wall
# When the first grid is clicked
- elsif grid_clicked?
+ elsif grid_clicked?
state.current_input = :add_wall
end
end
# Processes click and drag based on what the user is currently dragging
def process_input
- if state.current_input == :star
- input_star
- elsif state.current_input == :target
- input_target
- elsif state.current_input == :remove_wall
- input_remove_wall
- elsif state.current_input == :add_wall
- input_add_wall
+ if state.current_input == :star
+ input_star
+ elsif state.current_input == :target
+ input_target
+ elsif state.current_input == :remove_wall
+ input_remove_wall
+ elsif state.current_input == :add_wall
+ input_add_wall
end
end
@@ -347,10 +347,10 @@ class Breadcrumbs
# Only resets the search if the star changes position
# Called whenever the user is editing the star (puts mouse down on star)
def input_star
- old_star = grid.star.clone
+ old_star = grid.star.clone
grid.star = cell_closest_to_mouse
- unless old_star == grid.star
- reset_search
+ unless old_star == grid.star
+ reset_search
end
end
@@ -358,10 +358,10 @@ class Breadcrumbs
# Only reset_searchs the search if the target changes position
# Called whenever the user is editing the target (puts mouse down on target)
def input_target
- old_target = grid.target.clone
+ old_target = grid.target.clone
grid.target = cell_closest_to_mouse
- unless old_target == grid.target
- reset_search
+ unless old_target == grid.target
+ reset_search
end
end
@@ -370,32 +370,32 @@ class Breadcrumbs
# The mouse needs to be inside the grid, because we only want to remove walls
# the cursor is directly over
# Recalculations should only occur when a wall is actually deleted
- if mouse_inside_grid?
+ if mouse_inside_grid?
if grid.walls.has_key?(cell_closest_to_mouse)
- grid.walls.delete(cell_closest_to_mouse)
- reset_search
+ grid.walls.delete(cell_closest_to_mouse)
+ reset_search
end
end
end
# Adds a wall in the first grid in the cell the mouse is over
def input_add_wall
- if mouse_inside_grid?
+ if mouse_inside_grid?
unless grid.walls.has_key?(cell_closest_to_mouse)
- grid.walls[cell_closest_to_mouse] = true
- reset_search
+ grid.walls[cell_closest_to_mouse] = true
+ reset_search
end
end
end
-
+
# Whenever the user edits the grid,
# The search has to be reset_searchd upto the current step
# with the current grid as the initial state of the grid
def reset_search
# Reset_Searchs the search
- search.frontier = []
- search.came_from = {}
+ search.frontier = []
+ search.came_from = {}
search.path = {}
end
@@ -403,21 +403,21 @@ class Breadcrumbs
# Returns a list of adjacent cells
# Used to determine what the next cells to be added to the frontier are
def adjacent_neighbors(cell)
- neighbors = []
+ neighbors = []
# Gets all the valid neighbors into the array
# From southern neighbor, clockwise
- neighbors << [cell.x, cell.y - 1] unless cell.y == 0
- neighbors << [cell.x - 1, cell.y] unless cell.x == 0
- neighbors << [cell.x, cell.y + 1] unless cell.y == grid.height - 1
- neighbors << [cell.x + 1, cell.y] unless cell.x == grid.width - 1
+ neighbors << [cell.x, cell.y - 1] unless cell.y == 0
+ neighbors << [cell.x - 1, cell.y] unless cell.x == 0
+ neighbors << [cell.x, cell.y + 1] unless cell.y == grid.height - 1
+ neighbors << [cell.x + 1, cell.y] unless cell.x == grid.width - 1
# Sorts the neighbors so the rendered path is a zigzag path
# Cells in a diagonal direction are given priority
# Comment this line to see the difference
neighbors = neighbors.sort_by { |neighbor_x, neighbor_y| proximity_to_star(neighbor_x, neighbor_y) }
- neighbors
+ neighbors
end
# Finds the vertical and horizontal distance of a cell from the star
@@ -442,13 +442,13 @@ class Breadcrumbs
# Finding the cell closest to the mouse helps with this
def cell_closest_to_mouse
# Closest cell to the mouse in the first grid
- x = (inputs.mouse.point.x / grid.cell_size).to_i
- y = (inputs.mouse.point.y / grid.cell_size).to_i
+ x = (inputs.mouse.point.x / grid.cell_size).to_i
+ y = (inputs.mouse.point.y / grid.cell_size).to_i
# Bound x and y to the grid
- x = grid.width - 1 if x > grid.width - 1
- y = grid.height - 1 if y > grid.height - 1
+ x = grid.width - 1 if x > grid.width - 1
+ y = grid.height - 1 if y > grid.height - 1
# Return closest cell
- [x, y]
+ [x, y]
end
# Signal that the user is going to be moving the star from the first grid
@@ -476,13 +476,13 @@ class Breadcrumbs
# Light brown
def unvisited_color
- [221, 212, 213]
+ [221, 212, 213]
# [255, 255, 255]
end
# Camo Green
def wall_color
- [134, 134, 120]
+ [134, 134, 120]
end
# Pastel White
@@ -520,7 +520,7 @@ def tick args
end
# Every tick, new args are passed, and the Breadth First Search tick is called
- $breadcrumbs ||= Breadcrumbs.new(args)
+ $breadcrumbs ||= Breadcrumbs.new
$breadcrumbs.args = args
$breadcrumbs.tick
end
diff --git a/samples/13_path_finding_algorithms/03_breadcrumbs/replay.txt b/samples/13_path_finding_algorithms/03_breadcrumbs/replay.txt
new file mode 100644
index 0000000..4e98cf7
--- /dev/null
+++ b/samples/13_path_finding_algorithms/03_breadcrumbs/replay.txt
@@ -0,0 +1,365 @@
+replay_version 2.0
+stopped_at 211
+seed 100
+recorded_at 2021-11-20 11:18:41 -0600
+[:mouse_button_up, 1, 0, 1, 1, 1]
+[:mouse_move, 778, 91, 2, 2, 7]
+[:mouse_move, 778, 90, 2, 3, 7]
+[:mouse_move, 773, 94, 2, 4, 10]
+[:mouse_move, 748, 101, 2, 5, 11]
+[:mouse_move, 704, 112, 2, 6, 11]
+[:mouse_move, 656, 127, 2, 7, 11]
+[:mouse_move, 617, 138, 2, 8, 12]
+[:mouse_move, 595, 142, 2, 9, 12]
+[:mouse_move, 582, 143, 2, 10, 13]
+[:mouse_move, 574, 143, 2, 11, 13]
+[:mouse_move, 561, 144, 2, 12, 13]
+[:mouse_move, 550, 148, 2, 13, 13]
+[:mouse_move, 536, 155, 2, 14, 14]
+[:mouse_move, 519, 162, 2, 15, 14]
+[:mouse_move, 497, 168, 2, 16, 14]
+[:mouse_move, 475, 174, 2, 17, 15]
+[:mouse_move, 450, 179, 2, 18, 15]
+[:mouse_move, 420, 188, 2, 19, 15]
+[:mouse_move, 385, 200, 2, 20, 16]
+[:mouse_move, 350, 219, 2, 21, 16]
+[:mouse_move, 317, 239, 2, 22, 16]
+[:mouse_move, 278, 272, 2, 23, 17]
+[:mouse_move, 251, 292, 2, 24, 17]
+[:mouse_move, 229, 314, 2, 25, 17]
+[:mouse_move, 213, 335, 2, 26, 18]
+[:mouse_move, 205, 355, 2, 27, 18]
+[:mouse_move, 201, 375, 2, 28, 19]
+[:mouse_move, 199, 394, 2, 29, 19]
+[:mouse_move, 199, 409, 2, 30, 20]
+[:mouse_move, 199, 419, 2, 31, 20]
+[:mouse_move, 198, 427, 2, 32, 20]
+[:mouse_move, 198, 434, 2, 33, 20]
+[:mouse_move, 198, 441, 2, 34, 21]
+[:mouse_move, 198, 453, 2, 35, 21]
+[:mouse_move, 197, 457, 2, 36, 21]
+[:mouse_move, 188, 464, 2, 37, 22]
+[:mouse_move, 178, 470, 2, 38, 22]
+[:mouse_move, 169, 477, 2, 39, 22]
+[:mouse_move, 161, 484, 2, 40, 23]
+[:mouse_move, 148, 491, 2, 41, 23]
+[:mouse_move, 128, 499, 2, 42, 24]
+[:mouse_move, 109, 509, 2, 43, 24]
+[:mouse_move, 94, 521, 2, 44, 25]
+[:mouse_move, 86, 530, 2, 45, 25]
+[:mouse_move, 80, 540, 2, 46, 25]
+[:mouse_move, 76, 550, 2, 47, 25]
+[:mouse_move, 76, 552, 2, 48, 26]
+[:mouse_move, 77, 555, 2, 49, 26]
+[:mouse_move, 78, 556, 2, 50, 27]
+[:mouse_move, 86, 560, 2, 51, 27]
+[:mouse_move, 99, 564, 2, 52, 27]
+[:mouse_move, 111, 568, 2, 53, 27]
+[:mouse_move, 125, 571, 2, 54, 28]
+[:mouse_move, 142, 572, 2, 55, 28]
+[:mouse_move, 164, 572, 2, 56, 29]
+[:mouse_move, 190, 572, 2, 57, 29]
+[:mouse_move, 215, 572, 2, 58, 29]
+[:mouse_move, 249, 568, 2, 59, 30]
+[:mouse_move, 271, 565, 2, 60, 30]
+[:mouse_move, 288, 563, 2, 61, 31]
+[:mouse_move, 303, 561, 2, 62, 31]
+[:mouse_move, 314, 559, 2, 63, 31]
+[:mouse_move, 323, 556, 2, 64, 31]
+[:mouse_move, 330, 553, 2, 65, 32]
+[:mouse_move, 335, 550, 2, 66, 32]
+[:mouse_move, 342, 547, 2, 67, 32]
+[:mouse_move, 351, 543, 2, 68, 33]
+[:mouse_move, 359, 538, 2, 69, 33]
+[:mouse_move, 370, 533, 2, 70, 34]
+[:mouse_move, 393, 521, 2, 71, 34]
+[:mouse_move, 412, 511, 2, 72, 34]
+[:mouse_move, 432, 503, 2, 73, 35]
+[:mouse_move, 451, 497, 2, 74, 35]
+[:mouse_move, 468, 493, 2, 75, 35]
+[:mouse_move, 479, 492, 2, 76, 36]
+[:mouse_move, 487, 490, 2, 77, 36]
+[:mouse_move, 494, 489, 2, 78, 37]
+[:mouse_move, 501, 489, 2, 79, 37]
+[:mouse_move, 506, 487, 2, 80, 37]
+[:mouse_move, 507, 487, 2, 81, 38]
+[:mouse_move, 508, 486, 2, 82, 38]
+[:mouse_move, 502, 486, 2, 83, 38]
+[:mouse_move, 500, 486, 2, 84, 39]
+[:mouse_move, 496, 487, 2, 85, 39]
+[:mouse_move, 491, 489, 2, 86, 40]
+[:mouse_move, 492, 489, 2, 87, 45]
+[:mouse_move, 499, 487, 2, 88, 46]
+[:mouse_move, 509, 484, 2, 89, 46]
+[:mouse_move, 526, 480, 2, 90, 46]
+[:mouse_move, 548, 475, 2, 91, 47]
+[:mouse_move, 580, 468, 2, 92, 47]
+[:mouse_move, 598, 465, 2, 93, 47]
+[:mouse_move, 615, 461, 2, 94, 48]
+[:mouse_move, 628, 459, 2, 95, 48]
+[:mouse_move, 636, 459, 2, 96, 49]
+[:mouse_move, 641, 459, 2, 97, 49]
+[:mouse_move, 645, 459, 2, 98, 49]
+[:mouse_move, 647, 459, 2, 99, 50]
+[:mouse_move, 648, 459, 2, 100, 50]
+[:mouse_move, 650, 459, 2, 101, 51]
+[:mouse_move, 651, 459, 2, 102, 51]
+[:mouse_move, 652, 459, 2, 103, 52]
+[:mouse_move, 655, 459, 2, 104, 52]
+[:mouse_move, 661, 459, 2, 105, 52]
+[:mouse_move, 667, 459, 2, 106, 53]
+[:mouse_move, 674, 459, 2, 107, 53]
+[:mouse_move, 680, 460, 2, 108, 54]
+[:mouse_move, 687, 461, 2, 109, 54]
+[:mouse_move, 695, 462, 2, 110, 54]
+[:mouse_move, 699, 463, 2, 111, 55]
+[:mouse_move, 700, 463, 2, 112, 55]
+[:mouse_move, 702, 463, 2, 113, 56]
+[:mouse_move, 705, 463, 2, 114, 56]
+[:mouse_move, 709, 464, 2, 115, 56]
+[:mouse_move, 714, 464, 2, 116, 57]
+[:mouse_move, 718, 464, 2, 117, 57]
+[:mouse_move, 721, 464, 2, 118, 57]
+[:mouse_move, 723, 464, 2, 119, 58]
+[:mouse_move, 726, 465, 2, 120, 58]
+[:mouse_move, 729, 465, 2, 121, 59]
+[:mouse_move, 731, 465, 2, 122, 59]
+[:mouse_move, 732, 465, 2, 123, 60]
+[:mouse_move, 733, 465, 2, 124, 61]
+[:mouse_move, 734, 465, 2, 125, 61]
+[:mouse_move, 737, 465, 2, 126, 61]
+[:mouse_move, 739, 465, 2, 127, 62]
+[:mouse_move, 743, 465, 2, 128, 62]
+[:mouse_move, 751, 467, 2, 129, 62]
+[:mouse_move, 761, 469, 2, 130, 63]
+[:mouse_move, 772, 469, 2, 131, 63]
+[:mouse_move, 782, 469, 2, 132, 63]
+[:mouse_move, 793, 471, 2, 133, 64]
+[:mouse_move, 808, 471, 2, 134, 64]
+[:mouse_move, 818, 472, 2, 135, 64]
+[:mouse_move, 829, 473, 2, 136, 65]
+[:mouse_move, 839, 475, 2, 137, 65]
+[:mouse_move, 849, 477, 2, 138, 66]
+[:mouse_move, 861, 479, 2, 139, 66]
+[:mouse_move, 876, 480, 2, 140, 66]
+[:mouse_move, 893, 480, 2, 141, 67]
+[:mouse_move, 912, 480, 2, 142, 67]
+[:mouse_move, 933, 482, 2, 143, 68]
+[:mouse_move, 952, 482, 2, 144, 68]
+[:mouse_move, 967, 482, 2, 145, 68]
+[:mouse_move, 983, 482, 2, 146, 68]
+[:mouse_move, 1007, 482, 2, 147, 69]
+[:mouse_move, 1021, 482, 2, 148, 69]
+[:mouse_move, 1031, 482, 2, 149, 70]
+[:mouse_move, 1041, 482, 2, 150, 70]
+[:mouse_move, 1045, 482, 2, 151, 71]
+[:mouse_move, 1049, 481, 2, 152, 71]
+[:mouse_move, 1052, 481, 2, 153, 71]
+[:mouse_move, 1053, 481, 2, 154, 71]
+[:mouse_move, 1054, 481, 2, 155, 72]
+[:mouse_move, 1055, 480, 2, 156, 73]
+[:mouse_move, 1057, 480, 2, 157, 73]
+[:mouse_move, 1060, 479, 2, 158, 74]
+[:mouse_move, 1062, 479, 2, 159, 74]
+[:mouse_move, 1063, 478, 2, 160, 75]
+[:mouse_move, 1064, 478, 2, 161, 75]
+[:mouse_move, 1065, 478, 2, 162, 77]
+[:mouse_move, 1066, 478, 2, 163, 77]
+[:mouse_move, 1067, 478, 2, 164, 78]
+[:mouse_move, 1069, 478, 2, 165, 83]
+[:mouse_move, 1074, 477, 2, 166, 84]
+[:mouse_move, 1082, 476, 2, 167, 84]
+[:mouse_move, 1093, 469, 2, 168, 85]
+[:mouse_move, 1106, 459, 2, 169, 85]
+[:mouse_move, 1117, 447, 2, 170, 85]
+[:mouse_move, 1125, 433, 2, 171, 85]
+[:mouse_move, 1130, 414, 2, 172, 85]
+[:mouse_move, 1130, 382, 2, 173, 86]
+[:mouse_move, 1127, 358, 2, 174, 86]
+[:mouse_move, 1119, 333, 2, 175, 87]
+[:mouse_move, 1109, 309, 2, 176, 87]
+[:mouse_move, 1102, 293, 2, 177, 87]
+[:mouse_move, 1094, 280, 2, 178, 88]
+[:mouse_move, 1089, 272, 2, 179, 88]
+[:mouse_move, 1087, 264, 2, 180, 89]
+[:mouse_move, 1086, 258, 2, 181, 89]
+[:mouse_move, 1086, 248, 2, 182, 89]
+[:mouse_move, 1084, 241, 2, 183, 89]
+[:mouse_move, 1084, 240, 2, 184, 90]
+[:mouse_button_pressed, 1, 0, 1, 185, 95]
+[:mouse_button_up, 1, 0, 1, 186, 97]
+[:mouse_move, 1086, 251, 2, 187, 105]
+[:mouse_move, 1086, 267, 2, 188, 105]
+[:mouse_move, 1087, 287, 2, 189, 106]
+[:mouse_move, 1087, 310, 2, 190, 106]
+[:mouse_move, 1087, 339, 2, 191, 107]
+[:mouse_move, 1078, 387, 2, 192, 107]
+[:mouse_move, 1064, 422, 2, 193, 107]
+[:mouse_move, 1050, 449, 2, 194, 108]
+[:mouse_move, 1033, 470, 2, 195, 108]
+[:mouse_move, 1015, 485, 2, 196, 108]
+[:mouse_move, 995, 494, 2, 197, 109]
+[:mouse_move, 973, 500, 2, 198, 109]
+[:mouse_move, 955, 505, 2, 199, 109]
+[:mouse_move, 936, 506, 2, 200, 110]
+[:mouse_move, 919, 510, 2, 201, 110]
+[:mouse_move, 906, 510, 2, 202, 110]
+[:mouse_move, 891, 513, 2, 203, 111]
+[:mouse_move, 873, 516, 2, 204, 111]
+[:mouse_move, 854, 520, 2, 205, 111]
+[:mouse_move, 843, 522, 2, 206, 112]
+[:mouse_move, 830, 525, 2, 207, 112]
+[:mouse_move, 816, 526, 2, 208, 112]
+[:mouse_move, 804, 527, 2, 209, 113]
+[:mouse_move, 794, 527, 2, 210, 113]
+[:mouse_move, 784, 527, 2, 211, 114]
+[:mouse_move, 775, 526, 2, 212, 114]
+[:mouse_move, 765, 522, 2, 213, 114]
+[:mouse_move, 755, 518, 2, 214, 115]
+[:mouse_move, 746, 513, 2, 215, 115]
+[:mouse_move, 732, 505, 2, 216, 116]
+[:mouse_move, 706, 483, 2, 217, 116]
+[:mouse_move, 694, 463, 2, 218, 116]
+[:mouse_move, 689, 446, 2, 219, 116]
+[:mouse_move, 689, 429, 2, 220, 117]
+[:mouse_move, 689, 409, 2, 221, 117]
+[:mouse_move, 689, 388, 2, 222, 118]
+[:mouse_move, 689, 361, 2, 223, 118]
+[:mouse_move, 683, 327, 2, 224, 119]
+[:mouse_move, 677, 295, 2, 225, 119]
+[:mouse_move, 666, 266, 2, 226, 119]
+[:mouse_move, 656, 245, 2, 227, 119]
+[:mouse_move, 650, 233, 2, 228, 120]
+[:mouse_move, 640, 215, 2, 229, 120]
+[:mouse_move, 630, 203, 2, 230, 121]
+[:mouse_move, 612, 189, 2, 231, 121]
+[:mouse_move, 586, 178, 2, 232, 121]
+[:mouse_move, 553, 168, 2, 233, 121]
+[:mouse_move, 528, 166, 2, 234, 122]
+[:mouse_move, 510, 165, 2, 235, 122]
+[:mouse_move, 498, 165, 2, 236, 123]
+[:mouse_move, 482, 165, 2, 237, 123]
+[:mouse_move, 466, 165, 2, 238, 123]
+[:mouse_move, 450, 165, 2, 239, 124]
+[:mouse_move, 426, 165, 2, 240, 124]
+[:mouse_move, 416, 165, 2, 241, 125]
+[:mouse_move, 411, 166, 2, 242, 125]
+[:mouse_move, 407, 168, 2, 243, 126]
+[:mouse_move, 405, 169, 2, 244, 126]
+[:mouse_move, 400, 172, 2, 245, 126]
+[:mouse_move, 391, 178, 2, 246, 126]
+[:mouse_move, 381, 185, 2, 247, 127]
+[:mouse_move, 368, 195, 2, 248, 127]
+[:mouse_move, 355, 207, 2, 249, 128]
+[:mouse_move, 345, 223, 2, 250, 128]
+[:mouse_move, 343, 243, 2, 251, 128]
+[:mouse_move, 343, 273, 2, 252, 129]
+[:mouse_move, 343, 290, 2, 253, 129]
+[:mouse_move, 343, 308, 2, 254, 129]
+[:mouse_move, 342, 326, 2, 255, 130]
+[:mouse_move, 340, 343, 2, 256, 130]
+[:mouse_move, 339, 363, 2, 257, 130]
+[:mouse_move, 339, 384, 2, 258, 131]
+[:mouse_move, 339, 407, 2, 259, 131]
+[:mouse_move, 338, 427, 2, 260, 132]
+[:mouse_move, 333, 446, 2, 261, 132]
+[:mouse_move, 330, 463, 2, 262, 132]
+[:mouse_move, 325, 477, 2, 263, 133]
+[:mouse_move, 317, 488, 2, 264, 133]
+[:mouse_move, 313, 494, 2, 265, 133]
+[:mouse_move, 308, 500, 2, 266, 134]
+[:mouse_move, 302, 511, 2, 267, 134]
+[:mouse_move, 295, 522, 2, 268, 135]
+[:mouse_move, 285, 535, 2, 269, 135]
+[:mouse_move, 277, 547, 2, 270, 135]
+[:mouse_move, 267, 558, 2, 271, 136]
+[:mouse_move, 259, 568, 2, 272, 136]
+[:mouse_move, 250, 574, 2, 273, 137]
+[:mouse_move, 241, 580, 2, 274, 137]
+[:mouse_move, 233, 586, 2, 275, 137]
+[:mouse_move, 222, 593, 2, 276, 138]
+[:mouse_move, 213, 599, 2, 277, 138]
+[:mouse_move, 206, 606, 2, 278, 138]
+[:mouse_move, 203, 615, 2, 279, 139]
+[:mouse_move, 202, 622, 2, 280, 139]
+[:mouse_move, 200, 625, 2, 281, 139]
+[:mouse_move, 199, 627, 2, 282, 140]
+[:mouse_move, 198, 628, 2, 283, 140]
+[:mouse_move, 197, 628, 2, 284, 141]
+[:mouse_move, 194, 630, 2, 285, 141]
+[:mouse_move, 190, 632, 2, 286, 141]
+[:mouse_move, 186, 633, 2, 287, 142]
+[:mouse_move, 180, 635, 2, 288, 142]
+[:mouse_move, 175, 636, 2, 289, 143]
+[:mouse_move, 174, 636, 2, 290, 144]
+[:mouse_move, 173, 636, 2, 291, 144]
+[:mouse_move, 170, 636, 2, 292, 144]
+[:mouse_move, 164, 636, 2, 293, 144]
+[:mouse_move, 155, 636, 2, 294, 145]
+[:mouse_move, 147, 634, 2, 295, 145]
+[:mouse_move, 141, 634, 2, 296, 146]
+[:mouse_move, 139, 634, 2, 297, 146]
+[:mouse_move, 138, 634, 2, 298, 146]
+[:mouse_move, 136, 634, 2, 299, 147]
+[:mouse_move, 135, 633, 2, 300, 148]
+[:mouse_move, 134, 633, 2, 301, 148]
+[:mouse_move, 133, 633, 2, 302, 148]
+[:key_down_raw, 96, 0, 2, 303, 159]
+[:mouse_move, 134, 632, 2, 304, 160]
+[:mouse_move, 138, 632, 2, 305, 161]
+[:key_up_raw, 96, 0, 2, 306, 161]
+[:mouse_move, 144, 630, 2, 307, 161]
+[:mouse_move, 155, 628, 2, 308, 161]
+[:mouse_move, 170, 623, 2, 309, 161]
+[:mouse_move, 189, 618, 2, 310, 161]
+[:mouse_move, 213, 611, 2, 311, 162]
+[:mouse_move, 243, 600, 2, 312, 162]
+[:mouse_move, 281, 586, 2, 313, 163]
+[:mouse_move, 330, 565, 2, 314, 163]
+[:mouse_move, 400, 533, 2, 315, 163]
+[:mouse_move, 476, 492, 2, 316, 164]
+[:mouse_move, 564, 445, 2, 317, 164]
+[:mouse_move, 703, 362, 2, 318, 164]
+[:mouse_move, 797, 306, 2, 319, 165]
+[:mouse_move, 872, 251, 2, 320, 165]
+[:mouse_move, 951, 196, 2, 321, 165]
+[:mouse_move, 1012, 147, 2, 322, 166]
+[:mouse_move, 1058, 112, 2, 323, 166]
+[:mouse_move, 1085, 87, 2, 324, 166]
+[:mouse_move, 1100, 67, 2, 325, 166]
+[:mouse_move, 1111, 51, 2, 326, 167]
+[:mouse_move, 1117, 42, 2, 327, 167]
+[:mouse_move, 1118, 39, 2, 328, 168]
+[:mouse_move, 1110, 35, 2, 329, 170]
+[:mouse_move, 1101, 34, 2, 330, 171]
+[:mouse_move, 1095, 34, 2, 331, 171]
+[:mouse_move, 1087, 34, 2, 332, 171]
+[:mouse_move, 1076, 34, 2, 333, 172]
+[:mouse_move, 1064, 34, 2, 334, 172]
+[:mouse_move, 1045, 38, 2, 335, 172]
+[:mouse_move, 1031, 42, 2, 336, 172]
+[:mouse_move, 1018, 45, 2, 337, 173]
+[:mouse_move, 1002, 50, 2, 338, 173]
+[:mouse_move, 978, 53, 2, 339, 173]
+[:mouse_move, 947, 54, 2, 340, 174]
+[:mouse_move, 908, 54, 2, 341, 174]
+[:mouse_move, 864, 54, 2, 342, 174]
+[:mouse_move, 830, 54, 2, 343, 174]
+[:mouse_move, 810, 58, 2, 344, 175]
+[:mouse_move, 807, 59, 2, 345, 175]
+[:mouse_move, 808, 59, 2, 346, 177]
+[:mouse_move, 810, 61, 2, 347, 178]
+[:mouse_move, 814, 65, 2, 348, 178]
+[:mouse_move, 816, 66, 2, 349, 178]
+[:mouse_move, 818, 69, 2, 350, 178]
+[:mouse_move, 819, 71, 2, 351, 179]
+[:mouse_move, 820, 73, 2, 352, 179]
+[:mouse_move, 820, 74, 2, 353, 179]
+[:mouse_move, 819, 75, 2, 354, 183]
+[:mouse_move, 817, 77, 2, 355, 183]
+[:mouse_move, 814, 81, 2, 356, 184]
+[:mouse_move, 810, 84, 2, 357, 184]
+[:mouse_move, 809, 85, 2, 358, 184]
+[:mouse_move, 810, 85, 2, 359, 211]
+[:key_down_raw, 13, 0, 2, 360, 211]
+[:mouse_move, 811, 85, 2, 361, 211]
diff --git a/samples/13_path_finding_algorithms/04_early_exit/app/main.rb b/samples/13_path_finding_algorithms/04_early_exit/app/main.rb
index 1e9305b..40a3ba5 100644
--- a/samples/13_path_finding_algorithms/04_early_exit/app/main.rb
+++ b/samples/13_path_finding_algorithms/04_early_exit/app/main.rb
@@ -26,8 +26,8 @@ class EarlyExitBreadthFirstSearch
# And calculate the path
calc_path
end
- render
- input
+ render
+ input
end
def defaults
@@ -43,14 +43,14 @@ class EarlyExitBreadthFirstSearch
# This step is roughly the grid's width * height
# When anim_steps equals max_steps no more calculations will occur
# and the slider will be at the end
- state.max_steps ||= args.state.grid.width * args.state.grid.height
+ state.max_steps ||= args.state.grid.width * args.state.grid.height
# The location of the star and walls of the grid
# They can be modified to have a different initial grid
# Walls are stored in a hash for quick look up when doing the search
state.star ||= [2, 8]
state.target ||= [10, 5]
- state.walls ||= {}
+ state.walls ||= {}
# Variables that are used by the breadth first search
# Storing cells that the search has visited, prevents unnecessary steps
@@ -73,12 +73,12 @@ class EarlyExitBreadthFirstSearch
# We store this value, because we want to remember the value even when
# the user's cursor is no longer over what they're interacting with, but
# they are still clicking down on the mouse.
- state.current_input ||= :none
+ state.current_input ||= :none
end
# Draws everything onto the screen
def render
- render_background
+ render_background
render_heat_map
render_walls
render_path
@@ -91,8 +91,8 @@ class EarlyExitBreadthFirstSearch
# Draws what the grid looks like with nothing on it
def render_background
- render_unvisited
- render_grid_lines
+ render_unvisited
+ render_grid_lines
end
# Draws both grids
@@ -109,7 +109,7 @@ class EarlyExitBreadthFirstSearch
end
for y in 0..grid.height
- outputs.lines << horizontal_line(y)
+ outputs.lines << horizontal_line(y)
outputs.lines << early_exit_horizontal_line(y)
end
end
@@ -136,7 +136,7 @@ class EarlyExitBreadthFirstSearch
# Draws the walls on both grids
def render_walls
- state.walls.each_key do |wall|
+ state.walls.each_key do |wall|
outputs.solids << [scale_up(wall), wall_color]
outputs.solids << [early_exit_scale_up(wall), wall_color]
end
@@ -146,13 +146,13 @@ class EarlyExitBreadthFirstSearch
def render_star
outputs.sprites << [scale_up(state.star), 'star.png']
outputs.sprites << [early_exit_scale_up(state.star), 'star.png']
- end
+ end
# Renders the target on both grids
def render_target
outputs.sprites << [scale_up(state.target), 'target.png']
outputs.sprites << [early_exit_scale_up(state.target), 'target.png']
- end
+ end
# Labels the grids
def render_labels
@@ -244,8 +244,8 @@ class EarlyExitBreadthFirstSearch
# The program has to remember that the user is dragging an object
# even when the mouse is no longer over that object
# So detecting input and processing input is separate
- detect_input
- process_input
+ detect_input
+ process_input
end
# Determines what the user is editing and stores the value
@@ -253,53 +253,53 @@ class EarlyExitBreadthFirstSearch
# mouse left click is held
def detect_input
# When the mouse is up, nothing is being edited
- if inputs.mouse.up
- state.current_input = :none
+ if inputs.mouse.up
+ state.current_input = :none
# When the star in the no second grid is clicked
- elsif star_clicked?
- state.current_input = :star
+ elsif star_clicked?
+ state.current_input = :star
# When the star in the second grid is clicked
- elsif star2_clicked?
- state.current_input = :star2
+ elsif star2_clicked?
+ state.current_input = :star2
# When the target in the no second grid is clicked
- elsif target_clicked?
- state.current_input = :target
+ elsif target_clicked?
+ state.current_input = :target
# When the target in the second grid is clicked
- elsif target2_clicked?
- state.current_input = :target2
+ elsif target2_clicked?
+ state.current_input = :target2
# When a wall in the first grid is clicked
- elsif wall_clicked?
- state.current_input = :remove_wall
+ elsif wall_clicked?
+ state.current_input = :remove_wall
# When a wall in the second grid is clicked
- elsif wall2_clicked?
+ elsif wall2_clicked?
state.current_input = :remove_wall2
# When the first grid is clicked
- elsif grid_clicked?
+ elsif grid_clicked?
state.current_input = :add_wall
# When the second grid is clicked
- elsif grid2_clicked?
+ elsif grid2_clicked?
state.current_input = :add_wall2
end
end
# Processes click and drag based on what the user is currently dragging
def process_input
- if state.current_input == :star
- input_star
+ if state.current_input == :star
+ input_star
elsif state.current_input == :star2
- input_star2
- elsif state.current_input == :target
- input_target
- elsif state.current_input == :target2
- input_target2
- elsif state.current_input == :remove_wall
- input_remove_wall
+ input_star2
+ elsif state.current_input == :target
+ input_target
+ elsif state.current_input == :target2
+ input_target2
+ elsif state.current_input == :remove_wall
+ input_remove_wall
elsif state.current_input == :remove_wall2
- input_remove_wall2
- elsif state.current_input == :add_wall
- input_add_wall
- elsif state.current_input == :add_wall2
- input_add_wall2
+ input_remove_wall2
+ elsif state.current_input == :add_wall
+ input_add_wall
+ elsif state.current_input == :add_wall2
+ input_add_wall2
end
end
@@ -307,10 +307,10 @@ class EarlyExitBreadthFirstSearch
# Only resets the search if the star changes position
# Called whenever the user is editing the star (puts mouse down on star)
def input_star
- old_star = state.star.clone
+ old_star = state.star.clone
state.star = cell_closest_to_mouse
- unless old_star == state.star
- reset_search
+ unless old_star == state.star
+ reset_search
end
end
@@ -318,10 +318,10 @@ class EarlyExitBreadthFirstSearch
# Only resets the search if the star changes position
# Called whenever the user is editing the star (puts mouse down on star)
def input_star2
- old_star = state.star.clone
+ old_star = state.star.clone
state.star = cell_closest_to_mouse2
- unless old_star == state.star
- reset_search
+ unless old_star == state.star
+ reset_search
end
end
@@ -329,10 +329,10 @@ class EarlyExitBreadthFirstSearch
# Only reset_searchs the search if the target changes position
# Called whenever the user is editing the target (puts mouse down on target)
def input_target
- old_target = state.target.clone
+ old_target = state.target.clone
state.target = cell_closest_to_mouse
- unless old_target == state.target
- reset_search
+ unless old_target == state.target
+ reset_search
end
end
@@ -340,10 +340,10 @@ class EarlyExitBreadthFirstSearch
# Only reset_searchs the search if the target changes position
# Called whenever the user is editing the target (puts mouse down on target)
def input_target2
- old_target = state.target.clone
+ old_target = state.target.clone
state.target = cell_closest_to_mouse2
- unless old_target == state.target
- reset_search
+ unless old_target == state.target
+ reset_search
end
end
@@ -352,10 +352,10 @@ class EarlyExitBreadthFirstSearch
# The mouse needs to be inside the grid, because we only want to remove walls
# the cursor is directly over
# Recalculations should only occur when a wall is actually deleted
- if mouse_inside_grid?
+ if mouse_inside_grid?
if state.walls.has_key?(cell_closest_to_mouse)
- state.walls.delete(cell_closest_to_mouse)
- reset_search
+ state.walls.delete(cell_closest_to_mouse)
+ reset_search
end
end
end
@@ -365,31 +365,31 @@ class EarlyExitBreadthFirstSearch
# The mouse needs to be inside the grid, because we only want to remove walls
# the cursor is directly over
# Recalculations should only occur when a wall is actually deleted
- if mouse_inside_grid2?
+ if mouse_inside_grid2?
if state.walls.has_key?(cell_closest_to_mouse2)
- state.walls.delete(cell_closest_to_mouse2)
- reset_search
+ state.walls.delete(cell_closest_to_mouse2)
+ reset_search
end
end
end
# Adds a wall in the first grid in the cell the mouse is over
def input_add_wall
- if mouse_inside_grid?
+ if mouse_inside_grid?
unless state.walls.has_key?(cell_closest_to_mouse)
- state.walls[cell_closest_to_mouse] = true
- reset_search
+ state.walls[cell_closest_to_mouse] = true
+ reset_search
end
end
end
-
+
# Adds a wall in the second grid in the cell the mouse is over
def input_add_wall2
- if mouse_inside_grid2?
+ if mouse_inside_grid2?
unless state.walls.has_key?(cell_closest_to_mouse2)
- state.walls[cell_closest_to_mouse2] = true
- reset_search
+ state.walls[cell_closest_to_mouse2] = true
+ reset_search
end
end
end
@@ -399,10 +399,10 @@ class EarlyExitBreadthFirstSearch
# with the current grid as the initial state of the grid
def reset_search
# Reset_Searchs the search
- state.frontier = []
- state.visited = {}
- state.early_exit_visited = {}
- state.came_from = {}
+ state.frontier = []
+ state.visited = {}
+ state.early_exit_visited = {}
+ state.came_from = {}
state.path = {}
end
@@ -410,23 +410,23 @@ class EarlyExitBreadthFirstSearch
def step
# The setup to the search
# Runs once when there are no visited cells
- if state.visited.empty?
- state.visited[state.star] = true
- state.early_exit_visited[state.star] = true
- state.frontier << state.star
+ if state.visited.empty?
+ state.visited[state.star] = true
+ state.early_exit_visited[state.star] = true
+ state.frontier << state.star
state.came_from[state.star] = nil
end
# A step in the search
- unless state.frontier.empty?
+ unless state.frontier.empty?
# Takes the next frontier cell
- new_frontier = state.frontier.shift
+ new_frontier = state.frontier.shift
# For each of its neighbors
- adjacent_neighbors(new_frontier).each do |neighbor|
+ adjacent_neighbors(new_frontier).each do |neighbor|
# That have not been visited and are not walls
- unless state.visited.has_key?(neighbor) || state.walls.has_key?(neighbor)
+ unless state.visited.has_key?(neighbor) || state.walls.has_key?(neighbor)
# Add them to the frontier and mark them as visited in the first grid
- state.visited[neighbor] = true
+ state.visited[neighbor] = true
# Unless the target has been visited
unless state.visited.has_key?(state.target)
# Mark the neighbor as visited in the second grid as well
@@ -434,32 +434,32 @@ class EarlyExitBreadthFirstSearch
end
# Add the neighbor to the frontier and remember which cell it came from
- state.frontier << neighbor
+ state.frontier << neighbor
state.came_from[neighbor] = new_frontier
end
end
end
end
-
+
# Returns a list of adjacent cells
# Used to determine what the next cells to be added to the frontier are
def adjacent_neighbors(cell)
- neighbors = []
+ neighbors = []
# Gets all the valid neighbors into the array
# From southern neighbor, clockwise
- neighbors << [cell.x, cell.y - 1] unless cell.y == 0
- neighbors << [cell.x - 1, cell.y] unless cell.x == 0
- neighbors << [cell.x, cell.y + 1] unless cell.y == grid.height - 1
- neighbors << [cell.x + 1, cell.y] unless cell.x == grid.width - 1
+ neighbors << [cell.x, cell.y - 1] unless cell.y == 0
+ neighbors << [cell.x - 1, cell.y] unless cell.x == 0
+ neighbors << [cell.x, cell.y + 1] unless cell.y == grid.height - 1
+ neighbors << [cell.x + 1, cell.y] unless cell.x == grid.width - 1
# Sorts the neighbors so the rendered path is a zigzag path
# Cells in a diagonal direction are given priority
# Comment this line to see the difference
neighbors = neighbors.sort_by { |neighbor_x, neighbor_y| proximity_to_star(neighbor_x, neighbor_y) }
- neighbors
+ neighbors
end
# Finds the vertical and horizontal distance of a cell from the star
@@ -484,13 +484,13 @@ class EarlyExitBreadthFirstSearch
# Finding the cell closest to the mouse helps with this
def cell_closest_to_mouse
# Closest cell to the mouse in the first grid
- x = (inputs.mouse.point.x / grid.cell_size).to_i
- y = (inputs.mouse.point.y / grid.cell_size).to_i
+ x = (inputs.mouse.point.x / grid.cell_size).to_i
+ y = (inputs.mouse.point.y / grid.cell_size).to_i
# Bound x and y to the grid
- x = grid.width - 1 if x > grid.width - 1
- y = grid.height - 1 if y > grid.height - 1
+ x = grid.width - 1 if x > grid.width - 1
+ y = grid.height - 1 if y > grid.height - 1
# Return closest cell
- [x, y]
+ [x, y]
end
# When the user grabs the star and puts their cursor to the far right
@@ -498,15 +498,15 @@ class EarlyExitBreadthFirstSearch
# Finding the cell closest to the mouse in the second grid helps with this
def cell_closest_to_mouse2
# Closest cell grid to the mouse in the second
- x = (inputs.mouse.point.x / grid.cell_size).to_i
- y = (inputs.mouse.point.y / grid.cell_size).to_i
+ x = (inputs.mouse.point.x / grid.cell_size).to_i
+ y = (inputs.mouse.point.y / grid.cell_size).to_i
# Translate the cell to the first grid
x -= grid.width + 1
# Bound x and y to the first grid
- x = grid.width - 1 if x > grid.width - 1
- y = grid.height - 1 if y > grid.height - 1
+ x = grid.width - 1 if x > grid.width - 1
+ y = grid.height - 1 if y > grid.height - 1
# Return closest cell
- [x, y]
+ [x, y]
end
# Signal that the user is going to be moving the star from the first grid
@@ -585,12 +585,12 @@ class EarlyExitBreadthFirstSearch
# Light brown
def unvisited_color
- [221, 212, 213]
+ [221, 212, 213]
end
# Camo Green
def wall_color
- [134, 134, 120]
+ [134, 134, 120]
end
# Pastel White
@@ -620,7 +620,7 @@ def tick args
end
# Every tick, new args are passed, and the Breadth First Search tick is called
- $early_exit_breadth_first_search ||= EarlyExitBreadthFirstSearch.new(args)
+ $early_exit_breadth_first_search ||= EarlyExitBreadthFirstSearch.new
$early_exit_breadth_first_search.args = args
$early_exit_breadth_first_search.tick
end
diff --git a/samples/13_path_finding_algorithms/04_early_exit/replay.txt b/samples/13_path_finding_algorithms/04_early_exit/replay.txt
new file mode 100644
index 0000000..3ec9254
--- /dev/null
+++ b/samples/13_path_finding_algorithms/04_early_exit/replay.txt
@@ -0,0 +1,364 @@
+replay_version 2.0
+stopped_at 322
+seed 100
+recorded_at 2021-11-20 11:19:30 -0600
+[:mouse_button_up, 1, 0, 1, 1, 1]
+[:mouse_move, 806, 92, 2, 2, 12]
+[:mouse_move, 799, 105, 2, 3, 13]
+[:mouse_move, 786, 126, 2, 4, 13]
+[:mouse_move, 761, 154, 2, 5, 13]
+[:mouse_move, 722, 199, 2, 6, 14]
+[:mouse_move, 692, 230, 2, 7, 14]
+[:mouse_move, 659, 263, 2, 8, 14]
+[:mouse_move, 629, 297, 2, 9, 14]
+[:mouse_move, 598, 337, 2, 10, 15]
+[:mouse_move, 569, 376, 2, 11, 15]
+[:mouse_move, 538, 412, 2, 12, 15]
+[:mouse_move, 510, 438, 2, 13, 16]
+[:mouse_move, 488, 456, 2, 14, 16]
+[:mouse_move, 471, 467, 2, 15, 16]
+[:mouse_move, 459, 477, 2, 16, 17]
+[:mouse_move, 455, 481, 2, 17, 17]
+[:mouse_move, 455, 484, 2, 18, 18]
+[:mouse_move, 454, 485, 2, 19, 18]
+[:mouse_move, 464, 481, 2, 20, 23]
+[:mouse_move, 482, 477, 2, 21, 23]
+[:mouse_move, 490, 470, 2, 22, 23]
+[:mouse_move, 491, 469, 2, 23, 24]
+[:mouse_move, 492, 467, 2, 24, 24]
+[:mouse_move, 493, 466, 2, 25, 25]
+[:mouse_move, 485, 466, 2, 26, 26]
+[:mouse_move, 474, 468, 2, 27, 27]
+[:mouse_move, 460, 472, 2, 28, 27]
+[:mouse_move, 441, 476, 2, 29, 27]
+[:mouse_move, 419, 479, 2, 30, 27]
+[:mouse_move, 392, 480, 2, 31, 28]
+[:mouse_move, 359, 480, 2, 32, 28]
+[:mouse_move, 329, 483, 2, 33, 29]
+[:mouse_move, 306, 486, 2, 34, 29]
+[:mouse_move, 281, 493, 2, 35, 30]
+[:mouse_move, 271, 496, 2, 36, 30]
+[:mouse_move, 270, 496, 2, 37, 30]
+[:mouse_move, 272, 496, 2, 38, 32]
+[:mouse_move, 275, 496, 2, 39, 32]
+[:mouse_move, 279, 495, 2, 40, 32]
+[:mouse_move, 283, 494, 2, 41, 33]
+[:mouse_move, 289, 494, 2, 42, 33]
+[:mouse_move, 292, 494, 2, 43, 34]
+[:mouse_move, 293, 495, 2, 44, 35]
+[:mouse_button_pressed, 1, 0, 1, 45, 39]
+[:mouse_button_up, 1, 0, 1, 46, 40]
+[:mouse_move, 294, 495, 2, 47, 49]
+[:mouse_move, 294, 494, 2, 48, 50]
+[:mouse_move, 295, 491, 2, 49, 50]
+[:mouse_move, 296, 488, 2, 50, 50]
+[:mouse_move, 297, 484, 2, 51, 50]
+[:mouse_move, 297, 481, 2, 52, 51]
+[:mouse_move, 298, 477, 2, 53, 51]
+[:mouse_move, 298, 476, 2, 54, 51]
+[:mouse_move, 299, 475, 2, 55, 52]
+[:mouse_move, 300, 473, 2, 56, 52]
+[:mouse_move, 300, 472, 2, 57, 53]
+[:mouse_move, 300, 471, 2, 58, 55]
+[:mouse_move, 300, 470, 2, 59, 56]
+[:mouse_move, 300, 469, 2, 60, 57]
+[:mouse_move, 300, 467, 2, 61, 57]
+[:mouse_move, 300, 466, 2, 62, 57]
+[:mouse_button_pressed, 1, 0, 1, 63, 59]
+[:mouse_button_up, 1, 0, 1, 64, 61]
+[:mouse_move, 300, 465, 2, 65, 61]
+[:mouse_move, 300, 462, 2, 66, 62]
+[:mouse_move, 300, 456, 2, 67, 62]
+[:mouse_move, 300, 449, 2, 68, 62]
+[:mouse_move, 300, 443, 2, 69, 63]
+[:mouse_move, 299, 441, 2, 70, 63]
+[:mouse_move, 299, 440, 2, 71, 63]
+[:mouse_move, 299, 438, 2, 72, 64]
+[:mouse_move, 299, 437, 2, 73, 65]
+[:mouse_move, 299, 436, 2, 74, 65]
+[:mouse_move, 299, 434, 2, 75, 65]
+[:mouse_move, 299, 432, 2, 76, 65]
+[:mouse_move, 299, 431, 2, 77, 67]
+[:mouse_move, 299, 430, 2, 78, 67]
+[:mouse_move, 299, 429, 2, 79, 68]
+[:mouse_move, 299, 428, 2, 80, 68]
+[:mouse_move, 299, 424, 2, 81, 68]
+[:mouse_move, 300, 417, 2, 82, 69]
+[:mouse_move, 301, 413, 2, 83, 69]
+[:mouse_move, 302, 412, 2, 84, 70]
+[:mouse_button_pressed, 1, 0, 1, 85, 72]
+[:mouse_move, 302, 411, 2, 86, 72]
+[:mouse_button_up, 1, 0, 1, 87, 74]
+[:mouse_move, 302, 408, 2, 88, 94]
+[:mouse_move, 302, 396, 2, 89, 94]
+[:mouse_move, 302, 383, 2, 90, 95]
+[:mouse_move, 302, 375, 2, 91, 95]
+[:mouse_move, 303, 374, 2, 92, 95]
+[:mouse_move, 303, 373, 2, 93, 95]
+[:mouse_move, 303, 374, 2, 94, 99]
+[:mouse_button_pressed, 1, 0, 1, 95, 101]
+[:mouse_button_up, 1, 0, 1, 96, 103]
+[:mouse_move, 303, 375, 2, 97, 103]
+[:mouse_move, 306, 375, 2, 98, 132]
+[:mouse_move, 317, 376, 2, 99, 132]
+[:mouse_move, 333, 380, 2, 100, 133]
+[:mouse_move, 352, 384, 2, 101, 133]
+[:mouse_move, 374, 385, 2, 102, 133]
+[:mouse_move, 401, 390, 2, 103, 134]
+[:mouse_move, 424, 392, 2, 104, 134]
+[:mouse_move, 442, 395, 2, 105, 134]
+[:mouse_move, 455, 397, 2, 106, 135]
+[:mouse_move, 458, 398, 2, 107, 135]
+[:mouse_move, 460, 398, 2, 108, 136]
+[:mouse_move, 466, 398, 2, 109, 136]
+[:mouse_move, 473, 398, 2, 110, 136]
+[:mouse_move, 477, 398, 2, 111, 136]
+[:mouse_move, 478, 397, 2, 112, 136]
+[:mouse_move, 479, 397, 2, 113, 137]
+[:mouse_move, 480, 396, 2, 114, 137]
+[:mouse_move, 480, 395, 2, 115, 138]
+[:mouse_move, 480, 396, 2, 116, 138]
+[:mouse_move, 478, 404, 2, 117, 139]
+[:mouse_move, 474, 418, 2, 118, 139]
+[:mouse_move, 472, 426, 2, 119, 139]
+[:mouse_move, 466, 438, 2, 120, 140]
+[:mouse_move, 461, 453, 2, 121, 140]
+[:mouse_move, 453, 466, 2, 122, 140]
+[:mouse_move, 448, 473, 2, 123, 141]
+[:mouse_move, 446, 475, 2, 124, 141]
+[:mouse_move, 444, 477, 2, 125, 142]
+[:mouse_move, 441, 481, 2, 126, 142]
+[:mouse_move, 435, 489, 2, 127, 142]
+[:mouse_move, 426, 496, 2, 128, 143]
+[:mouse_move, 422, 498, 2, 129, 143]
+[:mouse_move, 422, 499, 2, 130, 143]
+[:mouse_move, 421, 499, 2, 131, 145]
+[:mouse_move, 420, 499, 2, 132, 145]
+[:mouse_button_pressed, 1, 0, 1, 133, 147]
+[:mouse_move, 419, 499, 2, 134, 148]
+[:mouse_move, 419, 497, 2, 135, 148]
+[:mouse_move, 421, 494, 2, 136, 149]
+[:mouse_move, 426, 484, 2, 137, 149]
+[:mouse_move, 432, 472, 2, 138, 149]
+[:mouse_move, 439, 460, 2, 139, 150]
+[:mouse_move, 445, 450, 2, 140, 150]
+[:mouse_move, 456, 434, 2, 141, 150]
+[:mouse_move, 466, 422, 2, 142, 150]
+[:mouse_move, 474, 411, 2, 143, 151]
+[:mouse_move, 480, 403, 2, 144, 151]
+[:mouse_move, 485, 397, 2, 145, 151]
+[:mouse_move, 489, 392, 2, 146, 151]
+[:mouse_move, 491, 389, 2, 147, 151]
+[:mouse_move, 494, 384, 2, 148, 151]
+[:mouse_move, 495, 381, 2, 149, 152]
+[:mouse_move, 497, 378, 2, 150, 152]
+[:mouse_move, 499, 376, 2, 151, 152]
+[:mouse_move, 500, 373, 2, 152, 152]
+[:mouse_move, 501, 372, 2, 153, 152]
+[:mouse_move, 501, 371, 2, 154, 152]
+[:mouse_move, 502, 370, 2, 155, 153]
+[:mouse_move, 502, 369, 2, 156, 153]
+[:mouse_move, 503, 369, 2, 157, 157]
+[:mouse_move, 504, 369, 2, 158, 158]
+[:mouse_move, 505, 368, 2, 159, 158]
+[:mouse_move, 508, 366, 2, 160, 158]
+[:mouse_move, 512, 364, 2, 161, 159]
+[:mouse_move, 513, 364, 2, 162, 159]
+[:mouse_move, 514, 364, 2, 163, 159]
+[:mouse_move, 515, 364, 2, 164, 160]
+[:mouse_move, 519, 364, 2, 165, 161]
+[:mouse_move, 526, 366, 2, 166, 161]
+[:mouse_move, 538, 372, 2, 167, 161]
+[:mouse_move, 550, 382, 2, 168, 161]
+[:mouse_move, 563, 397, 2, 169, 162]
+[:mouse_move, 570, 411, 2, 170, 162]
+[:mouse_move, 574, 425, 2, 171, 162]
+[:mouse_move, 576, 439, 2, 172, 163]
+[:mouse_move, 576, 448, 2, 173, 163]
+[:mouse_move, 576, 459, 2, 174, 163]
+[:mouse_move, 576, 470, 2, 175, 163]
+[:mouse_move, 576, 477, 2, 176, 163]
+[:mouse_move, 576, 481, 2, 177, 163]
+[:mouse_move, 576, 483, 2, 178, 163]
+[:mouse_move, 576, 485, 2, 179, 164]
+[:mouse_move, 576, 488, 2, 180, 164]
+[:mouse_move, 576, 494, 2, 181, 164]
+[:mouse_move, 577, 500, 2, 182, 164]
+[:mouse_move, 577, 501, 2, 183, 164]
+[:mouse_move, 579, 504, 2, 184, 164]
+[:mouse_move, 579, 505, 2, 185, 164]
+[:mouse_move, 581, 509, 2, 186, 165]
+[:mouse_move, 583, 512, 2, 187, 165]
+[:mouse_move, 584, 514, 2, 188, 165]
+[:mouse_move, 585, 516, 2, 189, 165]
+[:mouse_move, 586, 519, 2, 190, 165]
+[:mouse_move, 587, 521, 2, 191, 165]
+[:mouse_move, 588, 523, 2, 192, 166]
+[:mouse_move, 588, 524, 2, 193, 166]
+[:mouse_move, 588, 525, 2, 194, 166]
+[:mouse_move, 588, 526, 2, 195, 167]
+[:mouse_move, 588, 527, 2, 196, 167]
+[:mouse_move, 588, 526, 2, 197, 173]
+[:mouse_move, 586, 521, 2, 198, 173]
+[:mouse_move, 586, 516, 2, 199, 174]
+[:mouse_move, 585, 508, 2, 200, 174]
+[:mouse_move, 582, 500, 2, 201, 174]
+[:mouse_move, 578, 489, 2, 202, 174]
+[:mouse_move, 573, 476, 2, 203, 175]
+[:mouse_move, 568, 466, 2, 204, 175]
+[:mouse_move, 566, 461, 2, 205, 176]
+[:mouse_move, 565, 460, 2, 206, 176]
+[:mouse_move, 564, 460, 2, 207, 176]
+[:mouse_move, 563, 459, 2, 208, 176]
+[:mouse_move, 562, 459, 2, 209, 177]
+[:mouse_move, 561, 459, 2, 210, 177]
+[:mouse_move, 549, 459, 2, 211, 177]
+[:mouse_move, 522, 456, 2, 212, 177]
+[:mouse_move, 484, 456, 2, 213, 177]
+[:mouse_move, 423, 456, 2, 214, 177]
+[:mouse_move, 385, 454, 2, 215, 177]
+[:mouse_move, 359, 454, 2, 216, 178]
+[:mouse_move, 345, 452, 2, 217, 178]
+[:mouse_move, 343, 452, 2, 218, 178]
+[:mouse_move, 342, 451, 2, 219, 180]
+[:mouse_move, 343, 451, 2, 220, 180]
+[:mouse_move, 344, 449, 2, 221, 180]
+[:mouse_move, 348, 446, 2, 222, 180]
+[:mouse_move, 352, 444, 2, 223, 180]
+[:mouse_move, 362, 442, 2, 224, 181]
+[:mouse_move, 369, 441, 2, 225, 181]
+[:mouse_move, 376, 440, 2, 226, 181]
+[:mouse_move, 381, 439, 2, 227, 182]
+[:mouse_move, 385, 438, 2, 228, 182]
+[:mouse_move, 386, 438, 2, 229, 182]
+[:mouse_move, 387, 437, 2, 230, 183]
+[:mouse_move, 387, 436, 2, 231, 183]
+[:mouse_move, 388, 434, 2, 232, 183]
+[:mouse_move, 388, 430, 2, 233, 183]
+[:mouse_move, 387, 428, 2, 234, 183]
+[:mouse_move, 387, 427, 2, 235, 183]
+[:mouse_move, 386, 425, 2, 236, 184]
+[:mouse_move, 383, 425, 2, 237, 184]
+[:mouse_move, 382, 425, 2, 238, 185]
+[:mouse_move, 381, 425, 2, 239, 185]
+[:mouse_move, 380, 424, 2, 240, 185]
+[:mouse_move, 379, 424, 2, 241, 187]
+[:mouse_move, 378, 424, 2, 242, 189]
+[:mouse_move, 377, 424, 2, 243, 192]
+[:mouse_move, 376, 424, 2, 244, 192]
+[:mouse_move, 375, 424, 2, 245, 194]
+[:mouse_move, 374, 424, 2, 246, 195]
+[:mouse_move, 373, 424, 2, 247, 196]
+[:mouse_move, 372, 424, 2, 248, 197]
+[:mouse_move, 370, 425, 2, 249, 197]
+[:mouse_move, 368, 425, 2, 250, 198]
+[:mouse_move, 367, 425, 2, 251, 198]
+[:mouse_move, 366, 425, 2, 252, 198]
+[:mouse_button_up, 1, 0, 1, 253, 203]
+[:mouse_move, 365, 423, 2, 254, 204]
+[:mouse_move, 360, 418, 2, 255, 204]
+[:mouse_move, 356, 413, 2, 256, 205]
+[:mouse_move, 350, 407, 2, 257, 205]
+[:mouse_move, 344, 401, 2, 258, 205]
+[:mouse_move, 337, 396, 2, 259, 206]
+[:mouse_move, 326, 390, 2, 260, 206]
+[:mouse_move, 311, 381, 2, 261, 207]
+[:mouse_move, 303, 377, 2, 262, 207]
+[:mouse_move, 297, 374, 2, 263, 207]
+[:mouse_move, 296, 374, 2, 264, 207]
+[:mouse_button_pressed, 1, 0, 1, 265, 211]
+[:mouse_button_up, 1, 0, 1, 266, 212]
+[:mouse_move, 297, 374, 2, 267, 213]
+[:mouse_move, 298, 374, 2, 268, 220]
+[:mouse_move, 300, 378, 2, 269, 221]
+[:mouse_move, 301, 384, 2, 270, 221]
+[:mouse_move, 301, 393, 2, 271, 222]
+[:mouse_move, 301, 401, 2, 272, 222]
+[:mouse_move, 301, 409, 2, 273, 223]
+[:mouse_move, 301, 412, 2, 274, 223]
+[:mouse_move, 301, 413, 2, 275, 224]
+[:mouse_move, 301, 415, 2, 276, 224]
+[:mouse_move, 302, 418, 2, 277, 225]
+[:mouse_move, 303, 419, 2, 278, 225]
+[:mouse_move, 303, 420, 2, 279, 226]
+[:mouse_button_pressed, 1, 0, 1, 280, 228]
+[:mouse_button_up, 1, 0, 1, 281, 230]
+[:mouse_move, 303, 421, 2, 282, 230]
+[:mouse_move, 303, 422, 2, 283, 231]
+[:mouse_move, 303, 426, 2, 284, 231]
+[:mouse_move, 302, 429, 2, 285, 232]
+[:mouse_move, 302, 430, 2, 286, 232]
+[:mouse_move, 302, 432, 2, 287, 232]
+[:mouse_move, 302, 436, 2, 288, 233]
+[:mouse_move, 302, 438, 2, 289, 233]
+[:mouse_move, 302, 440, 2, 290, 233]
+[:mouse_move, 302, 441, 2, 291, 234]
+[:mouse_move, 302, 442, 2, 292, 234]
+[:mouse_move, 302, 443, 2, 293, 235]
+[:mouse_move, 302, 444, 2, 294, 236]
+[:mouse_move, 302, 445, 2, 295, 236]
+[:mouse_move, 303, 447, 2, 296, 237]
+[:mouse_move, 304, 451, 2, 297, 237]
+[:mouse_move, 304, 454, 2, 298, 237]
+[:mouse_move, 304, 456, 2, 299, 238]
+[:mouse_move, 304, 458, 2, 300, 238]
+[:mouse_move, 304, 460, 2, 301, 238]
+[:mouse_move, 304, 463, 2, 302, 239]
+[:mouse_button_pressed, 1, 0, 1, 303, 242]
+[:mouse_button_up, 1, 0, 1, 304, 244]
+[:mouse_move, 304, 464, 2, 305, 244]
+[:mouse_move, 304, 465, 2, 306, 245]
+[:mouse_move, 304, 470, 2, 307, 246]
+[:mouse_move, 304, 476, 2, 308, 246]
+[:mouse_move, 303, 485, 2, 309, 246]
+[:mouse_move, 301, 495, 2, 310, 247]
+[:mouse_move, 300, 500, 2, 311, 247]
+[:mouse_move, 300, 503, 2, 312, 247]
+[:mouse_move, 300, 506, 2, 313, 248]
+[:mouse_move, 301, 508, 2, 314, 248]
+[:mouse_move, 302, 510, 2, 315, 248]
+[:mouse_move, 302, 511, 2, 316, 249]
+[:mouse_move, 303, 512, 2, 317, 249]
+[:mouse_move, 303, 513, 2, 318, 251]
+[:mouse_button_pressed, 1, 0, 1, 319, 253]
+[:mouse_button_up, 1, 0, 1, 320, 255]
+[:mouse_move, 303, 512, 2, 321, 255]
+[:mouse_move, 304, 511, 2, 322, 265]
+[:mouse_move, 305, 511, 2, 323, 265]
+[:mouse_move, 307, 510, 2, 324, 266]
+[:mouse_move, 311, 509, 2, 325, 266]
+[:mouse_move, 315, 505, 2, 326, 266]
+[:mouse_move, 317, 504, 2, 327, 267]
+[:mouse_move, 317, 503, 2, 328, 268]
+[:mouse_move, 316, 503, 2, 329, 269]
+[:mouse_move, 316, 502, 2, 330, 289]
+[:mouse_move, 317, 501, 2, 331, 291]
+[:mouse_move, 318, 501, 2, 332, 292]
+[:mouse_move, 319, 501, 2, 333, 302]
+[:mouse_move, 319, 500, 2, 334, 303]
+[:key_down_raw, 96, 0, 2, 335, 303]
+[:mouse_move, 320, 500, 2, 336, 304]
+[:mouse_move, 323, 498, 2, 337, 304]
+[:mouse_move, 331, 496, 2, 338, 305]
+[:key_up_raw, 96, 0, 2, 339, 305]
+[:mouse_move, 341, 493, 2, 340, 305]
+[:mouse_move, 351, 489, 2, 341, 305]
+[:mouse_move, 363, 484, 2, 342, 306]
+[:mouse_move, 372, 482, 2, 343, 306]
+[:mouse_move, 384, 479, 2, 344, 306]
+[:mouse_move, 395, 479, 2, 345, 307]
+[:mouse_move, 402, 477, 2, 346, 307]
+[:mouse_move, 406, 475, 2, 347, 308]
+[:mouse_move, 403, 475, 2, 348, 308]
+[:mouse_move, 397, 473, 2, 349, 309]
+[:mouse_move, 394, 467, 2, 350, 311]
+[:mouse_move, 393, 467, 2, 351, 311]
+[:mouse_move, 397, 466, 2, 352, 312]
+[:mouse_move, 398, 465, 2, 353, 313]
+[:mouse_move, 399, 465, 2, 354, 313]
+[:mouse_move, 399, 464, 2, 355, 313]
+[:mouse_move, 400, 464, 2, 356, 314]
+[:mouse_move, 400, 463, 2, 357, 316]
+[:mouse_move, 401, 463, 2, 358, 318]
+[:mouse_move, 401, 462, 2, 359, 319]
+[:key_down_raw, 13, 0, 2, 360, 322]
diff --git a/samples/13_path_finding_algorithms/05_dijkstra/app/main.rb b/samples/13_path_finding_algorithms/05_dijkstra/app/main.rb
index b335447..1223779 100644
--- a/samples/13_path_finding_algorithms/05_dijkstra/app/main.rb
+++ b/samples/13_path_finding_algorithms/05_dijkstra/app/main.rb
@@ -19,8 +19,8 @@ class Movement_Costs
# The next step in the search is calculated
def tick
defaults
- render
- input
+ render
+ input
calc
end
@@ -37,7 +37,7 @@ class Movement_Costs
# Walls are stored in a hash for quick look up when doing the search
state.star ||= [1, 5]
state.target ||= [8, 4]
- state.walls ||= {[1, 1] => true, [2, 1] => true, [3, 1] => true, [1, 2] => true, [2, 2] => true, [3, 2] => true}
+ state.walls ||= {[1, 1] => true, [2, 1] => true, [3, 1] => true, [1, 2] => true, [2, 2] => true, [3, 2] => true}
state.hills ||= {
[4, 1] => true,
[5, 1] => true,
@@ -72,7 +72,7 @@ class Movement_Costs
# We store this value, because we want to remember the value even when
# the user's cursor is no longer over what they're interacting with, but
# they are still clicking down on the mouse.
- state.user_input ||= :none
+ state.user_input ||= :none
# Values that are used for the breadth first search
# Keeping track of what cells were visited prevents counting cells multiple times
@@ -96,7 +96,7 @@ class Movement_Costs
# Draws everything onto the screen
def render
- render_background
+ render_background
render_heat_maps
@@ -111,8 +111,8 @@ class Movement_Costs
# Draws what the grid looks like with nothing on it
def render_background
- render_unvisited
- render_grid_lines
+ render_unvisited
+ render_grid_lines
render_labels
end
@@ -131,7 +131,7 @@ class Movement_Costs
end
for y in 0..grid.height
- outputs.lines << horizontal_line(y)
+ outputs.lines << horizontal_line(y)
outputs.lines << shifted_horizontal_line(y)
end
end
@@ -244,16 +244,16 @@ class Movement_Costs
def render_star
outputs.sprites << [scale_up(state.star), 'star.png']
outputs.sprites << [move_and_scale_up(state.star), 'star.png']
- end
+ end
# Renders the target on both grids
def render_target
outputs.sprites << [scale_up(state.target), 'target.png']
outputs.sprites << [move_and_scale_up(state.target), 'target.png']
- end
+ end
def render_hills
- state.hills.each_key do |hill|
+ state.hills.each_key do |hill|
outputs.solids << [scale_up(hill), hill_color]
outputs.solids << [move_and_scale_up(hill), hill_color]
end
@@ -261,7 +261,7 @@ class Movement_Costs
# Draws the walls on both grids
def render_walls
- state.walls.each_key do |wall|
+ state.walls.each_key do |wall|
outputs.solids << [scale_up(wall), wall_color]
outputs.solids << [move_and_scale_up(wall), wall_color]
end
@@ -344,7 +344,7 @@ class Movement_Costs
# If the mouse was clicked this tick
if inputs.mouse.down
# Determine what the user is editing and edit the state.user_input variable
- determine_input
+ determine_input
end
# Process user input based on user_input variable and current mouse position
@@ -357,43 +357,43 @@ class Movement_Costs
# mouse left click is held
def determine_input
# If the mouse is over the star in the first grid
- if mouse_over_star?
+ if mouse_over_star?
# The user is editing the star from the first grid
- state.user_input = :star
+ state.user_input = :star
# If the mouse is over the star in the second grid
- elsif mouse_over_star2?
+ elsif mouse_over_star2?
# The user is editing the star from the second grid
- state.user_input = :star2
+ state.user_input = :star2
# If the mouse is over the target in the first grid
- elsif mouse_over_target?
+ elsif mouse_over_target?
# The user is editing the target from the first grid
- state.user_input = :target
+ state.user_input = :target
# If the mouse is over the target in the second grid
- elsif mouse_over_target2?
+ elsif mouse_over_target2?
# The user is editing the target from the second grid
- state.user_input = :target2
+ state.user_input = :target2
# If the mouse is over a wall in the first grid
- elsif mouse_over_wall?
+ elsif mouse_over_wall?
# The user is removing a wall from the first grid
- state.user_input = :remove_wall
+ state.user_input = :remove_wall
# If the mouse is over a wall in the second grid
- elsif mouse_over_wall2?
+ elsif mouse_over_wall2?
# The user is removing a wall from the second grid
state.user_input = :remove_wall2
# If the mouse is over a hill in the first grid
- elsif mouse_over_hill?
+ elsif mouse_over_hill?
# The user is adding a wall from the first grid
- state.user_input = :add_wall
+ state.user_input = :add_wall
# If the mouse is over a hill in the second grid
- elsif mouse_over_hill2?
+ elsif mouse_over_hill2?
# The user is adding a wall from the second grid
state.user_input = :add_wall2
# If the mouse is over the first grid
- elsif mouse_over_grid?
+ elsif mouse_over_grid?
# The user is adding a hill from the first grid
state.user_input = :add_hill
# If the mouse is over the second grid
- elsif mouse_over_grid2?
+ elsif mouse_over_grid2?
# The user is adding a hill from the second grid
state.user_input = :add_hill2
end
@@ -401,26 +401,26 @@ class Movement_Costs
# Processes click and drag based on what the user is currently dragging
def process_input
- if state.user_input == :star
- input_star
+ if state.user_input == :star
+ input_star
elsif state.user_input == :star2
- input_star2
- elsif state.user_input == :target
- input_target
- elsif state.user_input == :target2
- input_target2
- elsif state.user_input == :remove_wall
- input_remove_wall
+ input_star2
+ elsif state.user_input == :target
+ input_target
+ elsif state.user_input == :target2
+ input_target2
+ elsif state.user_input == :remove_wall
+ input_remove_wall
elsif state.user_input == :remove_wall2
- input_remove_wall2
- elsif state.user_input == :add_hill
- input_add_hill
- elsif state.user_input == :add_hill2
- input_add_hill2
- elsif state.user_input == :add_wall
- input_add_wall
- elsif state.user_input == :add_wall2
- input_add_wall2
+ input_remove_wall2
+ elsif state.user_input == :add_hill
+ input_add_hill
+ elsif state.user_input == :add_hill2
+ input_add_hill2
+ elsif state.user_input == :add_wall
+ input_add_wall
+ elsif state.user_input == :add_wall2
+ input_add_wall2
end
end
@@ -433,26 +433,26 @@ class Movement_Costs
calc_dijkstra
end
end
-
+
def calc_breadth_first
# Sets up the Breadth First Search
- breadth_first_search.visited[state.star] = true
- breadth_first_search.frontier << state.star
+ breadth_first_search.visited[state.star] = true
+ breadth_first_search.frontier << state.star
breadth_first_search.came_from[state.star] = nil
until breadth_first_search.frontier.empty?
return if breadth_first_search.visited.has_key?(state.target)
# A step in the search
# Takes the next frontier cell
- new_frontier = breadth_first_search.frontier.shift
+ new_frontier = breadth_first_search.frontier.shift
# For each of its neighbors
- adjacent_neighbors(new_frontier).each do | neighbor |
+ adjacent_neighbors(new_frontier).each do | neighbor |
# That have not been visited and are not walls
- unless breadth_first_search.visited.has_key?(neighbor) || state.walls.has_key?(neighbor)
+ unless breadth_first_search.visited.has_key?(neighbor) || state.walls.has_key?(neighbor)
# Add them to the frontier and mark them as visited in the first grid
- breadth_first_search.visited[neighbor] = true
- breadth_first_search.frontier << neighbor
+ breadth_first_search.visited[neighbor] = true
+ breadth_first_search.frontier << neighbor
# Remember which cell the neighbor came from
breadth_first_search.came_from[neighbor] = new_frontier
end
@@ -512,12 +512,12 @@ class Movement_Costs
# Only resets the search if the star changes position
# Called whenever the user is editing the star (puts mouse down on star)
def input_star
- old_star = state.star.clone
+ old_star = state.star.clone
unless cell_closest_to_mouse == state.target
- state.star = cell_closest_to_mouse
+ state.star = cell_closest_to_mouse
end
- unless old_star == state.star
- reset_search
+ unless old_star == state.star
+ reset_search
end
end
@@ -525,12 +525,12 @@ class Movement_Costs
# Only resets the search if the star changes position
# Called whenever the user is editing the star (puts mouse down on star)
def input_star2
- old_star = state.star.clone
+ old_star = state.star.clone
unless cell_closest_to_mouse2 == state.target
state.star = cell_closest_to_mouse2
end
- unless old_star == state.star
- reset_search
+ unless old_star == state.star
+ reset_search
end
end
@@ -538,12 +538,12 @@ class Movement_Costs
# Only reset_searchs the search if the target changes position
# Called whenever the user is editing the target (puts mouse down on target)
def input_target
- old_target = state.target.clone
+ old_target = state.target.clone
unless cell_closest_to_mouse == state.star
state.target = cell_closest_to_mouse
end
- unless old_target == state.target
- reset_search
+ unless old_target == state.target
+ reset_search
end
end
@@ -551,12 +551,12 @@ class Movement_Costs
# Only reset_searchs the search if the target changes position
# Called whenever the user is editing the target (puts mouse down on target)
def input_target2
- old_target = state.target.clone
+ old_target = state.target.clone
unless cell_closest_to_mouse2 == state.star
state.target = cell_closest_to_mouse2
end
- unless old_target == state.target
- reset_search
+ unless old_target == state.target
+ reset_search
end
end
@@ -565,11 +565,11 @@ class Movement_Costs
# The mouse needs to be inside the grid, because we only want to remove walls
# the cursor is directly over
# Recalculations should only occur when a wall is actually deleted
- if mouse_over_grid?
+ if mouse_over_grid?
if state.walls.has_key?(cell_closest_to_mouse) or state.hills.has_key?(cell_closest_to_mouse)
- state.walls.delete(cell_closest_to_mouse)
- state.hills.delete(cell_closest_to_mouse)
- reset_search
+ state.walls.delete(cell_closest_to_mouse)
+ state.hills.delete(cell_closest_to_mouse)
+ reset_search
end
end
end
@@ -579,21 +579,21 @@ class Movement_Costs
# The mouse needs to be inside the grid, because we only want to remove walls
# the cursor is directly over
# Recalculations should only occur when a wall is actually deleted
- if mouse_over_grid2?
+ if mouse_over_grid2?
if state.walls.has_key?(cell_closest_to_mouse2) or state.hills.has_key?(cell_closest_to_mouse2)
- state.walls.delete(cell_closest_to_mouse2)
- state.hills.delete(cell_closest_to_mouse2)
- reset_search
+ state.walls.delete(cell_closest_to_mouse2)
+ state.hills.delete(cell_closest_to_mouse2)
+ reset_search
end
end
end
# Adds a hill in the first grid in the cell the mouse is over
def input_add_hill
- if mouse_over_grid?
+ if mouse_over_grid?
unless state.hills.has_key?(cell_closest_to_mouse)
- state.hills[cell_closest_to_mouse] = true
- reset_search
+ state.hills[cell_closest_to_mouse] = true
+ reset_search
end
end
end
@@ -601,32 +601,32 @@ class Movement_Costs
# Adds a hill in the second grid in the cell the mouse is over
def input_add_hill2
- if mouse_over_grid2?
+ if mouse_over_grid2?
unless state.hills.has_key?(cell_closest_to_mouse2)
- state.hills[cell_closest_to_mouse2] = true
- reset_search
+ state.hills[cell_closest_to_mouse2] = true
+ reset_search
end
end
end
# Adds a wall in the first grid in the cell the mouse is over
def input_add_wall
- if mouse_over_grid?
+ if mouse_over_grid?
unless state.walls.has_key?(cell_closest_to_mouse)
- state.hills.delete(cell_closest_to_mouse)
- state.walls[cell_closest_to_mouse] = true
- reset_search
+ state.hills.delete(cell_closest_to_mouse)
+ state.walls[cell_closest_to_mouse] = true
+ reset_search
end
end
end
# Adds a wall in the second grid in the cell the mouse is over
def input_add_wall2
- if mouse_over_grid2?
+ if mouse_over_grid2?
unless state.walls.has_key?(cell_closest_to_mouse2)
- state.hills.delete(cell_closest_to_mouse2)
- state.walls[cell_closest_to_mouse2] = true
- reset_search
+ state.hills.delete(cell_closest_to_mouse2)
+ state.walls[cell_closest_to_mouse2] = true
+ reset_search
end
end
end
@@ -649,21 +649,21 @@ class Movement_Costs
# Returns a list of adjacent cells
# Used to determine what the next cells to be added to the frontier are
def adjacent_neighbors(cell)
- neighbors = []
+ neighbors = []
# Gets all the valid neighbors into the array
# From southern neighbor, clockwise
- neighbors << [cell.x , cell.y - 1] unless cell.y == 0
- neighbors << [cell.x - 1, cell.y ] unless cell.x == 0
- neighbors << [cell.x , cell.y + 1] unless cell.y == grid.height - 1
- neighbors << [cell.x + 1, cell.y ] unless cell.x == grid.width - 1
+ neighbors << [cell.x , cell.y - 1] unless cell.y == 0
+ neighbors << [cell.x - 1, cell.y ] unless cell.x == 0
+ neighbors << [cell.x , cell.y + 1] unless cell.y == grid.height - 1
+ neighbors << [cell.x + 1, cell.y ] unless cell.x == grid.width - 1
# Sorts the neighbors so the rendered path is a zigzag path
# Cells in a diagonal direction are given priority
# Comment this line to see the difference
neighbors = neighbors.sort_by { |neighbor_x, neighbor_y| proximity_to_star(neighbor_x, neighbor_y) }
- neighbors
+ neighbors
end
# Finds the vertical and horizontal distance of a cell from the star
@@ -688,13 +688,13 @@ class Movement_Costs
# Finding the cell closest to the mouse helps with this
def cell_closest_to_mouse
# Closest cell to the mouse in the first grid
- x = (inputs.mouse.point.x / grid.cell_size).to_i
- y = (inputs.mouse.point.y / grid.cell_size).to_i
+ x = (inputs.mouse.point.x / grid.cell_size).to_i
+ y = (inputs.mouse.point.y / grid.cell_size).to_i
# Bound x and y to the grid
- x = grid.width - 1 if x > grid.width - 1
- y = grid.height - 1 if y > grid.height - 1
+ x = grid.width - 1 if x > grid.width - 1
+ y = grid.height - 1 if y > grid.height - 1
# Return closest cell
- [x, y]
+ [x, y]
end
# When the user grabs the star and puts their cursor to the far right
@@ -702,17 +702,17 @@ class Movement_Costs
# Finding the cell closest to the mouse in the second grid helps with this
def cell_closest_to_mouse2
# Closest cell grid to the mouse in the second
- x = (inputs.mouse.point.x / grid.cell_size).to_i
- y = (inputs.mouse.point.y / grid.cell_size).to_i
+ x = (inputs.mouse.point.x / grid.cell_size).to_i
+ y = (inputs.mouse.point.y / grid.cell_size).to_i
# Translate the cell to the first grid
x -= grid.width + 1
# Bound x and y to the first grid
x = 0 if x < 0
y = 0 if y < 0
- x = grid.width - 1 if x > grid.width - 1
- y = grid.height - 1 if y > grid.height - 1
+ x = grid.width - 1 if x > grid.width - 1
+ y = grid.height - 1 if y > grid.height - 1
# Return closest cell
- [x, y]
+ [x, y]
end
# Signal that the user is going to be moving the star from the first grid
@@ -785,12 +785,12 @@ class Movement_Costs
# Light brown
def unvisited_color
- [221, 212, 213]
+ [221, 212, 213]
end
# Camo Green
def wall_color
- [134, 134, 120]
+ [134, 134, 120]
end
# Pastel White
@@ -833,7 +833,7 @@ def tick args
end
# Every tick, new args are passed, and the Dijkstra tick method is called
- $movement_costs ||= Movement_Costs.new(args)
+ $movement_costs ||= Movement_Costs.new
$movement_costs.args = args
$movement_costs.tick
end
diff --git a/samples/13_path_finding_algorithms/05_dijkstra/replay.txt b/samples/13_path_finding_algorithms/05_dijkstra/replay.txt
new file mode 100644
index 0000000..a459873
--- /dev/null
+++ b/samples/13_path_finding_algorithms/05_dijkstra/replay.txt
@@ -0,0 +1,686 @@
+replay_version 2.0
+stopped_at 730
+seed 100
+recorded_at 2021-11-20 11:20:27 -0600
+[:mouse_button_up, 1, 0, 1, 1, 1]
+[:mouse_move, 782, 97, 2, 2, 14]
+[:mouse_move, 782, 98, 2, 3, 15]
+[:mouse_move, 782, 99, 2, 4, 15]
+[:mouse_move, 782, 100, 2, 5, 16]
+[:mouse_move, 780, 102, 2, 6, 16]
+[:mouse_move, 773, 111, 2, 7, 17]
+[:mouse_move, 768, 123, 2, 8, 17]
+[:mouse_move, 759, 142, 2, 9, 18]
+[:mouse_move, 740, 166, 2, 10, 18]
+[:mouse_move, 718, 196, 2, 11, 19]
+[:mouse_move, 699, 232, 2, 12, 19]
+[:mouse_move, 686, 272, 2, 13, 20]
+[:mouse_move, 673, 314, 2, 14, 20]
+[:mouse_move, 648, 355, 2, 15, 21]
+[:mouse_move, 594, 404, 2, 16, 21]
+[:mouse_move, 562, 427, 2, 17, 22]
+[:mouse_move, 532, 446, 2, 18, 22]
+[:mouse_move, 509, 458, 2, 19, 23]
+[:mouse_move, 490, 464, 2, 20, 23]
+[:mouse_move, 482, 466, 2, 21, 23]
+[:mouse_move, 481, 466, 2, 22, 24]
+[:mouse_move, 481, 460, 2, 23, 25]
+[:mouse_move, 490, 451, 2, 24, 26]
+[:mouse_move, 501, 443, 2, 25, 26]
+[:mouse_move, 506, 441, 2, 26, 26]
+[:mouse_move, 506, 442, 2, 27, 29]
+[:mouse_move, 507, 442, 2, 28, 31]
+[:mouse_move, 508, 442, 2, 29, 32]
+[:mouse_move, 509, 442, 2, 30, 37]
+[:mouse_move, 510, 442, 2, 31, 48]
+[:mouse_move, 507, 442, 2, 32, 63]
+[:mouse_move, 500, 444, 2, 33, 63]
+[:mouse_move, 488, 446, 2, 34, 64]
+[:mouse_move, 476, 447, 2, 35, 64]
+[:mouse_move, 466, 449, 2, 36, 65]
+[:mouse_move, 459, 450, 2, 37, 65]
+[:mouse_move, 449, 452, 2, 38, 66]
+[:mouse_move, 440, 453, 2, 39, 66]
+[:mouse_move, 433, 454, 2, 40, 67]
+[:mouse_move, 432, 454, 2, 41, 67]
+[:mouse_move, 436, 455, 2, 42, 69]
+[:mouse_move, 442, 455, 2, 43, 69]
+[:mouse_move, 446, 455, 2, 44, 70]
+[:mouse_move, 450, 455, 2, 45, 70]
+[:mouse_move, 456, 448, 2, 46, 70]
+[:mouse_move, 458, 437, 2, 47, 71]
+[:mouse_move, 458, 422, 2, 48, 72]
+[:mouse_move, 451, 402, 2, 49, 72]
+[:mouse_move, 440, 376, 2, 50, 72]
+[:mouse_move, 414, 334, 2, 51, 73]
+[:mouse_move, 393, 303, 2, 52, 74]
+[:mouse_move, 378, 280, 2, 53, 74]
+[:mouse_move, 367, 265, 2, 54, 75]
+[:mouse_move, 358, 255, 2, 55, 75]
+[:mouse_move, 353, 251, 2, 56, 75]
+[:mouse_move, 349, 248, 2, 57, 76]
+[:mouse_move, 348, 248, 2, 58, 76]
+[:mouse_move, 345, 249, 2, 59, 77]
+[:mouse_move, 344, 249, 2, 60, 78]
+[:mouse_move, 338, 246, 2, 61, 79]
+[:mouse_move, 332, 240, 2, 62, 79]
+[:mouse_move, 328, 231, 2, 63, 80]
+[:mouse_move, 326, 222, 2, 64, 80]
+[:mouse_move, 326, 214, 2, 65, 81]
+[:mouse_move, 331, 208, 2, 66, 81]
+[:mouse_move, 340, 204, 2, 67, 82]
+[:mouse_move, 348, 202, 2, 68, 82]
+[:mouse_move, 357, 202, 2, 69, 83]
+[:mouse_move, 363, 202, 2, 70, 84]
+[:mouse_move, 365, 202, 2, 71, 84]
+[:mouse_move, 366, 202, 2, 72, 84]
+[:mouse_move, 374, 203, 2, 73, 85]
+[:mouse_move, 380, 204, 2, 74, 85]
+[:mouse_move, 382, 204, 2, 75, 86]
+[:mouse_move, 383, 204, 2, 76, 86]
+[:mouse_button_pressed, 1, 0, 1, 77, 88]
+[:mouse_button_up, 1, 0, 1, 78, 89]
+[:mouse_move, 384, 204, 2, 79, 99]
+[:mouse_move, 384, 205, 2, 80, 100]
+[:mouse_move, 389, 210, 2, 81, 101]
+[:mouse_move, 394, 214, 2, 82, 101]
+[:mouse_move, 399, 220, 2, 83, 101]
+[:mouse_move, 405, 228, 2, 84, 102]
+[:mouse_move, 410, 242, 2, 85, 103]
+[:mouse_move, 416, 261, 2, 86, 103]
+[:mouse_move, 422, 276, 2, 87, 104]
+[:mouse_move, 428, 284, 2, 88, 104]
+[:mouse_move, 430, 287, 2, 89, 104]
+[:mouse_move, 431, 288, 2, 90, 105]
+[:mouse_move, 433, 290, 2, 91, 105]
+[:mouse_move, 434, 295, 2, 92, 106]
+[:mouse_move, 435, 306, 2, 93, 106]
+[:mouse_move, 436, 311, 2, 94, 107]
+[:mouse_move, 436, 312, 2, 95, 108]
+[:mouse_move, 438, 314, 2, 96, 112]
+[:mouse_move, 441, 320, 2, 97, 113]
+[:mouse_move, 447, 341, 2, 98, 113]
+[:mouse_move, 453, 376, 2, 99, 114]
+[:mouse_move, 456, 413, 2, 100, 114]
+[:mouse_move, 456, 445, 2, 101, 115]
+[:mouse_move, 455, 475, 2, 102, 115]
+[:mouse_move, 450, 498, 2, 103, 116]
+[:mouse_move, 446, 519, 2, 104, 116]
+[:mouse_move, 446, 541, 2, 105, 117]
+[:mouse_move, 452, 559, 2, 106, 117]
+[:mouse_move, 458, 569, 2, 107, 117]
+[:mouse_move, 464, 573, 2, 108, 118]
+[:mouse_move, 468, 573, 2, 109, 119]
+[:mouse_move, 471, 570, 2, 110, 119]
+[:mouse_move, 474, 559, 2, 111, 120]
+[:mouse_move, 476, 539, 2, 112, 120]
+[:mouse_move, 483, 527, 2, 113, 120]
+[:mouse_move, 489, 519, 2, 114, 121]
+[:mouse_move, 493, 515, 2, 115, 121]
+[:mouse_move, 493, 511, 2, 116, 122]
+[:mouse_move, 493, 505, 2, 117, 122]
+[:mouse_move, 493, 499, 2, 118, 123]
+[:mouse_move, 490, 496, 2, 119, 123]
+[:mouse_move, 488, 493, 2, 120, 124]
+[:mouse_move, 487, 493, 2, 121, 124]
+[:mouse_move, 484, 493, 2, 122, 125]
+[:mouse_move, 482, 493, 2, 123, 125]
+[:mouse_move, 479, 494, 2, 124, 126]
+[:mouse_move, 474, 495, 2, 125, 126]
+[:mouse_move, 470, 499, 2, 126, 127]
+[:mouse_move, 470, 503, 2, 127, 127]
+[:mouse_move, 470, 506, 2, 128, 128]
+[:mouse_button_pressed, 1, 0, 1, 129, 131]
+[:mouse_button_up, 1, 0, 1, 130, 132]
+[:mouse_move, 470, 503, 2, 131, 135]
+[:mouse_move, 470, 495, 2, 132, 135]
+[:mouse_move, 470, 488, 2, 133, 135]
+[:mouse_move, 472, 478, 2, 134, 136]
+[:mouse_move, 473, 470, 2, 135, 137]
+[:mouse_move, 474, 459, 2, 136, 137]
+[:mouse_move, 474, 450, 2, 137, 138]
+[:mouse_move, 474, 445, 2, 138, 138]
+[:mouse_move, 472, 441, 2, 139, 138]
+[:mouse_move, 470, 439, 2, 140, 139]
+[:mouse_move, 467, 438, 2, 141, 139]
+[:mouse_move, 465, 438, 2, 142, 140]
+[:mouse_move, 464, 438, 2, 143, 140]
+[:mouse_move, 463, 438, 2, 144, 141]
+[:mouse_move, 460, 438, 2, 145, 141]
+[:mouse_move, 459, 438, 2, 146, 142]
+[:mouse_button_pressed, 1, 0, 1, 147, 144]
+[:mouse_button_up, 1, 0, 1, 148, 145]
+[:mouse_move, 459, 439, 2, 149, 153]
+[:mouse_move, 459, 438, 2, 150, 164]
+[:mouse_move, 458, 434, 2, 151, 164]
+[:mouse_move, 458, 426, 2, 152, 165]
+[:mouse_move, 458, 414, 2, 153, 165]
+[:mouse_move, 461, 400, 2, 154, 166]
+[:mouse_move, 461, 397, 2, 155, 166]
+[:mouse_move, 461, 396, 2, 156, 166]
+[:mouse_move, 461, 395, 2, 157, 167]
+[:mouse_button_pressed, 1, 0, 1, 158, 170]
+[:mouse_button_up, 1, 0, 1, 159, 171]
+[:mouse_move, 461, 394, 2, 160, 174]
+[:mouse_move, 461, 391, 2, 161, 175]
+[:mouse_move, 461, 387, 2, 162, 175]
+[:mouse_move, 461, 381, 2, 163, 176]
+[:mouse_move, 461, 379, 2, 164, 176]
+[:mouse_move, 461, 378, 2, 165, 177]
+[:mouse_move, 461, 377, 2, 166, 177]
+[:mouse_move, 461, 375, 2, 167, 179]
+[:mouse_move, 461, 374, 2, 168, 179]
+[:mouse_move, 461, 373, 2, 169, 180]
+[:mouse_move, 461, 372, 2, 170, 181]
+[:mouse_move, 461, 370, 2, 171, 181]
+[:mouse_move, 460, 365, 2, 172, 182]
+[:mouse_move, 460, 362, 2, 173, 182]
+[:mouse_move, 460, 359, 2, 174, 182]
+[:mouse_move, 460, 358, 2, 175, 184]
+[:mouse_move, 459, 356, 2, 176, 185]
+[:mouse_move, 459, 355, 2, 177, 186]
+[:mouse_move, 459, 352, 2, 178, 186]
+[:mouse_move, 459, 351, 2, 179, 187]
+[:mouse_move, 458, 350, 2, 180, 187]
+[:mouse_move, 458, 349, 2, 181, 187]
+[:mouse_move, 457, 352, 2, 182, 191]
+[:mouse_move, 456, 369, 2, 183, 192]
+[:mouse_move, 456, 381, 2, 184, 192]
+[:mouse_move, 456, 393, 2, 185, 193]
+[:mouse_move, 460, 412, 2, 186, 193]
+[:mouse_move, 466, 429, 2, 187, 193]
+[:mouse_move, 471, 448, 2, 188, 194]
+[:mouse_move, 472, 464, 2, 189, 194]
+[:mouse_move, 473, 477, 2, 190, 195]
+[:mouse_move, 474, 488, 2, 191, 196]
+[:mouse_move, 474, 497, 2, 192, 196]
+[:mouse_move, 474, 499, 2, 193, 196]
+[:mouse_move, 472, 504, 2, 194, 197]
+[:mouse_move, 470, 513, 2, 195, 197]
+[:mouse_move, 470, 516, 2, 196, 197]
+[:mouse_move, 470, 517, 2, 197, 198]
+[:mouse_move, 470, 519, 2, 198, 199]
+[:mouse_move, 470, 521, 2, 199, 199]
+[:mouse_move, 470, 522, 2, 200, 200]
+[:mouse_move, 470, 523, 2, 201, 201]
+[:mouse_move, 467, 521, 2, 202, 203]
+[:mouse_move, 464, 518, 2, 203, 203]
+[:mouse_move, 462, 515, 2, 204, 204]
+[:mouse_move, 461, 511, 2, 205, 205]
+[:mouse_button_pressed, 1, 0, 1, 206, 210]
+[:mouse_button_up, 1, 0, 1, 207, 211]
+[:mouse_move, 462, 511, 2, 208, 218]
+[:mouse_move, 465, 510, 2, 209, 218]
+[:mouse_move, 470, 508, 2, 210, 218]
+[:mouse_move, 475, 505, 2, 211, 219]
+[:mouse_move, 483, 502, 2, 212, 219]
+[:mouse_move, 493, 498, 2, 213, 220]
+[:mouse_move, 506, 491, 2, 214, 221]
+[:mouse_move, 517, 479, 2, 215, 221]
+[:mouse_move, 521, 471, 2, 216, 221]
+[:mouse_move, 523, 467, 2, 217, 222]
+[:mouse_move, 523, 464, 2, 218, 222]
+[:mouse_move, 522, 464, 2, 219, 227]
+[:mouse_move, 521, 464, 2, 220, 227]
+[:mouse_move, 518, 464, 2, 221, 228]
+[:mouse_move, 513, 460, 2, 222, 228]
+[:mouse_move, 513, 459, 2, 223, 228]
+[:mouse_move, 512, 459, 2, 224, 229]
+[:mouse_move, 512, 458, 2, 225, 229]
+[:mouse_button_pressed, 1, 0, 1, 226, 232]
+[:mouse_move, 513, 458, 2, 227, 233]
+[:mouse_move, 514, 458, 2, 228, 234]
+[:mouse_move, 516, 458, 2, 229, 234]
+[:mouse_move, 517, 458, 2, 230, 235]
+[:mouse_move, 523, 453, 2, 231, 235]
+[:mouse_move, 531, 444, 2, 232, 235]
+[:mouse_move, 537, 436, 2, 233, 236]
+[:mouse_move, 541, 428, 2, 234, 236]
+[:mouse_move, 543, 421, 2, 235, 237]
+[:mouse_move, 545, 413, 2, 236, 237]
+[:mouse_move, 546, 405, 2, 237, 237]
+[:mouse_move, 547, 396, 2, 238, 237]
+[:mouse_move, 547, 389, 2, 239, 237]
+[:mouse_move, 547, 383, 2, 240, 237]
+[:mouse_move, 547, 379, 2, 241, 238]
+[:mouse_move, 547, 378, 2, 242, 238]
+[:mouse_move, 547, 376, 2, 243, 238]
+[:mouse_move, 546, 375, 2, 244, 238]
+[:mouse_move, 546, 374, 2, 245, 238]
+[:mouse_move, 546, 372, 2, 246, 239]
+[:mouse_move, 545, 368, 2, 247, 239]
+[:mouse_move, 544, 366, 2, 248, 239]
+[:mouse_move, 543, 363, 2, 249, 240]
+[:mouse_move, 540, 357, 2, 250, 240]
+[:mouse_move, 534, 350, 2, 251, 241]
+[:mouse_move, 528, 344, 2, 252, 241]
+[:mouse_move, 520, 339, 2, 253, 241]
+[:mouse_move, 517, 339, 2, 254, 241]
+[:mouse_move, 514, 337, 2, 255, 241]
+[:mouse_move, 513, 337, 2, 256, 242]
+[:mouse_move, 511, 336, 2, 257, 242]
+[:mouse_move, 509, 336, 2, 258, 242]
+[:mouse_move, 508, 336, 2, 259, 242]
+[:mouse_move, 507, 336, 2, 260, 242]
+[:mouse_move, 505, 335, 2, 261, 242]
+[:mouse_move, 502, 335, 2, 262, 243]
+[:mouse_move, 498, 335, 2, 263, 244]
+[:mouse_move, 494, 335, 2, 264, 244]
+[:mouse_move, 484, 335, 2, 265, 244]
+[:mouse_move, 475, 335, 2, 266, 245]
+[:mouse_move, 469, 335, 2, 267, 245]
+[:mouse_move, 459, 338, 2, 268, 246]
+[:mouse_move, 451, 342, 2, 269, 246]
+[:mouse_move, 441, 347, 2, 270, 246]
+[:mouse_move, 430, 352, 2, 271, 246]
+[:mouse_move, 421, 357, 2, 272, 247]
+[:mouse_move, 408, 366, 2, 273, 247]
+[:mouse_move, 398, 375, 2, 274, 247]
+[:mouse_move, 390, 386, 2, 275, 248]
+[:mouse_move, 380, 402, 2, 276, 248]
+[:mouse_move, 374, 412, 2, 277, 248]
+[:mouse_move, 368, 420, 2, 278, 248]
+[:mouse_move, 364, 427, 2, 279, 248]
+[:mouse_move, 362, 437, 2, 280, 249]
+[:mouse_move, 362, 448, 2, 281, 249]
+[:mouse_move, 362, 455, 2, 282, 249]
+[:mouse_move, 362, 463, 2, 283, 249]
+[:mouse_move, 362, 467, 2, 284, 249]
+[:mouse_move, 362, 473, 2, 285, 250]
+[:mouse_move, 364, 483, 2, 286, 250]
+[:mouse_move, 368, 490, 2, 287, 251]
+[:mouse_move, 372, 496, 2, 288, 251]
+[:mouse_move, 379, 505, 2, 289, 251]
+[:mouse_move, 384, 509, 2, 290, 251]
+[:mouse_move, 385, 511, 2, 291, 251]
+[:mouse_move, 387, 511, 2, 292, 252]
+[:mouse_move, 387, 512, 2, 293, 252]
+[:mouse_move, 388, 512, 2, 294, 253]
+[:mouse_move, 390, 514, 2, 295, 254]
+[:mouse_move, 392, 516, 2, 296, 254]
+[:mouse_move, 392, 517, 2, 297, 254]
+[:mouse_move, 393, 518, 2, 298, 255]
+[:mouse_move, 394, 520, 2, 299, 255]
+[:mouse_move, 395, 523, 2, 300, 256]
+[:mouse_move, 395, 527, 2, 301, 257]
+[:mouse_move, 395, 533, 2, 302, 257]
+[:mouse_move, 392, 542, 2, 303, 258]
+[:mouse_move, 392, 555, 2, 304, 258]
+[:mouse_move, 392, 567, 2, 305, 258]
+[:mouse_move, 392, 576, 2, 306, 259]
+[:mouse_move, 392, 583, 2, 307, 259]
+[:mouse_move, 392, 587, 2, 308, 259]
+[:mouse_move, 392, 590, 2, 309, 259]
+[:mouse_move, 392, 592, 2, 310, 260]
+[:mouse_move, 391, 594, 2, 311, 260]
+[:mouse_move, 391, 595, 2, 312, 261]
+[:mouse_move, 389, 597, 2, 313, 262]
+[:mouse_move, 382, 602, 2, 314, 262]
+[:mouse_move, 372, 608, 2, 315, 263]
+[:mouse_move, 359, 612, 2, 316, 263]
+[:mouse_move, 345, 619, 2, 317, 263]
+[:mouse_move, 329, 626, 2, 318, 263]
+[:mouse_move, 314, 633, 2, 319, 263]
+[:mouse_move, 301, 639, 2, 320, 263]
+[:mouse_move, 286, 643, 2, 321, 264]
+[:mouse_move, 270, 646, 2, 322, 264]
+[:mouse_move, 255, 647, 2, 323, 264]
+[:mouse_move, 236, 650, 2, 324, 264]
+[:mouse_move, 227, 650, 2, 325, 265]
+[:mouse_move, 216, 650, 2, 326, 265]
+[:mouse_move, 207, 650, 2, 327, 265]
+[:mouse_move, 203, 651, 2, 328, 265]
+[:mouse_move, 202, 651, 2, 329, 265]
+[:mouse_move, 201, 651, 2, 330, 265]
+[:mouse_move, 200, 651, 2, 331, 267]
+[:mouse_move, 199, 651, 2, 332, 267]
+[:mouse_move, 198, 651, 2, 333, 268]
+[:mouse_move, 195, 652, 2, 334, 268]
+[:mouse_move, 194, 653, 2, 335, 269]
+[:mouse_move, 193, 654, 2, 336, 269]
+[:mouse_move, 193, 655, 2, 337, 272]
+[:mouse_move, 192, 655, 2, 338, 272]
+[:mouse_move, 192, 656, 2, 339, 274]
+[:mouse_move, 192, 658, 2, 340, 275]
+[:mouse_move, 192, 661, 2, 341, 275]
+[:mouse_move, 192, 662, 2, 342, 275]
+[:mouse_move, 192, 664, 2, 343, 276]
+[:mouse_move, 192, 665, 2, 344, 277]
+[:mouse_button_up, 1, 0, 1, 345, 329]
+[:mouse_move, 192, 664, 2, 346, 337]
+[:mouse_move, 193, 664, 2, 347, 354]
+[:mouse_move, 195, 663, 2, 348, 355]
+[:mouse_move, 201, 662, 2, 349, 355]
+[:mouse_move, 211, 660, 2, 350, 356]
+[:mouse_move, 227, 659, 2, 351, 357]
+[:mouse_move, 283, 651, 2, 352, 357]
+[:mouse_move, 348, 641, 2, 353, 358]
+[:mouse_move, 431, 632, 2, 354, 358]
+[:mouse_move, 522, 622, 2, 355, 359]
+[:mouse_move, 605, 609, 2, 356, 359]
+[:mouse_move, 661, 603, 2, 357, 360]
+[:mouse_move, 687, 599, 2, 358, 361]
+[:mouse_move, 702, 596, 2, 359, 361]
+[:mouse_move, 708, 595, 2, 360, 362]
+[:mouse_move, 711, 593, 2, 361, 362]
+[:mouse_move, 712, 592, 2, 362, 364]
+[:mouse_move, 714, 590, 2, 363, 364]
+[:mouse_move, 715, 589, 2, 364, 365]
+[:mouse_move, 715, 587, 2, 365, 365]
+[:mouse_move, 713, 584, 2, 366, 366]
+[:mouse_move, 712, 584, 2, 367, 367]
+[:mouse_move, 711, 583, 2, 368, 368]
+[:mouse_move, 712, 582, 2, 369, 369]
+[:mouse_move, 716, 579, 2, 370, 370]
+[:mouse_move, 719, 578, 2, 371, 371]
+[:mouse_move, 740, 571, 2, 372, 372]
+[:mouse_move, 757, 569, 2, 373, 372]
+[:mouse_move, 764, 568, 2, 374, 372]
+[:mouse_move, 764, 567, 2, 375, 374]
+[:mouse_button_pressed, 1, 0, 1, 376, 376]
+[:mouse_button_up, 1, 0, 1, 377, 377]
+[:mouse_move, 764, 571, 2, 378, 390]
+[:mouse_move, 764, 579, 2, 379, 391]
+[:mouse_move, 764, 584, 2, 380, 391]
+[:mouse_move, 763, 586, 2, 381, 392]
+[:mouse_move, 760, 592, 2, 382, 393]
+[:mouse_move, 755, 600, 2, 383, 393]
+[:mouse_move, 752, 606, 2, 384, 393]
+[:mouse_move, 750, 607, 2, 385, 394]
+[:mouse_move, 750, 608, 2, 386, 395]
+[:mouse_move, 750, 610, 2, 387, 396]
+[:mouse_move, 750, 614, 2, 388, 396]
+[:mouse_move, 750, 615, 2, 389, 396]
+[:mouse_move, 750, 617, 2, 390, 397]
+[:mouse_move, 750, 618, 2, 391, 398]
+[:mouse_move, 750, 620, 2, 392, 399]
+[:mouse_move, 749, 622, 2, 393, 400]
+[:mouse_button_pressed, 1, 0, 1, 394, 401]
+[:mouse_button_up, 1, 0, 1, 395, 403]
+[:mouse_move, 749, 623, 2, 396, 408]
+[:mouse_move, 750, 623, 2, 397, 410]
+[:mouse_move, 754, 624, 2, 398, 410]
+[:mouse_move, 760, 625, 2, 399, 411]
+[:mouse_move, 769, 628, 2, 400, 411]
+[:mouse_move, 785, 630, 2, 401, 412]
+[:mouse_move, 791, 631, 2, 402, 413]
+[:mouse_move, 792, 631, 2, 403, 414]
+[:mouse_move, 793, 631, 2, 404, 414]
+[:mouse_move, 794, 631, 2, 405, 415]
+[:mouse_move, 795, 631, 2, 406, 415]
+[:mouse_move, 796, 631, 2, 407, 416]
+[:mouse_move, 798, 631, 2, 408, 417]
+[:mouse_move, 799, 631, 2, 409, 422]
+[:mouse_move, 799, 630, 2, 410, 423]
+[:mouse_move, 800, 627, 2, 411, 426]
+[:mouse_move, 802, 621, 2, 412, 427]
+[:mouse_move, 804, 609, 2, 413, 427]
+[:mouse_move, 806, 601, 2, 414, 428]
+[:mouse_move, 804, 595, 2, 415, 429]
+[:mouse_move, 799, 591, 2, 416, 430]
+[:mouse_move, 796, 591, 2, 417, 430]
+[:mouse_move, 792, 591, 2, 418, 430]
+[:mouse_move, 786, 593, 2, 419, 431]
+[:mouse_move, 775, 597, 2, 420, 432]
+[:mouse_move, 766, 600, 2, 421, 433]
+[:mouse_move, 763, 600, 2, 422, 434]
+[:mouse_move, 762, 600, 2, 423, 434]
+[:mouse_move, 761, 599, 2, 424, 435]
+[:mouse_move, 759, 592, 2, 425, 435]
+[:mouse_move, 756, 578, 2, 426, 436]
+[:mouse_move, 755, 571, 2, 427, 437]
+[:mouse_move, 755, 566, 2, 428, 437]
+[:mouse_button_pressed, 1, 0, 1, 429, 440]
+[:mouse_button_up, 1, 0, 1, 430, 442]
+[:mouse_move, 755, 567, 2, 431, 443]
+[:mouse_move, 756, 567, 2, 432, 444]
+[:mouse_move, 756, 568, 2, 433, 446]
+[:mouse_move, 756, 573, 2, 434, 446]
+[:mouse_move, 756, 582, 2, 435, 447]
+[:mouse_move, 756, 592, 2, 436, 448]
+[:mouse_move, 758, 599, 2, 437, 448]
+[:mouse_move, 758, 604, 2, 438, 449]
+[:mouse_move, 759, 607, 2, 439, 449]
+[:mouse_move, 760, 610, 2, 440, 450]
+[:mouse_move, 760, 611, 2, 441, 451]
+[:mouse_move, 760, 612, 2, 442, 451]
+[:mouse_move, 760, 613, 2, 443, 452]
+[:mouse_move, 760, 614, 2, 444, 452]
+[:mouse_move, 760, 615, 2, 445, 454]
+[:mouse_move, 759, 616, 2, 446, 455]
+[:mouse_move, 759, 617, 2, 447, 455]
+[:mouse_move, 759, 618, 2, 448, 456]
+[:mouse_move, 759, 619, 2, 449, 457]
+[:mouse_move, 759, 621, 2, 450, 459]
+[:mouse_move, 758, 621, 2, 451, 460]
+[:mouse_move, 758, 622, 2, 452, 463]
+[:mouse_move, 758, 623, 2, 453, 464]
+[:mouse_move, 759, 623, 2, 454, 467]
+[:mouse_move, 759, 624, 2, 455, 468]
+[:mouse_move, 767, 624, 2, 456, 468]
+[:mouse_move, 776, 625, 2, 457, 469]
+[:mouse_move, 787, 627, 2, 458, 469]
+[:mouse_move, 795, 629, 2, 459, 470]
+[:mouse_move, 797, 630, 2, 460, 470]
+[:mouse_move, 798, 630, 2, 461, 471]
+[:mouse_button_pressed, 1, 0, 1, 462, 476]
+[:mouse_move, 799, 630, 2, 463, 476]
+[:mouse_button_up, 1, 0, 1, 464, 478]
+[:mouse_move, 799, 625, 2, 465, 478]
+[:mouse_move, 800, 615, 2, 466, 479]
+[:mouse_move, 801, 602, 2, 467, 480]
+[:mouse_move, 801, 590, 2, 468, 481]
+[:mouse_move, 801, 580, 2, 469, 481]
+[:mouse_move, 801, 571, 2, 470, 482]
+[:mouse_move, 801, 570, 2, 471, 482]
+[:mouse_move, 801, 569, 2, 472, 483]
+[:mouse_move, 801, 568, 2, 473, 485]
+[:mouse_move, 802, 567, 2, 474, 487]
+[:mouse_move, 803, 567, 2, 475, 488]
+[:mouse_button_pressed, 1, 0, 1, 476, 491]
+[:mouse_button_up, 1, 0, 1, 477, 493]
+[:mouse_move, 804, 567, 2, 478, 494]
+[:mouse_move, 811, 567, 2, 479, 495]
+[:mouse_move, 822, 567, 2, 480, 495]
+[:mouse_move, 837, 567, 2, 481, 496]
+[:mouse_move, 850, 567, 2, 482, 496]
+[:mouse_move, 861, 567, 2, 483, 497]
+[:mouse_move, 873, 568, 2, 484, 497]
+[:mouse_move, 875, 568, 2, 485, 498]
+[:mouse_move, 876, 568, 2, 486, 500]
+[:mouse_move, 877, 568, 2, 487, 501]
+[:mouse_move, 877, 569, 2, 488, 501]
+[:mouse_move, 868, 570, 2, 489, 516]
+[:mouse_move, 850, 574, 2, 490, 516]
+[:mouse_move, 835, 577, 2, 491, 517]
+[:mouse_move, 818, 577, 2, 492, 517]
+[:mouse_move, 810, 577, 2, 493, 518]
+[:mouse_move, 810, 578, 2, 494, 519]
+[:mouse_move, 813, 578, 2, 495, 520]
+[:mouse_move, 816, 578, 2, 496, 521]
+[:mouse_move, 819, 578, 2, 497, 521]
+[:mouse_move, 820, 578, 2, 498, 522]
+[:mouse_button_pressed, 1, 0, 1, 499, 526]
+[:mouse_button_up, 1, 0, 1, 500, 527]
+[:mouse_move, 822, 579, 2, 501, 529]
+[:mouse_move, 823, 581, 2, 502, 530]
+[:mouse_move, 824, 581, 2, 503, 531]
+[:mouse_move, 825, 581, 2, 504, 531]
+[:mouse_move, 829, 581, 2, 505, 531]
+[:mouse_move, 836, 581, 2, 506, 532]
+[:mouse_move, 843, 580, 2, 507, 533]
+[:mouse_move, 852, 577, 2, 508, 534]
+[:mouse_move, 862, 574, 2, 509, 534]
+[:mouse_move, 864, 574, 2, 510, 535]
+[:mouse_move, 865, 574, 2, 511, 541]
+[:mouse_button_pressed, 1, 0, 1, 512, 542]
+[:mouse_button_up, 1, 0, 1, 513, 544]
+[:mouse_move, 866, 581, 2, 514, 545]
+[:mouse_move, 868, 587, 2, 515, 545]
+[:mouse_move, 870, 592, 2, 516, 546]
+[:mouse_move, 871, 595, 2, 517, 546]
+[:mouse_move, 873, 598, 2, 518, 547]
+[:mouse_move, 874, 602, 2, 519, 548]
+[:mouse_move, 875, 608, 2, 520, 548]
+[:mouse_move, 875, 610, 2, 521, 549]
+[:mouse_move, 875, 613, 2, 522, 549]
+[:mouse_move, 875, 616, 2, 523, 550]
+[:mouse_move, 875, 617, 2, 524, 551]
+[:mouse_move, 875, 618, 2, 525, 552]
+[:mouse_move, 874, 620, 2, 526, 553]
+[:mouse_move, 872, 625, 2, 527, 553]
+[:mouse_move, 871, 627, 2, 528, 554]
+[:mouse_move, 871, 628, 2, 529, 554]
+[:mouse_move, 871, 629, 2, 530, 555]
+[:mouse_move, 870, 630, 2, 531, 556]
+[:mouse_button_pressed, 1, 0, 1, 532, 558]
+[:mouse_move, 871, 630, 2, 533, 558]
+[:mouse_button_up, 1, 0, 1, 534, 560]
+[:mouse_move, 869, 630, 2, 535, 564]
+[:mouse_move, 864, 631, 2, 536, 565]
+[:mouse_move, 857, 632, 2, 537, 566]
+[:mouse_move, 845, 633, 2, 538, 567]
+[:mouse_move, 830, 635, 2, 539, 567]
+[:mouse_move, 815, 636, 2, 540, 568]
+[:mouse_move, 800, 636, 2, 541, 568]
+[:mouse_move, 782, 636, 2, 542, 569]
+[:mouse_move, 773, 636, 2, 543, 570]
+[:mouse_move, 764, 636, 2, 544, 570]
+[:mouse_move, 757, 636, 2, 545, 571]
+[:mouse_move, 748, 636, 2, 546, 571]
+[:mouse_move, 741, 634, 2, 547, 572]
+[:mouse_move, 734, 634, 2, 548, 573]
+[:mouse_move, 728, 634, 2, 549, 574]
+[:mouse_move, 720, 634, 2, 550, 574]
+[:mouse_move, 713, 633, 2, 551, 575]
+[:mouse_move, 723, 632, 2, 552, 579]
+[:mouse_move, 734, 629, 2, 553, 580]
+[:mouse_move, 745, 626, 2, 554, 581]
+[:mouse_move, 761, 623, 2, 555, 581]
+[:mouse_move, 784, 617, 2, 556, 582]
+[:mouse_move, 811, 610, 2, 557, 582]
+[:mouse_move, 834, 601, 2, 558, 583]
+[:mouse_move, 850, 594, 2, 559, 584]
+[:mouse_move, 857, 590, 2, 560, 584]
+[:mouse_move, 858, 589, 2, 561, 585]
+[:mouse_move, 858, 588, 2, 562, 585]
+[:mouse_move, 858, 587, 2, 563, 586]
+[:mouse_move, 858, 586, 2, 564, 587]
+[:mouse_move, 858, 585, 2, 565, 588]
+[:mouse_move, 858, 584, 2, 566, 593]
+[:mouse_button_pressed, 1, 0, 1, 567, 595]
+[:mouse_button_up, 1, 0, 1, 568, 597]
+[:mouse_move, 851, 587, 2, 569, 599]
+[:mouse_move, 840, 590, 2, 570, 599]
+[:mouse_move, 825, 594, 2, 571, 600]
+[:mouse_move, 803, 600, 2, 572, 600]
+[:mouse_move, 777, 605, 2, 573, 601]
+[:mouse_move, 751, 607, 2, 574, 602]
+[:mouse_move, 729, 611, 2, 575, 602]
+[:mouse_move, 713, 614, 2, 576, 603]
+[:mouse_move, 701, 615, 2, 577, 603]
+[:mouse_move, 695, 615, 2, 578, 604]
+[:mouse_move, 694, 616, 2, 579, 605]
+[:mouse_move, 692, 615, 2, 580, 605]
+[:mouse_move, 690, 614, 2, 581, 606]
+[:mouse_move, 689, 614, 2, 582, 607]
+[:mouse_move, 688, 613, 2, 583, 607]
+[:mouse_move, 688, 610, 2, 584, 608]
+[:mouse_move, 687, 605, 2, 585, 608]
+[:mouse_move, 686, 598, 2, 586, 609]
+[:mouse_move, 686, 589, 2, 587, 610]
+[:mouse_move, 686, 582, 2, 588, 610]
+[:mouse_move, 687, 576, 2, 589, 611]
+[:mouse_move, 688, 576, 2, 590, 611]
+[:mouse_move, 688, 575, 2, 591, 612]
+[:mouse_move, 689, 574, 2, 592, 613]
+[:mouse_move, 689, 573, 2, 593, 613]
+[:mouse_move, 690, 573, 2, 594, 614]
+[:mouse_button_pressed, 1, 0, 1, 595, 615]
+[:mouse_move, 690, 572, 2, 596, 616]
+[:mouse_button_up, 1, 0, 1, 597, 617]
+[:mouse_move, 690, 573, 2, 598, 617]
+[:mouse_move, 690, 574, 2, 599, 619]
+[:mouse_move, 690, 575, 2, 600, 620]
+[:mouse_move, 690, 576, 2, 601, 621]
+[:mouse_move, 690, 578, 2, 602, 621]
+[:mouse_move, 690, 579, 2, 603, 622]
+[:mouse_move, 690, 583, 2, 604, 622]
+[:mouse_move, 691, 594, 2, 605, 622]
+[:mouse_move, 693, 605, 2, 606, 623]
+[:mouse_move, 696, 614, 2, 607, 624]
+[:mouse_move, 698, 619, 2, 608, 625]
+[:mouse_move, 699, 621, 2, 609, 625]
+[:mouse_move, 700, 622, 2, 610, 626]
+[:mouse_move, 701, 622, 2, 611, 634]
+[:mouse_move, 702, 622, 2, 612, 649]
+[:mouse_move, 702, 621, 2, 613, 656]
+[:mouse_move, 705, 620, 2, 614, 656]
+[:mouse_move, 718, 614, 2, 615, 657]
+[:mouse_move, 750, 600, 2, 616, 657]
+[:mouse_move, 811, 576, 2, 617, 658]
+[:mouse_move, 895, 538, 2, 618, 659]
+[:mouse_move, 984, 489, 2, 619, 659]
+[:mouse_move, 1076, 432, 2, 620, 660]
+[:mouse_move, 1151, 376, 2, 621, 661]
+[:mouse_move, 1205, 336, 2, 622, 661]
+[:mouse_move, 1232, 312, 2, 623, 662]
+[:mouse_move, 1244, 292, 2, 624, 662]
+[:mouse_move, 1244, 286, 2, 625, 663]
+[:mouse_move, 1243, 284, 2, 626, 663]
+[:mouse_move, 1244, 284, 2, 627, 667]
+[:key_down_raw, 96, 0, 2, 628, 675]
+[:mouse_move, 1243, 284, 2, 629, 676]
+[:mouse_move, 1243, 283, 2, 630, 676]
+[:mouse_move, 1243, 282, 2, 631, 676]
+[:mouse_move, 1243, 281, 2, 632, 677]
+[:key_up_raw, 96, 0, 2, 633, 677]
+[:mouse_move, 1243, 280, 2, 634, 677]
+[:mouse_move, 1242, 279, 2, 635, 678]
+[:mouse_move, 1242, 277, 2, 636, 678]
+[:mouse_move, 1242, 274, 2, 637, 679]
+[:mouse_move, 1241, 271, 2, 638, 679]
+[:mouse_move, 1239, 268, 2, 639, 680]
+[:mouse_move, 1237, 264, 2, 640, 680]
+[:mouse_move, 1233, 261, 2, 641, 681]
+[:mouse_move, 1231, 259, 2, 642, 682]
+[:mouse_move, 1231, 258, 2, 643, 682]
+[:mouse_move, 1230, 256, 2, 644, 683]
+[:mouse_move, 1229, 255, 2, 645, 683]
+[:mouse_move, 1227, 252, 2, 646, 684]
+[:mouse_move, 1222, 247, 2, 647, 685]
+[:mouse_move, 1219, 244, 2, 648, 685]
+[:mouse_move, 1217, 242, 2, 649, 685]
+[:mouse_move, 1216, 241, 2, 650, 686]
+[:mouse_move, 1214, 240, 2, 651, 686]
+[:mouse_move, 1206, 237, 2, 652, 687]
+[:mouse_move, 1194, 232, 2, 653, 688]
+[:mouse_move, 1176, 228, 2, 654, 688]
+[:mouse_move, 1161, 224, 2, 655, 688]
+[:mouse_move, 1157, 224, 2, 656, 689]
+[:mouse_move, 1154, 222, 2, 657, 689]
+[:mouse_move, 1148, 217, 2, 658, 690]
+[:mouse_move, 1139, 205, 2, 659, 691]
+[:mouse_move, 1127, 186, 2, 660, 691]
+[:mouse_move, 1118, 165, 2, 661, 691]
+[:mouse_move, 1109, 140, 2, 662, 692]
+[:mouse_move, 1105, 120, 2, 663, 692]
+[:mouse_move, 1107, 107, 2, 664, 693]
+[:mouse_move, 1108, 105, 2, 665, 693]
+[:mouse_move, 1108, 104, 2, 666, 694]
+[:mouse_move, 1100, 103, 2, 667, 697]
+[:mouse_move, 1085, 101, 2, 668, 697]
+[:mouse_move, 1067, 99, 2, 669, 698]
+[:mouse_move, 1051, 96, 2, 670, 698]
+[:mouse_move, 1026, 94, 2, 671, 698]
+[:mouse_move, 988, 90, 2, 672, 699]
+[:mouse_move, 919, 86, 2, 673, 700]
+[:mouse_move, 868, 83, 2, 674, 700]
+[:mouse_move, 822, 83, 2, 675, 701]
+[:mouse_move, 796, 85, 2, 676, 701]
+[:mouse_move, 787, 87, 2, 677, 701]
+[:mouse_move, 786, 88, 2, 678, 702]
+[:mouse_move, 787, 88, 2, 679, 710]
+[:mouse_move, 789, 88, 2, 680, 718]
+[:mouse_move, 790, 89, 2, 681, 720]
+[:key_down_raw, 13, 0, 2, 682, 730]
diff --git a/samples/13_path_finding_algorithms/06_heuristic/app/main.rb b/samples/13_path_finding_algorithms/06_heuristic/app/main.rb
index cbdfca7..ad4c5ce 100644
--- a/samples/13_path_finding_algorithms/06_heuristic/app/main.rb
+++ b/samples/13_path_finding_algorithms/06_heuristic/app/main.rb
@@ -969,7 +969,7 @@ def tick args
end
# Every tick, new args are passed, and the Breadth First Search tick is called
- $heuristic_with_walls ||= Heuristic_With_Walls.new(args)
+ $heuristic_with_walls ||= Heuristic_With_Walls.new
$heuristic_with_walls.args = args
$heuristic_with_walls.tick
end
diff --git a/samples/13_path_finding_algorithms/06_heuristic/replay.txt b/samples/13_path_finding_algorithms/06_heuristic/replay.txt
new file mode 100644
index 0000000..1683449
--- /dev/null
+++ b/samples/13_path_finding_algorithms/06_heuristic/replay.txt
@@ -0,0 +1,719 @@
+replay_version 2.0
+stopped_at 1004
+seed 100
+recorded_at 2021-11-20 11:21:45 -0600
+[:mouse_button_up, 1, 0, 1, 1, 3]
+[:mouse_move, 767, 87, 2, 2, 22]
+[:mouse_move, 742, 87, 2, 3, 22]
+[:mouse_move, 713, 87, 2, 4, 23]
+[:mouse_move, 685, 87, 2, 5, 24]
+[:mouse_move, 656, 87, 2, 6, 25]
+[:mouse_move, 633, 87, 2, 7, 26]
+[:mouse_move, 616, 87, 2, 8, 27]
+[:mouse_move, 603, 85, 2, 9, 28]
+[:mouse_move, 587, 77, 2, 10, 29]
+[:mouse_move, 567, 69, 2, 11, 30]
+[:mouse_move, 543, 60, 2, 12, 31]
+[:mouse_move, 528, 55, 2, 13, 31]
+[:mouse_move, 517, 53, 2, 14, 32]
+[:mouse_move, 513, 51, 2, 15, 33]
+[:mouse_move, 511, 50, 2, 16, 34]
+[:mouse_move, 506, 49, 2, 17, 35]
+[:mouse_move, 501, 48, 2, 18, 36]
+[:mouse_move, 497, 46, 2, 19, 36]
+[:mouse_move, 496, 46, 2, 20, 37]
+[:mouse_move, 495, 46, 2, 21, 38]
+[:mouse_move, 490, 46, 2, 22, 39]
+[:mouse_move, 483, 46, 2, 23, 40]
+[:mouse_move, 470, 46, 2, 24, 41]
+[:mouse_move, 461, 46, 2, 25, 41]
+[:mouse_move, 456, 46, 2, 26, 42]
+[:mouse_move, 457, 46, 2, 27, 55]
+[:mouse_button_pressed, 1, 0, 1, 28, 58]
+[:mouse_move, 458, 46, 2, 29, 59]
+[:mouse_move, 460, 46, 2, 30, 62]
+[:mouse_move, 461, 46, 2, 31, 62]
+[:mouse_move, 463, 46, 2, 32, 63]
+[:mouse_move, 464, 46, 2, 33, 64]
+[:mouse_move, 465, 46, 2, 34, 64]
+[:mouse_move, 466, 46, 2, 35, 65]
+[:mouse_move, 467, 46, 2, 36, 65]
+[:mouse_move, 469, 46, 2, 37, 66]
+[:mouse_move, 470, 46, 2, 38, 66]
+[:mouse_move, 472, 46, 2, 39, 67]
+[:mouse_move, 473, 46, 2, 40, 67]
+[:mouse_move, 474, 46, 2, 41, 68]
+[:mouse_move, 477, 46, 2, 42, 68]
+[:mouse_move, 479, 46, 2, 43, 68]
+[:mouse_move, 480, 46, 2, 44, 69]
+[:mouse_move, 481, 46, 2, 45, 70]
+[:mouse_move, 483, 46, 2, 46, 71]
+[:mouse_move, 484, 46, 2, 47, 71]
+[:mouse_move, 485, 46, 2, 48, 71]
+[:mouse_move, 487, 46, 2, 49, 72]
+[:mouse_move, 489, 46, 2, 50, 72]
+[:mouse_move, 492, 46, 2, 51, 72]
+[:mouse_move, 496, 46, 2, 52, 72]
+[:mouse_move, 502, 47, 2, 53, 73]
+[:mouse_move, 507, 47, 2, 54, 73]
+[:mouse_move, 513, 47, 2, 55, 73]
+[:mouse_move, 519, 47, 2, 56, 73]
+[:mouse_move, 521, 47, 2, 57, 74]
+[:mouse_move, 524, 47, 2, 58, 74]
+[:mouse_move, 527, 47, 2, 59, 74]
+[:mouse_move, 531, 47, 2, 60, 74]
+[:mouse_move, 535, 47, 2, 61, 75]
+[:mouse_move, 539, 47, 2, 62, 75]
+[:mouse_move, 542, 47, 2, 63, 75]
+[:mouse_move, 544, 47, 2, 64, 75]
+[:mouse_move, 546, 47, 2, 65, 76]
+[:mouse_move, 550, 47, 2, 66, 76]
+[:mouse_move, 552, 47, 2, 67, 76]
+[:mouse_move, 553, 47, 2, 68, 76]
+[:mouse_move, 555, 47, 2, 69, 76]
+[:mouse_move, 556, 47, 2, 70, 77]
+[:mouse_move, 557, 47, 2, 71, 77]
+[:mouse_move, 558, 47, 2, 72, 77]
+[:mouse_move, 561, 47, 2, 73, 77]
+[:mouse_move, 563, 47, 2, 74, 78]
+[:mouse_move, 564, 47, 2, 75, 78]
+[:mouse_move, 566, 47, 2, 76, 78]
+[:mouse_move, 570, 47, 2, 77, 78]
+[:mouse_move, 571, 47, 2, 78, 78]
+[:mouse_move, 572, 47, 2, 79, 79]
+[:mouse_move, 573, 47, 2, 80, 79]
+[:mouse_move, 575, 47, 2, 81, 79]
+[:mouse_move, 581, 47, 2, 82, 80]
+[:mouse_move, 582, 47, 2, 83, 80]
+[:mouse_move, 585, 47, 2, 84, 80]
+[:mouse_move, 586, 47, 2, 85, 80]
+[:mouse_move, 588, 47, 2, 86, 80]
+[:mouse_move, 589, 47, 2, 87, 81]
+[:mouse_move, 591, 47, 2, 88, 81]
+[:mouse_move, 593, 47, 2, 89, 81]
+[:mouse_move, 594, 47, 2, 90, 81]
+[:mouse_move, 595, 47, 2, 91, 81]
+[:mouse_move, 596, 47, 2, 92, 82]
+[:mouse_move, 600, 47, 2, 93, 82]
+[:mouse_move, 602, 47, 2, 94, 82]
+[:mouse_move, 607, 47, 2, 95, 82]
+[:mouse_move, 611, 46, 2, 96, 82]
+[:mouse_move, 613, 46, 2, 97, 82]
+[:mouse_move, 614, 46, 2, 98, 83]
+[:mouse_move, 617, 46, 2, 99, 83]
+[:mouse_move, 621, 46, 2, 100, 83]
+[:mouse_move, 623, 46, 2, 101, 83]
+[:mouse_move, 625, 46, 2, 102, 83]
+[:mouse_move, 626, 46, 2, 103, 83]
+[:mouse_move, 627, 46, 2, 104, 84]
+[:mouse_move, 629, 46, 2, 105, 84]
+[:mouse_move, 632, 46, 2, 106, 84]
+[:mouse_move, 634, 46, 2, 107, 84]
+[:mouse_move, 636, 46, 2, 108, 84]
+[:mouse_move, 637, 46, 2, 109, 84]
+[:mouse_move, 639, 45, 2, 110, 85]
+[:mouse_move, 641, 45, 2, 111, 85]
+[:mouse_move, 643, 45, 2, 112, 85]
+[:mouse_move, 646, 44, 2, 113, 85]
+[:mouse_move, 648, 43, 2, 114, 85]
+[:mouse_move, 650, 43, 2, 115, 85]
+[:mouse_move, 652, 43, 2, 116, 85]
+[:mouse_move, 654, 43, 2, 117, 86]
+[:mouse_move, 661, 42, 2, 118, 86]
+[:mouse_move, 667, 42, 2, 119, 86]
+[:mouse_move, 676, 42, 2, 120, 86]
+[:mouse_move, 682, 42, 2, 121, 86]
+[:mouse_move, 691, 41, 2, 122, 86]
+[:mouse_move, 694, 41, 2, 123, 86]
+[:mouse_move, 697, 41, 2, 124, 87]
+[:mouse_move, 700, 41, 2, 125, 87]
+[:mouse_move, 703, 41, 2, 126, 87]
+[:mouse_move, 704, 41, 2, 127, 87]
+[:mouse_move, 706, 41, 2, 128, 87]
+[:mouse_move, 707, 41, 2, 129, 87]
+[:mouse_move, 709, 41, 2, 130, 87]
+[:mouse_move, 710, 41, 2, 131, 87]
+[:mouse_move, 713, 41, 2, 132, 88]
+[:mouse_move, 717, 41, 2, 133, 88]
+[:mouse_move, 721, 41, 2, 134, 88]
+[:mouse_move, 725, 41, 2, 135, 88]
+[:mouse_move, 726, 41, 2, 136, 88]
+[:mouse_move, 728, 41, 2, 137, 88]
+[:mouse_move, 732, 41, 2, 138, 88]
+[:mouse_move, 742, 41, 2, 139, 88]
+[:mouse_move, 754, 43, 2, 140, 89]
+[:mouse_move, 769, 45, 2, 141, 89]
+[:mouse_move, 772, 45, 2, 142, 89]
+[:mouse_move, 776, 45, 2, 143, 89]
+[:mouse_move, 777, 45, 2, 144, 89]
+[:mouse_move, 778, 45, 2, 145, 91]
+[:mouse_move, 778, 44, 2, 146, 91]
+[:mouse_move, 779, 44, 2, 147, 91]
+[:mouse_move, 780, 44, 2, 148, 91]
+[:mouse_move, 781, 44, 2, 149, 91]
+[:mouse_move, 782, 44, 2, 150, 92]
+[:mouse_move, 784, 44, 2, 151, 92]
+[:mouse_move, 785, 44, 2, 152, 92]
+[:mouse_move, 786, 44, 2, 153, 92]
+[:mouse_move, 787, 44, 2, 154, 92]
+[:mouse_move, 788, 44, 2, 155, 92]
+[:mouse_move, 789, 44, 2, 156, 93]
+[:mouse_move, 790, 44, 2, 157, 93]
+[:mouse_move, 790, 43, 2, 158, 93]
+[:mouse_move, 791, 43, 2, 159, 93]
+[:mouse_move, 792, 43, 2, 160, 93]
+[:mouse_move, 793, 43, 2, 161, 93]
+[:mouse_move, 791, 43, 2, 162, 94]
+[:mouse_move, 790, 43, 2, 163, 95]
+[:mouse_move, 785, 43, 2, 164, 95]
+[:mouse_move, 775, 43, 2, 165, 95]
+[:mouse_move, 762, 43, 2, 166, 95]
+[:mouse_move, 745, 43, 2, 167, 95]
+[:mouse_move, 727, 43, 2, 168, 95]
+[:mouse_move, 704, 43, 2, 169, 95]
+[:mouse_move, 680, 43, 2, 170, 95]
+[:mouse_move, 653, 43, 2, 171, 95]
+[:mouse_move, 628, 43, 2, 172, 95]
+[:mouse_move, 606, 43, 2, 173, 96]
+[:mouse_move, 589, 43, 2, 174, 96]
+[:mouse_move, 577, 43, 2, 175, 96]
+[:mouse_move, 568, 43, 2, 176, 96]
+[:mouse_move, 558, 43, 2, 177, 96]
+[:mouse_move, 552, 43, 2, 178, 96]
+[:mouse_move, 544, 43, 2, 179, 96]
+[:mouse_move, 532, 43, 2, 180, 97]
+[:mouse_move, 523, 43, 2, 181, 97]
+[:mouse_move, 517, 43, 2, 182, 97]
+[:mouse_move, 512, 43, 2, 183, 97]
+[:mouse_move, 508, 43, 2, 184, 97]
+[:mouse_move, 506, 43, 2, 185, 98]
+[:mouse_move, 503, 43, 2, 186, 98]
+[:mouse_move, 501, 43, 2, 187, 98]
+[:mouse_move, 500, 43, 2, 188, 98]
+[:mouse_move, 498, 43, 2, 189, 98]
+[:mouse_move, 495, 43, 2, 190, 99]
+[:mouse_move, 492, 43, 2, 191, 99]
+[:mouse_move, 489, 43, 2, 192, 99]
+[:mouse_move, 485, 43, 2, 193, 99]
+[:mouse_move, 480, 43, 2, 194, 100]
+[:mouse_move, 476, 43, 2, 195, 100]
+[:mouse_move, 472, 43, 2, 196, 100]
+[:mouse_move, 471, 43, 2, 197, 101]
+[:mouse_move, 470, 43, 2, 198, 102]
+[:mouse_move, 469, 43, 2, 199, 102]
+[:mouse_move, 468, 43, 2, 200, 103]
+[:mouse_move, 467, 43, 2, 201, 105]
+[:mouse_move, 467, 44, 2, 202, 111]
+[:mouse_move, 468, 43, 2, 203, 114]
+[:mouse_move, 469, 43, 2, 204, 115]
+[:mouse_move, 474, 43, 2, 205, 115]
+[:mouse_move, 479, 43, 2, 206, 116]
+[:mouse_move, 482, 43, 2, 207, 116]
+[:mouse_move, 484, 42, 2, 208, 117]
+[:mouse_move, 486, 42, 2, 209, 118]
+[:mouse_move, 488, 42, 2, 210, 118]
+[:mouse_move, 490, 42, 2, 211, 118]
+[:mouse_move, 492, 42, 2, 212, 118]
+[:mouse_move, 493, 42, 2, 213, 120]
+[:mouse_button_up, 1, 0, 1, 214, 123]
+[:mouse_move, 495, 47, 2, 215, 127]
+[:mouse_move, 498, 56, 2, 216, 128]
+[:mouse_move, 500, 63, 2, 217, 128]
+[:mouse_move, 500, 71, 2, 218, 129]
+[:mouse_move, 500, 73, 2, 219, 129]
+[:mouse_move, 500, 75, 2, 220, 130]
+[:mouse_move, 499, 78, 2, 221, 131]
+[:mouse_move, 497, 80, 2, 222, 131]
+[:mouse_move, 495, 82, 2, 223, 132]
+[:mouse_move, 494, 83, 2, 224, 132]
+[:mouse_move, 493, 83, 2, 225, 133]
+[:mouse_move, 493, 84, 2, 226, 141]
+[:mouse_move, 498, 90, 2, 227, 141]
+[:mouse_move, 506, 95, 2, 228, 142]
+[:mouse_move, 509, 98, 2, 229, 142]
+[:mouse_move, 510, 98, 2, 230, 143]
+[:mouse_move, 509, 98, 2, 231, 147]
+[:mouse_move, 507, 98, 2, 232, 148]
+[:mouse_move, 506, 97, 2, 233, 151]
+[:mouse_button_pressed, 1, 0, 1, 234, 152]
+[:mouse_button_up, 1, 0, 1, 235, 154]
+[:mouse_button_pressed, 1, 0, 1, 236, 170]
+[:mouse_move, 507, 97, 2, 237, 170]
+[:mouse_button_up, 1, 0, 1, 238, 173]
+[:mouse_button_pressed, 1, 0, 1, 239, 174]
+[:mouse_button_up, 1, 0, 1, 240, 178]
+[:mouse_button_pressed, 1, 0, 1, 241, 180]
+[:mouse_button_up, 1, 0, 1, 242, 183]
+[:mouse_button_pressed, 1, 0, 1, 243, 185]
+[:mouse_button_up, 1, 0, 1, 244, 189]
+[:mouse_button_pressed, 1, 0, 1, 245, 190]
+[:mouse_button_up, 1, 0, 1, 246, 195]
+[:mouse_button_pressed, 1, 0, 1, 247, 196]
+[:mouse_button_up, 1, 0, 1, 248, 199]
+[:mouse_button_pressed, 1, 0, 1, 249, 201]
+[:mouse_button_up, 1, 0, 1, 250, 203]
+[:mouse_move, 508, 97, 2, 251, 205]
+[:mouse_button_pressed, 1, 0, 1, 252, 205]
+[:mouse_button_up, 1, 0, 1, 253, 209]
+[:mouse_button_pressed, 1, 0, 1, 254, 210]
+[:mouse_button_up, 1, 0, 1, 255, 214]
+[:mouse_button_pressed, 1, 0, 1, 256, 215]
+[:mouse_button_up, 1, 0, 1, 257, 219]
+[:mouse_button_pressed, 1, 0, 1, 258, 222]
+[:mouse_button_up, 1, 0, 1, 259, 226]
+[:mouse_move, 508, 98, 2, 260, 226]
+[:mouse_button_pressed, 1, 0, 1, 261, 229]
+[:mouse_button_up, 1, 0, 1, 262, 232]
+[:mouse_move, 509, 98, 2, 263, 235]
+[:mouse_move, 509, 97, 2, 264, 237]
+[:mouse_move, 515, 96, 2, 265, 238]
+[:mouse_move, 529, 94, 2, 266, 239]
+[:mouse_move, 573, 93, 2, 267, 240]
+[:mouse_move, 609, 93, 2, 268, 242]
+[:mouse_move, 639, 93, 2, 269, 242]
+[:mouse_move, 663, 93, 2, 270, 243]
+[:mouse_move, 680, 93, 2, 271, 244]
+[:mouse_move, 691, 93, 2, 272, 245]
+[:mouse_move, 695, 93, 2, 273, 246]
+[:mouse_move, 696, 93, 2, 274, 247]
+[:mouse_move, 698, 93, 2, 275, 248]
+[:mouse_move, 701, 94, 2, 276, 249]
+[:mouse_move, 702, 94, 2, 277, 250]
+[:mouse_move, 703, 94, 2, 278, 251]
+[:mouse_move, 705, 94, 2, 279, 256]
+[:mouse_move, 707, 94, 2, 280, 256]
+[:mouse_move, 712, 94, 2, 281, 257]
+[:mouse_move, 718, 94, 2, 282, 258]
+[:mouse_move, 727, 94, 2, 283, 259]
+[:mouse_move, 734, 94, 2, 284, 260]
+[:mouse_move, 736, 94, 2, 285, 261]
+[:mouse_move, 737, 94, 2, 286, 265]
+[:mouse_move, 738, 94, 2, 287, 271]
+[:mouse_button_pressed, 1, 0, 1, 288, 272]
+[:mouse_button_up, 1, 0, 1, 289, 275]
+[:mouse_button_pressed, 1, 0, 1, 290, 280]
+[:mouse_button_up, 1, 0, 1, 291, 284]
+[:mouse_move, 739, 94, 2, 292, 287]
+[:mouse_button_pressed, 1, 0, 1, 293, 288]
+[:mouse_button_up, 1, 0, 1, 294, 292]
+[:mouse_button_pressed, 1, 0, 1, 295, 296]
+[:mouse_button_up, 1, 0, 1, 296, 300]
+[:mouse_button_pressed, 1, 0, 1, 297, 303]
+[:mouse_button_up, 1, 0, 1, 298, 306]
+[:mouse_move, 740, 94, 2, 299, 308]
+[:mouse_button_pressed, 1, 0, 1, 300, 309]
+[:mouse_button_up, 1, 0, 1, 301, 312]
+[:mouse_button_pressed, 1, 0, 1, 302, 317]
+[:mouse_button_up, 1, 0, 1, 303, 319]
+[:mouse_move, 733, 100, 2, 304, 321]
+[:mouse_move, 716, 115, 2, 305, 322]
+[:mouse_move, 694, 133, 2, 306, 322]
+[:mouse_move, 669, 152, 2, 307, 323]
+[:mouse_move, 645, 172, 2, 308, 324]
+[:mouse_move, 618, 207, 2, 309, 325]
+[:mouse_move, 602, 229, 2, 310, 325]
+[:mouse_move, 586, 244, 2, 311, 326]
+[:mouse_move, 571, 255, 2, 312, 326]
+[:mouse_move, 560, 263, 2, 313, 327]
+[:mouse_move, 558, 268, 2, 314, 328]
+[:mouse_move, 557, 274, 2, 315, 329]
+[:mouse_move, 559, 279, 2, 316, 329]
+[:mouse_move, 559, 284, 2, 317, 329]
+[:mouse_move, 553, 295, 2, 318, 330]
+[:mouse_move, 538, 310, 2, 319, 331]
+[:mouse_move, 515, 328, 2, 320, 332]
+[:mouse_move, 476, 357, 2, 321, 332]
+[:mouse_move, 448, 381, 2, 322, 333]
+[:mouse_move, 423, 406, 2, 323, 333]
+[:mouse_move, 404, 428, 2, 324, 334]
+[:mouse_move, 381, 448, 2, 325, 335]
+[:mouse_move, 354, 469, 2, 326, 336]
+[:mouse_move, 325, 492, 2, 327, 336]
+[:mouse_move, 297, 512, 2, 328, 337]
+[:mouse_move, 274, 526, 2, 329, 337]
+[:mouse_move, 252, 535, 2, 330, 338]
+[:mouse_move, 237, 544, 2, 331, 339]
+[:mouse_move, 227, 553, 2, 332, 340]
+[:mouse_move, 226, 555, 2, 333, 340]
+[:mouse_move, 226, 556, 2, 334, 341]
+[:mouse_move, 228, 557, 2, 335, 342]
+[:mouse_move, 239, 558, 2, 336, 343]
+[:mouse_move, 266, 563, 2, 337, 343]
+[:mouse_move, 303, 568, 2, 338, 344]
+[:mouse_move, 333, 575, 2, 339, 344]
+[:mouse_move, 356, 581, 2, 340, 345]
+[:mouse_move, 375, 587, 2, 341, 346]
+[:mouse_move, 390, 591, 2, 342, 347]
+[:mouse_move, 407, 598, 2, 343, 347]
+[:mouse_move, 414, 600, 2, 344, 348]
+[:mouse_move, 415, 600, 2, 345, 348]
+[:mouse_move, 416, 601, 2, 346, 349]
+[:mouse_move, 419, 602, 2, 347, 350]
+[:mouse_move, 420, 602, 2, 348, 350]
+[:mouse_button_pressed, 1, 0, 1, 349, 352]
+[:mouse_button_up, 1, 0, 1, 350, 354]
+[:mouse_move, 421, 602, 2, 351, 354]
+[:mouse_move, 422, 602, 2, 352, 356]
+[:mouse_move, 422, 603, 2, 353, 370]
+[:mouse_move, 422, 602, 2, 354, 373]
+[:mouse_move, 423, 595, 2, 355, 374]
+[:mouse_move, 426, 589, 2, 356, 374]
+[:mouse_move, 429, 583, 2, 357, 375]
+[:mouse_move, 429, 582, 2, 358, 376]
+[:mouse_move, 424, 580, 2, 359, 377]
+[:mouse_move, 416, 580, 2, 360, 378]
+[:mouse_move, 410, 579, 2, 361, 378]
+[:mouse_move, 406, 577, 2, 362, 379]
+[:mouse_move, 401, 575, 2, 363, 380]
+[:mouse_move, 392, 573, 2, 364, 380]
+[:mouse_move, 381, 571, 2, 365, 381]
+[:mouse_move, 369, 571, 2, 366, 382]
+[:mouse_move, 354, 571, 2, 367, 382]
+[:mouse_move, 333, 571, 2, 368, 383]
+[:mouse_move, 306, 571, 2, 369, 383]
+[:mouse_move, 281, 576, 2, 370, 384]
+[:mouse_move, 249, 585, 2, 371, 385]
+[:mouse_move, 230, 586, 2, 372, 385]
+[:mouse_move, 213, 590, 2, 373, 386]
+[:mouse_move, 201, 593, 2, 374, 386]
+[:mouse_move, 192, 597, 2, 375, 387]
+[:mouse_move, 188, 599, 2, 376, 388]
+[:mouse_move, 186, 601, 2, 377, 388]
+[:mouse_move, 185, 601, 2, 378, 391]
+[:mouse_move, 183, 599, 2, 379, 391]
+[:mouse_move, 183, 598, 2, 380, 393]
+[:mouse_move, 184, 596, 2, 381, 393]
+[:mouse_move, 188, 594, 2, 382, 394]
+[:mouse_move, 199, 591, 2, 383, 395]
+[:mouse_move, 221, 586, 2, 384, 395]
+[:mouse_move, 246, 578, 2, 385, 395]
+[:mouse_move, 262, 574, 2, 386, 396]
+[:mouse_move, 266, 573, 2, 387, 397]
+[:mouse_move, 271, 573, 2, 388, 398]
+[:mouse_move, 279, 573, 2, 389, 398]
+[:mouse_move, 285, 573, 2, 390, 399]
+[:mouse_move, 293, 574, 2, 391, 399]
+[:mouse_move, 302, 576, 2, 392, 400]
+[:mouse_move, 316, 580, 2, 393, 401]
+[:mouse_move, 333, 583, 2, 394, 402]
+[:mouse_move, 351, 583, 2, 395, 402]
+[:mouse_move, 363, 583, 2, 396, 403]
+[:mouse_move, 369, 583, 2, 397, 403]
+[:mouse_move, 379, 583, 2, 398, 404]
+[:mouse_move, 385, 583, 2, 399, 404]
+[:mouse_move, 390, 583, 2, 400, 405]
+[:mouse_move, 392, 583, 2, 401, 406]
+[:mouse_move, 394, 583, 2, 402, 406]
+[:mouse_move, 395, 583, 2, 403, 407]
+[:mouse_move, 395, 580, 2, 404, 408]
+[:mouse_move, 395, 578, 2, 405, 408]
+[:mouse_move, 395, 572, 2, 406, 409]
+[:mouse_move, 396, 565, 2, 407, 410]
+[:mouse_move, 402, 560, 2, 408, 410]
+[:mouse_move, 404, 559, 2, 409, 411]
+[:mouse_move, 405, 559, 2, 410, 413]
+[:mouse_move, 406, 559, 2, 411, 414]
+[:mouse_move, 407, 560, 2, 412, 416]
+[:mouse_move, 407, 561, 2, 413, 417]
+[:mouse_move, 408, 561, 2, 414, 418]
+[:mouse_move, 409, 563, 2, 415, 419]
+[:mouse_move, 410, 564, 2, 416, 420]
+[:mouse_move, 411, 565, 2, 417, 421]
+[:mouse_move, 411, 566, 2, 418, 423]
+[:mouse_button_pressed, 1, 0, 1, 419, 424]
+[:mouse_button_up, 1, 0, 1, 420, 425]
+[:mouse_move, 411, 562, 2, 421, 426]
+[:mouse_move, 411, 547, 2, 422, 426]
+[:mouse_move, 411, 532, 2, 423, 427]
+[:mouse_move, 417, 513, 2, 424, 427]
+[:mouse_move, 421, 503, 2, 425, 428]
+[:mouse_move, 424, 496, 2, 426, 429]
+[:mouse_move, 425, 494, 2, 427, 430]
+[:mouse_move, 425, 493, 2, 428, 430]
+[:mouse_move, 426, 492, 2, 429, 432]
+[:mouse_move, 426, 493, 2, 430, 436]
+[:mouse_move, 426, 494, 2, 431, 437]
+[:mouse_move, 426, 495, 2, 432, 438]
+[:mouse_move, 426, 496, 2, 433, 438]
+[:mouse_move, 425, 498, 2, 434, 440]
+[:mouse_move, 423, 503, 2, 435, 441]
+[:mouse_move, 422, 506, 2, 436, 441]
+[:mouse_move, 422, 507, 2, 437, 442]
+[:mouse_move, 422, 508, 2, 438, 446]
+[:mouse_move, 422, 514, 2, 439, 447]
+[:mouse_move, 421, 525, 2, 440, 448]
+[:mouse_move, 418, 533, 2, 441, 448]
+[:mouse_move, 416, 536, 2, 442, 449]
+[:mouse_move, 415, 537, 2, 443, 449]
+[:mouse_move, 415, 538, 2, 444, 450]
+[:mouse_button_pressed, 1, 0, 1, 445, 455]
+[:mouse_move, 414, 538, 2, 446, 456]
+[:mouse_button_up, 1, 0, 1, 447, 456]
+[:mouse_move, 412, 535, 2, 448, 456]
+[:mouse_move, 409, 529, 2, 449, 456]
+[:mouse_move, 408, 514, 2, 450, 457]
+[:mouse_move, 408, 502, 2, 451, 458]
+[:mouse_move, 411, 497, 2, 452, 458]
+[:mouse_move, 413, 492, 2, 453, 459]
+[:mouse_move, 415, 491, 2, 454, 460]
+[:mouse_move, 415, 490, 2, 455, 460]
+[:mouse_move, 415, 489, 2, 456, 461]
+[:mouse_move, 416, 489, 2, 457, 461]
+[:mouse_move, 416, 488, 2, 458, 462]
+[:mouse_move, 416, 487, 2, 459, 464]
+[:mouse_button_pressed, 1, 0, 1, 460, 465]
+[:mouse_button_up, 1, 0, 1, 461, 468]
+[:mouse_move, 417, 487, 2, 462, 470]
+[:mouse_move, 417, 486, 2, 463, 471]
+[:mouse_move, 418, 486, 2, 464, 471]
+[:mouse_move, 418, 485, 2, 465, 472]
+[:mouse_move, 418, 483, 2, 466, 473]
+[:mouse_move, 418, 478, 2, 467, 474]
+[:mouse_move, 418, 473, 2, 468, 474]
+[:mouse_move, 419, 471, 2, 469, 475]
+[:mouse_move, 420, 470, 2, 470, 475]
+[:mouse_move, 420, 469, 2, 471, 477]
+[:mouse_move, 420, 468, 2, 472, 477]
+[:mouse_move, 421, 467, 2, 473, 479]
+[:mouse_move, 421, 464, 2, 474, 479]
+[:mouse_move, 421, 462, 2, 475, 480]
+[:mouse_move, 422, 460, 2, 476, 480]
+[:mouse_button_pressed, 1, 0, 1, 477, 482]
+[:mouse_button_up, 1, 0, 1, 478, 484]
+[:mouse_move, 422, 459, 2, 479, 484]
+[:mouse_move, 422, 451, 2, 480, 484]
+[:mouse_move, 424, 443, 2, 481, 485]
+[:mouse_move, 428, 436, 2, 482, 486]
+[:mouse_move, 431, 431, 2, 483, 487]
+[:mouse_move, 433, 428, 2, 484, 487]
+[:mouse_move, 435, 424, 2, 485, 488]
+[:mouse_move, 435, 422, 2, 486, 488]
+[:mouse_move, 435, 420, 2, 487, 489]
+[:mouse_move, 435, 419, 2, 488, 490]
+[:mouse_move, 435, 418, 2, 489, 490]
+[:mouse_button_pressed, 1, 0, 1, 490, 494]
+[:mouse_button_up, 1, 0, 1, 491, 497]
+[:mouse_move, 435, 415, 2, 492, 501]
+[:mouse_move, 435, 408, 2, 493, 502]
+[:mouse_move, 435, 401, 2, 494, 503]
+[:mouse_move, 435, 398, 2, 495, 503]
+[:mouse_move, 435, 396, 2, 496, 504]
+[:mouse_move, 435, 395, 2, 497, 504]
+[:mouse_move, 435, 394, 2, 498, 507]
+[:mouse_move, 434, 393, 2, 499, 507]
+[:mouse_move, 434, 389, 2, 500, 508]
+[:mouse_move, 433, 388, 2, 501, 509]
+[:mouse_move, 433, 385, 2, 502, 509]
+[:mouse_move, 433, 384, 2, 503, 510]
+[:mouse_button_pressed, 1, 0, 1, 504, 514]
+[:mouse_button_up, 1, 0, 1, 505, 516]
+[:mouse_move, 433, 383, 2, 506, 517]
+[:mouse_move, 433, 377, 2, 507, 518]
+[:mouse_move, 433, 372, 2, 508, 518]
+[:mouse_move, 433, 365, 2, 509, 519]
+[:mouse_move, 433, 360, 2, 510, 520]
+[:mouse_move, 433, 353, 2, 511, 520]
+[:mouse_move, 433, 346, 2, 512, 520]
+[:mouse_move, 432, 338, 2, 513, 521]
+[:mouse_move, 431, 331, 2, 514, 522]
+[:mouse_move, 431, 328, 2, 515, 523]
+[:mouse_move, 431, 326, 2, 516, 523]
+[:mouse_move, 431, 325, 2, 517, 524]
+[:mouse_move, 430, 324, 2, 518, 524]
+[:mouse_button_pressed, 1, 0, 1, 519, 528]
+[:mouse_button_up, 1, 0, 1, 520, 531]
+[:mouse_move, 430, 323, 2, 521, 533]
+[:mouse_move, 430, 322, 2, 522, 534]
+[:mouse_move, 430, 321, 2, 523, 534]
+[:mouse_move, 429, 319, 2, 524, 535]
+[:mouse_move, 428, 316, 2, 525, 536]
+[:mouse_move, 428, 315, 2, 526, 537]
+[:mouse_move, 428, 314, 2, 527, 540]
+[:mouse_move, 428, 313, 2, 528, 540]
+[:mouse_move, 427, 309, 2, 529, 540]
+[:mouse_move, 427, 308, 2, 530, 541]
+[:mouse_move, 426, 306, 2, 531, 542]
+[:mouse_move, 426, 304, 2, 532, 543]
+[:mouse_move, 426, 303, 2, 533, 543]
+[:mouse_button_pressed, 1, 0, 1, 534, 544]
+[:mouse_button_up, 1, 0, 1, 535, 546]
+[:mouse_move, 426, 302, 2, 536, 548]
+[:mouse_move, 426, 299, 2, 537, 548]
+[:mouse_move, 426, 294, 2, 538, 549]
+[:mouse_move, 426, 288, 2, 539, 550]
+[:mouse_move, 426, 282, 2, 540, 550]
+[:mouse_move, 426, 276, 2, 541, 550]
+[:mouse_move, 426, 273, 2, 542, 551]
+[:mouse_move, 426, 272, 2, 543, 552]
+[:mouse_move, 426, 271, 2, 544, 553]
+[:mouse_button_pressed, 1, 0, 1, 545, 556]
+[:mouse_button_up, 1, 0, 1, 546, 557]
+[:mouse_move, 426, 269, 2, 547, 558]
+[:mouse_move, 426, 266, 2, 548, 559]
+[:mouse_move, 426, 263, 2, 549, 559]
+[:mouse_move, 426, 258, 2, 550, 560]
+[:mouse_move, 425, 256, 2, 551, 561]
+[:mouse_move, 424, 251, 2, 552, 561]
+[:mouse_move, 424, 246, 2, 553, 562]
+[:mouse_move, 424, 244, 2, 554, 563]
+[:mouse_move, 424, 241, 2, 555, 563]
+[:mouse_move, 424, 238, 2, 556, 563]
+[:mouse_move, 423, 236, 2, 557, 564]
+[:mouse_move, 423, 235, 2, 558, 565]
+[:mouse_button_pressed, 1, 0, 1, 559, 568]
+[:mouse_button_up, 1, 0, 1, 560, 569]
+[:mouse_move, 423, 233, 2, 561, 570]
+[:mouse_move, 423, 228, 2, 562, 570]
+[:mouse_move, 423, 224, 2, 563, 571]
+[:mouse_move, 423, 218, 2, 564, 572]
+[:mouse_move, 423, 214, 2, 565, 572]
+[:mouse_move, 423, 210, 2, 566, 573]
+[:mouse_move, 423, 209, 2, 567, 573]
+[:mouse_move, 423, 208, 2, 568, 574]
+[:mouse_move, 423, 207, 2, 569, 575]
+[:mouse_move, 423, 206, 2, 570, 577]
+[:mouse_button_pressed, 1, 0, 1, 571, 582]
+[:mouse_button_up, 1, 0, 1, 572, 583]
+[:mouse_move, 423, 205, 2, 573, 586]
+[:mouse_move, 423, 204, 2, 574, 587]
+[:mouse_move, 423, 201, 2, 575, 587]
+[:mouse_move, 423, 197, 2, 576, 588]
+[:mouse_move, 422, 195, 2, 577, 589]
+[:mouse_move, 422, 191, 2, 578, 589]
+[:mouse_move, 422, 189, 2, 579, 589]
+[:mouse_move, 422, 188, 2, 580, 590]
+[:mouse_move, 422, 187, 2, 581, 591]
+[:mouse_move, 422, 186, 2, 582, 592]
+[:mouse_move, 422, 188, 2, 583, 606]
+[:mouse_move, 422, 193, 2, 584, 607]
+[:mouse_move, 423, 202, 2, 585, 608]
+[:mouse_move, 425, 216, 2, 586, 609]
+[:mouse_move, 426, 223, 2, 587, 609]
+[:mouse_move, 426, 225, 2, 588, 609]
+[:mouse_button_pressed, 1, 0, 1, 589, 613]
+[:mouse_button_up, 1, 0, 1, 590, 615]
+[:mouse_move, 426, 224, 2, 591, 615]
+[:mouse_move, 424, 220, 2, 592, 615]
+[:mouse_move, 424, 209, 2, 593, 616]
+[:mouse_move, 421, 192, 2, 594, 617]
+[:mouse_move, 419, 182, 2, 595, 617]
+[:mouse_move, 418, 180, 2, 596, 618]
+[:mouse_move, 418, 179, 2, 597, 618]
+[:mouse_button_pressed, 1, 0, 1, 598, 624]
+[:mouse_button_up, 1, 0, 1, 599, 625]
+[:mouse_move, 418, 178, 2, 600, 626]
+[:mouse_move, 418, 174, 2, 601, 627]
+[:mouse_move, 418, 171, 2, 602, 628]
+[:mouse_move, 418, 164, 2, 603, 628]
+[:mouse_move, 417, 161, 2, 604, 629]
+[:mouse_move, 415, 156, 2, 605, 630]
+[:mouse_move, 415, 155, 2, 606, 631]
+[:mouse_move, 415, 154, 2, 607, 633]
+[:mouse_move, 415, 153, 2, 608, 634]
+[:mouse_move, 415, 152, 2, 609, 635]
+[:mouse_move, 416, 151, 2, 610, 635]
+[:mouse_move, 416, 150, 2, 611, 636]
+[:mouse_move, 416, 149, 2, 612, 637]
+[:mouse_move, 417, 147, 2, 613, 638]
+[:mouse_move, 418, 144, 2, 614, 639]
+[:mouse_move, 418, 142, 2, 615, 640]
+[:mouse_move, 419, 141, 2, 616, 640]
+[:mouse_move, 419, 139, 2, 617, 641]
+[:mouse_move, 420, 138, 2, 618, 642]
+[:mouse_move, 420, 137, 2, 619, 642]
+[:mouse_button_pressed, 1, 0, 1, 620, 643]
+[:mouse_button_up, 1, 0, 1, 621, 645]
+[:mouse_move, 420, 138, 2, 622, 649]
+[:mouse_move, 420, 141, 2, 623, 650]
+[:mouse_move, 421, 142, 2, 624, 651]
+[:mouse_move, 421, 147, 2, 625, 652]
+[:mouse_move, 421, 148, 2, 626, 653]
+[:mouse_move, 421, 149, 2, 627, 653]
+[:mouse_move, 421, 148, 2, 628, 674]
+[:mouse_move, 420, 147, 2, 629, 675]
+[:mouse_move, 420, 146, 2, 630, 675]
+[:mouse_move, 420, 142, 2, 631, 677]
+[:mouse_move, 422, 139, 2, 632, 677]
+[:mouse_move, 422, 138, 2, 633, 681]
+[:mouse_move, 421, 138, 2, 634, 686]
+[:mouse_move, 441, 132, 2, 635, 691]
+[:mouse_move, 483, 120, 2, 636, 692]
+[:mouse_move, 539, 103, 2, 637, 693]
+[:mouse_move, 590, 85, 2, 638, 693]
+[:mouse_move, 658, 61, 2, 639, 694]
+[:mouse_move, 677, 52, 2, 640, 694]
+[:mouse_move, 725, 34, 2, 641, 695]
+[:mouse_move, 739, 30, 2, 642, 696]
+[:mouse_move, 775, 26, 2, 643, 697]
+[:mouse_move, 791, 26, 2, 644, 697]
+[:mouse_move, 796, 26, 2, 645, 698]
+[:mouse_move, 801, 25, 2, 646, 699]
+[:mouse_move, 802, 25, 2, 647, 700]
+[:mouse_move, 803, 25, 2, 648, 701]
+[:mouse_move, 804, 25, 2, 649, 702]
+[:mouse_move, 804, 28, 2, 650, 703]
+[:mouse_move, 804, 33, 2, 651, 704]
+[:mouse_move, 793, 48, 2, 652, 705]
+[:mouse_move, 787, 54, 2, 653, 705]
+[:mouse_move, 769, 66, 2, 654, 706]
+[:mouse_move, 766, 69, 2, 655, 707]
+[:mouse_move, 759, 75, 2, 656, 708]
+[:mouse_move, 756, 78, 2, 657, 708]
+[:mouse_move, 754, 82, 2, 658, 709]
+[:mouse_move, 750, 88, 2, 659, 710]
+[:mouse_move, 747, 97, 2, 660, 710]
+[:mouse_move, 747, 98, 2, 661, 711]
+[:mouse_move, 747, 100, 2, 662, 712]
+[:mouse_move, 747, 101, 2, 663, 717]
+[:mouse_button_pressed, 1, 0, 1, 664, 717]
+[:mouse_button_up, 1, 0, 1, 665, 720]
+[:mouse_button_pressed, 1, 0, 1, 666, 723]
+[:mouse_button_up, 1, 0, 1, 667, 727]
+[:mouse_button_pressed, 1, 0, 1, 668, 731]
+[:mouse_move, 747, 100, 2, 669, 731]
+[:mouse_button_up, 1, 0, 1, 670, 734]
+[:mouse_button_pressed, 1, 0, 1, 671, 737]
+[:mouse_button_up, 1, 0, 1, 672, 741]
+[:mouse_button_pressed, 1, 0, 1, 673, 744]
+[:mouse_button_up, 1, 0, 1, 674, 747]
+[:mouse_button_pressed, 1, 0, 1, 675, 751]
+[:mouse_button_up, 1, 0, 1, 676, 753]
+[:mouse_button_pressed, 1, 0, 1, 677, 757]
+[:mouse_move, 748, 100, 2, 678, 757]
+[:mouse_button_up, 1, 0, 1, 679, 760]
+[:mouse_button_pressed, 1, 0, 1, 680, 764]
+[:mouse_button_up, 1, 0, 1, 681, 766]
+[:mouse_button_pressed, 1, 0, 1, 682, 769]
+[:mouse_button_up, 1, 0, 1, 683, 772]
+[:mouse_button_pressed, 1, 0, 1, 684, 775]
+[:mouse_button_up, 1, 0, 1, 685, 778]
+[:mouse_move, 748, 99, 2, 686, 779]
+[:mouse_move, 749, 99, 2, 687, 781]
+[:mouse_button_pressed, 1, 0, 1, 688, 781]
+[:mouse_button_up, 1, 0, 1, 689, 785]
+[:mouse_button_pressed, 1, 0, 1, 690, 788]
+[:mouse_button_up, 1, 0, 1, 691, 790]
+[:mouse_button_pressed, 1, 0, 1, 692, 795]
+[:mouse_button_up, 1, 0, 1, 693, 797]
+[:mouse_button_pressed, 1, 0, 1, 694, 800]
+[:mouse_button_up, 1, 0, 1, 695, 802]
+[:mouse_move, 748, 99, 2, 696, 802]
+[:mouse_move, 738, 99, 2, 697, 803]
+[:mouse_move, 729, 99, 2, 698, 803]
+[:mouse_move, 709, 99, 2, 699, 804]
+[:mouse_move, 689, 96, 2, 700, 805]
+[:mouse_move, 674, 95, 2, 701, 806]
+[:mouse_move, 654, 92, 2, 702, 806]
+[:mouse_move, 629, 90, 2, 703, 806]
+[:mouse_move, 623, 90, 2, 704, 807]
+[:mouse_move, 611, 90, 2, 705, 808]
+[:mouse_move, 610, 90, 2, 706, 808]
+[:mouse_move, 609, 90, 2, 707, 809]
+[:mouse_move, 611, 90, 2, 708, 811]
+[:mouse_button_pressed, 1, 0, 1, 709, 811]
+[:mouse_move, 612, 90, 2, 710, 811]
+[:mouse_button_up, 1, 0, 1, 711, 813]
+[:mouse_move, 613, 90, 2, 712, 813]
+[:key_down_raw, 96, 0, 2, 713, 986]
+[:key_up_raw, 96, 0, 2, 714, 987]
+[:key_down_raw, 13, 0, 2, 715, 1004]
diff --git a/samples/13_path_finding_algorithms/07_heuristic_with_walls/app/main.rb b/samples/13_path_finding_algorithms/07_heuristic_with_walls/app/main.rb
index b106e34..2dc3e74 100644
--- a/samples/13_path_finding_algorithms/07_heuristic_with_walls/app/main.rb
+++ b/samples/13_path_finding_algorithms/07_heuristic_with_walls/app/main.rb
@@ -1002,7 +1002,7 @@ def tick args
end
# Every tick, new args are passed, and the Breadth First Search tick is called
- $heuristic ||= Heuristic.new(args)
+ $heuristic ||= Heuristic.new
$heuristic.args = args
$heuristic.tick
end
diff --git a/samples/13_path_finding_algorithms/07_heuristic_with_walls/replay.txt b/samples/13_path_finding_algorithms/07_heuristic_with_walls/replay.txt
new file mode 100644
index 0000000..4c5a2a6
--- /dev/null
+++ b/samples/13_path_finding_algorithms/07_heuristic_with_walls/replay.txt
@@ -0,0 +1,352 @@
+replay_version 2.0
+stopped_at 637
+seed 100
+recorded_at 2021-11-20 11:23:35 -0600
+[:mouse_button_up, 1, 0, 1, 1, 2]
+[:mouse_move, 777, 81, 2, 2, 5]
+[:mouse_move, 778, 83, 2, 3, 23]
+[:mouse_move, 778, 91, 2, 4, 24]
+[:mouse_move, 778, 97, 2, 5, 25]
+[:mouse_move, 778, 101, 2, 6, 26]
+[:mouse_move, 777, 106, 2, 7, 26]
+[:mouse_move, 774, 112, 2, 8, 27]
+[:mouse_move, 769, 116, 2, 9, 28]
+[:mouse_move, 765, 119, 2, 10, 29]
+[:mouse_move, 763, 120, 2, 11, 29]
+[:mouse_move, 762, 120, 2, 12, 30]
+[:mouse_move, 761, 121, 2, 13, 31]
+[:mouse_move, 761, 122, 2, 14, 32]
+[:mouse_move, 760, 123, 2, 15, 32]
+[:mouse_move, 760, 124, 2, 16, 33]
+[:mouse_move, 759, 125, 2, 17, 34]
+[:mouse_move, 758, 126, 2, 18, 36]
+[:mouse_move, 757, 126, 2, 19, 37]
+[:mouse_move, 754, 127, 2, 20, 38]
+[:mouse_move, 753, 127, 2, 21, 39]
+[:mouse_move, 752, 127, 2, 22, 40]
+[:mouse_move, 753, 127, 2, 23, 56]
+[:mouse_move, 752, 127, 2, 24, 65]
+[:mouse_move, 745, 127, 2, 25, 66]
+[:mouse_move, 737, 127, 2, 26, 67]
+[:mouse_move, 726, 125, 2, 27, 68]
+[:mouse_move, 716, 122, 2, 28, 68]
+[:mouse_move, 709, 120, 2, 29, 69]
+[:mouse_move, 697, 117, 2, 30, 70]
+[:mouse_move, 691, 115, 2, 31, 71]
+[:mouse_move, 689, 114, 2, 32, 72]
+[:mouse_move, 686, 113, 2, 33, 72]
+[:mouse_move, 686, 112, 2, 34, 73]
+[:mouse_move, 685, 112, 2, 35, 74]
+[:mouse_move, 684, 112, 2, 36, 75]
+[:mouse_move, 683, 112, 2, 37, 76]
+[:mouse_move, 682, 111, 2, 38, 77]
+[:mouse_move, 679, 110, 2, 39, 77]
+[:mouse_move, 674, 108, 2, 40, 78]
+[:mouse_move, 665, 104, 2, 41, 79]
+[:mouse_move, 660, 101, 2, 42, 80]
+[:mouse_move, 657, 101, 2, 43, 81]
+[:mouse_move, 657, 100, 2, 44, 89]
+[:mouse_button_pressed, 1, 0, 1, 45, 109]
+[:mouse_button_up, 1, 0, 1, 46, 113]
+[:mouse_button_pressed, 1, 0, 1, 47, 228]
+[:mouse_button_up, 1, 0, 1, 48, 229]
+[:mouse_move, 657, 99, 2, 49, 240]
+[:mouse_move, 656, 96, 2, 50, 240]
+[:mouse_move, 655, 95, 2, 51, 240]
+[:mouse_move, 654, 94, 2, 52, 241]
+[:mouse_move, 654, 87, 2, 53, 242]
+[:mouse_move, 654, 80, 2, 54, 242]
+[:mouse_move, 654, 74, 2, 55, 242]
+[:mouse_move, 654, 69, 2, 56, 242]
+[:mouse_move, 654, 67, 2, 57, 243]
+[:mouse_move, 654, 63, 2, 58, 243]
+[:mouse_move, 654, 62, 2, 59, 244]
+[:mouse_move, 653, 61, 2, 60, 244]
+[:mouse_move, 651, 61, 2, 61, 245]
+[:mouse_move, 648, 60, 2, 62, 246]
+[:mouse_move, 645, 60, 2, 63, 246]
+[:mouse_move, 637, 57, 2, 64, 246]
+[:mouse_move, 633, 55, 2, 65, 246]
+[:mouse_move, 626, 53, 2, 66, 247]
+[:mouse_move, 620, 51, 2, 67, 247]
+[:mouse_move, 593, 47, 2, 68, 247]
+[:mouse_move, 580, 45, 2, 69, 248]
+[:mouse_move, 577, 45, 2, 70, 248]
+[:mouse_move, 576, 45, 2, 71, 248]
+[:mouse_move, 576, 44, 2, 72, 251]
+[:mouse_button_pressed, 1, 0, 1, 73, 251]
+[:mouse_button_up, 1, 0, 1, 74, 253]
+[:mouse_move, 577, 44, 2, 75, 257]
+[:mouse_move, 578, 45, 2, 76, 257]
+[:mouse_move, 584, 45, 2, 77, 258]
+[:mouse_move, 594, 47, 2, 78, 258]
+[:mouse_move, 606, 48, 2, 79, 258]
+[:mouse_move, 619, 50, 2, 80, 259]
+[:mouse_move, 627, 50, 2, 81, 259]
+[:mouse_move, 629, 50, 2, 82, 259]
+[:mouse_move, 630, 50, 2, 83, 259]
+[:mouse_move, 631, 50, 2, 84, 260]
+[:mouse_move, 632, 50, 2, 85, 261]
+[:mouse_button_pressed, 1, 0, 1, 86, 263]
+[:mouse_move, 629, 50, 2, 87, 264]
+[:mouse_move, 624, 50, 2, 88, 264]
+[:mouse_move, 617, 50, 2, 89, 264]
+[:mouse_move, 612, 50, 2, 90, 264]
+[:mouse_move, 609, 50, 2, 91, 264]
+[:mouse_move, 607, 50, 2, 92, 264]
+[:mouse_move, 603, 49, 2, 93, 264]
+[:mouse_move, 600, 49, 2, 94, 264]
+[:mouse_move, 597, 48, 2, 95, 265]
+[:mouse_move, 595, 48, 2, 96, 265]
+[:mouse_move, 594, 48, 2, 97, 265]
+[:mouse_move, 593, 48, 2, 98, 265]
+[:mouse_move, 592, 48, 2, 99, 265]
+[:mouse_move, 590, 48, 2, 100, 265]
+[:mouse_move, 587, 48, 2, 101, 265]
+[:mouse_move, 582, 48, 2, 102, 265]
+[:mouse_move, 575, 48, 2, 103, 265]
+[:mouse_move, 571, 47, 2, 104, 265]
+[:mouse_move, 568, 47, 2, 105, 265]
+[:mouse_move, 567, 47, 2, 106, 266]
+[:mouse_move, 566, 47, 2, 107, 266]
+[:mouse_move, 565, 46, 2, 108, 266]
+[:mouse_move, 564, 46, 2, 109, 266]
+[:mouse_move, 563, 46, 2, 110, 266]
+[:mouse_move, 562, 46, 2, 111, 266]
+[:mouse_move, 561, 46, 2, 112, 266]
+[:mouse_move, 560, 46, 2, 113, 267]
+[:mouse_move, 559, 46, 2, 114, 267]
+[:mouse_move, 558, 46, 2, 115, 267]
+[:mouse_move, 555, 46, 2, 116, 268]
+[:mouse_move, 551, 46, 2, 117, 268]
+[:mouse_move, 549, 46, 2, 118, 268]
+[:mouse_move, 548, 46, 2, 119, 268]
+[:mouse_move, 547, 46, 2, 120, 268]
+[:mouse_move, 546, 46, 2, 121, 269]
+[:mouse_move, 545, 46, 2, 122, 269]
+[:mouse_move, 540, 46, 2, 123, 269]
+[:mouse_move, 534, 46, 2, 124, 269]
+[:mouse_move, 531, 46, 2, 125, 269]
+[:mouse_move, 527, 46, 2, 126, 269]
+[:mouse_move, 525, 46, 2, 127, 269]
+[:mouse_button_up, 1, 0, 1, 128, 276]
+[:mouse_move, 526, 47, 2, 129, 287]
+[:mouse_move, 527, 47, 2, 130, 288]
+[:mouse_move, 528, 48, 2, 131, 290]
+[:mouse_move, 531, 51, 2, 132, 290]
+[:mouse_move, 534, 54, 2, 133, 290]
+[:mouse_move, 539, 61, 2, 134, 291]
+[:mouse_move, 548, 71, 2, 135, 291]
+[:mouse_move, 558, 81, 2, 136, 292]
+[:mouse_move, 570, 94, 2, 137, 292]
+[:mouse_move, 585, 110, 2, 138, 293]
+[:mouse_move, 595, 123, 2, 139, 293]
+[:mouse_move, 607, 136, 2, 140, 293]
+[:mouse_move, 618, 146, 2, 141, 294]
+[:mouse_move, 626, 154, 2, 142, 295]
+[:mouse_move, 632, 161, 2, 143, 295]
+[:mouse_move, 633, 162, 2, 144, 296]
+[:mouse_move, 633, 163, 2, 145, 296]
+[:mouse_move, 634, 164, 2, 146, 296]
+[:mouse_move, 634, 165, 2, 147, 297]
+[:mouse_move, 635, 168, 2, 148, 297]
+[:mouse_move, 635, 172, 2, 149, 298]
+[:mouse_move, 635, 178, 2, 150, 299]
+[:mouse_move, 635, 182, 2, 151, 299]
+[:mouse_move, 635, 183, 2, 152, 299]
+[:mouse_move, 635, 184, 2, 153, 300]
+[:mouse_move, 634, 187, 2, 154, 300]
+[:mouse_move, 632, 191, 2, 155, 301]
+[:mouse_move, 629, 193, 2, 156, 301]
+[:mouse_move, 627, 194, 2, 157, 302]
+[:mouse_move, 625, 194, 2, 158, 302]
+[:mouse_move, 625, 195, 2, 159, 303]
+[:mouse_move, 624, 195, 2, 160, 304]
+[:mouse_move, 619, 195, 2, 161, 305]
+[:mouse_move, 608, 195, 2, 162, 305]
+[:mouse_move, 597, 194, 2, 163, 305]
+[:mouse_move, 584, 188, 2, 164, 306]
+[:mouse_move, 572, 180, 2, 165, 307]
+[:mouse_move, 563, 173, 2, 166, 307]
+[:mouse_move, 556, 166, 2, 167, 308]
+[:mouse_move, 550, 160, 2, 168, 308]
+[:mouse_move, 548, 157, 2, 169, 308]
+[:mouse_move, 547, 154, 2, 170, 309]
+[:mouse_move, 542, 149, 2, 171, 309]
+[:mouse_move, 538, 142, 2, 172, 310]
+[:mouse_move, 533, 134, 2, 173, 310]
+[:mouse_move, 531, 132, 2, 174, 311]
+[:mouse_move, 530, 132, 2, 175, 311]
+[:mouse_move, 530, 131, 2, 176, 312]
+[:mouse_move, 528, 129, 2, 177, 312]
+[:mouse_move, 524, 127, 2, 178, 312]
+[:mouse_move, 523, 126, 2, 179, 313]
+[:mouse_move, 522, 126, 2, 180, 314]
+[:mouse_move, 520, 124, 2, 181, 314]
+[:mouse_move, 512, 118, 2, 182, 315]
+[:mouse_move, 502, 112, 2, 183, 316]
+[:mouse_move, 498, 108, 2, 184, 316]
+[:mouse_move, 495, 107, 2, 185, 317]
+[:mouse_move, 495, 106, 2, 186, 317]
+[:mouse_move, 493, 105, 2, 187, 317]
+[:mouse_move, 493, 104, 2, 188, 318]
+[:mouse_move, 492, 104, 2, 189, 318]
+[:mouse_move, 492, 103, 2, 190, 319]
+[:mouse_button_pressed, 1, 0, 1, 191, 326]
+[:mouse_button_up, 1, 0, 1, 192, 328]
+[:mouse_button_pressed, 1, 0, 1, 193, 339]
+[:mouse_button_up, 1, 0, 1, 194, 342]
+[:mouse_button_pressed, 1, 0, 1, 195, 343]
+[:mouse_button_up, 1, 0, 1, 196, 344]
+[:mouse_button_pressed, 1, 0, 1, 197, 345]
+[:mouse_button_up, 1, 0, 1, 198, 347]
+[:mouse_move, 493, 103, 2, 199, 348]
+[:mouse_move, 497, 103, 2, 200, 348]
+[:mouse_move, 507, 103, 2, 201, 348]
+[:mouse_move, 522, 103, 2, 202, 349]
+[:mouse_move, 542, 103, 2, 203, 349]
+[:mouse_move, 566, 103, 2, 204, 350]
+[:mouse_move, 595, 103, 2, 205, 350]
+[:mouse_move, 627, 103, 2, 206, 351]
+[:mouse_move, 655, 103, 2, 207, 351]
+[:mouse_move, 678, 103, 2, 208, 352]
+[:mouse_move, 693, 103, 2, 209, 352]
+[:mouse_move, 698, 103, 2, 210, 353]
+[:mouse_move, 699, 103, 2, 211, 353]
+[:mouse_move, 702, 103, 2, 212, 354]
+[:mouse_move, 704, 103, 2, 213, 354]
+[:mouse_move, 708, 103, 2, 214, 354]
+[:mouse_move, 709, 103, 2, 215, 355]
+[:mouse_move, 711, 103, 2, 216, 356]
+[:mouse_move, 714, 103, 2, 217, 357]
+[:mouse_move, 715, 103, 2, 218, 357]
+[:mouse_move, 719, 103, 2, 219, 357]
+[:mouse_move, 721, 103, 2, 220, 358]
+[:mouse_move, 723, 103, 2, 221, 359]
+[:mouse_move, 724, 103, 2, 222, 359]
+[:mouse_move, 725, 103, 2, 223, 364]
+[:mouse_move, 729, 101, 2, 224, 365]
+[:mouse_move, 732, 101, 2, 225, 365]
+[:mouse_move, 734, 100, 2, 226, 366]
+[:mouse_move, 735, 99, 2, 227, 367]
+[:mouse_button_pressed, 1, 0, 1, 228, 368]
+[:mouse_button_up, 1, 0, 1, 229, 371]
+[:mouse_button_pressed, 1, 0, 1, 230, 373]
+[:mouse_button_up, 1, 0, 1, 231, 375]
+[:mouse_button_pressed, 1, 0, 1, 232, 378]
+[:mouse_button_up, 1, 0, 1, 233, 380]
+[:mouse_button_pressed, 1, 0, 1, 234, 383]
+[:mouse_button_up, 1, 0, 1, 235, 385]
+[:mouse_button_pressed, 1, 0, 1, 236, 387]
+[:mouse_button_up, 1, 0, 1, 237, 389]
+[:mouse_move, 736, 99, 2, 238, 390]
+[:mouse_button_pressed, 1, 0, 1, 239, 392]
+[:mouse_button_up, 1, 0, 1, 240, 395]
+[:mouse_button_pressed, 1, 0, 1, 241, 432]
+[:mouse_button_up, 1, 0, 1, 242, 434]
+[:mouse_move, 736, 103, 2, 243, 446]
+[:mouse_move, 736, 113, 2, 244, 446]
+[:mouse_move, 734, 125, 2, 245, 447]
+[:mouse_move, 732, 140, 2, 246, 447]
+[:mouse_move, 726, 158, 2, 247, 448]
+[:mouse_move, 718, 174, 2, 248, 448]
+[:mouse_move, 712, 193, 2, 249, 448]
+[:mouse_move, 709, 203, 2, 250, 449]
+[:mouse_move, 709, 208, 2, 251, 449]
+[:mouse_move, 708, 211, 2, 252, 450]
+[:mouse_move, 708, 212, 2, 253, 451]
+[:mouse_move, 708, 213, 2, 254, 451]
+[:mouse_move, 707, 215, 2, 255, 451]
+[:mouse_move, 704, 217, 2, 256, 452]
+[:mouse_move, 700, 221, 2, 257, 452]
+[:mouse_move, 698, 223, 2, 258, 453]
+[:mouse_move, 697, 223, 2, 259, 454]
+[:mouse_move, 699, 223, 2, 260, 455]
+[:mouse_move, 700, 222, 2, 261, 455]
+[:mouse_move, 701, 222, 2, 262, 456]
+[:mouse_move, 702, 222, 2, 263, 456]
+[:mouse_move, 702, 221, 2, 264, 457]
+[:mouse_button_pressed, 1, 0, 1, 265, 458]
+[:mouse_button_up, 1, 0, 1, 266, 459]
+[:mouse_move, 695, 221, 2, 267, 468]
+[:mouse_move, 684, 221, 2, 268, 469]
+[:mouse_move, 673, 221, 2, 269, 469]
+[:mouse_move, 663, 221, 2, 270, 470]
+[:mouse_move, 656, 221, 2, 271, 470]
+[:mouse_move, 655, 221, 2, 272, 471]
+[:mouse_button_pressed, 1, 0, 1, 273, 475]
+[:mouse_button_up, 1, 0, 1, 274, 476]
+[:mouse_move, 657, 218, 2, 275, 479]
+[:mouse_move, 661, 213, 2, 276, 479]
+[:mouse_move, 670, 201, 2, 277, 479]
+[:mouse_move, 679, 190, 2, 278, 479]
+[:mouse_move, 687, 178, 2, 279, 480]
+[:mouse_move, 695, 165, 2, 280, 481]
+[:mouse_move, 703, 151, 2, 281, 481]
+[:mouse_move, 712, 139, 2, 282, 482]
+[:mouse_move, 720, 129, 2, 283, 482]
+[:mouse_move, 727, 121, 2, 284, 482]
+[:mouse_move, 735, 111, 2, 285, 483]
+[:mouse_move, 737, 108, 2, 286, 483]
+[:mouse_move, 739, 105, 2, 287, 484]
+[:mouse_move, 739, 104, 2, 288, 484]
+[:mouse_move, 740, 103, 2, 289, 485]
+[:mouse_move, 740, 102, 2, 290, 485]
+[:mouse_move, 740, 101, 2, 291, 486]
+[:mouse_move, 740, 100, 2, 292, 488]
+[:mouse_button_pressed, 1, 0, 1, 293, 489]
+[:mouse_move, 740, 99, 2, 294, 490]
+[:mouse_button_up, 1, 0, 1, 295, 491]
+[:mouse_button_pressed, 1, 0, 1, 296, 493]
+[:mouse_move, 740, 100, 2, 297, 493]
+[:mouse_button_up, 1, 0, 1, 298, 496]
+[:mouse_button_pressed, 1, 0, 1, 299, 498]
+[:mouse_button_up, 1, 0, 1, 300, 500]
+[:mouse_button_pressed, 1, 0, 1, 301, 502]
+[:mouse_button_up, 1, 0, 1, 302, 505]
+[:mouse_button_pressed, 1, 0, 1, 303, 508]
+[:mouse_button_up, 1, 0, 1, 304, 509]
+[:mouse_button_pressed, 1, 0, 1, 305, 511]
+[:mouse_button_up, 1, 0, 1, 306, 514]
+[:mouse_button_pressed, 1, 0, 1, 307, 516]
+[:mouse_button_up, 1, 0, 1, 308, 518]
+[:mouse_button_pressed, 1, 0, 1, 309, 520]
+[:mouse_button_up, 1, 0, 1, 310, 522]
+[:mouse_button_pressed, 1, 0, 1, 311, 524]
+[:mouse_button_up, 1, 0, 1, 312, 526]
+[:mouse_move, 738, 100, 2, 313, 528]
+[:mouse_move, 732, 101, 2, 314, 528]
+[:mouse_move, 715, 101, 2, 315, 529]
+[:mouse_move, 690, 101, 2, 316, 529]
+[:mouse_move, 677, 101, 2, 317, 530]
+[:mouse_move, 666, 101, 2, 318, 530]
+[:mouse_move, 662, 101, 2, 319, 531]
+[:mouse_move, 661, 101, 2, 320, 531]
+[:mouse_button_pressed, 1, 0, 1, 321, 534]
+[:mouse_button_up, 1, 0, 1, 322, 536]
+[:mouse_move, 660, 100, 2, 323, 550]
+[:mouse_move, 661, 100, 2, 324, 550]
+[:mouse_move, 662, 100, 2, 325, 553]
+[:key_down_raw, 96, 0, 2, 326, 615]
+[:key_up_raw, 96, 0, 2, 327, 616]
+[:mouse_move, 660, 102, 2, 328, 625]
+[:mouse_move, 657, 104, 2, 329, 626]
+[:mouse_move, 655, 107, 2, 330, 626]
+[:mouse_move, 653, 110, 2, 331, 626]
+[:mouse_move, 653, 117, 2, 332, 626]
+[:mouse_move, 655, 122, 2, 333, 626]
+[:mouse_move, 658, 124, 2, 334, 627]
+[:mouse_move, 664, 126, 2, 335, 627]
+[:mouse_move, 671, 128, 2, 336, 627]
+[:mouse_move, 681, 133, 2, 337, 627]
+[:mouse_move, 693, 141, 2, 338, 628]
+[:mouse_move, 710, 154, 2, 339, 628]
+[:mouse_move, 731, 167, 2, 340, 628]
+[:mouse_move, 753, 176, 2, 341, 628]
+[:mouse_move, 772, 181, 2, 342, 629]
+[:mouse_move, 786, 182, 2, 343, 629]
+[:mouse_move, 791, 184, 2, 344, 629]
+[:mouse_move, 790, 185, 2, 345, 629]
+[:mouse_move, 789, 187, 2, 346, 630]
+[:mouse_move, 788, 187, 2, 347, 630]
+[:key_down_raw, 13, 0, 2, 348, 637]
diff --git a/samples/13_path_finding_algorithms/08_a_star/app/main.rb b/samples/13_path_finding_algorithms/08_a_star/app/main.rb
index e9fcb8c..eaf7e09 100644
--- a/samples/13_path_finding_algorithms/08_a_star/app/main.rb
+++ b/samples/13_path_finding_algorithms/08_a_star/app/main.rb
@@ -11,8 +11,8 @@ class A_Star_Algorithm
def tick
defaults
- render
- input
+ render
+ input
if dijkstra.came_from.empty?
calc_searches
@@ -65,7 +65,7 @@ class A_Star_Algorithm
# We store this value, because we want to remember the value even when
# the user's cursor is no longer over what they're interacting with, but
# they are still clicking down on the mouse.
- state.user_input ||= :none
+ state.user_input ||= :none
# These variables allow the breadth first search to take place
# Came_from is a hash with a key of a cell and a value of the cell that was expanded from to find the key.
@@ -143,7 +143,7 @@ class A_Star_Algorithm
# If the mouse was clicked this tick
if inputs.mouse.down
# Determine what the user is editing and appropriately edit the state.user_input variable
- determine_input
+ determine_input
end
# Process user input based on user_input variable and current mouse position
@@ -154,51 +154,51 @@ class A_Star_Algorithm
# This method is called when the mouse is clicked down
def determine_input
# If the mouse is over the star in the first grid
- if dijkstra_mouse_over_star?
+ if dijkstra_mouse_over_star?
# The user is editing the star from the first grid
- state.user_input = :dijkstra_star
+ state.user_input = :dijkstra_star
# If the mouse is over the star in the second grid
- elsif greedy_mouse_over_star?
+ elsif greedy_mouse_over_star?
# The user is editing the star from the second grid
- state.user_input = :greedy_star
+ state.user_input = :greedy_star
# If the mouse is over the star in the third grid
- elsif a_star_mouse_over_star?
+ elsif a_star_mouse_over_star?
# The user is editing the star from the third grid
- state.user_input = :a_star_star
+ state.user_input = :a_star_star
# If the mouse is over the target in the first grid
- elsif dijkstra_mouse_over_target?
+ elsif dijkstra_mouse_over_target?
# The user is editing the target from the first grid
- state.user_input = :dijkstra_target
+ state.user_input = :dijkstra_target
# If the mouse is over the target in the second grid
- elsif greedy_mouse_over_target?
+ elsif greedy_mouse_over_target?
# The user is editing the target from the second grid
- state.user_input = :greedy_target
+ state.user_input = :greedy_target
# If the mouse is over the target in the third grid
- elsif a_star_mouse_over_target?
+ elsif a_star_mouse_over_target?
# The user is editing the target from the third grid
- state.user_input = :a_star_target
+ state.user_input = :a_star_target
# If the mouse is over a wall in the first grid
- elsif dijkstra_mouse_over_wall?
+ elsif dijkstra_mouse_over_wall?
# The user is removing a wall from the first grid
- state.user_input = :dijkstra_remove_wall
+ state.user_input = :dijkstra_remove_wall
# If the mouse is over a wall in the second grid
- elsif greedy_mouse_over_wall?
+ elsif greedy_mouse_over_wall?
# The user is removing a wall from the second grid
state.user_input = :greedy_remove_wall
# If the mouse is over a wall in the third grid
- elsif a_star_mouse_over_wall?
+ elsif a_star_mouse_over_wall?
# The user is removing a wall from the third grid
state.user_input = :a_star_remove_wall
# If the mouse is over the first grid
- elsif dijkstra_mouse_over_grid?
+ elsif dijkstra_mouse_over_grid?
# The user is adding a wall from the first grid
state.user_input = :dijkstra_add_wall
# If the mouse is over the second grid
- elsif greedy_mouse_over_grid?
+ elsif greedy_mouse_over_grid?
# The user is adding a wall from the second grid
state.user_input = :greedy_add_wall
# If the mouse is over the third grid
- elsif a_star_mouse_over_grid?
+ elsif a_star_mouse_over_grid?
# The user is adding a wall from the third grid
state.user_input = :a_star_add_wall
end
@@ -206,30 +206,30 @@ class A_Star_Algorithm
# Processes click and drag based on what the user is currently dragging
def process_input
- if state.user_input == :dijkstra_star
- process_input_dijkstra_star
+ if state.user_input == :dijkstra_star
+ process_input_dijkstra_star
elsif state.user_input == :greedy_star
- process_input_greedy_star
+ process_input_greedy_star
elsif state.user_input == :a_star_star
- process_input_a_star_star
- elsif state.user_input == :dijkstra_target
- process_input_dijkstra_target
- elsif state.user_input == :greedy_target
- process_input_greedy_target
- elsif state.user_input == :a_star_target
- process_input_a_star_target
- elsif state.user_input == :dijkstra_remove_wall
- process_input_dijkstra_remove_wall
+ process_input_a_star_star
+ elsif state.user_input == :dijkstra_target
+ process_input_dijkstra_target
+ elsif state.user_input == :greedy_target
+ process_input_greedy_target
+ elsif state.user_input == :a_star_target
+ process_input_a_star_target
+ elsif state.user_input == :dijkstra_remove_wall
+ process_input_dijkstra_remove_wall
elsif state.user_input == :greedy_remove_wall
- process_input_greedy_remove_wall
+ process_input_greedy_remove_wall
elsif state.user_input == :a_star_remove_wall
- process_input_a_star_remove_wall
- elsif state.user_input == :dijkstra_add_wall
- process_input_dijkstra_add_wall
- elsif state.user_input == :greedy_add_wall
- process_input_greedy_add_wall
- elsif state.user_input == :a_star_add_wall
- process_input_a_star_add_wall
+ process_input_a_star_remove_wall
+ elsif state.user_input == :dijkstra_add_wall
+ process_input_dijkstra_add_wall
+ elsif state.user_input == :greedy_add_wall
+ process_input_greedy_add_wall
+ elsif state.user_input == :a_star_add_wall
+ process_input_a_star_add_wall
end
end
@@ -244,7 +244,7 @@ class A_Star_Algorithm
# The horizontal grid lines
for y in 0..grid.height
- outputs.lines << dijkstra_horizontal_line(y)
+ outputs.lines << dijkstra_horizontal_line(y)
end
end
@@ -259,7 +259,7 @@ class A_Star_Algorithm
# The horizontal grid lines
for y in 0..grid.height
- outputs.lines << greedy_horizontal_line(y)
+ outputs.lines << greedy_horizontal_line(y)
end
end
@@ -274,10 +274,10 @@ class A_Star_Algorithm
# The horizontal grid lines
for y in 0..grid.height
- outputs.lines << a_star_horizontal_line(y)
+ outputs.lines << a_star_horizontal_line(y)
end
end
-
+
# Returns a vertical line for a column of the first grid
def dijkstra_vertical_line column
dijkstra_scale_up([column, 0, column, grid.height])
@@ -327,7 +327,7 @@ class A_Star_Algorithm
def render_dijkstra_target
outputs.sprites << [dijkstra_scale_up(grid.target), 'target.png']
end
-
+
# Renders the target on the second grid
def render_greedy_target
outputs.sprites << [greedy_scale_up(grid.target), 'target.png']
@@ -340,21 +340,21 @@ class A_Star_Algorithm
# Renders the walls on the first grid
def render_dijkstra_walls
- grid.walls.each_key do | wall |
+ grid.walls.each_key do | wall |
outputs.solids << [dijkstra_scale_up(wall), wall_color]
end
end
# Renders the walls on the second grid
def render_greedy_walls
- grid.walls.each_key do | wall |
+ grid.walls.each_key do | wall |
outputs.solids << [greedy_scale_up(wall), wall_color]
end
end
# Renders the walls on the third grid
def render_a_star_walls
- grid.walls.each_key do | wall |
+ grid.walls.each_key do | wall |
outputs.solids << [a_star_scale_up(wall), wall_color]
end
end
@@ -554,12 +554,12 @@ class A_Star_Algorithm
# Only resets the search if the star changes position
# Called whenever the user is editing the star (puts mouse down on star)
def process_input_dijkstra_star
- old_star = grid.star.clone
+ old_star = grid.star.clone
unless dijkstra_cell_closest_to_mouse == grid.target
- grid.star = dijkstra_cell_closest_to_mouse
+ grid.star = dijkstra_cell_closest_to_mouse
end
- unless old_star == grid.star
- reset_searches
+ unless old_star == grid.star
+ reset_searches
end
end
@@ -567,12 +567,12 @@ class A_Star_Algorithm
# Only resets the search if the star changes position
# Called whenever the user is editing the star (puts mouse down on star)
def process_input_greedy_star
- old_star = grid.star.clone
+ old_star = grid.star.clone
unless greedy_cell_closest_to_mouse == grid.target
grid.star = greedy_cell_closest_to_mouse
end
- unless old_star == grid.star
- reset_searches
+ unless old_star == grid.star
+ reset_searches
end
end
@@ -580,12 +580,12 @@ class A_Star_Algorithm
# Only resets the search if the star changes position
# Called whenever the user is editing the star (puts mouse down on star)
def process_input_a_star_star
- old_star = grid.star.clone
+ old_star = grid.star.clone
unless a_star_cell_closest_to_mouse == grid.target
grid.star = a_star_cell_closest_to_mouse
end
- unless old_star == grid.star
- reset_searches
+ unless old_star == grid.star
+ reset_searches
end
end
@@ -593,12 +593,12 @@ class A_Star_Algorithm
# Only reset_searchess the search if the target changes position
# Called whenever the user is editing the target (puts mouse down on target)
def process_input_dijkstra_target
- old_target = grid.target.clone
+ old_target = grid.target.clone
unless dijkstra_cell_closest_to_mouse == grid.star
grid.target = dijkstra_cell_closest_to_mouse
end
- unless old_target == grid.target
- reset_searches
+ unless old_target == grid.target
+ reset_searches
end
end
@@ -606,12 +606,12 @@ class A_Star_Algorithm
# Only reset_searchess the search if the target changes position
# Called whenever the user is editing the target (puts mouse down on target)
def process_input_greedy_target
- old_target = grid.target.clone
+ old_target = grid.target.clone
unless greedy_cell_closest_to_mouse == grid.star
grid.target = greedy_cell_closest_to_mouse
end
- unless old_target == grid.target
- reset_searches
+ unless old_target == grid.target
+ reset_searches
end
end
@@ -619,12 +619,12 @@ class A_Star_Algorithm
# Only reset_searchess the search if the target changes position
# Called whenever the user is editing the target (puts mouse down on target)
def process_input_a_star_target
- old_target = grid.target.clone
+ old_target = grid.target.clone
unless a_star_cell_closest_to_mouse == grid.star
grid.target = a_star_cell_closest_to_mouse
end
- unless old_target == grid.target
- reset_searches
+ unless old_target == grid.target
+ reset_searches
end
end
@@ -633,10 +633,10 @@ class A_Star_Algorithm
# The mouse needs to be inside the grid, because we only want to remove walls
# the cursor is directly over
# Recalculations should only occur when a wall is actually deleted
- if dijkstra_mouse_over_grid?
+ if dijkstra_mouse_over_grid?
if grid.walls.has_key?(dijkstra_cell_closest_to_mouse)
- grid.walls.delete(dijkstra_cell_closest_to_mouse)
- reset_searches
+ grid.walls.delete(dijkstra_cell_closest_to_mouse)
+ reset_searches
end
end
end
@@ -646,10 +646,10 @@ class A_Star_Algorithm
# The mouse needs to be inside the grid, because we only want to remove walls
# the cursor is directly over
# Recalculations should only occur when a wall is actually deleted
- if greedy_mouse_over_grid?
+ if greedy_mouse_over_grid?
if grid.walls.has_key?(greedy_cell_closest_to_mouse)
- grid.walls.delete(greedy_cell_closest_to_mouse)
- reset_searches
+ grid.walls.delete(greedy_cell_closest_to_mouse)
+ reset_searches
end
end
end
@@ -659,40 +659,40 @@ class A_Star_Algorithm
# The mouse needs to be inside the grid, because we only want to remove walls
# the cursor is directly over
# Recalculations should only occur when a wall is actually deleted
- if a_star_mouse_over_grid?
+ if a_star_mouse_over_grid?
if grid.walls.has_key?(a_star_cell_closest_to_mouse)
- grid.walls.delete(a_star_cell_closest_to_mouse)
- reset_searches
+ grid.walls.delete(a_star_cell_closest_to_mouse)
+ reset_searches
end
end
end
# Adds a wall in the first grid in the cell the mouse is over
def process_input_dijkstra_add_wall
- if dijkstra_mouse_over_grid?
+ if dijkstra_mouse_over_grid?
unless grid.walls.has_key?(dijkstra_cell_closest_to_mouse)
- grid.walls[dijkstra_cell_closest_to_mouse] = true
- reset_searches
+ grid.walls[dijkstra_cell_closest_to_mouse] = true
+ reset_searches
end
end
end
# Adds a wall in the second grid in the cell the mouse is over
def process_input_greedy_add_wall
- if greedy_mouse_over_grid?
+ if greedy_mouse_over_grid?
unless grid.walls.has_key?(greedy_cell_closest_to_mouse)
- grid.walls[greedy_cell_closest_to_mouse] = true
- reset_searches
+ grid.walls[greedy_cell_closest_to_mouse] = true
+ reset_searches
end
end
end
# Adds a wall in the third grid in the cell the mouse is over
def process_input_a_star_add_wall
- if a_star_mouse_over_grid?
+ if a_star_mouse_over_grid?
unless grid.walls.has_key?(a_star_cell_closest_to_mouse)
- grid.walls[a_star_cell_closest_to_mouse] = true
- reset_searches
+ grid.walls[a_star_cell_closest_to_mouse] = true
+ reset_searches
end
end
end
@@ -702,13 +702,13 @@ class A_Star_Algorithm
# Finding the cell closest to the mouse helps with this
def dijkstra_cell_closest_to_mouse
# Closest cell to the mouse in the first grid
- x = (inputs.mouse.point.x / grid.cell_size).to_i
- y = (inputs.mouse.point.y / grid.cell_size).to_i
+ x = (inputs.mouse.point.x / grid.cell_size).to_i
+ y = (inputs.mouse.point.y / grid.cell_size).to_i
# Bound x and y to the grid
- x = grid.width - 1 if x > grid.width - 1
- y = grid.height - 1 if y > grid.height - 1
+ x = grid.width - 1 if x > grid.width - 1
+ y = grid.height - 1 if y > grid.height - 1
# Return closest cell
- [x, y]
+ [x, y]
end
# When the user grabs the star and puts their cursor to the far right
@@ -716,17 +716,17 @@ class A_Star_Algorithm
# Finding the cell closest to the mouse in the second grid helps with this
def greedy_cell_closest_to_mouse
# Closest cell grid to the mouse in the second
- x = (inputs.mouse.point.x / grid.cell_size).to_i
- y = (inputs.mouse.point.y / grid.cell_size).to_i
+ x = (inputs.mouse.point.x / grid.cell_size).to_i
+ y = (inputs.mouse.point.y / grid.cell_size).to_i
# Translate the cell to the first grid
x -= grid.width + 1
# Bound x and y to the first grid
x = 0 if x < 0
y = 0 if y < 0
- x = grid.width - 1 if x > grid.width - 1
- y = grid.height - 1 if y > grid.height - 1
+ x = grid.width - 1 if x > grid.width - 1
+ y = grid.height - 1 if y > grid.height - 1
# Return closest cell
- [x, y]
+ [x, y]
end
# When the user grabs the star and puts their cursor to the far right
@@ -734,17 +734,17 @@ class A_Star_Algorithm
# Finding the cell closest to the mouse in the third grid helps with this
def a_star_cell_closest_to_mouse
# Closest cell grid to the mouse in the second
- x = (inputs.mouse.point.x / grid.cell_size).to_i
- y = (inputs.mouse.point.y / grid.cell_size).to_i
+ x = (inputs.mouse.point.x / grid.cell_size).to_i
+ y = (inputs.mouse.point.y / grid.cell_size).to_i
# Translate the cell to the first grid
x -= (grid.width + 1) * 2
# Bound x and y to the first grid
x = 0 if x < 0
y = 0 if y < 0
- x = grid.width - 1 if x > grid.width - 1
- y = grid.height - 1 if y > grid.height - 1
+ x = grid.width - 1 if x > grid.width - 1
+ y = grid.height - 1 if y > grid.height - 1
# Return closest cell
- [x, y]
+ [x, y]
end
def reset_searches
@@ -772,21 +772,21 @@ class A_Star_Algorithm
def calc_dijkstra
# Sets up the search to begin from the star
- dijkstra.frontier << grid.star
- dijkstra.came_from[grid.star] = nil
- dijkstra.cost_so_far[grid.star] = 0
+ dijkstra.frontier << grid.star
+ dijkstra.came_from[grid.star] = nil
+ dijkstra.cost_so_far[grid.star] = 0
# Until the target is found or there are no more cells to explore from
until dijkstra.came_from.has_key?(grid.target) or dijkstra.frontier.empty?
# Take the next frontier cell. The first element is the cell, the second is the priority.
new_frontier = dijkstra.frontier.shift#[0]
# For each of its neighbors
- adjacent_neighbors(new_frontier).each do | neighbor |
+ adjacent_neighbors(new_frontier).each do | neighbor |
# That have not been visited and are not walls
- unless dijkstra.came_from.has_key?(neighbor) or grid.walls.has_key?(neighbor)
+ unless dijkstra.came_from.has_key?(neighbor) or grid.walls.has_key?(neighbor)
# Add them to the frontier and mark them as visited
dijkstra.frontier << neighbor
- dijkstra.came_from[neighbor] = new_frontier
+ dijkstra.came_from[neighbor] = new_frontier
dijkstra.cost_so_far[neighbor] = dijkstra.cost_so_far[new_frontier] + 1
end
end
@@ -807,20 +807,20 @@ class A_Star_Algorithm
def calc_greedy
# Sets up the search to begin from the star
- greedy.frontier << grid.star
- greedy.came_from[grid.star] = nil
+ greedy.frontier << grid.star
+ greedy.came_from[grid.star] = nil
# Until the target is found or there are no more cells to explore from
until greedy.came_from.has_key?(grid.target) or greedy.frontier.empty?
# Take the next frontier cell
- new_frontier = greedy.frontier.shift
+ new_frontier = greedy.frontier.shift
# For each of its neighbors
- adjacent_neighbors(new_frontier).each do | neighbor |
+ adjacent_neighbors(new_frontier).each do | neighbor |
# That have not been visited and are not walls
- unless greedy.came_from.has_key?(neighbor) or grid.walls.has_key?(neighbor)
+ unless greedy.came_from.has_key?(neighbor) or grid.walls.has_key?(neighbor)
# Add them to the frontier and mark them as visited
- greedy.frontier << neighbor
- greedy.came_from[neighbor] = new_frontier
+ greedy.frontier << neighbor
+ greedy.came_from[neighbor] = new_frontier
end
end
# Sort the frontier so that cells that are in a zigzag pattern are prioritized over those in an line
@@ -850,12 +850,12 @@ class A_Star_Algorithm
current_frontier = a_star.frontier.shift
# For each of that cells neighbors
- adjacent_neighbors(current_frontier).each do | neighbor |
+ adjacent_neighbors(current_frontier).each do | neighbor |
# That have not been visited and are not walls
- unless a_star.came_from.has_key?(neighbor) or grid.walls.has_key?(neighbor)
+ unless a_star.came_from.has_key?(neighbor) or grid.walls.has_key?(neighbor)
# Add them to the frontier and mark them as visited
- a_star.frontier << neighbor
- a_star.came_from[neighbor] = current_frontier
+ a_star.frontier << neighbor
+ a_star.came_from[neighbor] = current_frontier
a_star.cost_so_far[neighbor] = a_star.cost_so_far[current_frontier] + 1
end
end
@@ -937,16 +937,16 @@ class A_Star_Algorithm
# Returns a list of adjacent cells
# Used to determine what the next cells to be added to the frontier are
def adjacent_neighbors(cell)
- neighbors = []
+ neighbors = []
# Gets all the valid neighbors into the array
# From southern neighbor, clockwise
- neighbors << [cell.x , cell.y - 1] unless cell.y == 0
- neighbors << [cell.x - 1, cell.y ] unless cell.x == 0
- neighbors << [cell.x , cell.y + 1] unless cell.y == grid.height - 1
- neighbors << [cell.x + 1, cell.y ] unless cell.x == grid.width - 1
+ neighbors << [cell.x , cell.y - 1] unless cell.y == 0
+ neighbors << [cell.x - 1, cell.y ] unless cell.x == 0
+ neighbors << [cell.x , cell.y + 1] unless cell.y == grid.height - 1
+ neighbors << [cell.x + 1, cell.y ] unless cell.x == grid.width - 1
- neighbors
+ neighbors
end
# Finds the vertical and horizontal distance of a cell from the star
@@ -991,11 +991,11 @@ class A_Star_Algorithm
def wall_color
[134, 134, 120] # Camo Green
end
-
+
def visited_color
[204, 191, 179] # Dark Brown
end
-
+
def path_color
[231, 230, 228] # Pastel White
end
@@ -1018,7 +1018,7 @@ def tick args
end
# Every tick, new args are passed, and the Breadth First Search tick is called
- $a_star_algorithm ||= A_Star_Algorithm.new(args)
+ $a_star_algorithm ||= A_Star_Algorithm.new
$a_star_algorithm.args = args
$a_star_algorithm.tick
end
diff --git a/samples/13_path_finding_algorithms/08_a_star/replay.txt b/samples/13_path_finding_algorithms/08_a_star/replay.txt
new file mode 100644
index 0000000..001a564
--- /dev/null
+++ b/samples/13_path_finding_algorithms/08_a_star/replay.txt
@@ -0,0 +1,434 @@
+replay_version 2.0
+stopped_at 341
+seed 100
+recorded_at 2021-11-20 11:24:45 -0600
+[:mouse_button_up, 1, 0, 1, 1, 1]
+[:mouse_move, 769, 97, 2, 2, 8]
+[:mouse_move, 763, 101, 2, 3, 8]
+[:mouse_move, 755, 109, 2, 4, 8]
+[:mouse_move, 748, 123, 2, 5, 8]
+[:mouse_move, 746, 148, 2, 6, 9]
+[:mouse_move, 742, 180, 2, 7, 9]
+[:mouse_move, 733, 215, 2, 8, 9]
+[:mouse_move, 719, 278, 2, 9, 9]
+[:mouse_move, 712, 336, 2, 10, 9]
+[:mouse_move, 701, 397, 2, 11, 10]
+[:mouse_move, 685, 440, 2, 12, 10]
+[:mouse_move, 667, 472, 2, 13, 10]
+[:mouse_move, 654, 493, 2, 14, 10]
+[:mouse_move, 644, 506, 2, 15, 11]
+[:mouse_move, 637, 514, 2, 16, 11]
+[:mouse_move, 635, 516, 2, 17, 11]
+[:mouse_move, 634, 517, 2, 18, 11]
+[:mouse_move, 630, 518, 2, 19, 12]
+[:mouse_move, 624, 524, 2, 20, 12]
+[:mouse_move, 619, 537, 2, 21, 12]
+[:mouse_move, 612, 553, 2, 22, 13]
+[:mouse_move, 609, 561, 2, 23, 13]
+[:mouse_move, 608, 565, 2, 24, 13]
+[:mouse_move, 613, 565, 2, 25, 14]
+[:mouse_move, 627, 565, 2, 26, 14]
+[:mouse_move, 641, 565, 2, 27, 14]
+[:mouse_move, 654, 565, 2, 28, 14]
+[:mouse_move, 658, 565, 2, 29, 15]
+[:mouse_move, 659, 565, 2, 30, 15]
+[:mouse_move, 662, 565, 2, 31, 15]
+[:mouse_move, 667, 566, 2, 32, 15]
+[:mouse_move, 671, 566, 2, 33, 16]
+[:mouse_move, 676, 566, 2, 34, 16]
+[:mouse_move, 685, 566, 2, 35, 16]
+[:mouse_move, 701, 565, 2, 36, 16]
+[:mouse_move, 719, 562, 2, 37, 17]
+[:mouse_move, 731, 560, 2, 38, 17]
+[:mouse_move, 744, 559, 2, 39, 17]
+[:mouse_move, 750, 559, 2, 40, 17]
+[:mouse_move, 757, 559, 2, 41, 17]
+[:mouse_move, 763, 559, 2, 42, 17]
+[:mouse_move, 767, 559, 2, 43, 18]
+[:mouse_move, 769, 559, 2, 44, 18]
+[:mouse_move, 770, 558, 2, 45, 18]
+[:mouse_move, 774, 557, 2, 46, 18]
+[:mouse_move, 784, 555, 2, 47, 18]
+[:mouse_move, 796, 551, 2, 48, 19]
+[:mouse_move, 804, 550, 2, 49, 19]
+[:mouse_move, 810, 548, 2, 50, 19]
+[:mouse_move, 814, 547, 2, 51, 20]
+[:mouse_move, 817, 547, 2, 52, 20]
+[:mouse_move, 818, 547, 2, 53, 20]
+[:mouse_move, 819, 547, 2, 54, 20]
+[:mouse_move, 819, 546, 2, 55, 20]
+[:mouse_move, 819, 545, 2, 56, 20]
+[:mouse_move, 820, 545, 2, 57, 21]
+[:mouse_move, 820, 544, 2, 58, 21]
+[:mouse_move, 820, 543, 2, 59, 21]
+[:mouse_move, 820, 542, 2, 60, 22]
+[:mouse_move, 820, 541, 2, 61, 22]
+[:mouse_move, 820, 540, 2, 62, 23]
+[:mouse_move, 819, 540, 2, 63, 23]
+[:mouse_button_pressed, 1, 0, 1, 64, 24]
+[:mouse_button_up, 1, 0, 1, 65, 25]
+[:mouse_move, 820, 540, 2, 66, 29]
+[:mouse_move, 820, 541, 2, 67, 29]
+[:mouse_move, 820, 542, 2, 68, 29]
+[:mouse_move, 820, 543, 2, 69, 30]
+[:mouse_move, 819, 543, 2, 70, 31]
+[:mouse_move, 818, 543, 2, 71, 31]
+[:mouse_move, 817, 542, 2, 72, 31]
+[:mouse_move, 816, 542, 2, 73, 32]
+[:mouse_move, 812, 542, 2, 74, 32]
+[:mouse_move, 808, 542, 2, 75, 32]
+[:mouse_move, 802, 542, 2, 76, 33]
+[:mouse_move, 796, 542, 2, 77, 33]
+[:mouse_move, 790, 542, 2, 78, 33]
+[:mouse_move, 784, 540, 2, 79, 33]
+[:mouse_move, 783, 540, 2, 80, 34]
+[:mouse_move, 782, 538, 2, 81, 34]
+[:mouse_move, 782, 533, 2, 82, 34]
+[:mouse_move, 785, 525, 2, 83, 34]
+[:mouse_move, 788, 512, 2, 84, 34]
+[:mouse_move, 791, 494, 2, 85, 35]
+[:mouse_move, 791, 469, 2, 86, 35]
+[:mouse_move, 785, 442, 2, 87, 35]
+[:mouse_move, 776, 417, 2, 88, 35]
+[:mouse_move, 767, 398, 2, 89, 36]
+[:mouse_move, 759, 381, 2, 90, 36]
+[:mouse_move, 747, 365, 2, 91, 36]
+[:mouse_move, 737, 356, 2, 92, 36]
+[:mouse_move, 718, 345, 2, 93, 36]
+[:mouse_move, 702, 337, 2, 94, 37]
+[:mouse_move, 693, 333, 2, 95, 37]
+[:mouse_move, 689, 331, 2, 96, 37]
+[:mouse_move, 688, 331, 2, 97, 38]
+[:mouse_move, 687, 331, 2, 98, 38]
+[:mouse_move, 686, 342, 2, 99, 38]
+[:mouse_move, 684, 352, 2, 100, 39]
+[:mouse_move, 682, 359, 2, 101, 39]
+[:mouse_move, 682, 362, 2, 102, 39]
+[:mouse_move, 682, 364, 2, 103, 40]
+[:mouse_move, 683, 364, 2, 104, 40]
+[:mouse_move, 686, 364, 2, 105, 40]
+[:mouse_move, 688, 363, 2, 106, 40]
+[:mouse_move, 692, 362, 2, 107, 40]
+[:mouse_move, 698, 362, 2, 108, 41]
+[:mouse_move, 702, 362, 2, 109, 41]
+[:mouse_move, 705, 362, 2, 110, 41]
+[:mouse_move, 706, 362, 2, 111, 42]
+[:mouse_move, 706, 361, 2, 112, 42]
+[:mouse_move, 707, 361, 2, 113, 42]
+[:mouse_move, 708, 360, 2, 114, 42]
+[:mouse_move, 709, 359, 2, 115, 43]
+[:mouse_move, 709, 358, 2, 116, 43]
+[:mouse_move, 710, 358, 2, 117, 43]
+[:mouse_button_pressed, 1, 0, 1, 118, 44]
+[:mouse_button_up, 1, 0, 1, 119, 45]
+[:mouse_move, 710, 357, 2, 120, 56]
+[:mouse_move, 713, 357, 2, 121, 56]
+[:mouse_move, 715, 357, 2, 122, 57]
+[:mouse_move, 716, 357, 2, 123, 57]
+[:mouse_move, 717, 357, 2, 124, 57]
+[:mouse_move, 719, 357, 2, 125, 58]
+[:mouse_move, 720, 357, 2, 126, 58]
+[:mouse_move, 720, 356, 2, 127, 59]
+[:mouse_move, 721, 356, 2, 128, 59]
+[:mouse_move, 723, 356, 2, 129, 59]
+[:mouse_move, 724, 356, 2, 130, 59]
+[:mouse_move, 727, 356, 2, 131, 59]
+[:mouse_move, 728, 356, 2, 132, 59]
+[:mouse_move, 730, 356, 2, 133, 60]
+[:mouse_move, 731, 355, 2, 134, 60]
+[:mouse_move, 732, 355, 2, 135, 60]
+[:mouse_move, 734, 355, 2, 136, 60]
+[:mouse_move, 735, 355, 2, 137, 60]
+[:mouse_button_pressed, 1, 0, 1, 138, 62]
+[:mouse_move, 737, 358, 2, 139, 63]
+[:mouse_move, 739, 364, 2, 140, 63]
+[:mouse_move, 739, 372, 2, 141, 63]
+[:mouse_move, 739, 381, 2, 142, 64]
+[:mouse_move, 740, 390, 2, 143, 64]
+[:mouse_move, 742, 403, 2, 144, 64]
+[:mouse_move, 744, 415, 2, 145, 64]
+[:mouse_move, 744, 426, 2, 146, 64]
+[:mouse_move, 745, 438, 2, 147, 64]
+[:mouse_move, 746, 445, 2, 148, 64]
+[:mouse_move, 747, 449, 2, 149, 64]
+[:mouse_move, 747, 450, 2, 150, 64]
+[:mouse_move, 747, 451, 2, 151, 64]
+[:mouse_move, 748, 452, 2, 152, 64]
+[:mouse_move, 749, 452, 2, 153, 64]
+[:mouse_move, 750, 452, 2, 154, 64]
+[:mouse_move, 751, 452, 2, 155, 64]
+[:mouse_move, 753, 454, 2, 156, 64]
+[:mouse_move, 754, 455, 2, 157, 64]
+[:mouse_move, 756, 456, 2, 158, 64]
+[:mouse_move, 759, 459, 2, 159, 64]
+[:mouse_move, 765, 465, 2, 160, 64]
+[:mouse_move, 769, 469, 2, 161, 64]
+[:mouse_move, 773, 474, 2, 162, 64]
+[:mouse_move, 776, 479, 2, 163, 64]
+[:mouse_move, 781, 486, 2, 164, 64]
+[:mouse_move, 782, 490, 2, 165, 65]
+[:mouse_move, 783, 494, 2, 166, 65]
+[:mouse_move, 783, 498, 2, 167, 65]
+[:mouse_move, 784, 506, 2, 168, 65]
+[:mouse_move, 786, 515, 2, 169, 65]
+[:mouse_move, 789, 526, 2, 170, 65]
+[:mouse_move, 791, 534, 2, 171, 65]
+[:mouse_move, 795, 549, 2, 172, 65]
+[:mouse_move, 798, 556, 2, 173, 65]
+[:mouse_move, 799, 561, 2, 174, 65]
+[:mouse_move, 799, 564, 2, 175, 65]
+[:mouse_move, 801, 570, 2, 176, 65]
+[:mouse_move, 802, 577, 2, 177, 65]
+[:mouse_move, 804, 583, 2, 178, 65]
+[:mouse_move, 804, 587, 2, 179, 65]
+[:mouse_move, 805, 590, 2, 180, 65]
+[:mouse_move, 807, 594, 2, 181, 65]
+[:mouse_move, 809, 598, 2, 182, 65]
+[:mouse_move, 811, 601, 2, 183, 65]
+[:mouse_move, 812, 602, 2, 184, 65]
+[:mouse_move, 812, 603, 2, 185, 65]
+[:mouse_move, 813, 604, 2, 186, 65]
+[:mouse_move, 814, 604, 2, 187, 65]
+[:mouse_move, 817, 599, 2, 188, 65]
+[:mouse_move, 819, 595, 2, 189, 65]
+[:mouse_move, 820, 594, 2, 190, 65]
+[:mouse_move, 819, 594, 2, 191, 77]
+[:mouse_button_up, 1, 0, 1, 192, 77]
+[:mouse_move, 818, 594, 2, 193, 77]
+[:mouse_move, 817, 594, 2, 194, 78]
+[:mouse_move, 816, 594, 2, 195, 79]
+[:mouse_move, 815, 593, 2, 196, 109]
+[:mouse_move, 812, 592, 2, 197, 109]
+[:mouse_move, 808, 592, 2, 198, 109]
+[:mouse_move, 799, 591, 2, 199, 109]
+[:mouse_move, 780, 588, 2, 200, 110]
+[:mouse_move, 758, 584, 2, 201, 110]
+[:mouse_move, 738, 584, 2, 202, 110]
+[:mouse_move, 724, 584, 2, 203, 110]
+[:mouse_move, 710, 584, 2, 204, 110]
+[:mouse_move, 691, 583, 2, 205, 111]
+[:mouse_move, 668, 579, 2, 206, 111]
+[:mouse_move, 647, 577, 2, 207, 111]
+[:mouse_move, 630, 577, 2, 208, 111]
+[:mouse_move, 610, 577, 2, 209, 112]
+[:mouse_move, 602, 577, 2, 210, 112]
+[:mouse_move, 597, 576, 2, 211, 112]
+[:mouse_move, 595, 575, 2, 212, 112]
+[:mouse_move, 603, 575, 2, 213, 114]
+[:mouse_move, 626, 575, 2, 214, 114]
+[:mouse_move, 651, 575, 2, 215, 114]
+[:mouse_move, 680, 579, 2, 216, 114]
+[:mouse_move, 723, 583, 2, 217, 114]
+[:mouse_move, 745, 585, 2, 218, 114]
+[:mouse_move, 756, 585, 2, 219, 115]
+[:mouse_move, 758, 585, 2, 220, 115]
+[:mouse_move, 759, 585, 2, 221, 115]
+[:mouse_move, 760, 584, 2, 222, 115]
+[:mouse_move, 761, 584, 2, 223, 116]
+[:mouse_move, 764, 584, 2, 224, 116]
+[:mouse_move, 767, 584, 2, 225, 116]
+[:mouse_move, 769, 584, 2, 226, 116]
+[:mouse_move, 773, 584, 2, 227, 117]
+[:mouse_move, 791, 588, 2, 228, 117]
+[:mouse_move, 803, 596, 2, 229, 117]
+[:mouse_move, 807, 599, 2, 230, 118]
+[:mouse_move, 808, 599, 2, 231, 118]
+[:mouse_move, 809, 599, 2, 232, 119]
+[:mouse_move, 812, 599, 2, 233, 120]
+[:mouse_move, 813, 599, 2, 234, 120]
+[:mouse_move, 814, 599, 2, 235, 120]
+[:mouse_move, 815, 599, 2, 236, 122]
+[:mouse_move, 816, 598, 2, 237, 122]
+[:mouse_move, 817, 598, 2, 238, 123]
+[:mouse_button_pressed, 1, 0, 1, 239, 123]
+[:mouse_move, 805, 598, 2, 240, 124]
+[:mouse_move, 777, 598, 2, 241, 124]
+[:mouse_move, 748, 598, 2, 242, 124]
+[:mouse_move, 722, 598, 2, 243, 124]
+[:mouse_move, 692, 598, 2, 244, 124]
+[:mouse_move, 668, 598, 2, 245, 124]
+[:mouse_move, 648, 598, 2, 246, 125]
+[:mouse_move, 624, 598, 2, 247, 125]
+[:mouse_move, 615, 598, 2, 248, 125]
+[:mouse_move, 610, 598, 2, 249, 125]
+[:mouse_move, 609, 598, 2, 250, 125]
+[:mouse_move, 607, 598, 2, 251, 125]
+[:mouse_move, 606, 598, 2, 252, 125]
+[:mouse_move, 604, 595, 2, 253, 127]
+[:mouse_move, 598, 590, 2, 254, 128]
+[:mouse_move, 592, 584, 2, 255, 128]
+[:mouse_move, 588, 581, 2, 256, 129]
+[:mouse_move, 588, 580, 2, 257, 129]
+[:mouse_move, 587, 580, 2, 258, 129]
+[:mouse_move, 586, 579, 2, 259, 130]
+[:mouse_move, 585, 579, 2, 260, 130]
+[:mouse_move, 584, 578, 2, 261, 131]
+[:mouse_move, 584, 577, 2, 262, 131]
+[:mouse_move, 584, 576, 2, 263, 132]
+[:mouse_move, 583, 576, 2, 264, 133]
+[:mouse_move, 584, 576, 2, 265, 135]
+[:mouse_button_up, 1, 0, 1, 266, 147]
+[:mouse_move, 585, 575, 2, 267, 153]
+[:mouse_move, 585, 571, 2, 268, 196]
+[:mouse_move, 585, 568, 2, 269, 197]
+[:mouse_move, 586, 563, 2, 270, 197]
+[:mouse_move, 587, 558, 2, 271, 197]
+[:mouse_move, 587, 557, 2, 272, 198]
+[:mouse_move, 587, 555, 2, 273, 199]
+[:mouse_move, 588, 555, 2, 274, 200]
+[:mouse_move, 588, 554, 2, 275, 200]
+[:mouse_move, 588, 550, 2, 276, 235]
+[:mouse_move, 594, 541, 2, 277, 236]
+[:mouse_move, 605, 525, 2, 278, 236]
+[:mouse_move, 622, 502, 2, 279, 236]
+[:mouse_move, 654, 458, 2, 280, 237]
+[:mouse_move, 672, 425, 2, 281, 237]
+[:mouse_move, 682, 391, 2, 282, 238]
+[:mouse_move, 688, 358, 2, 283, 239]
+[:mouse_move, 692, 333, 2, 284, 239]
+[:mouse_move, 694, 319, 2, 285, 239]
+[:mouse_move, 697, 308, 2, 286, 240]
+[:mouse_move, 698, 303, 2, 287, 240]
+[:mouse_move, 700, 299, 2, 288, 241]
+[:mouse_move, 702, 295, 2, 289, 241]
+[:mouse_move, 703, 291, 2, 290, 242]
+[:mouse_move, 704, 289, 2, 291, 242]
+[:mouse_move, 705, 288, 2, 292, 243]
+[:mouse_move, 706, 288, 2, 293, 245]
+[:mouse_move, 706, 291, 2, 294, 246]
+[:mouse_move, 706, 294, 2, 295, 246]
+[:mouse_move, 706, 298, 2, 296, 247]
+[:mouse_move, 706, 303, 2, 297, 247]
+[:mouse_move, 707, 308, 2, 298, 247]
+[:mouse_move, 709, 315, 2, 299, 248]
+[:mouse_move, 710, 321, 2, 300, 248]
+[:mouse_move, 711, 324, 2, 301, 249]
+[:mouse_move, 711, 325, 2, 302, 249]
+[:mouse_move, 712, 325, 2, 303, 250]
+[:mouse_move, 713, 325, 2, 304, 252]
+[:mouse_move, 713, 324, 2, 305, 252]
+[:mouse_move, 714, 324, 2, 306, 253]
+[:mouse_button_pressed, 1, 0, 1, 307, 254]
+[:mouse_button_up, 1, 0, 1, 308, 255]
+[:mouse_move, 714, 325, 2, 309, 263]
+[:mouse_move, 714, 331, 2, 310, 263]
+[:mouse_move, 714, 344, 2, 311, 264]
+[:mouse_move, 714, 365, 2, 312, 264]
+[:mouse_move, 710, 394, 2, 313, 264]
+[:mouse_move, 696, 432, 2, 314, 265]
+[:mouse_move, 678, 472, 2, 315, 265]
+[:mouse_move, 654, 506, 2, 316, 266]
+[:mouse_move, 637, 532, 2, 317, 267]
+[:mouse_move, 624, 549, 2, 318, 267]
+[:mouse_move, 615, 559, 2, 319, 267]
+[:mouse_move, 612, 562, 2, 320, 268]
+[:mouse_move, 609, 563, 2, 321, 268]
+[:mouse_move, 608, 564, 2, 322, 269]
+[:mouse_move, 606, 566, 2, 323, 269]
+[:mouse_move, 606, 568, 2, 324, 270]
+[:mouse_move, 606, 572, 2, 325, 270]
+[:mouse_move, 606, 573, 2, 326, 271]
+[:mouse_move, 606, 574, 2, 327, 271]
+[:mouse_move, 605, 573, 2, 328, 273]
+[:mouse_move, 606, 571, 2, 329, 273]
+[:mouse_move, 606, 566, 2, 330, 274]
+[:mouse_move, 606, 565, 2, 331, 274]
+[:mouse_move, 605, 565, 2, 332, 275]
+[:mouse_move, 601, 565, 2, 333, 275]
+[:mouse_move, 593, 565, 2, 334, 276]
+[:mouse_move, 583, 565, 2, 335, 276]
+[:mouse_move, 573, 567, 2, 336, 277]
+[:mouse_move, 570, 567, 2, 337, 278]
+[:mouse_move, 569, 567, 2, 338, 278]
+[:mouse_move, 570, 568, 2, 339, 284]
+[:mouse_move, 572, 568, 2, 340, 284]
+[:mouse_move, 573, 568, 2, 341, 286]
+[:mouse_button_pressed, 1, 0, 1, 342, 290]
+[:mouse_move, 574, 568, 2, 343, 290]
+[:mouse_move, 576, 568, 2, 344, 291]
+[:mouse_move, 586, 564, 2, 345, 292]
+[:mouse_move, 601, 560, 2, 346, 292]
+[:mouse_move, 622, 552, 2, 347, 292]
+[:mouse_move, 648, 544, 2, 348, 293]
+[:mouse_move, 675, 537, 2, 349, 293]
+[:mouse_move, 702, 533, 2, 350, 293]
+[:mouse_move, 726, 530, 2, 351, 293]
+[:mouse_move, 747, 526, 2, 352, 293]
+[:mouse_move, 771, 518, 2, 353, 293]
+[:mouse_move, 786, 514, 2, 354, 293]
+[:mouse_move, 802, 511, 2, 355, 294]
+[:mouse_move, 815, 508, 2, 356, 294]
+[:mouse_move, 827, 505, 2, 357, 294]
+[:mouse_move, 833, 504, 2, 358, 294]
+[:mouse_move, 835, 503, 2, 359, 294]
+[:mouse_move, 832, 503, 2, 360, 294]
+[:mouse_move, 830, 504, 2, 361, 294]
+[:mouse_move, 826, 506, 2, 362, 294]
+[:mouse_move, 822, 508, 2, 363, 294]
+[:mouse_move, 818, 511, 2, 364, 294]
+[:mouse_move, 816, 511, 2, 365, 294]
+[:mouse_move, 813, 513, 2, 366, 294]
+[:mouse_move, 813, 514, 2, 367, 294]
+[:mouse_move, 812, 515, 2, 368, 294]
+[:mouse_move, 812, 516, 2, 369, 294]
+[:mouse_move, 812, 517, 2, 370, 294]
+[:mouse_move, 813, 518, 2, 371, 295]
+[:mouse_move, 814, 518, 2, 372, 295]
+[:mouse_move, 815, 518, 2, 373, 295]
+[:mouse_move, 816, 518, 2, 374, 295]
+[:mouse_move, 817, 518, 2, 375, 295]
+[:mouse_button_up, 1, 0, 1, 376, 302]
+[:mouse_move, 817, 517, 2, 377, 313]
+[:key_down_raw, 96, 0, 2, 378, 320]
+[:key_up_raw, 96, 0, 2, 379, 321]
+[:mouse_move, 817, 518, 2, 380, 323]
+[:mouse_move, 819, 515, 2, 381, 324]
+[:mouse_move, 819, 510, 2, 382, 324]
+[:mouse_move, 811, 498, 2, 383, 324]
+[:mouse_move, 797, 486, 2, 384, 324]
+[:mouse_move, 786, 482, 2, 385, 324]
+[:mouse_move, 780, 479, 2, 386, 324]
+[:mouse_move, 779, 478, 2, 387, 324]
+[:mouse_move, 778, 479, 2, 388, 327]
+[:mouse_move, 779, 484, 2, 389, 327]
+[:mouse_move, 780, 487, 2, 390, 327]
+[:mouse_move, 781, 488, 2, 391, 327]
+[:mouse_move, 782, 488, 2, 392, 327]
+[:mouse_move, 782, 487, 2, 393, 328]
+[:mouse_move, 789, 485, 2, 394, 328]
+[:mouse_move, 800, 481, 2, 395, 328]
+[:mouse_move, 816, 472, 2, 396, 328]
+[:mouse_move, 839, 456, 2, 397, 328]
+[:mouse_move, 870, 434, 2, 398, 329]
+[:mouse_move, 904, 409, 2, 399, 329]
+[:mouse_move, 944, 380, 2, 400, 329]
+[:mouse_move, 996, 331, 2, 401, 329]
+[:mouse_move, 1011, 312, 2, 402, 329]
+[:mouse_move, 1042, 278, 2, 403, 329]
+[:mouse_move, 1081, 231, 2, 404, 329]
+[:mouse_move, 1101, 213, 2, 405, 330]
+[:mouse_move, 1114, 202, 2, 406, 330]
+[:mouse_move, 1118, 196, 2, 407, 330]
+[:mouse_move, 1118, 195, 2, 408, 330]
+[:mouse_move, 1117, 194, 2, 409, 331]
+[:mouse_move, 1115, 194, 2, 410, 331]
+[:mouse_move, 1110, 193, 2, 411, 331]
+[:mouse_move, 1102, 189, 2, 412, 331]
+[:mouse_move, 1084, 184, 2, 413, 331]
+[:mouse_move, 1052, 175, 2, 414, 332]
+[:mouse_move, 1005, 162, 2, 415, 332]
+[:mouse_move, 938, 144, 2, 416, 332]
+[:mouse_move, 892, 138, 2, 417, 332]
+[:mouse_move, 860, 134, 2, 418, 332]
+[:mouse_move, 833, 128, 2, 419, 333]
+[:mouse_move, 809, 120, 2, 420, 333]
+[:mouse_move, 782, 108, 2, 421, 333]
+[:mouse_move, 772, 104, 2, 422, 333]
+[:mouse_move, 770, 103, 2, 423, 333]
+[:mouse_move, 769, 103, 2, 424, 333]
+[:mouse_move, 766, 101, 2, 425, 334]
+[:mouse_move, 764, 100, 2, 426, 334]
+[:mouse_move, 763, 100, 2, 427, 334]
+[:mouse_move, 761, 99, 2, 428, 334]
+[:mouse_move, 760, 98, 2, 429, 334]
+[:key_down_raw, 13, 0, 2, 430, 341]
diff --git a/samples/99_genre_3d/02_wireframe/replay.txt b/samples/99_genre_3d/02_wireframe/replay.txt
new file mode 100644
index 0000000..2786904
--- /dev/null
+++ b/samples/99_genre_3d/02_wireframe/replay.txt
@@ -0,0 +1,242 @@
+replay_version 2.0
+stopped_at 706
+seed 100
+recorded_at 2021-11-20 11:26:04 -0600
+[:mouse_button_up, 1, 0, 1, 1, 4]
+[:key_down_raw, 1073741906, 0, 2, 2, 63]
+[:key_down_raw, 1073741906, 0, 2, 3, 77]
+[:key_down_raw, 1073741906, 0, 2, 4, 79]
+[:key_down_raw, 1073741906, 0, 2, 5, 81]
+[:key_down_raw, 1073741906, 0, 2, 6, 84]
+[:key_down_raw, 1073741906, 0, 2, 7, 85]
+[:key_down_raw, 1073741906, 0, 2, 8, 87]
+[:key_down_raw, 1073741906, 0, 2, 9, 90]
+[:key_down_raw, 1073741906, 0, 2, 10, 92]
+[:key_down_raw, 1073741906, 0, 2, 11, 94]
+[:key_down_raw, 1073741906, 0, 2, 12, 96]
+[:key_down_raw, 1073741906, 0, 2, 13, 98]
+[:key_down_raw, 1073741906, 0, 2, 14, 100]
+[:key_down_raw, 1073741906, 0, 2, 15, 102]
+[:key_up_raw, 1073741906, 0, 2, 16, 103]
+[:key_down_raw, 1073741905, 0, 2, 17, 110]
+[:key_down_raw, 1073741905, 0, 2, 18, 125]
+[:key_down_raw, 1073741905, 0, 2, 19, 127]
+[:key_down_raw, 1073741905, 0, 2, 20, 129]
+[:key_down_raw, 1073741905, 0, 2, 21, 131]
+[:key_down_raw, 1073741905, 0, 2, 22, 133]
+[:key_down_raw, 1073741905, 0, 2, 23, 135]
+[:key_down_raw, 1073741905, 0, 2, 24, 137]
+[:key_down_raw, 1073741905, 0, 2, 25, 139]
+[:key_down_raw, 1073741905, 0, 2, 26, 141]
+[:key_down_raw, 1073741905, 0, 2, 27, 143]
+[:key_down_raw, 1073741905, 0, 2, 28, 145]
+[:key_down_raw, 1073741905, 0, 2, 29, 147]
+[:key_down_raw, 1073741905, 0, 2, 30, 149]
+[:key_down_raw, 1073741905, 0, 2, 31, 151]
+[:key_down_raw, 1073741905, 0, 2, 32, 153]
+[:key_down_raw, 1073741905, 0, 2, 33, 155]
+[:key_down_raw, 1073741905, 0, 2, 34, 157]
+[:key_down_raw, 1073741905, 0, 2, 35, 159]
+[:key_down_raw, 1073741905, 0, 2, 36, 161]
+[:key_down_raw, 1073741905, 0, 2, 37, 163]
+[:key_down_raw, 1073741905, 0, 2, 38, 165]
+[:key_down_raw, 1073741905, 0, 2, 39, 167]
+[:key_down_raw, 1073741905, 0, 2, 40, 169]
+[:key_down_raw, 1073741905, 0, 2, 41, 171]
+[:key_up_raw, 1073741905, 0, 2, 42, 171]
+[:key_down_raw, 1073741904, 0, 2, 43, 175]
+[:key_down_raw, 1073741904, 0, 2, 44, 190]
+[:key_down_raw, 1073741904, 0, 2, 45, 192]
+[:key_down_raw, 1073741904, 0, 2, 46, 194]
+[:key_down_raw, 1073741904, 0, 2, 47, 196]
+[:key_down_raw, 1073741904, 0, 2, 48, 198]
+[:key_down_raw, 1073741904, 0, 2, 49, 200]
+[:key_down_raw, 1073741904, 0, 2, 50, 202]
+[:key_down_raw, 1073741904, 0, 2, 51, 204]
+[:key_down_raw, 1073741904, 0, 2, 52, 206]
+[:key_down_raw, 1073741904, 0, 2, 53, 208]
+[:key_down_raw, 1073741904, 0, 2, 54, 210]
+[:key_down_raw, 1073741904, 0, 2, 55, 212]
+[:key_down_raw, 1073741903, 0, 2, 56, 214]
+[:key_down_raw, 1073741903, 0, 2, 57, 229]
+[:key_down_raw, 1073741903, 0, 2, 58, 231]
+[:key_down_raw, 1073741903, 0, 2, 59, 233]
+[:key_down_raw, 1073741906, 0, 2, 60, 234]
+[:key_up_raw, 1073741904, 0, 2, 61, 238]
+[:key_down_raw, 1073741906, 0, 2, 62, 249]
+[:key_down_raw, 1073741906, 0, 2, 63, 251]
+[:key_down_raw, 1073741906, 0, 2, 64, 253]
+[:key_down_raw, 1073741906, 0, 2, 65, 255]
+[:key_down_raw, 1073741906, 0, 2, 66, 257]
+[:key_down_raw, 1073741906, 0, 2, 67, 259]
+[:key_down_raw, 1073741906, 0, 2, 68, 261]
+[:key_down_raw, 1073741906, 0, 2, 69, 263]
+[:key_down_raw, 1073741906, 0, 2, 70, 265]
+[:key_down_raw, 1073741906, 0, 2, 71, 267]
+[:key_down_raw, 1073741906, 0, 2, 72, 269]
+[:key_down_raw, 1073741906, 0, 2, 73, 271]
+[:key_down_raw, 1073741906, 0, 2, 74, 273]
+[:key_down_raw, 1073741906, 0, 2, 75, 275]
+[:key_down_raw, 1073741906, 0, 2, 76, 277]
+[:key_down_raw, 1073741906, 0, 2, 77, 279]
+[:key_down_raw, 1073741906, 0, 2, 78, 281]
+[:key_down_raw, 1073741906, 0, 2, 79, 283]
+[:key_down_raw, 1073741906, 0, 2, 80, 285]
+[:key_down_raw, 1073741906, 0, 2, 81, 287]
+[:key_down_raw, 1073741906, 0, 2, 82, 289]
+[:key_down_raw, 1073741906, 0, 2, 83, 291]
+[:key_down_raw, 1073741906, 0, 2, 84, 293]
+[:key_down_raw, 1073741906, 0, 2, 85, 295]
+[:key_down_raw, 1073741906, 0, 2, 86, 297]
+[:key_down_raw, 1073741906, 0, 2, 87, 299]
+[:key_down_raw, 1073741906, 0, 2, 88, 301]
+[:key_down_raw, 1073741905, 0, 2, 89, 301]
+[:key_up_raw, 1073741906, 0, 2, 90, 310]
+[:key_up_raw, 1073741903, 0, 2, 91, 310]
+[:key_down_raw, 1073741904, 0, 2, 92, 316]
+[:key_down_raw, 1073741904, 0, 2, 93, 331]
+[:key_down_raw, 1073741904, 0, 2, 94, 333]
+[:key_down_raw, 1073741904, 0, 2, 95, 335]
+[:key_down_raw, 1073741904, 0, 2, 96, 337]
+[:key_down_raw, 1073741904, 0, 2, 97, 339]
+[:key_down_raw, 1073741904, 0, 2, 98, 341]
+[:key_down_raw, 1073741904, 0, 2, 99, 343]
+[:key_down_raw, 1073741904, 0, 2, 100, 345]
+[:key_down_raw, 1073741904, 0, 2, 101, 347]
+[:key_down_raw, 1073741904, 0, 2, 102, 349]
+[:key_down_raw, 1073741904, 0, 2, 103, 351]
+[:key_down_raw, 1073741904, 0, 2, 104, 353]
+[:key_down_raw, 1073741904, 0, 2, 105, 355]
+[:key_down_raw, 1073741904, 0, 2, 106, 357]
+[:key_down_raw, 1073741904, 0, 2, 107, 359]
+[:key_down_raw, 1073741904, 0, 2, 108, 361]
+[:key_up_raw, 1073741905, 0, 2, 109, 363]
+[:key_down_raw, 1073741904, 0, 2, 110, 363]
+[:key_down_raw, 1073741904, 0, 2, 111, 365]
+[:key_down_raw, 1073741904, 0, 2, 112, 367]
+[:key_down_raw, 1073741904, 0, 2, 113, 369]
+[:key_down_raw, 1073741904, 0, 2, 114, 371]
+[:key_down_raw, 1073741904, 0, 2, 115, 373]
+[:key_down_raw, 1073741904, 0, 2, 116, 375]
+[:key_down_raw, 1073741904, 0, 2, 117, 377]
+[:key_down_raw, 1073741904, 0, 2, 118, 379]
+[:key_down_raw, 1073741904, 0, 2, 119, 381]
+[:key_down_raw, 1073741904, 0, 2, 120, 383]
+[:key_down_raw, 1073741904, 0, 2, 121, 385]
+[:key_down_raw, 1073741904, 0, 2, 122, 387]
+[:key_down_raw, 1073741904, 0, 2, 123, 389]
+[:key_down_raw, 1073741904, 0, 2, 124, 391]
+[:key_down_raw, 1073741904, 0, 2, 125, 393]
+[:key_down_raw, 1073741904, 0, 2, 126, 395]
+[:key_down_raw, 1073741904, 0, 2, 127, 397]
+[:key_up_raw, 1073741904, 0, 2, 128, 399]
+[:key_down_raw, 1073741903, 0, 2, 129, 400]
+[:key_down_raw, 1073741903, 0, 2, 130, 415]
+[:key_down_raw, 1073741903, 0, 2, 131, 417]
+[:key_down_raw, 1073741903, 0, 2, 132, 419]
+[:key_down_raw, 1073741903, 0, 2, 133, 421]
+[:key_down_raw, 1073741903, 0, 2, 134, 423]
+[:key_down_raw, 1073741903, 0, 2, 135, 425]
+[:key_down_raw, 1073741903, 0, 2, 136, 427]
+[:key_down_raw, 1073741903, 0, 2, 137, 429]
+[:key_down_raw, 1073741903, 0, 2, 138, 431]
+[:key_down_raw, 1073741903, 0, 2, 139, 433]
+[:key_down_raw, 1073741903, 0, 2, 140, 435]
+[:key_down_raw, 1073741903, 0, 2, 141, 437]
+[:key_down_raw, 1073741903, 0, 2, 142, 439]
+[:key_down_raw, 1073741903, 0, 2, 143, 441]
+[:key_down_raw, 1073741903, 0, 2, 144, 443]
+[:key_down_raw, 1073741903, 0, 2, 145, 445]
+[:key_down_raw, 1073741903, 0, 2, 146, 447]
+[:key_down_raw, 1073741903, 0, 2, 147, 449]
+[:key_down_raw, 1073741903, 0, 2, 148, 451]
+[:key_down_raw, 1073741903, 0, 2, 149, 453]
+[:key_down_raw, 1073741903, 0, 2, 150, 455]
+[:key_down_raw, 1073741903, 0, 2, 151, 457]
+[:key_down_raw, 1073741903, 0, 2, 152, 459]
+[:key_down_raw, 1073741903, 0, 2, 153, 461]
+[:key_down_raw, 1073741903, 0, 2, 154, 463]
+[:key_down_raw, 1073741903, 0, 2, 155, 465]
+[:key_down_raw, 1073741903, 0, 2, 156, 467]
+[:key_down_raw, 1073741903, 0, 2, 157, 469]
+[:key_down_raw, 1073741903, 0, 2, 158, 471]
+[:key_down_raw, 1073741903, 0, 2, 159, 473]
+[:key_down_raw, 1073741903, 0, 2, 160, 475]
+[:key_down_raw, 1073741903, 0, 2, 161, 477]
+[:key_down_raw, 1073741903, 0, 2, 162, 479]
+[:key_down_raw, 1073741903, 0, 2, 163, 481]
+[:key_down_raw, 1073741903, 0, 2, 164, 483]
+[:key_down_raw, 1073741903, 0, 2, 165, 485]
+[:key_down_raw, 1073741903, 0, 2, 166, 487]
+[:key_down_raw, 1073741903, 0, 2, 167, 489]
+[:key_down_raw, 1073741903, 0, 2, 168, 491]
+[:key_down_raw, 1073741903, 0, 2, 169, 493]
+[:key_down_raw, 1073741903, 0, 2, 170, 495]
+[:key_down_raw, 1073741903, 0, 2, 171, 497]
+[:key_down_raw, 1073741905, 0, 2, 172, 498]
+[:key_down_raw, 1073741905, 0, 2, 173, 513]
+[:key_down_raw, 1073741905, 0, 2, 174, 515]
+[:key_down_raw, 1073741905, 0, 2, 175, 517]
+[:key_down_raw, 1073741905, 0, 2, 176, 519]
+[:key_down_raw, 1073741905, 0, 2, 177, 521]
+[:key_down_raw, 1073741905, 0, 2, 178, 523]
+[:key_down_raw, 1073741905, 0, 2, 179, 525]
+[:key_down_raw, 1073741905, 0, 2, 180, 527]
+[:key_down_raw, 1073741905, 0, 2, 181, 529]
+[:key_down_raw, 1073741905, 0, 2, 182, 531]
+[:key_down_raw, 1073741905, 0, 2, 183, 533]
+[:key_down_raw, 1073741905, 0, 2, 184, 535]
+[:key_down_raw, 1073741905, 0, 2, 185, 537]
+[:key_down_raw, 1073741905, 0, 2, 186, 539]
+[:key_down_raw, 1073741905, 0, 2, 187, 541]
+[:key_down_raw, 1073741905, 0, 2, 188, 543]
+[:key_up_raw, 1073741905, 0, 2, 189, 543]
+[:key_up_raw, 1073741903, 0, 2, 190, 544]
+[:key_down_raw, 1073741906, 0, 2, 191, 547]
+[:key_down_raw, 1073741906, 0, 2, 192, 562]
+[:key_down_raw, 1073741906, 0, 2, 193, 564]
+[:key_down_raw, 1073741906, 0, 2, 194, 566]
+[:key_down_raw, 1073741906, 0, 2, 195, 568]
+[:key_down_raw, 1073741906, 0, 2, 196, 570]
+[:key_down_raw, 1073741906, 0, 2, 197, 572]
+[:key_down_raw, 1073741906, 0, 2, 198, 574]
+[:key_down_raw, 1073741906, 0, 2, 199, 576]
+[:key_down_raw, 1073741906, 0, 2, 200, 578]
+[:key_down_raw, 1073741906, 0, 2, 201, 580]
+[:key_down_raw, 1073741906, 0, 2, 202, 582]
+[:key_down_raw, 1073741906, 0, 2, 203, 584]
+[:key_down_raw, 1073741906, 0, 2, 204, 586]
+[:key_down_raw, 1073741906, 0, 2, 205, 588]
+[:key_down_raw, 1073741906, 0, 2, 206, 590]
+[:key_down_raw, 1073741906, 0, 2, 207, 592]
+[:key_down_raw, 1073741906, 0, 2, 208, 594]
+[:key_down_raw, 1073741906, 0, 2, 209, 596]
+[:key_down_raw, 1073741906, 0, 2, 210, 598]
+[:key_down_raw, 1073741906, 0, 2, 211, 600]
+[:key_down_raw, 1073741906, 0, 2, 212, 602]
+[:key_down_raw, 1073741906, 0, 2, 213, 604]
+[:key_down_raw, 1073741906, 0, 2, 214, 606]
+[:key_down_raw, 1073741906, 0, 2, 215, 608]
+[:key_down_raw, 1073741906, 0, 2, 216, 610]
+[:key_down_raw, 1073741906, 0, 2, 217, 612]
+[:key_down_raw, 1073741906, 0, 2, 218, 614]
+[:key_down_raw, 1073741906, 0, 2, 219, 616]
+[:key_down_raw, 1073741906, 0, 2, 220, 618]
+[:key_down_raw, 1073741906, 0, 2, 221, 620]
+[:key_down_raw, 1073741906, 0, 2, 222, 622]
+[:key_down_raw, 1073741906, 0, 2, 223, 624]
+[:key_down_raw, 1073741906, 0, 2, 224, 626]
+[:key_down_raw, 1073741906, 0, 2, 225, 628]
+[:key_down_raw, 1073741906, 0, 2, 226, 630]
+[:key_down_raw, 1073741906, 0, 2, 227, 632]
+[:key_down_raw, 1073741906, 0, 2, 228, 634]
+[:key_up_raw, 1073741906, 0, 2, 229, 634]
+[:key_down_raw, 96, 0, 2, 230, 648]
+[:key_up_raw, 96, 0, 2, 231, 652]
+[:mouse_move, 800, 84, 2, 232, 674]
+[:mouse_move, 782, 88, 2, 233, 675]
+[:mouse_move, 764, 94, 2, 234, 676]
+[:mouse_move, 760, 94, 2, 235, 677]
+[:mouse_move, 761, 94, 2, 236, 679]
+[:mouse_move, 762, 93, 2, 237, 680]
+[:key_down_raw, 13, 0, 2, 238, 706]
diff --git a/samples/99_genre_3d/03_yaw_pitch_roll/app/main.rb b/samples/99_genre_3d/03_yaw_pitch_roll/app/main.rb
new file mode 100644
index 0000000..52b5962
--- /dev/null
+++ b/samples/99_genre_3d/03_yaw_pitch_roll/app/main.rb
@@ -0,0 +1,351 @@
+class Game
+ attr_gtk
+
+ def tick
+ defaults
+ render
+ input
+ end
+
+ def matrix_mul m, v
+ (hmap x: ((m.x.x * v.x) + (m.x.y * v.y) + (m.x.z * v.z) + (m.x.w * v.w)),
+ y: ((m.y.x * v.x) + (m.y.y * v.y) + (m.y.z * v.z) + (m.y.w * v.w)),
+ z: ((m.z.x * v.x) + (m.z.y * v.y) + (m.z.z * v.z) + (m.z.w * v.w)),
+ w: ((m.w.x * v.x) + (m.w.y * v.y) + (m.w.z * v.z) + (m.w.w * v.w)))
+ end
+
+ def player_ship
+ [
+ # engine back
+ { x: -1, y: -1, z: 1, w: 0 },
+ { x: -1, y: 1, z: 1, w: 0 },
+
+ { x: -1, y: 1, z: 1, w: 0 },
+ { x: 1, y: 1, z: 1, w: 0 },
+
+ { x: 1, y: 1, z: 1, w: 0 },
+ { x: 1, y: -1, z: 1, w: 0 },
+
+ { x: 1, y: -1, z: 1, w: 0 },
+ { x: -1, y: -1, z: 1, w: 0 },
+
+ # engine front
+ { x: -1, y: -1, z: -1, w: 0 },
+ { x: -1, y: 1, z: -1, w: 0 },
+
+ { x: -1, y: 1, z: -1, w: 0 },
+ { x: 1, y: 1, z: -1, w: 0 },
+
+ { x: 1, y: 1, z: -1, w: 0 },
+ { x: 1, y: -1, z: -1, w: 0 },
+
+ { x: 1, y: -1, z: -1, w: 0 },
+ { x: -1, y: -1, z: -1, w: 0 },
+
+ # engine left
+ { x: -1, z: -1, y: -1, w: 0 },
+ { x: -1, z: -1, y: 1, w: 0 },
+
+ { x: -1, z: -1, y: 1, w: 0 },
+ { x: -1, z: 1, y: 1, w: 0 },
+
+ { x: -1, z: 1, y: 1, w: 0 },
+ { x: -1, z: 1, y: -1, w: 0 },
+
+ { x: -1, z: 1, y: -1, w: 0 },
+ { x: -1, z: -1, y: -1, w: 0 },
+
+ # engine right
+ { x: 1, z: -1, y: -1, w: 0 },
+ { x: 1, z: -1, y: 1, w: 0 },
+
+ { x: 1, z: -1, y: 1, w: 0 },
+ { x: 1, z: 1, y: 1, w: 0 },
+
+ { x: 1, z: 1, y: 1, w: 0 },
+ { x: 1, z: 1, y: -1, w: 0 },
+
+ { x: 1, z: 1, y: -1, w: 0 },
+ { x: 1, z: -1, y: -1, w: 0 },
+
+ # top front of engine to front of ship
+ { x: 1, y: 1, z: 1, w: 0 },
+ { x: 0, y: -1, z: 9, w: 0 },
+
+ { x: 0, y: -1, z: 9, w: 0 },
+ { x: -1, y: 1, z: 1, w: 0 },
+
+ # bottom front of engine
+ { x: 1, y: -1, z: 1, w: 0 },
+ { x: 0, y: -1, z: 9, w: 0 },
+
+ { x: -1, y: -1, z: 1, w: 0 },
+ { x: 0, y: -1, z: 9, w: 0 },
+
+ # right wing
+ # front of wing
+ { x: 1, y: 0.10, z: 1, w: 0 },
+ { x: 9, y: 0.10, z: -1, w: 0 },
+
+ { x: 9, y: 0.10, z: -1, w: 0 },
+ { x: 10, y: 0.10, z: -2, w: 0 },
+
+ # back of wing
+ { x: 1, y: 0.10, z: -1, w: 0 },
+ { x: 9, y: 0.10, z: -1, w: 0 },
+
+ { x: 10, y: 0.10, z: -2, w: 0 },
+ { x: 8, y: 0.10, z: -1, w: 0 },
+
+ # front of wing
+ { x: 1, y: -0.10, z: 1, w: 0 },
+ { x: 9, y: -0.10, z: -1, w: 0 },
+
+ { x: 9, y: -0.10, z: -1, w: 0 },
+ { x: 10, y: -0.10, z: -2, w: 0 },
+
+ # back of wing
+ { x: 1, y: -0.10, z: -1, w: 0 },
+ { x: 9, y: -0.10, z: -1, w: 0 },
+
+ { x: 10, y: -0.10, z: -2, w: 0 },
+ { x: 8, y: -0.10, z: -1, w: 0 },
+
+ # left wing
+ # front of wing
+ { x: -1, y: 0.10, z: 1, w: 0 },
+ { x: -9, y: 0.10, z: -1, w: 0 },
+
+ { x: -9, y: 0.10, z: -1, w: 0 },
+ { x: -10, y: 0.10, z: -2, w: 0 },
+
+ # back of wing
+ { x: -1, y: 0.10, z: -1, w: 0 },
+ { x: -9, y: 0.10, z: -1, w: 0 },
+
+ { x: -10, y: 0.10, z: -2, w: 0 },
+ { x: -8, y: 0.10, z: -1, w: 0 },
+
+ # front of wing
+ { x: -1, y: -0.10, z: 1, w: 0 },
+ { x: -9, y: -0.10, z: -1, w: 0 },
+
+ { x: -9, y: -0.10, z: -1, w: 0 },
+ { x: -10, y: -0.10, z: -2, w: 0 },
+
+ # back of wing
+ { x: -1, y: -0.10, z: -1, w: 0 },
+ { x: -9, y: -0.10, z: -1, w: 0 },
+
+ { x: -10, y: -0.10, z: -2, w: 0 },
+ { x: -8, y: -0.10, z: -1, w: 0 },
+
+ # left fin
+ # top
+ { x: -1, y: 0.10, z: 1, w: 0 },
+ { x: -1, y: 3, z: -3, w: 0 },
+
+ { x: -1, y: 0.10, z: -1, w: 0 },
+ { x: -1, y: 3, z: -3, w: 0 },
+
+ { x: -1.1, y: 0.10, z: 1, w: 0 },
+ { x: -1.1, y: 3, z: -3, w: 0 },
+
+ { x: -1.1, y: 0.10, z: -1, w: 0 },
+ { x: -1.1, y: 3, z: -3, w: 0 },
+
+ # bottom
+ { x: -1, y: -0.10, z: 1, w: 0 },
+ { x: -1, y: -2, z: -2, w: 0 },
+
+ { x: -1, y: -0.10, z: -1, w: 0 },
+ { x: -1, y: -2, z: -2, w: 0 },
+
+ { x: -1.1, y: -0.10, z: 1, w: 0 },
+ { x: -1.1, y: -2, z: -2, w: 0 },
+
+ { x: -1.1, y: -0.10, z: -1, w: 0 },
+ { x: -1.1, y: -2, z: -2, w: 0 },
+
+ # right fin
+ { x: 1, y: 0.10, z: 1, w: 0 },
+ { x: 1, y: 3, z: -3, w: 0 },
+
+ { x: 1, y: 0.10, z: -1, w: 0 },
+ { x: 1, y: 3, z: -3, w: 0 },
+
+ { x: 1.1, y: 0.10, z: 1, w: 0 },
+ { x: 1.1, y: 3, z: -3, w: 0 },
+
+ { x: 1.1, y: 0.10, z: -1, w: 0 },
+ { x: 1.1, y: 3, z: -3, w: 0 },
+
+ # bottom
+ { x: 1, y: -0.10, z: 1, w: 0 },
+ { x: 1, y: -2, z: -2, w: 0 },
+
+ { x: 1, y: -0.10, z: -1, w: 0 },
+ { x: 1, y: -2, z: -2, w: 0 },
+
+ { x: 1.1, y: -0.10, z: 1, w: 0 },
+ { x: 1.1, y: -2, z: -2, w: 0 },
+
+ { x: 1.1, y: -0.10, z: -1, w: 0 },
+ { x: 1.1, y: -2, z: -2, w: 0 },
+ ]
+ end
+
+ def defaults
+ state.points ||= player_ship
+ state.shifted_points ||= state.points.map { |point| point }
+
+ state.scale ||= 1
+ state.angle_x ||= 0
+ state.angle_y ||= 0
+ state.angle_z ||= 0
+ end
+
+ def matrix_new x0, y0, z0, w0, x1, y1, z1, w1, x2, y2, z2, w2, x3, y3, z3, w3
+ (hmap x: (hmap x: x0, y: y0, z: z0, w: w0),
+ y: (hmap x: x1, y: y1, z: z1, w: w1),
+ z: (hmap x: x2, y: y2, z: z2, w: w2),
+ w: (hmap x: x3, y: y3, z: z3, w: w3))
+ end
+
+ def angle_z_matrix degrees
+ cos_t = Math.cos degrees.to_radians
+ sin_t = Math.sin degrees.to_radians
+ (matrix_new cos_t, -sin_t, 0, 0,
+ sin_t, cos_t, 0, 0,
+ 0, 0, 1, 0,
+ 0, 0, 0, 1)
+ end
+
+ def angle_y_matrix degrees
+ cos_t = Math.cos degrees.to_radians
+ sin_t = Math.sin degrees.to_radians
+ (matrix_new cos_t, 0, sin_t, 0,
+ 0, 1, 0, 0,
+ -sin_t, 0, cos_t, 0,
+ 0, 0, 0, 1)
+ end
+
+ def angle_x_matrix degrees
+ cos_t = Math.cos degrees.to_radians
+ sin_t = Math.sin degrees.to_radians
+ (matrix_new 1, 0, 0, 0,
+ 0, cos_t, -sin_t, 0,
+ 0, sin_t, cos_t, 0,
+ 0, 0, 0, 1)
+ end
+
+ def scale_matrix factor
+ (matrix_new factor, 0, 0, 0,
+ 0, factor, 0, 0,
+ 0, 0, factor, 0,
+ 0, 0, 0, 1)
+ end
+
+ def input
+ if (inputs.keyboard.shift && inputs.keyboard.p)
+ state.scale -= 0.1
+ elsif inputs.keyboard.p
+ state.scale += 0.1
+ end
+
+ if inputs.mouse.wheel
+ state.scale += inputs.mouse.wheel.y
+ end
+
+ state.scale = state.scale.clamp(0.1, 1000)
+
+ if (inputs.keyboard.shift && inputs.keyboard.y) || inputs.keyboard.right
+ state.angle_y += 1
+ elsif (inputs.keyboard.y) || inputs.keyboard.left
+ state.angle_y -= 1
+ end
+
+ if (inputs.keyboard.shift && inputs.keyboard.x) || inputs.keyboard.down
+ state.angle_x -= 1
+ elsif (inputs.keyboard.x || inputs.keyboard.up)
+ state.angle_x += 1
+ end
+
+ if inputs.keyboard.shift && inputs.keyboard.z
+ state.angle_z += 1
+ elsif inputs.keyboard.z
+ state.angle_z -= 1
+ end
+
+ if inputs.keyboard.zero
+ state.angle_x = 0
+ state.angle_y = 0
+ state.angle_z = 0
+ end
+
+ angle_x = state.angle_x
+ angle_y = state.angle_y
+ angle_z = state.angle_z
+ scale = state.scale
+
+ s_matrix = scale_matrix state.scale
+ x_matrix = angle_z_matrix angle_z
+ y_matrix = angle_y_matrix angle_y
+ z_matrix = angle_x_matrix angle_x
+
+ state.shifted_points = state.points.map do |point|
+ (matrix_mul s_matrix,
+ (matrix_mul z_matrix,
+ (matrix_mul x_matrix,
+ (matrix_mul y_matrix, point)))).merge(original: point)
+ end
+ end
+
+ def thick_line line
+ [
+ line.merge(y: line.y - 1, y2: line.y2 - 1, r: 0, g: 0, b: 0),
+ line.merge(x: line.x - 1, x2: line.x2 - 1, r: 0, g: 0, b: 0),
+ line.merge(x: line.x - 0, x2: line.x2 - 0, r: 0, g: 0, b: 0),
+ line.merge(y: line.y + 1, y2: line.y2 + 1, r: 0, g: 0, b: 0),
+ line.merge(x: line.x + 1, x2: line.x2 + 1, r: 0, g: 0, b: 0)
+ ]
+ end
+
+ def render
+ outputs.lines << state.shifted_points.each_slice(2).map do |(p1, p2)|
+ perc = 0
+ thick_line({ x: p1.x.*(10) + 640, y: p1.y.*(10) + 320,
+ x2: p2.x.*(10) + 640, y2: p2.y.*(10) + 320,
+ r: 255 * perc,
+ g: 255 * perc,
+ b: 255 * perc })
+ end
+
+ outputs.labels << [ 10, 700, "angle_x: #{state.angle_x.to_sf}", 0]
+ outputs.labels << [ 10, 670, "x, shift+x", 0]
+
+ outputs.labels << [210, 700, "angle_y: #{state.angle_y.to_sf}", 0]
+ outputs.labels << [210, 670, "y, shift+y", 0]
+
+ outputs.labels << [410, 700, "angle_z: #{state.angle_z.to_sf}", 0]
+ outputs.labels << [410, 670, "z, shift+z", 0]
+
+ outputs.labels << [610, 700, "scale: #{state.scale.to_sf}", 0]
+ outputs.labels << [610, 670, "p, shift+p", 0]
+ end
+end
+
+$game = Game.new
+
+def tick args
+ $game.args = args
+ $game.tick
+end
+
+def set_angles x, y, z
+ $game.state.angle_x = x
+ $game.state.angle_y = y
+ $game.state.angle_z = z
+end
+
+$gtk.reset
diff --git a/samples/99_genre_3d/03_yaw_pitch_roll/replay.txt b/samples/99_genre_3d/03_yaw_pitch_roll/replay.txt
new file mode 100644
index 0000000..918fc9e
--- /dev/null
+++ b/samples/99_genre_3d/03_yaw_pitch_roll/replay.txt
@@ -0,0 +1,361 @@
+replay_version 2.0
+stopped_at 493
+seed 100
+recorded_at 2021-10-18 16:32:03 -0500
+[:mouse_button_up, 1, 0, 1, 1, 1]
+[:mouse_move, 813, 82, 2, 2, 9]
+[:mouse_move, 813, 83, 2, 3, 17]
+[:mouse_move, 812, 84, 2, 4, 17]
+[:mouse_move, 809, 86, 2, 5, 17]
+[:mouse_move, 803, 91, 2, 6, 18]
+[:mouse_move, 795, 96, 2, 7, 18]
+[:mouse_move, 792, 98, 2, 8, 19]
+[:mouse_move, 791, 106, 2, 9, 19]
+[:mouse_move, 791, 120, 2, 10, 19]
+[:mouse_move, 791, 138, 2, 11, 20]
+[:mouse_move, 794, 157, 2, 12, 20]
+[:mouse_move, 795, 175, 2, 13, 21]
+[:mouse_move, 795, 193, 2, 14, 21]
+[:mouse_move, 795, 211, 2, 15, 21]
+[:mouse_move, 795, 225, 2, 16, 22]
+[:mouse_move, 795, 233, 2, 17, 22]
+[:mouse_move, 795, 236, 2, 18, 23]
+[:mouse_move, 795, 237, 2, 19, 23]
+[:mouse_move, 795, 238, 2, 20, 24]
+[:mouse_move, 795, 239, 2, 21, 24]
+[:mouse_move, 795, 240, 2, 22, 25]
+[:mouse_move, 794, 241, 2, 23, 26]
+[:mouse_button_pressed, 1, 0, 1, 24, 29]
+[:mouse_button_up, 1, 0, 1, 25, 31]
+[:key_down_raw, 120, 0, 2, 26, 49]
+[:key_down_raw, 120, 0, 2, 27, 55]
+[:key_down_raw, 120, 0, 2, 28, 56]
+[:key_down_raw, 120, 0, 2, 29, 56]
+[:key_down_raw, 120, 0, 2, 30, 57]
+[:key_down_raw, 120, 0, 2, 31, 58]
+[:key_down_raw, 120, 0, 2, 32, 59]
+[:key_down_raw, 120, 0, 2, 33, 60]
+[:key_down_raw, 120, 0, 2, 34, 60]
+[:key_down_raw, 120, 0, 2, 35, 61]
+[:key_down_raw, 120, 0, 2, 36, 62]
+[:key_down_raw, 120, 0, 2, 37, 63]
+[:key_down_raw, 120, 0, 2, 38, 64]
+[:key_down_raw, 120, 0, 2, 39, 65]
+[:key_down_raw, 120, 0, 2, 40, 66]
+[:key_down_raw, 120, 0, 2, 41, 66]
+[:key_down_raw, 120, 0, 2, 42, 67]
+[:key_down_raw, 120, 0, 2, 43, 68]
+[:key_down_raw, 120, 0, 2, 44, 69]
+[:key_down_raw, 120, 0, 2, 45, 70]
+[:key_down_raw, 120, 0, 2, 46, 70]
+[:key_down_raw, 120, 0, 2, 47, 71]
+[:key_down_raw, 120, 0, 2, 48, 72]
+[:key_down_raw, 120, 0, 2, 49, 73]
+[:key_down_raw, 120, 0, 2, 50, 74]
+[:key_down_raw, 120, 0, 2, 51, 75]
+[:key_up_raw, 120, 0, 2, 52, 75]
+[:key_down_raw, 1073742053, 2, 2, 53, 81]
+[:key_down_raw, 120, 2, 2, 54, 83]
+[:key_down_raw, 120, 2, 2, 55, 89]
+[:key_down_raw, 120, 2, 2, 56, 90]
+[:key_down_raw, 120, 2, 2, 57, 91]
+[:key_down_raw, 120, 2, 2, 58, 92]
+[:key_down_raw, 120, 2, 2, 59, 93]
+[:key_down_raw, 120, 2, 2, 60, 93]
+[:key_down_raw, 120, 2, 2, 61, 94]
+[:key_down_raw, 120, 2, 2, 62, 95]
+[:key_down_raw, 120, 2, 2, 63, 96]
+[:key_down_raw, 120, 2, 2, 64, 97]
+[:key_down_raw, 120, 2, 2, 65, 97]
+[:key_down_raw, 120, 2, 2, 66, 98]
+[:key_down_raw, 120, 2, 2, 67, 99]
+[:key_down_raw, 120, 2, 2, 68, 100]
+[:key_down_raw, 120, 2, 2, 69, 101]
+[:key_down_raw, 120, 2, 2, 70, 102]
+[:key_down_raw, 120, 2, 2, 71, 102]
+[:key_down_raw, 120, 2, 2, 72, 103]
+[:key_down_raw, 120, 2, 2, 73, 104]
+[:key_down_raw, 120, 2, 2, 74, 105]
+[:key_down_raw, 120, 2, 2, 75, 106]
+[:key_down_raw, 120, 2, 2, 76, 107]
+[:key_down_raw, 120, 2, 2, 77, 107]
+[:key_down_raw, 120, 2, 2, 78, 108]
+[:key_down_raw, 120, 2, 2, 79, 109]
+[:key_down_raw, 120, 2, 2, 80, 110]
+[:key_down_raw, 120, 2, 2, 81, 111]
+[:key_down_raw, 120, 2, 2, 82, 111]
+[:key_down_raw, 120, 2, 2, 83, 112]
+[:key_down_raw, 120, 2, 2, 84, 113]
+[:key_down_raw, 120, 2, 2, 85, 114]
+[:key_down_raw, 120, 2, 2, 86, 115]
+[:key_down_raw, 120, 2, 2, 87, 116]
+[:key_down_raw, 120, 2, 2, 88, 117]
+[:key_down_raw, 120, 2, 2, 89, 117]
+[:key_down_raw, 120, 2, 2, 90, 118]
+[:key_down_raw, 120, 2, 2, 91, 119]
+[:key_down_raw, 120, 2, 2, 92, 120]
+[:key_down_raw, 120, 2, 2, 93, 121]
+[:key_down_raw, 120, 2, 2, 94, 122]
+[:key_down_raw, 120, 2, 2, 95, 122]
+[:key_down_raw, 120, 2, 2, 96, 123]
+[:key_down_raw, 120, 2, 2, 97, 124]
+[:key_down_raw, 120, 2, 2, 98, 125]
+[:key_down_raw, 120, 2, 2, 99, 126]
+[:key_down_raw, 120, 2, 2, 100, 127]
+[:key_down_raw, 120, 2, 2, 101, 127]
+[:key_down_raw, 120, 2, 2, 102, 128]
+[:key_down_raw, 120, 2, 2, 103, 129]
+[:key_down_raw, 120, 2, 2, 104, 130]
+[:key_down_raw, 120, 2, 2, 105, 131]
+[:key_down_raw, 120, 2, 2, 106, 131]
+[:key_down_raw, 120, 2, 2, 107, 132]
+[:key_down_raw, 120, 2, 2, 108, 133]
+[:key_down_raw, 120, 2, 2, 109, 134]
+[:key_down_raw, 120, 2, 2, 110, 135]
+[:key_down_raw, 120, 2, 2, 111, 136]
+[:key_down_raw, 120, 2, 2, 112, 136]
+[:key_down_raw, 120, 2, 2, 113, 137]
+[:key_down_raw, 120, 2, 2, 114, 138]
+[:key_down_raw, 120, 2, 2, 115, 139]
+[:key_down_raw, 120, 2, 2, 116, 140]
+[:key_down_raw, 120, 2, 2, 117, 140]
+[:key_down_raw, 120, 2, 2, 118, 141]
+[:key_down_raw, 120, 2, 2, 119, 142]
+[:key_down_raw, 120, 2, 2, 120, 143]
+[:key_down_raw, 120, 2, 2, 121, 144]
+[:key_up_raw, 1073742053, 0, 2, 122, 144]
+[:key_down_raw, 120, 0, 2, 123, 145]
+[:key_up_raw, 120, 0, 2, 124, 145]
+[:key_down_raw, 121, 0, 2, 125, 158]
+[:key_down_raw, 121, 0, 2, 126, 165]
+[:key_down_raw, 121, 0, 2, 127, 166]
+[:key_down_raw, 121, 0, 2, 128, 166]
+[:key_down_raw, 121, 0, 2, 129, 167]
+[:key_down_raw, 121, 0, 2, 130, 168]
+[:key_down_raw, 121, 0, 2, 131, 169]
+[:key_down_raw, 121, 0, 2, 132, 170]
+[:key_down_raw, 121, 0, 2, 133, 171]
+[:key_down_raw, 121, 0, 2, 134, 171]
+[:key_down_raw, 121, 0, 2, 135, 172]
+[:key_down_raw, 121, 0, 2, 136, 173]
+[:key_down_raw, 121, 0, 2, 137, 174]
+[:key_down_raw, 121, 0, 2, 138, 175]
+[:key_down_raw, 121, 0, 2, 139, 175]
+[:key_down_raw, 121, 0, 2, 140, 176]
+[:key_down_raw, 121, 0, 2, 141, 177]
+[:key_down_raw, 121, 0, 2, 142, 178]
+[:key_down_raw, 121, 0, 2, 143, 179]
+[:key_down_raw, 121, 0, 2, 144, 180]
+[:key_down_raw, 121, 0, 2, 145, 180]
+[:key_down_raw, 121, 0, 2, 146, 181]
+[:key_down_raw, 121, 0, 2, 147, 182]
+[:key_down_raw, 121, 0, 2, 148, 183]
+[:key_down_raw, 121, 0, 2, 149, 184]
+[:key_down_raw, 121, 0, 2, 150, 185]
+[:key_down_raw, 121, 0, 2, 151, 185]
+[:key_down_raw, 121, 0, 2, 152, 186]
+[:key_down_raw, 121, 0, 2, 153, 187]
+[:key_down_raw, 121, 0, 2, 154, 188]
+[:key_down_raw, 121, 0, 2, 155, 189]
+[:key_down_raw, 121, 0, 2, 156, 190]
+[:key_down_raw, 121, 0, 2, 157, 190]
+[:key_up_raw, 121, 0, 2, 158, 191]
+[:key_down_raw, 1073742053, 2, 2, 159, 198]
+[:key_down_raw, 121, 2, 2, 160, 203]
+[:key_down_raw, 121, 2, 2, 161, 209]
+[:key_down_raw, 121, 2, 2, 162, 210]
+[:key_down_raw, 121, 2, 2, 163, 211]
+[:key_down_raw, 121, 2, 2, 164, 212]
+[:key_down_raw, 121, 2, 2, 165, 213]
+[:key_down_raw, 121, 2, 2, 166, 213]
+[:key_down_raw, 121, 2, 2, 167, 214]
+[:key_down_raw, 121, 2, 2, 168, 215]
+[:key_down_raw, 121, 2, 2, 169, 216]
+[:key_down_raw, 121, 2, 2, 170, 217]
+[:key_down_raw, 121, 2, 2, 171, 217]
+[:key_down_raw, 121, 2, 2, 172, 219]
+[:key_down_raw, 121, 2, 2, 173, 220]
+[:key_down_raw, 121, 2, 2, 174, 220]
+[:key_down_raw, 121, 2, 2, 175, 221]
+[:key_down_raw, 121, 2, 2, 176, 222]
+[:key_down_raw, 121, 2, 2, 177, 223]
+[:key_down_raw, 121, 2, 2, 178, 224]
+[:key_down_raw, 121, 2, 2, 179, 224]
+[:key_down_raw, 121, 2, 2, 180, 225]
+[:key_down_raw, 121, 2, 2, 181, 226]
+[:key_down_raw, 121, 2, 2, 182, 227]
+[:key_down_raw, 121, 2, 2, 183, 228]
+[:key_down_raw, 121, 2, 2, 184, 229]
+[:key_down_raw, 121, 2, 2, 185, 229]
+[:key_down_raw, 121, 2, 2, 186, 230]
+[:key_down_raw, 121, 2, 2, 187, 231]
+[:key_down_raw, 121, 2, 2, 188, 232]
+[:key_down_raw, 121, 2, 2, 189, 233]
+[:key_down_raw, 121, 2, 2, 190, 233]
+[:key_down_raw, 121, 2, 2, 191, 234]
+[:key_down_raw, 121, 2, 2, 192, 235]
+[:key_down_raw, 121, 2, 2, 193, 236]
+[:key_down_raw, 121, 2, 2, 194, 237]
+[:key_down_raw, 121, 2, 2, 195, 238]
+[:key_down_raw, 121, 2, 2, 196, 238]
+[:key_down_raw, 121, 2, 2, 197, 239]
+[:key_down_raw, 121, 2, 2, 198, 240]
+[:key_down_raw, 121, 2, 2, 199, 241]
+[:key_down_raw, 121, 2, 2, 200, 242]
+[:key_down_raw, 121, 2, 2, 201, 242]
+[:key_down_raw, 121, 2, 2, 202, 243]
+[:key_down_raw, 121, 2, 2, 203, 244]
+[:key_down_raw, 121, 2, 2, 204, 245]
+[:key_down_raw, 121, 2, 2, 205, 246]
+[:key_down_raw, 121, 2, 2, 206, 247]
+[:key_down_raw, 121, 2, 2, 207, 247]
+[:key_down_raw, 121, 2, 2, 208, 248]
+[:key_down_raw, 121, 2, 2, 209, 249]
+[:key_down_raw, 121, 2, 2, 210, 250]
+[:key_down_raw, 121, 2, 2, 211, 251]
+[:key_down_raw, 121, 2, 2, 212, 251]
+[:key_down_raw, 121, 2, 2, 213, 252]
+[:key_down_raw, 121, 2, 2, 214, 253]
+[:key_down_raw, 121, 2, 2, 215, 254]
+[:key_down_raw, 121, 2, 2, 216, 255]
+[:key_down_raw, 121, 2, 2, 217, 255]
+[:key_down_raw, 121, 2, 2, 218, 256]
+[:key_down_raw, 121, 2, 2, 219, 257]
+[:key_down_raw, 121, 2, 2, 220, 258]
+[:key_down_raw, 121, 2, 2, 221, 259]
+[:key_down_raw, 121, 2, 2, 222, 260]
+[:key_down_raw, 121, 2, 2, 223, 260]
+[:key_down_raw, 121, 2, 2, 224, 261]
+[:key_down_raw, 121, 2, 2, 225, 262]
+[:key_down_raw, 121, 2, 2, 226, 263]
+[:key_up_raw, 121, 2, 2, 227, 263]
+[:key_up_raw, 1073742053, 0, 2, 228, 266]
+[:key_down_raw, 122, 0, 2, 229, 270]
+[:key_up_raw, 122, 0, 2, 230, 272]
+[:key_down_raw, 122, 0, 2, 231, 289]
+[:key_down_raw, 122, 0, 2, 232, 295]
+[:key_down_raw, 122, 0, 2, 233, 296]
+[:key_down_raw, 122, 0, 2, 234, 297]
+[:key_down_raw, 122, 0, 2, 235, 297]
+[:key_down_raw, 122, 0, 2, 236, 298]
+[:key_down_raw, 122, 0, 2, 237, 299]
+[:key_down_raw, 122, 0, 2, 238, 300]
+[:key_down_raw, 122, 0, 2, 239, 301]
+[:key_down_raw, 122, 0, 2, 240, 302]
+[:key_down_raw, 122, 0, 2, 241, 302]
+[:key_down_raw, 122, 0, 2, 242, 303]
+[:key_down_raw, 122, 0, 2, 243, 304]
+[:key_down_raw, 122, 0, 2, 244, 305]
+[:key_down_raw, 122, 0, 2, 245, 306]
+[:key_down_raw, 122, 0, 2, 246, 306]
+[:key_down_raw, 122, 0, 2, 247, 307]
+[:key_down_raw, 122, 0, 2, 248, 308]
+[:key_down_raw, 122, 0, 2, 249, 309]
+[:key_down_raw, 122, 0, 2, 250, 310]
+[:key_up_raw, 122, 0, 2, 251, 310]
+[:key_down_raw, 1073742053, 2, 2, 252, 319]
+[:key_down_raw, 122, 2, 2, 253, 322]
+[:key_down_raw, 122, 2, 2, 254, 328]
+[:key_down_raw, 122, 2, 2, 255, 329]
+[:key_down_raw, 122, 2, 2, 256, 330]
+[:key_down_raw, 122, 2, 2, 257, 331]
+[:key_down_raw, 122, 2, 2, 258, 332]
+[:key_down_raw, 122, 2, 2, 259, 333]
+[:key_down_raw, 122, 2, 2, 260, 333]
+[:key_down_raw, 122, 2, 2, 261, 334]
+[:key_down_raw, 122, 2, 2, 262, 335]
+[:key_down_raw, 122, 2, 2, 263, 336]
+[:key_down_raw, 122, 2, 2, 264, 337]
+[:key_down_raw, 122, 2, 2, 265, 338]
+[:key_down_raw, 122, 2, 2, 266, 339]
+[:key_down_raw, 122, 2, 2, 267, 340]
+[:key_down_raw, 122, 2, 2, 268, 341]
+[:key_down_raw, 122, 2, 2, 269, 341]
+[:key_down_raw, 122, 2, 2, 270, 342]
+[:key_down_raw, 122, 2, 2, 271, 343]
+[:key_down_raw, 122, 2, 2, 272, 344]
+[:key_down_raw, 122, 2, 2, 273, 345]
+[:key_down_raw, 122, 2, 2, 274, 346]
+[:key_down_raw, 122, 2, 2, 275, 346]
+[:key_down_raw, 122, 2, 2, 276, 347]
+[:key_down_raw, 122, 2, 2, 277, 348]
+[:key_down_raw, 122, 2, 2, 278, 349]
+[:key_down_raw, 122, 2, 2, 279, 350]
+[:key_down_raw, 122, 2, 2, 280, 350]
+[:key_down_raw, 122, 2, 2, 281, 351]
+[:key_down_raw, 122, 2, 2, 282, 352]
+[:key_down_raw, 122, 2, 2, 283, 353]
+[:key_down_raw, 122, 2, 2, 284, 354]
+[:key_down_raw, 122, 2, 2, 285, 355]
+[:key_down_raw, 122, 2, 2, 286, 355]
+[:key_down_raw, 122, 2, 2, 287, 356]
+[:key_down_raw, 122, 2, 2, 288, 357]
+[:key_down_raw, 122, 2, 2, 289, 358]
+[:key_down_raw, 122, 2, 2, 290, 359]
+[:key_down_raw, 122, 2, 2, 291, 360]
+[:key_down_raw, 122, 2, 2, 292, 360]
+[:key_down_raw, 122, 2, 2, 293, 361]
+[:key_down_raw, 122, 2, 2, 294, 362]
+[:key_down_raw, 122, 2, 2, 295, 363]
+[:key_up_raw, 122, 2, 2, 296, 363]
+[:key_up_raw, 1073742053, 0, 2, 297, 366]
+[:key_down_raw, 112, 0, 2, 298, 370]
+[:key_down_raw, 112, 0, 2, 299, 376]
+[:key_down_raw, 112, 0, 2, 300, 377]
+[:key_down_raw, 112, 0, 2, 301, 378]
+[:key_down_raw, 112, 0, 2, 302, 379]
+[:key_down_raw, 112, 0, 2, 303, 380]
+[:key_down_raw, 112, 0, 2, 304, 381]
+[:key_down_raw, 112, 0, 2, 305, 381]
+[:key_down_raw, 112, 0, 2, 306, 382]
+[:key_down_raw, 112, 0, 2, 307, 383]
+[:key_down_raw, 112, 0, 2, 308, 384]
+[:key_down_raw, 112, 0, 2, 309, 385]
+[:key_down_raw, 112, 0, 2, 310, 386]
+[:key_down_raw, 112, 0, 2, 311, 386]
+[:key_down_raw, 112, 0, 2, 312, 387]
+[:key_down_raw, 112, 0, 2, 313, 388]
+[:key_down_raw, 112, 0, 2, 314, 389]
+[:key_down_raw, 112, 0, 2, 315, 390]
+[:key_down_raw, 112, 0, 2, 316, 391]
+[:key_down_raw, 112, 0, 2, 317, 391]
+[:key_down_raw, 112, 0, 2, 318, 392]
+[:key_down_raw, 112, 0, 2, 319, 393]
+[:key_down_raw, 112, 0, 2, 320, 394]
+[:key_down_raw, 112, 0, 2, 321, 395]
+[:key_up_raw, 112, 0, 2, 322, 395]
+[:key_down_raw, 1073742049, 1, 2, 323, 402]
+[:key_down_raw, 112, 1, 2, 324, 402]
+[:key_down_raw, 112, 1, 2, 325, 409]
+[:key_down_raw, 112, 1, 2, 326, 410]
+[:key_down_raw, 112, 1, 2, 327, 410]
+[:key_down_raw, 112, 1, 2, 328, 411]
+[:key_down_raw, 112, 1, 2, 329, 412]
+[:key_down_raw, 112, 1, 2, 330, 413]
+[:key_down_raw, 112, 1, 2, 331, 414]
+[:key_down_raw, 112, 1, 2, 332, 415]
+[:key_down_raw, 112, 1, 2, 333, 415]
+[:key_down_raw, 112, 1, 2, 334, 416]
+[:key_down_raw, 112, 1, 2, 335, 417]
+[:key_down_raw, 112, 1, 2, 336, 418]
+[:key_down_raw, 112, 1, 2, 337, 419]
+[:key_down_raw, 112, 1, 2, 338, 420]
+[:key_down_raw, 112, 1, 2, 339, 420]
+[:key_down_raw, 112, 1, 2, 340, 421]
+[:key_down_raw, 112, 1, 2, 341, 422]
+[:key_down_raw, 112, 1, 2, 342, 423]
+[:key_down_raw, 112, 1, 2, 343, 424]
+[:key_down_raw, 112, 1, 2, 344, 424]
+[:key_down_raw, 112, 1, 2, 345, 425]
+[:key_down_raw, 112, 1, 2, 346, 426]
+[:key_down_raw, 112, 1, 2, 347, 427]
+[:key_down_raw, 112, 1, 2, 348, 428]
+[:key_down_raw, 112, 1, 2, 349, 429]
+[:key_down_raw, 112, 1, 2, 350, 429]
+[:key_down_raw, 112, 1, 2, 351, 430]
+[:key_down_raw, 112, 1, 2, 352, 431]
+[:key_up_raw, 112, 1, 2, 353, 432]
+[:key_up_raw, 1073742049, 0, 2, 354, 433]
+[:key_down_raw, 96, 0, 2, 355, 439]
+[:key_up_raw, 96, 0, 2, 356, 441]
+[:key_down_raw, 13, 0, 2, 357, 493]
diff --git a/samples/99_genre_arcade/bullet_hell/replay.txt b/samples/99_genre_arcade/bullet_hell/replay.txt
new file mode 100644
index 0000000..49a22d1
--- /dev/null
+++ b/samples/99_genre_arcade/bullet_hell/replay.txt
@@ -0,0 +1,126 @@
+replay_version 2.0
+stopped_at 718
+seed 100
+recorded_at 2021-11-20 11:26:42 -0600
+[:mouse_button_up, 1, 0, 1, 1, 4]
+[:mouse_move, 824, 91, 2, 2, 27]
+[:key_down_raw, 1073741903, 0, 2, 3, 64]
+[:key_down_raw, 1073741903, 0, 2, 4, 78]
+[:key_down_raw, 1073741903, 0, 2, 5, 80]
+[:key_down_raw, 1073741903, 0, 2, 6, 82]
+[:key_down_raw, 1073741903, 0, 2, 7, 84]
+[:key_down_raw, 1073741903, 0, 2, 8, 86]
+[:key_down_raw, 1073741903, 0, 2, 9, 88]
+[:key_down_raw, 1073741903, 0, 2, 10, 90]
+[:key_down_raw, 1073741903, 0, 2, 11, 92]
+[:key_down_raw, 1073741903, 0, 2, 12, 94]
+[:key_down_raw, 1073741903, 0, 2, 13, 96]
+[:key_down_raw, 1073741903, 0, 2, 14, 98]
+[:key_down_raw, 1073741903, 0, 2, 15, 100]
+[:key_down_raw, 1073741903, 0, 2, 16, 102]
+[:key_down_raw, 1073741903, 0, 2, 17, 104]
+[:key_down_raw, 1073741903, 0, 2, 18, 106]
+[:key_down_raw, 1073741903, 0, 2, 19, 108]
+[:key_down_raw, 32, 0, 2, 20, 108]
+[:key_up_raw, 1073741903, 0, 2, 21, 108]
+[:key_up_raw, 32, 0, 2, 22, 114]
+[:key_down_raw, 32, 0, 2, 23, 120]
+[:key_up_raw, 32, 0, 2, 24, 126]
+[:key_down_raw, 1073741903, 0, 2, 25, 127]
+[:key_down_raw, 1073741903, 0, 2, 26, 142]
+[:key_up_raw, 1073741903, 0, 2, 27, 143]
+[:key_down_raw, 32, 0, 2, 28, 144]
+[:key_up_raw, 32, 0, 2, 29, 152]
+[:key_down_raw, 32, 0, 2, 30, 156]
+[:key_down_raw, 1073741904, 0, 2, 31, 159]
+[:key_up_raw, 32, 0, 2, 32, 163]
+[:key_down_raw, 1073741904, 0, 2, 33, 174]
+[:key_down_raw, 1073741904, 0, 2, 34, 176]
+[:key_down_raw, 1073741904, 0, 2, 35, 178]
+[:key_down_raw, 1073741904, 0, 2, 36, 180]
+[:key_down_raw, 1073741904, 0, 2, 37, 182]
+[:key_down_raw, 32, 0, 2, 38, 183]
+[:key_up_raw, 1073741904, 0, 2, 39, 186]
+[:key_up_raw, 32, 0, 2, 40, 191]
+[:key_down_raw, 32, 0, 2, 41, 195]
+[:key_up_raw, 32, 0, 2, 42, 203]
+[:key_down_raw, 1073741904, 0, 2, 43, 228]
+[:key_down_raw, 1073741904, 0, 2, 44, 243]
+[:key_down_raw, 1073741904, 0, 2, 45, 245]
+[:key_down_raw, 1073741904, 0, 2, 46, 247]
+[:key_down_raw, 1073741904, 0, 2, 47, 249]
+[:key_down_raw, 1073741904, 0, 2, 48, 251]
+[:key_down_raw, 1073741904, 0, 2, 49, 253]
+[:key_down_raw, 32, 0, 2, 50, 253]
+[:key_up_raw, 1073741904, 0, 2, 51, 255]
+[:key_up_raw, 32, 0, 2, 52, 260]
+[:key_down_raw, 32, 0, 2, 53, 265]
+[:key_up_raw, 32, 0, 2, 54, 270]
+[:key_down_raw, 1073741904, 0, 2, 55, 278]
+[:key_down_raw, 1073741904, 0, 2, 56, 293]
+[:key_down_raw, 1073741904, 0, 2, 57, 295]
+[:key_down_raw, 1073741904, 0, 2, 58, 297]
+[:key_down_raw, 1073741904, 0, 2, 59, 299]
+[:key_down_raw, 1073741904, 0, 2, 60, 301]
+[:key_down_raw, 1073741904, 0, 2, 61, 303]
+[:key_up_raw, 1073741904, 0, 2, 62, 305]
+[:key_down_raw, 32, 0, 2, 63, 307]
+[:key_up_raw, 32, 0, 2, 64, 314]
+[:key_down_raw, 32, 0, 2, 65, 319]
+[:key_up_raw, 32, 0, 2, 66, 326]
+[:key_down_raw, 32, 0, 2, 67, 331]
+[:key_up_raw, 32, 0, 2, 68, 337]
+[:key_down_raw, 1073741904, 0, 2, 69, 339]
+[:key_down_raw, 1073741904, 0, 2, 70, 354]
+[:key_down_raw, 1073741904, 0, 2, 71, 356]
+[:key_down_raw, 1073741904, 0, 2, 72, 358]
+[:key_down_raw, 1073741904, 0, 2, 73, 360]
+[:key_down_raw, 32, 0, 2, 74, 361]
+[:key_up_raw, 1073741904, 0, 2, 75, 361]
+[:key_up_raw, 32, 0, 2, 76, 368]
+[:key_down_raw, 32, 0, 2, 77, 373]
+[:key_up_raw, 32, 0, 2, 78, 379]
+[:key_down_raw, 1073741903, 0, 2, 79, 397]
+[:key_down_raw, 1073741903, 0, 2, 80, 412]
+[:key_down_raw, 1073741903, 0, 2, 81, 414]
+[:key_down_raw, 1073741903, 0, 2, 82, 416]
+[:key_down_raw, 1073741903, 0, 2, 83, 418]
+[:key_down_raw, 1073741903, 0, 2, 84, 420]
+[:key_down_raw, 1073741903, 0, 2, 85, 422]
+[:key_down_raw, 1073741903, 0, 2, 86, 424]
+[:key_down_raw, 1073741903, 0, 2, 87, 426]
+[:key_down_raw, 1073741903, 0, 2, 88, 428]
+[:key_down_raw, 32, 0, 2, 89, 428]
+[:key_up_raw, 1073741903, 0, 2, 90, 429]
+[:key_up_raw, 32, 0, 2, 91, 435]
+[:key_down_raw, 1073741903, 0, 2, 92, 456]
+[:key_down_raw, 32, 0, 2, 93, 468]
+[:key_up_raw, 1073741903, 0, 2, 94, 468]
+[:key_up_raw, 32, 0, 2, 95, 475]
+[:key_down_raw, 32, 0, 2, 96, 480]
+[:key_up_raw, 32, 0, 2, 97, 487]
+[:key_down_raw, 32, 0, 2, 98, 493]
+[:key_up_raw, 32, 0, 2, 99, 499]
+[:key_down_raw, 1073741903, 0, 2, 100, 516]
+[:key_down_raw, 32, 0, 2, 101, 522]
+[:key_up_raw, 32, 0, 2, 102, 529]
+[:key_up_raw, 1073741903, 0, 2, 103, 529]
+[:key_down_raw, 32, 0, 2, 104, 535]
+[:key_up_raw, 32, 0, 2, 105, 542]
+[:key_down_raw, 1073741903, 0, 2, 106, 582]
+[:key_up_raw, 1073741903, 0, 2, 107, 591]
+[:key_down_raw, 96, 0, 2, 108, 652]
+[:mouse_move, 824, 90, 2, 109, 656]
+[:key_up_raw, 96, 0, 2, 110, 658]
+[:mouse_move, 833, 91, 2, 111, 684]
+[:mouse_move, 852, 92, 2, 112, 685]
+[:mouse_move, 873, 95, 2, 113, 686]
+[:mouse_move, 895, 98, 2, 114, 687]
+[:mouse_move, 914, 101, 2, 115, 688]
+[:mouse_move, 921, 102, 2, 116, 689]
+[:mouse_move, 922, 102, 2, 117, 690]
+[:mouse_move, 913, 106, 2, 118, 692]
+[:mouse_move, 902, 110, 2, 119, 693]
+[:mouse_move, 892, 114, 2, 120, 694]
+[:mouse_move, 890, 114, 2, 121, 695]
+[:key_down_raw, 13, 0, 2, 122, 718]
diff --git a/samples/99_genre_arcade/flappy_dragon/app/main.rb b/samples/99_genre_arcade/flappy_dragon/app/main.rb
index 56ce3ec..7ddc5a0 100644
--- a/samples/99_genre_arcade/flappy_dragon/app/main.rb
+++ b/samples/99_genre_arcade/flappy_dragon/app/main.rb
@@ -38,31 +38,36 @@ class FlappyDragon
end
def render_score
- outputs.primitives << [10, 710, "HI SCORE: #{state.hi_score}", large_white_typeset].label
- outputs.primitives << [10, 680, "SCORE: #{state.score}", large_white_typeset].label
- outputs.primitives << [10, 650, "DIFFICULTY: #{state.difficulty.upcase}", large_white_typeset].label
+ outputs.primitives << { x: 10, y: 710, text: "HI SCORE: #{state.hi_score}", **large_white_typeset }
+ outputs.primitives << { x: 10, y: 680, text: "SCORE: #{state.score}", **large_white_typeset }
+ outputs.primitives << { x: 10, y: 650, text: "DIFFICULTY: #{state.difficulty.upcase}", **large_white_typeset }
end
def render_menu
return unless state.scene == :menu
render_overlay
- outputs.labels << [640, 700, "Flappy Dragon", 50, 1, 255, 255, 255]
- outputs.labels << [640, 500, "Instructions: Press Spacebar to flap. Don't die.", 4, 1, 255, 255, 255]
- outputs.labels << [430, 430, "[Tab] Change difficulty", 4, 0, 255, 255, 255]
- outputs.labels << [430, 400, "[Enter] Start at New Difficulty ", 4, 0, 255, 255, 255]
- outputs.labels << [430, 370, "[Escape] Cancel/Resume ", 4, 0, 255, 255, 255]
- outputs.labels << [640, 300, "(mouse, touch, and game controllers work, too!) ", 4, 1, 255, 255, 255]
- outputs.labels << [640, 200, "Difficulty: #{state.new_difficulty.capitalize}", 4, 1, 255, 255, 255]
-
- outputs.labels << [10, 100, "Code: @amirrajan", 255, 255, 255]
- outputs.labels << [10, 80, "Art: @mobypixel", 255, 255, 255]
- outputs.labels << [10, 60, "Music: @mobypixel", 255, 255, 255]
- outputs.labels << [10, 40, "Engine: DragonRuby GTK", 255, 255, 255]
+ outputs.labels << { x: 640, y: 700, text: "Flappy Dragon", size_enum: 50, alignment_enum: 1, **white }
+ outputs.labels << { x: 640, y: 500, text: "Instructions: Press Spacebar to flap. Don't die.", size_enum: 4, alignment_enum: 1, **white }
+ outputs.labels << { x: 430, y: 430, text: "[Tab] Change difficulty", size_enum: 4, alignment_enum: 0, **white }
+ outputs.labels << { x: 430, y: 400, text: "[Enter] Start at New Difficulty ", size_enum: 4, alignment_enum: 0, **white }
+ outputs.labels << { x: 430, y: 370, text: "[Escape] Cancel/Resume ", size_enum: 4, alignment_enum: 0, **white }
+ outputs.labels << { x: 640, y: 300, text: "(mouse, touch, and game controllers work, too!) ", size_enum: 4, alignment_enum: 1, **white }
+ outputs.labels << { x: 640, y: 200, text: "Difficulty: #{state.new_difficulty.capitalize}", size_enum: 4, alignment_enum: 1, **white }
+
+ outputs.labels << { x: 10, y: 100, text: "Code: @amirrajan", **white }
+ outputs.labels << { x: 10, y: 80, text: "Art: @mobypixel", **white }
+ outputs.labels << { x: 10, y: 60, text: "Music: @mobypixel", **white }
+ outputs.labels << { x: 10, y: 40, text: "Engine: DragonRuby GTK", **white }
end
def render_overlay
- outputs.primitives << [grid.rect.scale_rect(1.1, 0, 0), 0, 0, 0, 230].solid
+ overlay_rect = grid.rect.scale_rect(1.1, 0, 0)
+ outputs.primitives << { x: overlay_rect.x,
+ y: overlay_rect.y,
+ w: overlay_rect.w,
+ h: overlay_rect.h,
+ r: 0, g: 0, b: 0, a: 230 }.solid!
end
def render_game
@@ -75,14 +80,14 @@ class FlappyDragon
def render_game_over
return unless state.scene == :game
- outputs.labels << [638, 358, score_text, 20, 1]
- outputs.labels << [635, 360, score_text, 20, 1, 255, 255, 255]
- outputs.labels << [638, 428, countdown_text, 20, 1]
- outputs.labels << [635, 430, countdown_text, 20, 1, 255, 255, 255]
+ outputs.labels << { x: 638, y: 358, text: score_text, size_enum: 20, alignment_enum: 1 }
+ outputs.labels << { x: 635, y: 360, text: score_text, size_enum: 20, alignment_enum: 1, r: 255, g: 255, b: 255 }
+ outputs.labels << { x: 638, y: 428, text: countdown_text, size_enum: 20, alignment_enum: 1 }
+ outputs.labels << { x: 635, y: 430, text: countdown_text, size_enum: 20, alignment_enum: 1, r: 255, g: 255, b: 255 }
end
def render_background
- outputs.sprites << [0, 0, 1280, 720, 'sprites/background.png']
+ outputs.sprites << { x: 0, y: 0, w: 1280, h: 720, path: 'sprites/background.png' }
scroll_point_at = state.tick_count
scroll_point_at = state.scene_at if state.scene == :menu
@@ -94,11 +99,18 @@ class FlappyDragon
outputs.sprites << scrolling_background(scroll_point_at, 'sprites/parallax_front.png', 1.00, -80)
end
+ def scrolling_background at, path, rate, y = 0
+ [
+ { x: 0 - at.*(rate) % 1440, y: y, w: 1440, h: 720, path: path },
+ { x: 1440 - at.*(rate) % 1440, y: y, w: 1440, h: 720, path: path }
+ ]
+ end
+
def render_walls
state.walls.each do |w|
w.sprites = [
- [w.x, w.bottom_height - 720, 100, 720, 'sprites/wall.png', 180],
- [w.x, w.top_y, 100, 720, 'sprites/wallbottom.png', 0]
+ { x: w.x, y: w.bottom_height - 720, w: 100, h: 720, path: 'sprites/wall.png', angle: 180 },
+ { x: w.x, y: w.top_y, w: 100, h: 720, path: 'sprites/wallbottom.png', angle: 0 }
]
end
outputs.sprites << state.walls.map(&:sprites)
@@ -107,15 +119,13 @@ class FlappyDragon
def render_dragon
state.show_death = true if state.countdown == 3.seconds
- render_debug_hitbox false
-
if state.show_death == false || !state.death_at
animation_index = state.flapped_at.frame_index 6, 2, false if state.flapped_at
sprite_name = "sprites/dragon_fly#{animation_index.or(0) + 1}.png"
- state.dragon_sprite = [state.x, state.y, 100, 80, sprite_name, state.dy * 1.2]
+ state.dragon_sprite = { x: state.x, y: state.y, w: 100, h: 80, path: sprite_name, angle: state.dy * 1.2 }
else
sprite_name = "sprites/dragon_die.png"
- state.dragon_sprite = [state.x, state.y, 100, 80, sprite_name, state.dy * 1.2]
+ state.dragon_sprite = { x: state.x, y: state.y, w: 100, h: 80, path: sprite_name, angle: state.dy * 1.2 }
sprite_changed_elapsed = state.death_at.elapsed_time - 1.seconds
state.dragon_sprite.angle += (sprite_changed_elapsed ** 1.3) * state.death_fall_direction * -1
state.dragon_sprite.x += (sprite_changed_elapsed ** 1.2) * state.death_fall_direction
@@ -125,20 +135,12 @@ class FlappyDragon
outputs.sprites << state.dragon_sprite
end
- def render_debug_hitbox show
- return unless show
- outputs.borders << [dragon_collision_box.rect, 255, 0, 0] if state.dragon_sprite
- outputs.borders << state.walls.flat_map do |w|
- w.sprites.map { |s| [s.rect, 255, 0, 0] }
- end
- end
-
def render_flash
return unless state.flash_at
- outputs.primitives << [grid.rect,
- white,
- 255 * state.flash_at.ease(20, :flip)].solid
+ outputs.primitives << { **grid.rect.to_hash,
+ **white,
+ a: 255 * state.flash_at.ease(20, :flip) }.solid!
state.flash_at = 0 if state.flash_at.elapsed_time > 20
end
@@ -258,19 +260,12 @@ class FlappyDragon
end
end
- def scrolling_background at, path, rate, y = 0
- [
- [ 0 - at.*(rate) % 1440, y, 1440, 720, path],
- [1440 - at.*(rate) % 1440, y, 1440, 720, path]
- ]
- end
-
def white
- [255, 255, 255]
+ { r: 255, g: 255, b: 255 }
end
def large_white_typeset
- [5, 0, 255, 255, 255]
+ { size_enum: 5, alignment_enum: 0, r: 255, g: 255, b: 255 }
end
def at_beginning?
@@ -279,9 +274,9 @@ class FlappyDragon
def dragon_collision_box
state.dragon_sprite
- .scale_rect(1.0 - collision_forgiveness, 0.5, 0.5)
- .rect_shift_right(10)
- .rect_shift_up(state.dy * 2)
+ .scale_rect(1.0 - collision_forgiveness, 0.5, 0.5)
+ .rect_shift_right(10)
+ .rect_shift_up(state.dy * 2)
end
def game_over?
@@ -290,7 +285,7 @@ class FlappyDragon
state.walls
.flat_map { |w| w.sprites }
.any? do |s|
- s.intersect_rect?(dragon_collision_box)
+ s && s.intersect_rect?(dragon_collision_box)
end
end
diff --git a/samples/99_genre_arcade/twinstick/replay.txt b/samples/99_genre_arcade/twinstick/replay.txt
new file mode 100644
index 0000000..e05480f
--- /dev/null
+++ b/samples/99_genre_arcade/twinstick/replay.txt
@@ -0,0 +1,174 @@
+replay_version 2.0
+stopped_at 819
+seed 100
+recorded_at 2021-11-20 11:29:24 -0600
+[:mouse_button_up, 1, 0, 1, 1, 3]
+[:key_down_raw, 1073741903, 0, 2, 2, 89]
+[:key_down_raw, 1073741903, 0, 2, 3, 104]
+[:key_down_raw, 1073741903, 0, 2, 4, 106]
+[:key_down_raw, 1073741903, 0, 2, 5, 108]
+[:key_down_raw, 1073741903, 0, 2, 6, 110]
+[:key_down_raw, 1073741903, 0, 2, 7, 112]
+[:key_down_raw, 1073741903, 0, 2, 8, 114]
+[:key_down_raw, 1073741903, 0, 2, 9, 116]
+[:key_up_raw, 1073741903, 0, 2, 10, 117]
+[:key_down_raw, 115, 0, 2, 11, 121]
+[:key_down_raw, 1073741905, 0, 2, 12, 133]
+[:key_down_raw, 1073741905, 0, 2, 13, 148]
+[:key_down_raw, 1073741905, 0, 2, 14, 150]
+[:key_down_raw, 1073741905, 0, 2, 15, 152]
+[:key_down_raw, 1073741904, 0, 2, 16, 152]
+[:key_up_raw, 1073741904, 0, 2, 17, 158]
+[:key_up_raw, 1073741905, 0, 2, 18, 159]
+[:key_down_raw, 1073741906, 0, 2, 19, 163]
+[:key_down_raw, 1073741903, 0, 2, 20, 178]
+[:key_up_raw, 1073741903, 0, 2, 21, 185]
+[:key_down_raw, 100, 0, 2, 22, 195]
+[:key_up_raw, 1073741906, 0, 2, 23, 195]
+[:key_up_raw, 115, 0, 2, 24, 195]
+[:key_down_raw, 1073741904, 0, 2, 25, 209]
+[:key_down_raw, 1073741904, 0, 2, 26, 224]
+[:key_down_raw, 1073741904, 0, 2, 27, 226]
+[:key_down_raw, 1073741904, 0, 2, 28, 228]
+[:key_down_raw, 1073741904, 0, 2, 29, 230]
+[:key_down_raw, 119, 0, 2, 30, 230]
+[:key_down_raw, 1073741906, 0, 2, 31, 237]
+[:key_up_raw, 100, 0, 2, 32, 251]
+[:key_down_raw, 1073741906, 0, 2, 33, 252]
+[:key_down_raw, 1073741906, 0, 2, 34, 254]
+[:key_down_raw, 1073741906, 0, 2, 35, 256]
+[:key_down_raw, 1073741906, 0, 2, 36, 258]
+[:key_down_raw, 97, 0, 2, 37, 259]
+[:key_up_raw, 119, 0, 2, 38, 267]
+[:key_up_raw, 1073741906, 0, 2, 39, 268]
+[:key_down_raw, 1073741903, 0, 2, 40, 269]
+[:key_up_raw, 1073741904, 0, 2, 41, 270]
+[:key_down_raw, 1073741903, 0, 2, 42, 284]
+[:key_down_raw, 1073741903, 0, 2, 43, 286]
+[:key_down_raw, 1073741903, 0, 2, 44, 288]
+[:key_down_raw, 1073741903, 0, 2, 45, 290]
+[:key_down_raw, 1073741903, 0, 2, 46, 292]
+[:key_down_raw, 1073741903, 0, 2, 47, 294]
+[:key_down_raw, 1073741903, 0, 2, 48, 296]
+[:key_down_raw, 1073741903, 0, 2, 49, 298]
+[:key_down_raw, 1073741903, 0, 2, 50, 300]
+[:key_down_raw, 1073741903, 0, 2, 51, 302]
+[:key_down_raw, 1073741903, 0, 2, 52, 304]
+[:key_down_raw, 119, 0, 2, 53, 304]
+[:key_down_raw, 1073741906, 0, 2, 54, 311]
+[:key_down_raw, 1073741906, 0, 2, 55, 326]
+[:key_down_raw, 1073741906, 0, 2, 56, 328]
+[:key_down_raw, 1073741906, 0, 2, 57, 330]
+[:key_down_raw, 1073741906, 0, 2, 58, 332]
+[:key_down_raw, 1073741906, 0, 2, 59, 334]
+[:key_down_raw, 1073741906, 0, 2, 60, 336]
+[:key_up_raw, 1073741903, 0, 2, 61, 336]
+[:key_down_raw, 1073741906, 0, 2, 62, 338]
+[:key_down_raw, 1073741906, 0, 2, 63, 340]
+[:key_down_raw, 1073741906, 0, 2, 64, 342]
+[:key_down_raw, 1073741906, 0, 2, 65, 344]
+[:key_up_raw, 119, 0, 2, 66, 344]
+[:key_down_raw, 1073741906, 0, 2, 67, 346]
+[:key_up_raw, 1073741906, 0, 2, 68, 347]
+[:key_down_raw, 1073741903, 0, 2, 69, 347]
+[:key_down_raw, 115, 0, 2, 70, 353]
+[:key_down_raw, 1073741906, 0, 2, 71, 355]
+[:key_up_raw, 97, 0, 2, 72, 356]
+[:key_up_raw, 1073741903, 0, 2, 73, 360]
+[:key_down_raw, 1073741906, 0, 2, 74, 370]
+[:key_down_raw, 1073741906, 0, 2, 75, 372]
+[:key_down_raw, 1073741906, 0, 2, 76, 374]
+[:key_down_raw, 1073741906, 0, 2, 77, 376]
+[:key_down_raw, 1073741906, 0, 2, 78, 378]
+[:key_down_raw, 1073741906, 0, 2, 79, 380]
+[:key_down_raw, 97, 0, 2, 80, 381]
+[:key_up_raw, 115, 0, 2, 81, 385]
+[:key_down_raw, 1073741903, 0, 2, 82, 386]
+[:key_up_raw, 1073741906, 0, 2, 83, 391]
+[:key_down_raw, 1073741903, 0, 2, 84, 401]
+[:key_down_raw, 1073741903, 0, 2, 85, 403]
+[:key_down_raw, 1073741903, 0, 2, 86, 405]
+[:key_down_raw, 1073741903, 0, 2, 87, 407]
+[:key_down_raw, 1073741903, 0, 2, 88, 409]
+[:key_down_raw, 1073741903, 0, 2, 89, 411]
+[:key_down_raw, 1073741903, 0, 2, 90, 413]
+[:key_down_raw, 1073741903, 0, 2, 91, 415]
+[:key_down_raw, 1073741903, 0, 2, 92, 417]
+[:key_down_raw, 1073741903, 0, 2, 93, 419]
+[:key_down_raw, 1073741903, 0, 2, 94, 421]
+[:key_down_raw, 1073741903, 0, 2, 95, 423]
+[:key_down_raw, 1073741903, 0, 2, 96, 425]
+[:key_down_raw, 1073741903, 0, 2, 97, 428]
+[:key_down_raw, 1073741903, 0, 2, 98, 430]
+[:key_up_raw, 97, 0, 2, 99, 430]
+[:key_down_raw, 1073741903, 0, 2, 100, 432]
+[:key_down_raw, 1073741903, 0, 2, 101, 434]
+[:key_down_raw, 1073741903, 0, 2, 102, 436]
+[:key_up_raw, 1073741903, 0, 2, 103, 436]
+[:key_down_raw, 100, 0, 2, 104, 447]
+[:key_down_raw, 1073741904, 0, 2, 105, 447]
+[:key_down_raw, 1073741904, 0, 2, 106, 462]
+[:key_down_raw, 1073741904, 0, 2, 107, 464]
+[:key_down_raw, 1073741904, 0, 2, 108, 466]
+[:key_down_raw, 1073741904, 0, 2, 109, 468]
+[:key_down_raw, 1073741904, 0, 2, 110, 470]
+[:key_down_raw, 1073741904, 0, 2, 111, 472]
+[:key_down_raw, 1073741904, 0, 2, 112, 474]
+[:key_down_raw, 1073741904, 0, 2, 113, 476]
+[:key_down_raw, 1073741904, 0, 2, 114, 478]
+[:key_down_raw, 1073741904, 0, 2, 115, 480]
+[:key_down_raw, 1073741904, 0, 2, 116, 482]
+[:key_down_raw, 1073741904, 0, 2, 117, 484]
+[:key_down_raw, 1073741904, 0, 2, 118, 486]
+[:key_down_raw, 1073741904, 0, 2, 119, 488]
+[:key_down_raw, 1073741904, 0, 2, 120, 490]
+[:key_down_raw, 1073741904, 0, 2, 121, 492]
+[:key_down_raw, 1073741904, 0, 2, 122, 494]
+[:key_down_raw, 1073741904, 0, 2, 123, 496]
+[:key_down_raw, 1073741904, 0, 2, 124, 498]
+[:key_down_raw, 1073741904, 0, 2, 125, 500]
+[:key_down_raw, 1073741904, 0, 2, 126, 502]
+[:key_down_raw, 1073741904, 0, 2, 127, 504]
+[:key_down_raw, 1073741904, 0, 2, 128, 506]
+[:key_down_raw, 1073741904, 0, 2, 129, 508]
+[:key_up_raw, 100, 0, 2, 130, 508]
+[:key_down_raw, 1073741904, 0, 2, 131, 510]
+[:key_down_raw, 1073741904, 0, 2, 132, 512]
+[:key_up_raw, 1073741904, 0, 2, 133, 513]
+[:key_down_raw, 1073741906, 0, 2, 134, 569]
+[:key_down_raw, 1073741903, 0, 2, 135, 570]
+[:key_down_raw, 1073741903, 0, 2, 136, 585]
+[:key_down_raw, 1073741903, 0, 2, 137, 587]
+[:key_up_raw, 1073741903, 0, 2, 138, 588]
+[:key_down_raw, 1073741903, 0, 2, 139, 597]
+[:key_up_raw, 1073741906, 0, 2, 140, 600]
+[:key_up_raw, 1073741903, 0, 2, 141, 608]
+[:key_down_raw, 1073741906, 0, 2, 142, 610]
+[:key_up_raw, 1073741906, 0, 2, 143, 615]
+[:key_down_raw, 1073741906, 0, 2, 144, 619]
+[:key_down_raw, 119, 0, 2, 145, 621]
+[:key_up_raw, 1073741906, 0, 2, 146, 623]
+[:key_down_raw, 119, 0, 2, 147, 636]
+[:key_down_raw, 119, 0, 2, 148, 638]
+[:key_down_raw, 119, 0, 2, 149, 640]
+[:key_down_raw, 119, 0, 2, 150, 642]
+[:key_up_raw, 119, 0, 2, 151, 642]
+[:key_down_raw, 100, 0, 2, 152, 653]
+[:key_down_raw, 100, 0, 2, 153, 668]
+[:key_down_raw, 100, 0, 2, 154, 670]
+[:key_down_raw, 100, 0, 2, 155, 672]
+[:key_down_raw, 100, 0, 2, 156, 674]
+[:key_down_raw, 100, 0, 2, 157, 676]
+[:key_down_raw, 100, 0, 2, 158, 678]
+[:key_down_raw, 100, 0, 2, 159, 680]
+[:key_down_raw, 100, 0, 2, 160, 682]
+[:key_down_raw, 100, 0, 2, 161, 684]
+[:key_down_raw, 100, 0, 2, 162, 686]
+[:key_down_raw, 115, 0, 2, 163, 686]
+[:key_up_raw, 100, 0, 2, 164, 697]
+[:key_down_raw, 97, 0, 2, 165, 699]
+[:key_up_raw, 115, 0, 2, 166, 704]
+[:key_up_raw, 97, 0, 2, 167, 714]
+[:key_down_raw, 96, 0, 2, 168, 769]
+[:key_up_raw, 96, 0, 2, 169, 774]
+[:key_down_raw, 13, 0, 2, 170, 819]
diff --git a/samples/99_genre_crafting/farming_game_starting_point/replay.txt b/samples/99_genre_crafting/farming_game_starting_point/replay.txt
new file mode 100644
index 0000000..740810d
--- /dev/null
+++ b/samples/99_genre_crafting/farming_game_starting_point/replay.txt
@@ -0,0 +1,170 @@
+replay_version 2.0
+stopped_at 851
+seed 100
+recorded_at 2021-11-20 11:30:20 -0600
+[:mouse_button_up, 1, 0, 1, 1, 4]
+[:key_down_raw, 1073741904, 0, 2, 2, 69]
+[:key_down_raw, 1073741904, 0, 2, 3, 83]
+[:key_up_raw, 1073741904, 0, 2, 4, 84]
+[:key_down_raw, 1073741906, 0, 2, 5, 89]
+[:key_down_raw, 1073741903, 0, 2, 6, 95]
+[:key_up_raw, 1073741906, 0, 2, 7, 103]
+[:key_down_raw, 1073741903, 0, 2, 8, 110]
+[:key_down_raw, 1073741903, 0, 2, 9, 112]
+[:key_down_raw, 1073741903, 0, 2, 10, 114]
+[:key_down_raw, 1073741903, 0, 2, 11, 116]
+[:key_down_raw, 1073741903, 0, 2, 12, 118]
+[:key_down_raw, 1073741903, 0, 2, 13, 120]
+[:key_down_raw, 1073741903, 0, 2, 14, 122]
+[:key_down_raw, 1073741903, 0, 2, 15, 124]
+[:key_up_raw, 1073741903, 0, 2, 16, 125]
+[:key_down_raw, 106, 0, 2, 17, 147]
+[:key_up_raw, 106, 0, 2, 18, 156]
+[:key_down_raw, 1073741904, 0, 2, 19, 180]
+[:key_down_raw, 1073741904, 0, 2, 20, 195]
+[:key_down_raw, 1073741904, 0, 2, 21, 197]
+[:key_down_raw, 1073741904, 0, 2, 22, 199]
+[:key_down_raw, 1073741904, 0, 2, 23, 201]
+[:key_down_raw, 1073741904, 0, 2, 24, 203]
+[:key_down_raw, 1073741904, 0, 2, 25, 205]
+[:key_up_raw, 1073741904, 0, 2, 26, 207]
+[:key_down_raw, 1073741903, 0, 2, 27, 208]
+[:key_down_raw, 1073741903, 0, 2, 28, 223]
+[:key_down_raw, 1073741903, 0, 2, 29, 225]
+[:key_down_raw, 1073741903, 0, 2, 30, 227]
+[:key_down_raw, 1073741903, 0, 2, 31, 229]
+[:key_down_raw, 1073741903, 0, 2, 32, 231]
+[:key_down_raw, 1073741903, 0, 2, 33, 233]
+[:key_down_raw, 1073741903, 0, 2, 34, 235]
+[:key_down_raw, 1073741903, 0, 2, 35, 237]
+[:key_down_raw, 1073741903, 0, 2, 36, 239]
+[:key_down_raw, 1073741903, 0, 2, 37, 241]
+[:key_down_raw, 1073741903, 0, 2, 38, 243]
+[:key_down_raw, 1073741903, 0, 2, 39, 245]
+[:key_down_raw, 1073741903, 0, 2, 40, 247]
+[:key_down_raw, 1073741903, 0, 2, 41, 249]
+[:key_down_raw, 1073741903, 0, 2, 42, 251]
+[:key_down_raw, 1073741903, 0, 2, 43, 253]
+[:key_down_raw, 1073741903, 0, 2, 44, 255]
+[:key_down_raw, 1073741906, 0, 2, 45, 257]
+[:key_up_raw, 1073741903, 0, 2, 46, 258]
+[:key_down_raw, 1073741906, 0, 2, 47, 271]
+[:key_down_raw, 1073741906, 0, 2, 48, 274]
+[:key_down_raw, 1073741906, 0, 2, 49, 276]
+[:key_down_raw, 1073741906, 0, 2, 50, 278]
+[:key_down_raw, 1073741906, 0, 2, 51, 280]
+[:key_up_raw, 1073741906, 0, 2, 52, 280]
+[:key_down_raw, 1073741903, 0, 2, 53, 280]
+[:key_down_raw, 1073741903, 0, 2, 54, 296]
+[:key_down_raw, 1073741903, 0, 2, 55, 298]
+[:key_down_raw, 1073741905, 0, 2, 56, 298]
+[:key_up_raw, 1073741903, 0, 2, 57, 300]
+[:key_down_raw, 1073741905, 0, 2, 58, 313]
+[:key_down_raw, 1073741905, 0, 2, 59, 315]
+[:key_down_raw, 1073741905, 0, 2, 60, 317]
+[:key_down_raw, 1073741905, 0, 2, 61, 319]
+[:key_down_raw, 1073741905, 0, 2, 62, 321]
+[:key_down_raw, 1073741905, 0, 2, 63, 323]
+[:key_down_raw, 1073741905, 0, 2, 64, 325]
+[:key_down_raw, 1073741905, 0, 2, 65, 327]
+[:key_down_raw, 1073741905, 0, 2, 66, 329]
+[:key_down_raw, 1073741904, 0, 2, 67, 330]
+[:key_up_raw, 1073741905, 0, 2, 68, 332]
+[:key_down_raw, 1073741904, 0, 2, 69, 345]
+[:key_down_raw, 1073741904, 0, 2, 70, 347]
+[:key_down_raw, 1073741904, 0, 2, 71, 349]
+[:key_down_raw, 1073741904, 0, 2, 72, 351]
+[:key_up_raw, 1073741904, 0, 2, 73, 353]
+[:key_down_raw, 1073741903, 0, 2, 74, 354]
+[:key_down_raw, 1073741903, 0, 2, 75, 369]
+[:key_down_raw, 1073741903, 0, 2, 76, 371]
+[:key_down_raw, 1073741903, 0, 2, 77, 373]
+[:key_down_raw, 1073741903, 0, 2, 78, 375]
+[:key_down_raw, 1073741903, 0, 2, 79, 377]
+[:key_down_raw, 1073741903, 0, 2, 80, 379]
+[:key_down_raw, 1073741903, 0, 2, 81, 382]
+[:key_down_raw, 1073741903, 0, 2, 82, 383]
+[:key_down_raw, 1073741903, 0, 2, 83, 385]
+[:key_down_raw, 1073741903, 0, 2, 84, 387]
+[:key_down_raw, 1073741903, 0, 2, 85, 390]
+[:key_down_raw, 1073741903, 0, 2, 86, 392]
+[:key_down_raw, 1073741903, 0, 2, 87, 394]
+[:key_down_raw, 1073741905, 0, 2, 88, 395]
+[:key_up_raw, 1073741903, 0, 2, 89, 400]
+[:key_down_raw, 1073741904, 0, 2, 90, 405]
+[:key_up_raw, 1073741905, 0, 2, 91, 416]
+[:key_down_raw, 1073741904, 0, 2, 92, 420]
+[:key_down_raw, 1073741904, 0, 2, 93, 422]
+[:key_down_raw, 1073741904, 0, 2, 94, 424]
+[:key_down_raw, 1073741904, 0, 2, 95, 426]
+[:key_down_raw, 1073741904, 0, 2, 96, 428]
+[:key_down_raw, 1073741904, 0, 2, 97, 430]
+[:key_down_raw, 1073741904, 0, 2, 98, 432]
+[:key_down_raw, 1073741904, 0, 2, 99, 434]
+[:key_down_raw, 1073741904, 0, 2, 100, 436]
+[:key_down_raw, 1073741904, 0, 2, 101, 438]
+[:key_down_raw, 1073741904, 0, 2, 102, 440]
+[:key_down_raw, 1073741904, 0, 2, 103, 442]
+[:key_down_raw, 1073741904, 0, 2, 104, 444]
+[:key_up_raw, 1073741904, 0, 2, 105, 444]
+[:key_down_raw, 1073741906, 0, 2, 106, 445]
+[:key_up_raw, 1073741906, 0, 2, 107, 448]
+[:key_down_raw, 1073741905, 0, 2, 108, 452]
+[:key_down_raw, 1073741905, 0, 2, 109, 467]
+[:key_down_raw, 1073741905, 0, 2, 110, 469]
+[:key_up_raw, 1073741905, 0, 2, 111, 470]
+[:key_down_raw, 1073741906, 0, 2, 112, 484]
+[:key_up_raw, 1073741906, 0, 2, 113, 496]
+[:key_down_raw, 32, 0, 2, 114, 499]
+[:key_up_raw, 32, 0, 2, 115, 505]
+[:key_down_raw, 1073741903, 0, 2, 116, 538]
+[:key_up_raw, 1073741903, 0, 2, 117, 553]
+[:key_down_raw, 106, 0, 2, 118, 604]
+[:key_up_raw, 106, 0, 2, 119, 608]
+[:key_down_raw, 1073741903, 0, 2, 120, 640]
+[:key_down_raw, 1073741906, 0, 2, 121, 654]
+[:key_up_raw, 1073741903, 0, 2, 122, 654]
+[:key_down_raw, 1073741906, 0, 2, 123, 669]
+[:key_down_raw, 1073741906, 0, 2, 124, 671]
+[:key_down_raw, 1073741906, 0, 2, 125, 673]
+[:key_down_raw, 1073741906, 0, 2, 126, 675]
+[:key_up_raw, 1073741906, 0, 2, 127, 677]
+[:key_down_raw, 1073741903, 0, 2, 128, 677]
+[:key_down_raw, 1073741903, 0, 2, 129, 692]
+[:key_down_raw, 1073741903, 0, 2, 130, 694]
+[:key_down_raw, 1073741905, 0, 2, 131, 694]
+[:key_up_raw, 1073741903, 0, 2, 132, 696]
+[:key_down_raw, 1073741905, 0, 2, 133, 709]
+[:key_down_raw, 1073741905, 0, 2, 134, 711]
+[:key_down_raw, 1073741905, 0, 2, 135, 713]
+[:key_down_raw, 1073741905, 0, 2, 136, 715]
+[:key_down_raw, 1073741905, 0, 2, 137, 717]
+[:key_down_raw, 1073741904, 0, 2, 138, 719]
+[:key_up_raw, 1073741905, 0, 2, 139, 721]
+[:key_down_raw, 1073741904, 0, 2, 140, 734]
+[:key_down_raw, 1073741904, 0, 2, 141, 736]
+[:key_down_raw, 1073741904, 0, 2, 142, 738]
+[:key_down_raw, 1073741904, 0, 2, 143, 740]
+[:key_down_raw, 1073741904, 0, 2, 144, 742]
+[:key_down_raw, 1073741904, 0, 2, 145, 744]
+[:key_down_raw, 1073741904, 0, 2, 146, 746]
+[:key_down_raw, 1073741904, 0, 2, 147, 748]
+[:key_up_raw, 1073741904, 0, 2, 148, 748]
+[:key_down_raw, 96, 0, 2, 149, 778]
+[:key_up_raw, 96, 0, 2, 150, 782]
+[:mouse_move, 782, 86, 2, 151, 822]
+[:mouse_move, 774, 93, 2, 152, 823]
+[:mouse_move, 764, 101, 2, 153, 824]
+[:mouse_move, 752, 113, 2, 154, 825]
+[:mouse_move, 732, 126, 2, 155, 826]
+[:mouse_move, 716, 141, 2, 156, 827]
+[:mouse_move, 705, 152, 2, 157, 828]
+[:mouse_move, 699, 162, 2, 158, 829]
+[:mouse_move, 693, 172, 2, 159, 830]
+[:mouse_move, 690, 177, 2, 160, 831]
+[:mouse_move, 690, 176, 2, 161, 839]
+[:mouse_move, 691, 175, 2, 162, 840]
+[:mouse_move, 693, 173, 2, 163, 841]
+[:mouse_move, 695, 173, 2, 164, 842]
+[:mouse_move, 695, 172, 2, 165, 844]
+[:key_down_raw, 13, 0, 2, 166, 851]
diff --git a/samples/99_genre_crafting/replay.txt b/samples/99_genre_crafting/replay.txt
new file mode 100644
index 0000000..740810d
--- /dev/null
+++ b/samples/99_genre_crafting/replay.txt
@@ -0,0 +1,170 @@
+replay_version 2.0
+stopped_at 851
+seed 100
+recorded_at 2021-11-20 11:30:20 -0600
+[:mouse_button_up, 1, 0, 1, 1, 4]
+[:key_down_raw, 1073741904, 0, 2, 2, 69]
+[:key_down_raw, 1073741904, 0, 2, 3, 83]
+[:key_up_raw, 1073741904, 0, 2, 4, 84]
+[:key_down_raw, 1073741906, 0, 2, 5, 89]
+[:key_down_raw, 1073741903, 0, 2, 6, 95]
+[:key_up_raw, 1073741906, 0, 2, 7, 103]
+[:key_down_raw, 1073741903, 0, 2, 8, 110]
+[:key_down_raw, 1073741903, 0, 2, 9, 112]
+[:key_down_raw, 1073741903, 0, 2, 10, 114]
+[:key_down_raw, 1073741903, 0, 2, 11, 116]
+[:key_down_raw, 1073741903, 0, 2, 12, 118]
+[:key_down_raw, 1073741903, 0, 2, 13, 120]
+[:key_down_raw, 1073741903, 0, 2, 14, 122]
+[:key_down_raw, 1073741903, 0, 2, 15, 124]
+[:key_up_raw, 1073741903, 0, 2, 16, 125]
+[:key_down_raw, 106, 0, 2, 17, 147]
+[:key_up_raw, 106, 0, 2, 18, 156]
+[:key_down_raw, 1073741904, 0, 2, 19, 180]
+[:key_down_raw, 1073741904, 0, 2, 20, 195]
+[:key_down_raw, 1073741904, 0, 2, 21, 197]
+[:key_down_raw, 1073741904, 0, 2, 22, 199]
+[:key_down_raw, 1073741904, 0, 2, 23, 201]
+[:key_down_raw, 1073741904, 0, 2, 24, 203]
+[:key_down_raw, 1073741904, 0, 2, 25, 205]
+[:key_up_raw, 1073741904, 0, 2, 26, 207]
+[:key_down_raw, 1073741903, 0, 2, 27, 208]
+[:key_down_raw, 1073741903, 0, 2, 28, 223]
+[:key_down_raw, 1073741903, 0, 2, 29, 225]
+[:key_down_raw, 1073741903, 0, 2, 30, 227]
+[:key_down_raw, 1073741903, 0, 2, 31, 229]
+[:key_down_raw, 1073741903, 0, 2, 32, 231]
+[:key_down_raw, 1073741903, 0, 2, 33, 233]
+[:key_down_raw, 1073741903, 0, 2, 34, 235]
+[:key_down_raw, 1073741903, 0, 2, 35, 237]
+[:key_down_raw, 1073741903, 0, 2, 36, 239]
+[:key_down_raw, 1073741903, 0, 2, 37, 241]
+[:key_down_raw, 1073741903, 0, 2, 38, 243]
+[:key_down_raw, 1073741903, 0, 2, 39, 245]
+[:key_down_raw, 1073741903, 0, 2, 40, 247]
+[:key_down_raw, 1073741903, 0, 2, 41, 249]
+[:key_down_raw, 1073741903, 0, 2, 42, 251]
+[:key_down_raw, 1073741903, 0, 2, 43, 253]
+[:key_down_raw, 1073741903, 0, 2, 44, 255]
+[:key_down_raw, 1073741906, 0, 2, 45, 257]
+[:key_up_raw, 1073741903, 0, 2, 46, 258]
+[:key_down_raw, 1073741906, 0, 2, 47, 271]
+[:key_down_raw, 1073741906, 0, 2, 48, 274]
+[:key_down_raw, 1073741906, 0, 2, 49, 276]
+[:key_down_raw, 1073741906, 0, 2, 50, 278]
+[:key_down_raw, 1073741906, 0, 2, 51, 280]
+[:key_up_raw, 1073741906, 0, 2, 52, 280]
+[:key_down_raw, 1073741903, 0, 2, 53, 280]
+[:key_down_raw, 1073741903, 0, 2, 54, 296]
+[:key_down_raw, 1073741903, 0, 2, 55, 298]
+[:key_down_raw, 1073741905, 0, 2, 56, 298]
+[:key_up_raw, 1073741903, 0, 2, 57, 300]
+[:key_down_raw, 1073741905, 0, 2, 58, 313]
+[:key_down_raw, 1073741905, 0, 2, 59, 315]
+[:key_down_raw, 1073741905, 0, 2, 60, 317]
+[:key_down_raw, 1073741905, 0, 2, 61, 319]
+[:key_down_raw, 1073741905, 0, 2, 62, 321]
+[:key_down_raw, 1073741905, 0, 2, 63, 323]
+[:key_down_raw, 1073741905, 0, 2, 64, 325]
+[:key_down_raw, 1073741905, 0, 2, 65, 327]
+[:key_down_raw, 1073741905, 0, 2, 66, 329]
+[:key_down_raw, 1073741904, 0, 2, 67, 330]
+[:key_up_raw, 1073741905, 0, 2, 68, 332]
+[:key_down_raw, 1073741904, 0, 2, 69, 345]
+[:key_down_raw, 1073741904, 0, 2, 70, 347]
+[:key_down_raw, 1073741904, 0, 2, 71, 349]
+[:key_down_raw, 1073741904, 0, 2, 72, 351]
+[:key_up_raw, 1073741904, 0, 2, 73, 353]
+[:key_down_raw, 1073741903, 0, 2, 74, 354]
+[:key_down_raw, 1073741903, 0, 2, 75, 369]
+[:key_down_raw, 1073741903, 0, 2, 76, 371]
+[:key_down_raw, 1073741903, 0, 2, 77, 373]
+[:key_down_raw, 1073741903, 0, 2, 78, 375]
+[:key_down_raw, 1073741903, 0, 2, 79, 377]
+[:key_down_raw, 1073741903, 0, 2, 80, 379]
+[:key_down_raw, 1073741903, 0, 2, 81, 382]
+[:key_down_raw, 1073741903, 0, 2, 82, 383]
+[:key_down_raw, 1073741903, 0, 2, 83, 385]
+[:key_down_raw, 1073741903, 0, 2, 84, 387]
+[:key_down_raw, 1073741903, 0, 2, 85, 390]
+[:key_down_raw, 1073741903, 0, 2, 86, 392]
+[:key_down_raw, 1073741903, 0, 2, 87, 394]
+[:key_down_raw, 1073741905, 0, 2, 88, 395]
+[:key_up_raw, 1073741903, 0, 2, 89, 400]
+[:key_down_raw, 1073741904, 0, 2, 90, 405]
+[:key_up_raw, 1073741905, 0, 2, 91, 416]
+[:key_down_raw, 1073741904, 0, 2, 92, 420]
+[:key_down_raw, 1073741904, 0, 2, 93, 422]
+[:key_down_raw, 1073741904, 0, 2, 94, 424]
+[:key_down_raw, 1073741904, 0, 2, 95, 426]
+[:key_down_raw, 1073741904, 0, 2, 96, 428]
+[:key_down_raw, 1073741904, 0, 2, 97, 430]
+[:key_down_raw, 1073741904, 0, 2, 98, 432]
+[:key_down_raw, 1073741904, 0, 2, 99, 434]
+[:key_down_raw, 1073741904, 0, 2, 100, 436]
+[:key_down_raw, 1073741904, 0, 2, 101, 438]
+[:key_down_raw, 1073741904, 0, 2, 102, 440]
+[:key_down_raw, 1073741904, 0, 2, 103, 442]
+[:key_down_raw, 1073741904, 0, 2, 104, 444]
+[:key_up_raw, 1073741904, 0, 2, 105, 444]
+[:key_down_raw, 1073741906, 0, 2, 106, 445]
+[:key_up_raw, 1073741906, 0, 2, 107, 448]
+[:key_down_raw, 1073741905, 0, 2, 108, 452]
+[:key_down_raw, 1073741905, 0, 2, 109, 467]
+[:key_down_raw, 1073741905, 0, 2, 110, 469]
+[:key_up_raw, 1073741905, 0, 2, 111, 470]
+[:key_down_raw, 1073741906, 0, 2, 112, 484]
+[:key_up_raw, 1073741906, 0, 2, 113, 496]
+[:key_down_raw, 32, 0, 2, 114, 499]
+[:key_up_raw, 32, 0, 2, 115, 505]
+[:key_down_raw, 1073741903, 0, 2, 116, 538]
+[:key_up_raw, 1073741903, 0, 2, 117, 553]
+[:key_down_raw, 106, 0, 2, 118, 604]
+[:key_up_raw, 106, 0, 2, 119, 608]
+[:key_down_raw, 1073741903, 0, 2, 120, 640]
+[:key_down_raw, 1073741906, 0, 2, 121, 654]
+[:key_up_raw, 1073741903, 0, 2, 122, 654]
+[:key_down_raw, 1073741906, 0, 2, 123, 669]
+[:key_down_raw, 1073741906, 0, 2, 124, 671]
+[:key_down_raw, 1073741906, 0, 2, 125, 673]
+[:key_down_raw, 1073741906, 0, 2, 126, 675]
+[:key_up_raw, 1073741906, 0, 2, 127, 677]
+[:key_down_raw, 1073741903, 0, 2, 128, 677]
+[:key_down_raw, 1073741903, 0, 2, 129, 692]
+[:key_down_raw, 1073741903, 0, 2, 130, 694]
+[:key_down_raw, 1073741905, 0, 2, 131, 694]
+[:key_up_raw, 1073741903, 0, 2, 132, 696]
+[:key_down_raw, 1073741905, 0, 2, 133, 709]
+[:key_down_raw, 1073741905, 0, 2, 134, 711]
+[:key_down_raw, 1073741905, 0, 2, 135, 713]
+[:key_down_raw, 1073741905, 0, 2, 136, 715]
+[:key_down_raw, 1073741905, 0, 2, 137, 717]
+[:key_down_raw, 1073741904, 0, 2, 138, 719]
+[:key_up_raw, 1073741905, 0, 2, 139, 721]
+[:key_down_raw, 1073741904, 0, 2, 140, 734]
+[:key_down_raw, 1073741904, 0, 2, 141, 736]
+[:key_down_raw, 1073741904, 0, 2, 142, 738]
+[:key_down_raw, 1073741904, 0, 2, 143, 740]
+[:key_down_raw, 1073741904, 0, 2, 144, 742]
+[:key_down_raw, 1073741904, 0, 2, 145, 744]
+[:key_down_raw, 1073741904, 0, 2, 146, 746]
+[:key_down_raw, 1073741904, 0, 2, 147, 748]
+[:key_up_raw, 1073741904, 0, 2, 148, 748]
+[:key_down_raw, 96, 0, 2, 149, 778]
+[:key_up_raw, 96, 0, 2, 150, 782]
+[:mouse_move, 782, 86, 2, 151, 822]
+[:mouse_move, 774, 93, 2, 152, 823]
+[:mouse_move, 764, 101, 2, 153, 824]
+[:mouse_move, 752, 113, 2, 154, 825]
+[:mouse_move, 732, 126, 2, 155, 826]
+[:mouse_move, 716, 141, 2, 156, 827]
+[:mouse_move, 705, 152, 2, 157, 828]
+[:mouse_move, 699, 162, 2, 158, 829]
+[:mouse_move, 693, 172, 2, 159, 830]
+[:mouse_move, 690, 177, 2, 160, 831]
+[:mouse_move, 690, 176, 2, 161, 839]
+[:mouse_move, 691, 175, 2, 162, 840]
+[:mouse_move, 693, 173, 2, 163, 841]
+[:mouse_move, 695, 173, 2, 164, 842]
+[:mouse_move, 695, 172, 2, 165, 844]
+[:key_down_raw, 13, 0, 2, 166, 851]
diff --git a/samples/99_genre_dungeon_crawl/classics_jam/replay.txt b/samples/99_genre_dungeon_crawl/classics_jam/replay.txt
new file mode 100644
index 0000000..eab6ec5
--- /dev/null
+++ b/samples/99_genre_dungeon_crawl/classics_jam/replay.txt
@@ -0,0 +1,197 @@
+replay_version 2.0
+stopped_at 873
+seed 100
+recorded_at 2021-11-20 11:38:43 -0600
+[:mouse_button_up, 1, 0, 1, 1, 4]
+[:key_down_raw, 1073741905, 0, 2, 2, 99]
+[:key_down_raw, 1073741905, 0, 2, 3, 113]
+[:key_down_raw, 1073741905, 0, 2, 4, 115]
+[:key_down_raw, 1073741905, 0, 2, 5, 117]
+[:key_down_raw, 1073741905, 0, 2, 6, 119]
+[:key_down_raw, 1073741905, 0, 2, 7, 121]
+[:key_down_raw, 1073741905, 0, 2, 8, 123]
+[:key_down_raw, 1073741905, 0, 2, 9, 125]
+[:key_down_raw, 1073741905, 0, 2, 10, 127]
+[:key_down_raw, 1073741905, 0, 2, 11, 129]
+[:key_down_raw, 1073741905, 0, 2, 12, 131]
+[:key_down_raw, 1073741905, 0, 2, 13, 133]
+[:key_down_raw, 1073741905, 0, 2, 14, 135]
+[:key_down_raw, 1073741905, 0, 2, 15, 137]
+[:key_down_raw, 1073741905, 0, 2, 16, 139]
+[:key_down_raw, 1073741905, 0, 2, 17, 141]
+[:key_down_raw, 1073741905, 0, 2, 18, 143]
+[:key_down_raw, 1073741905, 0, 2, 19, 145]
+[:key_down_raw, 1073741905, 0, 2, 20, 147]
+[:key_down_raw, 1073741905, 0, 2, 21, 149]
+[:key_down_raw, 1073741905, 0, 2, 22, 151]
+[:key_down_raw, 1073741905, 0, 2, 23, 153]
+[:key_down_raw, 1073741905, 0, 2, 24, 155]
+[:key_down_raw, 1073741905, 0, 2, 25, 157]
+[:key_down_raw, 1073741905, 0, 2, 26, 159]
+[:key_down_raw, 1073741905, 0, 2, 27, 161]
+[:key_down_raw, 1073741905, 0, 2, 28, 163]
+[:key_down_raw, 1073741905, 0, 2, 29, 165]
+[:key_down_raw, 1073741905, 0, 2, 30, 167]
+[:key_down_raw, 1073741905, 0, 2, 31, 169]
+[:key_down_raw, 1073741905, 0, 2, 32, 171]
+[:key_down_raw, 1073741905, 0, 2, 33, 173]
+[:key_down_raw, 1073741905, 0, 2, 34, 175]
+[:key_down_raw, 1073741905, 0, 2, 35, 177]
+[:key_down_raw, 1073741905, 0, 2, 36, 179]
+[:key_down_raw, 1073741905, 0, 2, 37, 181]
+[:key_down_raw, 1073741905, 0, 2, 38, 183]
+[:key_down_raw, 1073741905, 0, 2, 39, 185]
+[:key_down_raw, 1073741905, 0, 2, 40, 187]
+[:key_down_raw, 1073741905, 0, 2, 41, 189]
+[:key_down_raw, 1073741905, 0, 2, 42, 191]
+[:key_down_raw, 1073741905, 0, 2, 43, 193]
+[:key_down_raw, 1073741905, 0, 2, 44, 195]
+[:key_down_raw, 1073741904, 0, 2, 45, 196]
+[:key_up_raw, 1073741905, 0, 2, 46, 196]
+[:key_up_raw, 1073741904, 0, 2, 47, 205]
+[:key_down_raw, 32, 0, 2, 48, 206]
+[:key_up_raw, 32, 0, 2, 49, 212]
+[:key_down_raw, 32, 0, 2, 50, 217]
+[:key_up_raw, 32, 0, 2, 51, 222]
+[:key_down_raw, 32, 0, 2, 52, 227]
+[:key_up_raw, 32, 0, 2, 53, 233]
+[:key_down_raw, 32, 0, 2, 54, 237]
+[:key_up_raw, 32, 0, 2, 55, 243]
+[:key_down_raw, 32, 0, 2, 56, 266]
+[:key_up_raw, 32, 0, 2, 57, 271]
+[:key_down_raw, 32, 0, 2, 58, 276]
+[:key_up_raw, 32, 0, 2, 59, 282]
+[:key_down_raw, 32, 0, 2, 60, 294]
+[:key_up_raw, 32, 0, 2, 61, 300]
+[:key_down_raw, 32, 0, 2, 62, 305]
+[:key_down_raw, 1073741904, 0, 2, 63, 306]
+[:key_up_raw, 32, 0, 2, 64, 310]
+[:key_down_raw, 1073741904, 0, 2, 65, 322]
+[:key_down_raw, 1073741904, 0, 2, 66, 324]
+[:key_down_raw, 1073741904, 0, 2, 67, 326]
+[:key_down_raw, 1073741904, 0, 2, 68, 328]
+[:key_down_raw, 1073741904, 0, 2, 69, 330]
+[:key_down_raw, 1073741904, 0, 2, 70, 332]
+[:key_down_raw, 1073741904, 0, 2, 71, 334]
+[:key_down_raw, 1073741904, 0, 2, 72, 336]
+[:key_down_raw, 1073741904, 0, 2, 73, 338]
+[:key_down_raw, 1073741904, 0, 2, 74, 340]
+[:key_down_raw, 1073741904, 0, 2, 75, 342]
+[:key_down_raw, 1073741904, 0, 2, 76, 344]
+[:key_down_raw, 1073741904, 0, 2, 77, 346]
+[:key_down_raw, 1073741904, 0, 2, 78, 348]
+[:key_down_raw, 1073741904, 0, 2, 79, 350]
+[:key_down_raw, 1073741904, 0, 2, 80, 352]
+[:key_down_raw, 1073741904, 0, 2, 81, 354]
+[:key_down_raw, 1073741904, 0, 2, 82, 356]
+[:key_down_raw, 1073741904, 0, 2, 83, 358]
+[:key_down_raw, 1073741904, 0, 2, 84, 360]
+[:key_down_raw, 1073741904, 0, 2, 85, 362]
+[:key_down_raw, 1073741904, 0, 2, 86, 364]
+[:key_down_raw, 1073741904, 0, 2, 87, 366]
+[:key_down_raw, 1073741904, 0, 2, 88, 368]
+[:key_down_raw, 1073741904, 0, 2, 89, 370]
+[:key_down_raw, 1073741904, 0, 2, 90, 372]
+[:key_down_raw, 1073741904, 0, 2, 91, 374]
+[:key_down_raw, 1073741904, 0, 2, 92, 376]
+[:key_down_raw, 1073741904, 0, 2, 93, 378]
+[:key_down_raw, 1073741904, 0, 2, 94, 380]
+[:key_down_raw, 1073741904, 0, 2, 95, 382]
+[:key_down_raw, 1073741904, 0, 2, 96, 384]
+[:key_down_raw, 1073741904, 0, 2, 97, 386]
+[:key_down_raw, 1073741904, 0, 2, 98, 388]
+[:key_down_raw, 1073741904, 0, 2, 99, 390]
+[:key_down_raw, 1073741904, 0, 2, 100, 392]
+[:key_down_raw, 1073741904, 0, 2, 101, 394]
+[:key_down_raw, 1073741904, 0, 2, 102, 396]
+[:key_down_raw, 1073741904, 0, 2, 103, 398]
+[:key_down_raw, 1073741904, 0, 2, 104, 400]
+[:key_down_raw, 1073741904, 0, 2, 105, 402]
+[:key_down_raw, 1073741904, 0, 2, 106, 404]
+[:key_down_raw, 1073741904, 0, 2, 107, 406]
+[:key_down_raw, 1073741904, 0, 2, 108, 408]
+[:key_down_raw, 1073741904, 0, 2, 109, 410]
+[:key_down_raw, 1073741904, 0, 2, 110, 412]
+[:key_down_raw, 1073741904, 0, 2, 111, 414]
+[:key_down_raw, 1073741904, 0, 2, 112, 416]
+[:key_down_raw, 1073741904, 0, 2, 113, 418]
+[:key_down_raw, 1073741904, 0, 2, 114, 420]
+[:key_down_raw, 1073741904, 0, 2, 115, 422]
+[:key_down_raw, 1073741904, 0, 2, 116, 424]
+[:key_down_raw, 1073741904, 0, 2, 117, 426]
+[:key_down_raw, 1073741904, 0, 2, 118, 428]
+[:key_down_raw, 1073741904, 0, 2, 119, 430]
+[:key_down_raw, 1073741904, 0, 2, 120, 432]
+[:key_down_raw, 1073741904, 0, 2, 121, 434]
+[:key_down_raw, 1073741904, 0, 2, 122, 436]
+[:key_down_raw, 1073741904, 0, 2, 123, 438]
+[:key_down_raw, 1073741904, 0, 2, 124, 440]
+[:key_up_raw, 1073741904, 0, 2, 125, 442]
+[:key_down_raw, 1073741903, 0, 2, 126, 461]
+[:key_down_raw, 1073741903, 0, 2, 127, 476]
+[:key_down_raw, 1073741903, 0, 2, 128, 478]
+[:key_down_raw, 1073741903, 0, 2, 129, 480]
+[:key_down_raw, 1073741903, 0, 2, 130, 482]
+[:key_down_raw, 1073741903, 0, 2, 131, 484]
+[:key_down_raw, 1073741903, 0, 2, 132, 486]
+[:key_down_raw, 1073741903, 0, 2, 133, 488]
+[:key_down_raw, 1073741903, 0, 2, 134, 490]
+[:key_down_raw, 1073741903, 0, 2, 135, 492]
+[:key_down_raw, 1073741903, 0, 2, 136, 494]
+[:key_down_raw, 1073741903, 0, 2, 137, 496]
+[:key_down_raw, 1073741903, 0, 2, 138, 498]
+[:key_down_raw, 1073741903, 0, 2, 139, 500]
+[:key_down_raw, 1073741903, 0, 2, 140, 502]
+[:key_down_raw, 1073741903, 0, 2, 141, 504]
+[:key_down_raw, 1073741903, 0, 2, 142, 506]
+[:key_down_raw, 1073741903, 0, 2, 143, 508]
+[:key_down_raw, 1073741903, 0, 2, 144, 510]
+[:key_down_raw, 1073741903, 0, 2, 145, 512]
+[:key_down_raw, 1073741903, 0, 2, 146, 514]
+[:key_down_raw, 1073741903, 0, 2, 147, 516]
+[:key_down_raw, 1073741903, 0, 2, 148, 518]
+[:key_down_raw, 1073741903, 0, 2, 149, 520]
+[:key_down_raw, 1073741903, 0, 2, 150, 522]
+[:key_down_raw, 1073741903, 0, 2, 151, 524]
+[:key_down_raw, 1073741903, 0, 2, 152, 526]
+[:key_down_raw, 1073741903, 0, 2, 153, 528]
+[:key_down_raw, 1073741904, 0, 2, 154, 528]
+[:key_up_raw, 1073741903, 0, 2, 155, 528]
+[:key_down_raw, 32, 0, 2, 156, 534]
+[:key_up_raw, 32, 0, 2, 157, 539]
+[:key_down_raw, 32, 0, 2, 158, 545]
+[:key_up_raw, 32, 0, 2, 159, 549]
+[:key_down_raw, 32, 0, 2, 160, 554]
+[:key_up_raw, 32, 0, 2, 161, 560]
+[:key_down_raw, 32, 0, 2, 162, 564]
+[:key_up_raw, 32, 0, 2, 163, 570]
+[:key_down_raw, 32, 0, 2, 164, 575]
+[:key_up_raw, 32, 0, 2, 165, 581]
+[:key_down_raw, 32, 0, 2, 166, 585]
+[:key_up_raw, 32, 0, 2, 167, 590]
+[:key_down_raw, 32, 0, 2, 168, 594]
+[:key_up_raw, 32, 0, 2, 169, 600]
+[:key_down_raw, 32, 0, 2, 170, 605]
+[:key_up_raw, 32, 0, 2, 171, 610]
+[:key_down_raw, 32, 0, 2, 172, 615]
+[:key_up_raw, 32, 0, 2, 173, 620]
+[:key_down_raw, 32, 0, 2, 174, 624]
+[:key_up_raw, 32, 0, 2, 175, 630]
+[:key_up_raw, 1073741904, 0, 2, 176, 631]
+[:key_down_raw, 32, 0, 2, 177, 634]
+[:key_up_raw, 32, 0, 2, 178, 639]
+[:key_down_raw, 32, 0, 2, 179, 644]
+[:key_up_raw, 32, 0, 2, 180, 649]
+[:key_down_raw, 32, 0, 2, 181, 654]
+[:key_up_raw, 32, 0, 2, 182, 659]
+[:key_down_raw, 32, 0, 2, 183, 664]
+[:key_up_raw, 32, 0, 2, 184, 669]
+[:key_down_raw, 32, 0, 2, 185, 674]
+[:key_up_raw, 32, 0, 2, 186, 679]
+[:key_down_raw, 32, 0, 2, 187, 684]
+[:key_up_raw, 32, 0, 2, 188, 689]
+[:key_down_raw, 32, 0, 2, 189, 694]
+[:key_up_raw, 32, 0, 2, 190, 699]
+[:key_down_raw, 96, 0, 2, 191, 823]
+[:key_up_raw, 96, 0, 2, 192, 828]
+[:key_down_raw, 13, 0, 2, 193, 873]
diff --git a/samples/99_genre_mario/01_jumping/app/main.rb b/samples/99_genre_mario/01_jumping/app/main.rb
new file mode 100644
index 0000000..2d12a22
--- /dev/null
+++ b/samples/99_genre_mario/01_jumping/app/main.rb
@@ -0,0 +1,78 @@
+def tick args
+ defaults args
+ render args
+ input args
+ calc args
+end
+
+def defaults args
+ args.state.player.x ||= args.grid.w.half
+ args.state.player.y ||= 0
+ args.state.player.size ||= 100
+ args.state.player.dy ||= 0
+ args.state.player.action ||= :jumping
+ args.state.jump.power = 20
+ args.state.jump.increase_frames = 10
+ args.state.jump.increase_power = 1
+ args.state.gravity = -1
+end
+
+def render args
+ args.outputs.sprites << {
+ x: args.state.player.x -
+ args.state.player.size.half,
+ y: args.state.player.y,
+ w: args.state.player.size,
+ h: args.state.player.size,
+ path: 'sprites/square/red.png'
+ }
+end
+
+def input args
+ if args.inputs.keyboard.key_down.space
+ if args.state.player.action == :standing
+ args.state.player.action = :jumping
+ args.state.player.dy = args.state.jump.power
+
+ # record when the action took place
+ current_frame = args.state.tick_count
+ args.state.player.action_at = current_frame
+ end
+ end
+
+ # if the space bar is being held
+ if args.inputs.keyboard.key_held.space
+ # is the player jumping
+ is_jumping = args.state.player.action == :jumping
+
+ # when was the jump performed
+ time_of_jump = args.state.player.action_at
+
+ # how much time has passed since the jump
+ jump_elapsed_time = time_of_jump.elapsed_time
+
+ # how much time is allowed for increasing power
+ time_allowed = args.state.jump.increase_frames
+
+ # if the player is jumping
+ # and the elapsed time is less than
+ # the allowed time
+ if is_jumping && jump_elapsed_time < time_allowed
+ # increase the dy by the increase power
+ power_to_add = args.state.jump.increase_power
+ args.state.player.dy += power_to_add
+ end
+ end
+end
+
+def calc args
+ if args.state.player.action == :jumping
+ args.state.player.y += args.state.player.dy
+ args.state.player.dy += args.state.gravity
+ end
+
+ if args.state.player.y < 0
+ args.state.player.y = 0
+ args.state.player.action = :standing
+ end
+end
diff --git a/samples/99_genre_mario/01_jumping/replay.txt b/samples/99_genre_mario/01_jumping/replay.txt
new file mode 100644
index 0000000..d56d585
--- /dev/null
+++ b/samples/99_genre_mario/01_jumping/replay.txt
@@ -0,0 +1,52 @@
+replay_version 2.0
+stopped_at 574
+seed 100
+recorded_at 2021-11-20 16:44:37 -0600
+[:mouse_button_up, 1, 0, 1, 1, 3]
+[:key_down_raw, 32, 0, 2, 2, 89]
+[:key_up_raw, 32, 0, 2, 3, 92]
+[:key_down_raw, 32, 0, 2, 4, 193]
+[:key_up_raw, 32, 0, 2, 5, 195]
+[:key_down_raw, 32, 0, 2, 6, 258]
+[:key_down_raw, 32, 0, 2, 7, 273]
+[:key_down_raw, 32, 0, 2, 8, 275]
+[:key_down_raw, 32, 0, 2, 9, 277]
+[:key_down_raw, 32, 0, 2, 10, 279]
+[:key_down_raw, 32, 0, 2, 11, 281]
+[:key_down_raw, 32, 0, 2, 12, 283]
+[:key_down_raw, 32, 0, 2, 13, 285]
+[:key_down_raw, 32, 0, 2, 14, 287]
+[:key_down_raw, 32, 0, 2, 15, 289]
+[:key_down_raw, 32, 0, 2, 16, 291]
+[:key_down_raw, 32, 0, 2, 17, 293]
+[:key_down_raw, 32, 0, 2, 18, 295]
+[:key_down_raw, 32, 0, 2, 19, 297]
+[:key_down_raw, 32, 0, 2, 20, 299]
+[:key_down_raw, 32, 0, 2, 21, 301]
+[:key_down_raw, 32, 0, 2, 22, 303]
+[:key_down_raw, 32, 0, 2, 23, 305]
+[:key_down_raw, 32, 0, 2, 24, 307]
+[:key_up_raw, 32, 0, 2, 25, 307]
+[:key_down_raw, 32, 0, 2, 26, 336]
+[:key_up_raw, 32, 0, 2, 27, 339]
+[:key_down_raw, 32, 0, 2, 28, 389]
+[:key_up_raw, 32, 0, 2, 29, 392]
+[:key_down_raw, 32, 0, 2, 30, 444]
+[:key_down_raw, 32, 0, 2, 31, 459]
+[:key_down_raw, 32, 0, 2, 32, 461]
+[:key_down_raw, 32, 0, 2, 33, 463]
+[:key_down_raw, 32, 0, 2, 34, 465]
+[:key_down_raw, 32, 0, 2, 35, 467]
+[:key_down_raw, 32, 0, 2, 36, 469]
+[:key_down_raw, 32, 0, 2, 37, 471]
+[:key_down_raw, 32, 0, 2, 38, 473]
+[:key_down_raw, 32, 0, 2, 39, 475]
+[:key_down_raw, 32, 0, 2, 40, 477]
+[:key_down_raw, 32, 0, 2, 41, 479]
+[:key_down_raw, 32, 0, 2, 42, 481]
+[:key_down_raw, 32, 0, 2, 43, 483]
+[:key_down_raw, 32, 0, 2, 44, 485]
+[:key_up_raw, 32, 0, 2, 45, 485]
+[:key_down_raw, 96, 0, 2, 46, 509]
+[:key_up_raw, 96, 0, 2, 47, 512]
+[:key_down_raw, 13, 0, 2, 48, 574]
diff --git a/samples/99_genre_mario/01_jumping/sprites/square/red.png b/samples/99_genre_mario/01_jumping/sprites/square/red.png
new file mode 100644
index 0000000..a59443e
--- /dev/null
+++ b/samples/99_genre_mario/01_jumping/sprites/square/red.png
Binary files differ
diff --git a/samples/99_genre_mario/02_jumping_and_collisions/app/main.rb b/samples/99_genre_mario/02_jumping_and_collisions/app/main.rb
new file mode 100644
index 0000000..52d9135
--- /dev/null
+++ b/samples/99_genre_mario/02_jumping_and_collisions/app/main.rb
@@ -0,0 +1,281 @@
+class Game
+ attr_gtk
+
+ def tick
+ defaults
+ render
+ input
+ calc
+ end
+
+ def defaults
+ return if state.tick_count != 0
+
+ player.x = 64
+ player.y = 800
+ player.size = 50
+ player.dx = 0
+ player.dy = 0
+ player.action = :falling
+
+ player.max_speed = 20
+ player.jump_power = 15
+ player.jump_air_time = 15
+ player.jump_increase_power = 1
+
+ state.gravity = -1
+ state.drag = 0.001
+ state.tile_size = 64
+ state.tiles ||= [
+ { ordinal_x: 0, ordinal_y: 0 },
+ { ordinal_x: 1, ordinal_y: 0 },
+ { ordinal_x: 2, ordinal_y: 0 },
+ { ordinal_x: 3, ordinal_y: 0 },
+ { ordinal_x: 4, ordinal_y: 0 },
+ { ordinal_x: 5, ordinal_y: 0 },
+ { ordinal_x: 6, ordinal_y: 0 },
+ { ordinal_x: 7, ordinal_y: 0 },
+ { ordinal_x: 8, ordinal_y: 0 },
+ { ordinal_x: 9, ordinal_y: 0 },
+ { ordinal_x: 10, ordinal_y: 0 },
+ { ordinal_x: 11, ordinal_y: 0 },
+ { ordinal_x: 12, ordinal_y: 0 },
+
+ { ordinal_x: 9, ordinal_y: 3 },
+ { ordinal_x: 10, ordinal_y: 3 },
+ { ordinal_x: 11, ordinal_y: 3 },
+ ]
+
+ tiles.each do |t|
+ t.rect = { x: t.ordinal_x * 64,
+ y: t.ordinal_y * 64,
+ w: 64,
+ h: 64 }
+ end
+ end
+
+ def render
+ render_player
+ render_tiles
+ # render_grid
+ end
+
+ def input
+ input_jump
+ input_move
+ end
+
+ def calc
+ calc_player_rect
+ calc_left
+ calc_right
+ calc_below
+ calc_above
+ calc_player_dy
+ calc_player_dx
+ calc_game_over
+ end
+
+ def render_player
+ outputs.sprites << {
+ x: player.x,
+ y: player.y,
+ w: player.size,
+ h: player.size,
+ path: 'sprites/square/red.png'
+ }
+ end
+
+ def render_tiles
+ outputs.sprites << state.tiles.map do |t|
+ t.merge path: 'sprites/square/white.png',
+ x: t.ordinal_x * 64,
+ y: t.ordinal_y * 64,
+ w: 64,
+ h: 64
+ end
+ end
+
+ def render_grid
+ if state.tick_count == 0
+ outputs[:grid].background_color = [0, 0, 0, 0]
+ outputs[:grid].borders << available_brick_locations
+ outputs[:grid].labels << available_brick_locations.map do |b|
+ [
+ b.merge(text: "#{b.ordinal_x},#{b.ordinal_y}",
+ x: b.x + 2,
+ y: b.y + 2,
+ size_enum: -3,
+ vertical_alignment_enum: 0,
+ blendmode_enum: 0),
+ b.merge(text: "#{b.x},#{b.y}",
+ x: b.x + 2,
+ y: b.y + 2 + 20,
+ size_enum: -3,
+ vertical_alignment_enum: 0,
+ blendmode_enum: 0)
+ ]
+ end
+ end
+
+ outputs.sprites << { x: 0, y: 0, w: 1280, h: 720, path: :grid }
+ end
+
+ def input_jump
+ if inputs.keyboard.key_down.space
+ player_jump
+ end
+
+ if inputs.keyboard.key_held.space
+ player_jump_increase_air_time
+ end
+ end
+
+ def input_move
+ if player.dx.abs < 20
+ if inputs.keyboard.left
+ player.dx -= 2
+ elsif inputs.keyboard.right
+ player.dx += 2
+ end
+ end
+ end
+
+ def calc_game_over
+ if player.y < -64
+ player.x = 64
+ player.y = 800
+ player.dx = 0
+ player.dy = 0
+ end
+ end
+
+ def calc_player_rect
+ player.rect = player_current_rect
+ player.next_rect = player_next_rect
+ player.prev_rect = player_prev_rect
+ end
+
+ def calc_player_dx
+ player.dx = player_next_dx
+ player.x += player.dx
+ end
+
+ def calc_player_dy
+ player.y += player.dy
+ player.dy = player_next_dy
+ end
+
+ def calc_below
+ return unless player.dy < 0
+ tiles_below = tiles_find { |t| t.rect.top <= player.prev_rect.y }
+ collision = tiles_find_colliding tiles_below, (player.rect.merge y: player.next_rect.y)
+ if collision
+ player.y = collision.rect.y + state.tile_size
+ player.dy = 0
+ player.action = :standing
+ else
+ player.action = :falling
+ end
+ end
+
+ def calc_left
+ return unless player.dx < 0 && player_next_dx < 0
+ tiles_left = tiles_find { |t| t.rect.right <= player.prev_rect.left }
+ collision = tiles_find_colliding tiles_left, (player.rect.merge x: player.next_rect.x)
+ return unless collision
+ player.x = collision.rect.right
+ player.dx = 0
+ end
+
+ def calc_right
+ return unless player.dx > 0 && player_next_dx > 0
+ tiles_right = tiles_find { |t| t.rect.left >= player.prev_rect.right }
+ collision = tiles_find_colliding tiles_right, (player.rect.merge x: player.next_rect.x)
+ return unless collision
+ player.x = collision.rect.left - player.rect.w
+ player.dx = 0
+ end
+
+ def calc_above
+ return unless player.dy > 0
+ tiles_above = tiles_find { |t| t.rect.y >= player.prev_rect.y }
+ collision = tiles_find_colliding tiles_above, (player.rect.merge y: player.next_rect.y)
+ return unless collision
+ player.dy = 0
+ player.y = collision.rect.bottom - player.rect.h
+ end
+
+ def player_current_rect
+ { x: player.x, y: player.y, w: player.size, h: player.size }
+ end
+
+ def available_brick_locations
+ (0..19).to_a
+ .product(0..11)
+ .map do |(ordinal_x, ordinal_y)|
+ { ordinal_x: ordinal_x,
+ ordinal_y: ordinal_y,
+ x: ordinal_x * 64,
+ y: ordinal_y * 64,
+ w: 64,
+ h: 64 }
+ end
+ end
+
+ def player
+ state.player ||= args.state.new_entity :player
+ end
+
+ def player_next_dy
+ player.dy + state.gravity + state.drag ** 2 * -1
+ end
+
+ def player_next_dx
+ player.dx * 0.8
+ end
+
+ def player_next_rect
+ player.rect.merge x: player.x + player_next_dx,
+ y: player.y + player_next_dy
+ end
+
+ def player_prev_rect
+ player.rect.merge x: player.x - player.dx,
+ y: player.y - player.dy
+ end
+
+ def player_jump
+ return if player.action != :standing
+ player.action = :jumping
+ player.dy = state.player.jump_power
+ current_frame = state.tick_count
+ player.action_at = current_frame
+ end
+
+ def player_jump_increase_air_time
+ return if player.action != :jumping
+ return if player.action_at.elapsed_time >= player.jump_air_time
+ player.dy += player.jump_increase_power
+ end
+
+ def tiles
+ state.tiles
+ end
+
+ def tiles_find_colliding tiles, target
+ tiles.find { |t| t.rect.intersect_rect? target }
+ end
+
+ def tiles_find &block
+ tiles.find_all(&block)
+ end
+end
+
+def tick args
+ $game ||= Game.new
+ $game.args = args
+ $game.tick
+end
+
+$gtk.reset
diff --git a/samples/99_genre_mario/02_jumping_and_collisions/replay.txt b/samples/99_genre_mario/02_jumping_and_collisions/replay.txt
new file mode 100644
index 0000000..17e610f
--- /dev/null
+++ b/samples/99_genre_mario/02_jumping_and_collisions/replay.txt
@@ -0,0 +1,159 @@
+replay_version 2.0
+stopped_at 913
+seed 100
+recorded_at 2021-11-20 17:04:30 -0600
+[:mouse_move, 784, 90, 2, 1, 1]
+[:mouse_button_up, 1, 0, 1, 2, 4]
+[:mouse_move, 785, 90, 2, 3, 7]
+[:key_down_raw, 1073741903, 0, 2, 4, 63]
+[:key_down_raw, 1073741903, 0, 2, 5, 78]
+[:key_down_raw, 1073741903, 0, 2, 6, 81]
+[:key_down_raw, 1073741903, 0, 2, 7, 83]
+[:key_down_raw, 1073741903, 0, 2, 8, 85]
+[:key_down_raw, 1073741903, 0, 2, 9, 87]
+[:key_down_raw, 1073741903, 0, 2, 10, 89]
+[:key_down_raw, 1073741903, 0, 2, 11, 91]
+[:key_down_raw, 1073741903, 0, 2, 12, 93]
+[:key_down_raw, 1073741903, 0, 2, 13, 95]
+[:key_down_raw, 1073741903, 0, 2, 14, 97]
+[:key_down_raw, 1073741903, 0, 2, 15, 99]
+[:key_down_raw, 1073741903, 0, 2, 16, 101]
+[:key_down_raw, 1073741903, 0, 2, 17, 103]
+[:key_down_raw, 1073741903, 0, 2, 18, 105]
+[:key_down_raw, 1073741903, 0, 2, 19, 107]
+[:key_down_raw, 1073741903, 0, 2, 20, 109]
+[:key_down_raw, 1073741903, 0, 2, 21, 111]
+[:key_down_raw, 1073741903, 0, 2, 22, 113]
+[:key_down_raw, 1073741903, 0, 2, 23, 115]
+[:key_down_raw, 1073741903, 0, 2, 24, 117]
+[:key_down_raw, 1073741903, 0, 2, 25, 119]
+[:key_down_raw, 1073741903, 0, 2, 26, 121]
+[:key_up_raw, 1073741903, 0, 2, 27, 121]
+[:key_down_raw, 1073741904, 0, 2, 28, 155]
+[:key_up_raw, 1073741904, 0, 2, 29, 159]
+[:key_down_raw, 32, 0, 2, 30, 170]
+[:key_up_raw, 32, 0, 2, 31, 176]
+[:key_down_raw, 1073741903, 0, 2, 32, 189]
+[:key_up_raw, 1073741903, 0, 2, 33, 199]
+[:key_down_raw, 1073741904, 0, 2, 34, 235]
+[:key_up_raw, 1073741904, 0, 2, 35, 249]
+[:key_down_raw, 32, 0, 2, 36, 258]
+[:key_down_raw, 1073741903, 0, 2, 37, 262]
+[:key_down_raw, 1073741903, 0, 2, 38, 277]
+[:key_down_raw, 1073741903, 0, 2, 39, 279]
+[:key_down_raw, 1073741903, 0, 2, 40, 281]
+[:key_down_raw, 1073741903, 0, 2, 41, 283]
+[:key_down_raw, 1073741903, 0, 2, 42, 285]
+[:key_down_raw, 1073741903, 0, 2, 43, 287]
+[:key_up_raw, 32, 0, 2, 44, 288]
+[:key_down_raw, 1073741903, 0, 2, 45, 289]
+[:key_up_raw, 1073741903, 0, 2, 46, 290]
+[:key_down_raw, 1073741904, 0, 2, 47, 309]
+[:key_down_raw, 32, 0, 2, 48, 320]
+[:key_up_raw, 32, 0, 2, 49, 330]
+[:key_down_raw, 32, 0, 2, 50, 335]
+[:key_up_raw, 32, 0, 2, 51, 339]
+[:key_up_raw, 1073741904, 0, 2, 52, 355]
+[:key_down_raw, 1073741903, 0, 2, 53, 361]
+[:key_down_raw, 1073741903, 0, 2, 54, 376]
+[:key_down_raw, 1073741903, 0, 2, 55, 378]
+[:key_down_raw, 1073741903, 0, 2, 56, 380]
+[:key_down_raw, 1073741903, 0, 2, 57, 382]
+[:key_down_raw, 1073741903, 0, 2, 58, 384]
+[:key_down_raw, 1073741903, 0, 2, 59, 386]
+[:key_down_raw, 1073741903, 0, 2, 60, 388]
+[:key_down_raw, 1073741903, 0, 2, 61, 390]
+[:key_down_raw, 1073741903, 0, 2, 62, 392]
+[:key_down_raw, 1073741903, 0, 2, 63, 394]
+[:key_down_raw, 1073741903, 0, 2, 64, 396]
+[:key_down_raw, 1073741903, 0, 2, 65, 398]
+[:key_down_raw, 1073741903, 0, 2, 66, 400]
+[:key_down_raw, 1073741903, 0, 2, 67, 402]
+[:key_up_raw, 1073741903, 0, 2, 68, 403]
+[:key_down_raw, 32, 0, 2, 69, 408]
+[:key_up_raw, 32, 0, 2, 70, 415]
+[:key_down_raw, 32, 0, 2, 71, 435]
+[:key_up_raw, 32, 0, 2, 72, 450]
+[:key_down_raw, 32, 0, 2, 73, 461]
+[:key_up_raw, 32, 0, 2, 74, 473]
+[:key_down_raw, 1073741903, 0, 2, 75, 480]
+[:key_up_raw, 1073741903, 0, 2, 76, 491]
+[:key_down_raw, 32, 0, 2, 77, 495]
+[:key_down_raw, 32, 0, 2, 78, 509]
+[:key_down_raw, 32, 0, 2, 79, 511]
+[:key_down_raw, 32, 0, 2, 80, 515]
+[:key_down_raw, 32, 0, 2, 81, 515]
+[:key_down_raw, 32, 0, 2, 82, 517]
+[:key_up_raw, 32, 0, 2, 83, 519]
+[:key_down_raw, 1073741903, 0, 2, 84, 525]
+[:key_down_raw, 32, 0, 2, 85, 537]
+[:key_up_raw, 1073741903, 0, 2, 86, 539]
+[:key_up_raw, 32, 0, 2, 87, 549]
+[:key_down_raw, 1073741904, 0, 2, 88, 567]
+[:key_down_raw, 1073741904, 0, 2, 89, 582]
+[:key_down_raw, 1073741904, 0, 2, 90, 584]
+[:key_down_raw, 1073741904, 0, 2, 91, 586]
+[:key_down_raw, 1073741904, 0, 2, 92, 588]
+[:key_down_raw, 1073741904, 0, 2, 93, 591]
+[:key_down_raw, 1073741904, 0, 2, 94, 593]
+[:key_down_raw, 1073741904, 0, 2, 95, 594]
+[:key_up_raw, 1073741904, 0, 2, 96, 595]
+[:key_down_raw, 1073741904, 0, 2, 97, 623]
+[:key_down_raw, 1073741904, 0, 2, 98, 640]
+[:key_down_raw, 1073741904, 0, 2, 99, 640]
+[:key_down_raw, 1073741904, 0, 2, 100, 642]
+[:key_down_raw, 1073741904, 0, 2, 101, 645]
+[:key_down_raw, 1073741904, 0, 2, 102, 647]
+[:key_down_raw, 1073741904, 0, 2, 103, 649]
+[:key_down_raw, 1073741904, 0, 2, 104, 651]
+[:key_up_raw, 1073741904, 0, 2, 105, 652]
+[:key_down_raw, 1073741903, 0, 2, 106, 683]
+[:key_down_raw, 1073741903, 0, 2, 107, 698]
+[:key_down_raw, 1073741903, 0, 2, 108, 700]
+[:key_down_raw, 1073741903, 0, 2, 109, 702]
+[:key_down_raw, 1073741903, 0, 2, 110, 704]
+[:key_down_raw, 1073741903, 0, 2, 111, 706]
+[:key_down_raw, 1073741903, 0, 2, 112, 708]
+[:key_down_raw, 1073741903, 0, 2, 113, 710]
+[:key_down_raw, 1073741903, 0, 2, 114, 712]
+[:key_down_raw, 1073741903, 0, 2, 115, 714]
+[:key_down_raw, 1073741903, 0, 2, 116, 716]
+[:key_down_raw, 1073741903, 0, 2, 117, 718]
+[:key_down_raw, 1073741903, 0, 2, 118, 720]
+[:key_down_raw, 1073741903, 0, 2, 119, 722]
+[:key_down_raw, 1073741903, 0, 2, 120, 724]
+[:key_down_raw, 1073741903, 0, 2, 121, 726]
+[:key_down_raw, 1073741903, 0, 2, 122, 728]
+[:key_down_raw, 1073741903, 0, 2, 123, 730]
+[:key_down_raw, 1073741903, 0, 2, 124, 732]
+[:key_down_raw, 1073741903, 0, 2, 125, 734]
+[:key_down_raw, 1073741903, 0, 2, 126, 736]
+[:key_down_raw, 1073741903, 0, 2, 127, 738]
+[:key_down_raw, 1073741903, 0, 2, 128, 740]
+[:key_down_raw, 1073741903, 0, 2, 129, 742]
+[:key_down_raw, 1073741903, 0, 2, 130, 744]
+[:key_down_raw, 1073741903, 0, 2, 131, 746]
+[:key_down_raw, 1073741903, 0, 2, 132, 748]
+[:key_down_raw, 32, 0, 2, 133, 748]
+[:key_down_raw, 32, 0, 2, 134, 763]
+[:key_down_raw, 32, 0, 2, 135, 765]
+[:key_down_raw, 32, 0, 2, 136, 767]
+[:key_down_raw, 32, 0, 2, 137, 769]
+[:key_down_raw, 32, 0, 2, 138, 771]
+[:key_up_raw, 32, 0, 2, 139, 773]
+[:key_down_raw, 1073741904, 0, 2, 140, 775]
+[:key_up_raw, 1073741903, 0, 2, 141, 776]
+[:key_down_raw, 1073741904, 0, 2, 142, 790]
+[:key_down_raw, 1073741904, 0, 2, 143, 792]
+[:key_down_raw, 1073741904, 0, 2, 144, 794]
+[:key_down_raw, 1073741904, 0, 2, 145, 796]
+[:key_down_raw, 1073741904, 0, 2, 146, 798]
+[:key_down_raw, 1073741904, 0, 2, 147, 801]
+[:key_down_raw, 1073741904, 0, 2, 148, 803]
+[:key_down_raw, 1073741904, 0, 2, 149, 804]
+[:key_down_raw, 1073741904, 0, 2, 150, 807]
+[:key_down_raw, 1073741904, 0, 2, 151, 809]
+[:key_up_raw, 1073741904, 0, 2, 152, 810]
+[:key_down_raw, 96, 0, 2, 153, 854]
+[:key_up_raw, 96, 0, 2, 154, 858]
+[:key_down_raw, 13, 0, 2, 155, 913]
diff --git a/samples/99_genre_mario/02_jumping_and_collisions/sprites/square/red.png b/samples/99_genre_mario/02_jumping_and_collisions/sprites/square/red.png
new file mode 100644
index 0000000..a59443e
--- /dev/null
+++ b/samples/99_genre_mario/02_jumping_and_collisions/sprites/square/red.png
Binary files differ
diff --git a/samples/99_genre_mario/02_jumping_and_collisions/sprites/square/white.png b/samples/99_genre_mario/02_jumping_and_collisions/sprites/square/white.png
new file mode 100644
index 0000000..7a233ea
--- /dev/null
+++ b/samples/99_genre_mario/02_jumping_and_collisions/sprites/square/white.png
Binary files differ
diff --git a/samples/99_genre_platformer/clepto_frog/app/main.rb b/samples/99_genre_platformer/clepto_frog/app/main.rb
index a4eb069..a3a237e 100644
--- a/samples/99_genre_platformer/clepto_frog/app/main.rb
+++ b/samples/99_genre_platformer/clepto_frog/app/main.rb
@@ -1,4 +1,4 @@
-MAP_FILE_PATH = 'app/map.txt'
+MAP_FILE_PATH = 'map.txt'
require 'app/map.rb'
@@ -53,35 +53,7 @@ class CleptoFrog
def render_intro
outputs.labels << [640, 700, "Clepto Frog", 4, 1]
- if state.tick_count >= 120
- outputs.labels << [640, 620, "\"Uh... your office has a pet frog?\" - New Guy",
- 4, 1, 0, 0, 0, 255 * 120.ease(60)]
- end
-
- if state.tick_count >= 240
- outputs.labels << [640, 580, "\"Yep! His name is Clepto.\" - Jim",
- 4, 1, 0, 0, 0, 255 * 240.ease(60)]
- end
-
- if state.tick_count >= 360
- outputs.labels << [640, 540, "\"Uh...\" - New Guy",
- 4, 1, 0, 0, 0, 255 * 360.ease(60)]
- end
-
- if state.tick_count >= 480
- outputs.labels << [640, 500, "\"He steals mugs while we're away...\" - Jim",
- 4, 1, 0, 0, 0, 255 * 480.ease(60)]
- end
-
- if state.tick_count >= 600
- outputs.labels << [640, 460, "\"It's not a big deal, we take them back in the morning.\" - Jim",
- 4, 1, 0, 0, 0, 255 * 600.ease(60)]
- end
-
- outputs.sprites << [640 - 50, 360 - 50, 100, 100,
- "sprites/square-green.png"]
-
- if state.tick_count == 800
+ if state.tick_count == 120
state.scene = :game
state.game_start_at = state.tick_count
end
@@ -89,7 +61,7 @@ class CleptoFrog
def tick
defaults
- if state.scene == :intro && state.tick_count <= 800
+ if state.scene == :intro && state.tick_count <= 120
render_intro
elsif state.scene == :ending
render_ending
@@ -192,15 +164,15 @@ class CleptoFrog
if state.god_mode
# SHOW HIDE COLLISIONS
- outputs.sprites << state.world.map do |x, y, w, h|
- x = vx(x)
- y = vy(y)
+ outputs.sprites << state.world.map do |rect|
+ x = vx(rect.x)
+ y = vy(rect.y)
if x > -80 && x < 1280 && y > -80 && y < 720
{
x: x,
y: y,
- w: vw(w || state.tile_size),
- h: vh(h || state.tile_size),
+ w: vw(rect.w || state.tile_size),
+ h: vh(rect.h || state.tile_size),
path: 'sprites/square-gray.png',
a: 128
}
@@ -223,8 +195,10 @@ class CleptoFrog
# Creates sprite following mouse to help indicate which sprite you have selected
- outputs.primitives << [inputs.mouse.position.x, inputs.mouse.position.y,
- state.tile_size, state.tile_size, 'sprites/square-indigo.png', 0, 100].sprite
+ outputs.primitives << [inputs.mouse.position.x - 32 * state.camera_scale,
+ inputs.mouse.position.y - 32 * state.camera_scale,
+ state.tile_size * state.camera_scale,
+ state.tile_size * state.camera_scale, 'sprites/square-indigo.png', 0, 100].sprite
end
render_mini_map
@@ -305,6 +279,29 @@ class CleptoFrog
set_camera_scale 1
end
+ if inputs.mouse.click
+ state.id_seed += 1
+ id = state.id_seed
+ x = state.camera_x + (inputs.mouse.click.x.fdiv(state.camera_scale) - 32)
+ y = state.camera_y + (inputs.mouse.click.y.fdiv(state.camera_scale) - 32)
+ x = ((x + 2).idiv 4) * 4
+ y = ((y + 2).idiv 4) * 4
+ w = 64
+ h = 64
+ candidate_rect = { id: id, x: x, y: y, w: w, h: h }
+ scaled_candidate_rect = { x: x + 30, y: y + 30, w: w - 60, h: h - 60 }
+ to_remove = state.world.find { |r| r.intersect_rect? scaled_candidate_rect }
+ if to_remove && args.inputs.keyboard.x
+ state.world.reject! { |r| r.id == to_remove.id }
+ else
+ state.world << candidate_rect
+ end
+ export_map
+ state.world_lookup = {}
+ state.world_collision_rects = nil
+ calc_world_lookup
+ end
+
if input_up?
state.y += 10
state.dy = 0
@@ -326,12 +323,6 @@ class CleptoFrog
if state.scene == :game
process_inputs_player_movement
process_inputs_god_mode
- elsif state.scene == :intro
- if args.inputs.keyboard.key_down.enter || args.inputs.keyboard.key_down.space
- if Kernel.tick_count < 600
- Kernel.tick_count = 600
- end
- end
end
end
@@ -429,17 +420,6 @@ class CleptoFrog
end
end
- def add_floors
- # floors
- state.world += [
- [0, 0, 10000, 40],
- [0, 1670, 3250, 60],
- [6691, 1653, 3290, 60],
- [1521, 3792, 7370, 60],
- [0, 5137, 3290, 60]
- ]
- end
-
def attempt_load_world_from_file
return if state.world
# exported_world = gtk.read_file(MAP_FILE_PATH)
@@ -447,26 +427,11 @@ class CleptoFrog
state.objects = []
if $collisions
- $collisions.map do |x, y, w, h|
- state.world << [x, y, w, h]
+ state.id_seed ||= 0
+ $collisions.each do |x, y, w, h|
+ state.id_seed += 1
+ state.world << { id: state.id_seed, x: x, y: y, w: w, h: h }
end
-
- add_floors
- # elsif exported_world
- # exported_world.each_line.map do |l|
- # tokens = l.strip.split(',')
- # x = tokens[0].to_i
- # y = tokens[1].to_i
- # type = tokens[2].to_i
- # if type == 1
- # state.world << [x, y, state.tile_size, state.tile_size]
- # elsif type == 2
- # w, h, path = tokens[3..-1]
- # state.objects << [x, y, w.to_i, h.to_i, path]
- # end
- # end
-
- # add_floors
end
if $mugs
@@ -487,23 +452,24 @@ class CleptoFrog
# Searches through the world and finds the cordinates that exist
state.world_lookup = {}
- state.world.each do |x, y, w, h|
- state.world_lookup[[x, y, w || state.tile_size, h || state.tile_size]] = true
+ state.world.each do |rect|
+ state.world_lookup[rect.id] = rect
end
# Assigns collision rects for every sprite drawn
state.world_collision_rects =
state.world_lookup
.keys
- .map do |x, y, w, h|
+ .map do |key|
+ rect = state.world_lookup[key]
s = state.tile_size
- w ||= s
- h ||= s
+ rect.w ||= s
+ rect.h ||= s
{
- args: [x, y, w, h],
- left_right: [x, y + 4, w, h - 6],
- top: [x + 4, y + 6, w - 8, h - 6],
- bottom: [x + 1, y - 1, w - 2, h - 8],
+ args: rect,
+ left_right: { x: rect.x, y: rect.y + 4, w: rect.w, h: rect.h - 6 },
+ top: { x: rect.x + 4, y: rect.y + 6, w: rect.w - 8, h: rect.h - 6 },
+ bottom: { x: rect.x + 1, y: rect.y - 1, w: rect.w - 2, h: rect.h - 8 },
}
end
@@ -559,12 +525,21 @@ class CleptoFrog
def end_of_tongue
p = state.tongue_angle.vector(state.tongue_length)
- [start_of_tongue.x + p.x, start_of_tongue.y + p.y]
+ { x: start_of_tongue.x + p.x, y: start_of_tongue.y + p.y }
end
def calc_shooting
+ calc_shooting_increment
+ calc_shooting_increment
+ calc_shooting_increment
+ calc_shooting_increment
+ calc_shooting_increment
+ calc_shooting_increment
+ end
+
+ def calc_shooting_increment
return unless state.action == :shooting
- state.tongue_length += 30
+ state.tongue_length += 5
potential_anchor = end_of_tongue
if potential_anchor.x <= 0
state.anchor_point = potential_anchor
@@ -583,9 +558,9 @@ class CleptoFrog
state.action = :anchored
outputs.sounds << 'sounds/attached.wav'
else
- anchor_rect = [potential_anchor.x - 5, potential_anchor.y - 5, 10, 10]
+ anchor_rect = { x: potential_anchor.x - 5, y: potential_anchor.y - 5, w: 10, h: 10 }
collision = state.world_collision_rects.find_all do |v|
- [v[:args].x, v[:args].y, v[:args].w, v[:args].h].intersect_rect?(anchor_rect)
+ v[:args].intersect_rect?(anchor_rect)
end.first
if collision
state.anchor_point = potential_anchor
@@ -681,7 +656,7 @@ class CleptoFrog
.first
return unless left_side_collisions
- state.x = left_side_collisions[:left_right].right
+ state.x = left_side_collisions[:left_right].right + 1
state.dx = state.dy.abs * 0.8
state.collision_on_x = true
end
@@ -696,7 +671,7 @@ class CleptoFrog
.first
return unless right_side_collisions
- state.x = right_side_collisions[:left_right].left - state.tile_size
+ state.x = right_side_collisions[:left_right].left - state.tile_size - 1
state.dx = state.dx.abs * 0.8 * -1
state.collision_on_x = true
end
@@ -712,7 +687,7 @@ class CleptoFrog
.first
return unless ceil_collisions
- state.y = ceil_collisions[:bottom].y - state.tile_size
+ state.y = ceil_collisions[:bottom].y - state.tile_size - 1
state.dy = state.dy.abs * 0.8 * -1
state.collision_on_y = true
end
@@ -725,13 +700,17 @@ class CleptoFrog
end
def export_map
- export_string = state.world.map do |x, y|
- "#{x},#{y},1"
- end
+ export_string = "$collisions = [\n"
+ export_string += state.world.map do |rect|
+ "[#{rect.x},#{rect.y},#{rect.w},#{rect.h}],"
+ end.join "\n"
+ export_string += "\n]\n\n"
+ export_string += "$mugs = [\n"
export_string += state.objects.map do |x, y, w, h, path|
- "#{x},#{y},2,#{w},#{h},#{path}"
- end
- gtk.write_file(MAP_FILE_PATH, export_string.join("\n"))
+ "[#{x},#{y},#{w},#{h},'#{path}'],"
+ end.join "\n"
+ export_string += "\n]\n\n"
+ gtk.write_file(MAP_FILE_PATH, export_string)
state.map_saved_at = state.tick_count
end
diff --git a/samples/99_genre_platformer/clepto_frog/app/map.rb b/samples/99_genre_platformer/clepto_frog/app/map.rb
index c048c82..a504ff9 100644
--- a/samples/99_genre_platformer/clepto_frog/app/map.rb
+++ b/samples/99_genre_platformer/clepto_frog/app/map.rb
@@ -989,6 +989,11 @@ $collisions = [
[4459, 3997, 64, 64],
[76, 5215, 64, 64],
[39, 5217, 64, 64],
+ [0, 0, 10000, 40],
+ [0, 1670, 3250, 60],
+ [6691, 1653, 3290, 60],
+ [1521, 3792, 7370, 60],
+ [0, 5137, 3290, 60]
]
$mugs = [
diff --git a/samples/99_genre_platformer/clepto_frog/replay.txt b/samples/99_genre_platformer/clepto_frog/replay.txt
new file mode 100644
index 0000000..8662d31
--- /dev/null
+++ b/samples/99_genre_platformer/clepto_frog/replay.txt
@@ -0,0 +1,249 @@
+replay_version 2.0
+stopped_at 1097
+seed 100
+recorded_at 2021-11-20 11:32:38 -0600
+[:mouse_button_up, 1, 0, 1, 1, 4]
+[:key_down_raw, 1073741903, 0, 2, 2, 157]
+[:key_down_raw, 1073741903, 0, 2, 3, 171]
+[:key_down_raw, 1073741903, 0, 2, 4, 174]
+[:key_down_raw, 1073741903, 0, 2, 5, 176]
+[:key_down_raw, 1073741903, 0, 2, 6, 177]
+[:key_down_raw, 1073741903, 0, 2, 7, 179]
+[:key_down_raw, 1073741903, 0, 2, 8, 181]
+[:key_down_raw, 1073741903, 0, 2, 9, 182]
+[:key_down_raw, 1073741903, 0, 2, 10, 185]
+[:key_up_raw, 1073741903, 0, 2, 11, 185]
+[:key_down_raw, 32, 0, 2, 12, 187]
+[:key_up_raw, 32, 0, 2, 13, 190]
+[:key_down_raw, 1073741906, 0, 2, 14, 231]
+[:key_down_raw, 1073741903, 0, 2, 15, 239]
+[:key_down_raw, 1073741903, 0, 2, 16, 252]
+[:key_down_raw, 1073741903, 0, 2, 17, 254]
+[:key_down_raw, 1073741903, 0, 2, 18, 256]
+[:key_down_raw, 1073741903, 0, 2, 19, 258]
+[:key_down_raw, 1073741903, 0, 2, 20, 259]
+[:key_down_raw, 1073741903, 0, 2, 21, 261]
+[:key_down_raw, 1073741903, 0, 2, 22, 263]
+[:key_down_raw, 1073741903, 0, 2, 23, 265]
+[:key_down_raw, 1073741903, 0, 2, 24, 267]
+[:key_down_raw, 1073741903, 0, 2, 25, 269]
+[:key_down_raw, 1073741903, 0, 2, 26, 271]
+[:key_down_raw, 1073741903, 0, 2, 27, 273]
+[:key_down_raw, 1073741903, 0, 2, 28, 274]
+[:key_down_raw, 1073741903, 0, 2, 29, 276]
+[:key_down_raw, 1073741903, 0, 2, 30, 278]
+[:key_down_raw, 1073741903, 0, 2, 31, 280]
+[:key_down_raw, 1073741903, 0, 2, 32, 282]
+[:key_down_raw, 1073741903, 0, 2, 33, 284]
+[:key_down_raw, 1073741903, 0, 2, 34, 286]
+[:key_down_raw, 1073741903, 0, 2, 35, 287]
+[:key_down_raw, 1073741903, 0, 2, 36, 289]
+[:key_down_raw, 1073741903, 0, 2, 37, 291]
+[:key_down_raw, 1073741903, 0, 2, 38, 293]
+[:key_down_raw, 1073741903, 0, 2, 39, 295]
+[:key_down_raw, 1073741903, 0, 2, 40, 296]
+[:key_down_raw, 1073741903, 0, 2, 41, 298]
+[:key_down_raw, 1073741903, 0, 2, 42, 300]
+[:key_down_raw, 1073741903, 0, 2, 43, 302]
+[:key_down_raw, 1073741903, 0, 2, 44, 303]
+[:key_down_raw, 1073741903, 0, 2, 45, 305]
+[:key_down_raw, 1073741903, 0, 2, 46, 307]
+[:key_down_raw, 1073741903, 0, 2, 47, 309]
+[:key_down_raw, 1073741903, 0, 2, 48, 310]
+[:key_down_raw, 1073741903, 0, 2, 49, 312]
+[:key_down_raw, 1073741903, 0, 2, 50, 314]
+[:key_down_raw, 1073741903, 0, 2, 51, 316]
+[:key_down_raw, 1073741903, 0, 2, 52, 318]
+[:key_down_raw, 1073741903, 0, 2, 53, 320]
+[:key_down_raw, 1073741903, 0, 2, 54, 322]
+[:key_down_raw, 1073741903, 0, 2, 55, 324]
+[:key_down_raw, 1073741903, 0, 2, 56, 326]
+[:key_down_raw, 1073741903, 0, 2, 57, 328]
+[:key_down_raw, 1073741903, 0, 2, 58, 330]
+[:key_down_raw, 1073741903, 0, 2, 59, 332]
+[:key_down_raw, 1073741903, 0, 2, 60, 334]
+[:key_down_raw, 1073741903, 0, 2, 61, 336]
+[:key_down_raw, 1073741903, 0, 2, 62, 338]
+[:key_down_raw, 1073741903, 0, 2, 63, 340]
+[:key_down_raw, 1073741903, 0, 2, 64, 342]
+[:key_down_raw, 1073741903, 0, 2, 65, 344]
+[:key_down_raw, 1073741903, 0, 2, 66, 345]
+[:key_down_raw, 1073741903, 0, 2, 67, 347]
+[:key_down_raw, 1073741903, 0, 2, 68, 349]
+[:key_up_raw, 1073741906, 0, 2, 69, 351]
+[:key_down_raw, 1073741903, 0, 2, 70, 351]
+[:key_down_raw, 1073741903, 0, 2, 71, 353]
+[:key_down_raw, 1073741903, 0, 2, 72, 355]
+[:key_down_raw, 1073741903, 0, 2, 73, 357]
+[:key_down_raw, 1073741903, 0, 2, 74, 359]
+[:key_down_raw, 1073741903, 0, 2, 75, 361]
+[:key_down_raw, 1073741903, 0, 2, 76, 363]
+[:key_down_raw, 1073741903, 0, 2, 77, 365]
+[:key_down_raw, 1073741903, 0, 2, 78, 367]
+[:key_down_raw, 1073741903, 0, 2, 79, 369]
+[:key_down_raw, 1073741903, 0, 2, 80, 371]
+[:key_down_raw, 1073741903, 0, 2, 81, 373]
+[:key_down_raw, 1073741903, 0, 2, 82, 375]
+[:key_down_raw, 1073741903, 0, 2, 83, 376]
+[:key_down_raw, 1073741903, 0, 2, 84, 378]
+[:key_down_raw, 1073741903, 0, 2, 85, 380]
+[:key_down_raw, 1073741903, 0, 2, 86, 382]
+[:key_down_raw, 1073741903, 0, 2, 87, 384]
+[:key_down_raw, 1073741903, 0, 2, 88, 386]
+[:key_down_raw, 1073741906, 0, 2, 89, 386]
+[:key_down_raw, 1073741906, 0, 2, 90, 400]
+[:key_down_raw, 1073741906, 0, 2, 91, 402]
+[:key_down_raw, 1073741906, 0, 2, 92, 404]
+[:key_down_raw, 1073741906, 0, 2, 93, 405]
+[:key_down_raw, 1073741906, 0, 2, 94, 407]
+[:key_down_raw, 1073741906, 0, 2, 95, 409]
+[:key_down_raw, 1073741906, 0, 2, 96, 411]
+[:key_down_raw, 1073741906, 0, 2, 97, 413]
+[:key_down_raw, 1073741906, 0, 2, 98, 415]
+[:key_down_raw, 1073741906, 0, 2, 99, 417]
+[:key_down_raw, 1073741906, 0, 2, 100, 419]
+[:key_down_raw, 1073741906, 0, 2, 101, 421]
+[:key_down_raw, 1073741906, 0, 2, 102, 422]
+[:key_down_raw, 1073741906, 0, 2, 103, 424]
+[:key_down_raw, 1073741906, 0, 2, 104, 426]
+[:key_down_raw, 1073741906, 0, 2, 105, 428]
+[:key_down_raw, 1073741906, 0, 2, 106, 430]
+[:key_down_raw, 1073741906, 0, 2, 107, 432]
+[:key_down_raw, 1073741906, 0, 2, 108, 434]
+[:key_down_raw, 32, 0, 2, 109, 434]
+[:key_up_raw, 32, 0, 2, 110, 442]
+[:key_up_raw, 1073741906, 0, 2, 111, 460]
+[:key_up_raw, 1073741903, 0, 2, 112, 576]
+[:key_down_raw, 1073741903, 0, 2, 113, 588]
+[:key_down_raw, 1073741903, 0, 2, 114, 602]
+[:key_down_raw, 1073741903, 0, 2, 115, 604]
+[:key_down_raw, 1073741903, 0, 2, 116, 606]
+[:key_down_raw, 1073741903, 0, 2, 117, 608]
+[:key_down_raw, 1073741903, 0, 2, 118, 610]
+[:key_down_raw, 1073741903, 0, 2, 119, 612]
+[:key_down_raw, 1073741903, 0, 2, 120, 614]
+[:key_down_raw, 1073741903, 0, 2, 121, 616]
+[:key_down_raw, 1073741903, 0, 2, 122, 617]
+[:key_down_raw, 1073741903, 0, 2, 123, 619]
+[:key_down_raw, 1073741903, 0, 2, 124, 621]
+[:key_down_raw, 1073741903, 0, 2, 125, 623]
+[:key_down_raw, 1073741903, 0, 2, 126, 624]
+[:key_down_raw, 1073741903, 0, 2, 127, 626]
+[:key_down_raw, 1073741903, 0, 2, 128, 628]
+[:key_down_raw, 1073741903, 0, 2, 129, 630]
+[:key_down_raw, 1073741903, 0, 2, 130, 632]
+[:key_down_raw, 1073741903, 0, 2, 131, 634]
+[:key_down_raw, 1073741903, 0, 2, 132, 636]
+[:key_down_raw, 1073741903, 0, 2, 133, 638]
+[:key_down_raw, 1073741903, 0, 2, 134, 640]
+[:key_down_raw, 1073741903, 0, 2, 135, 641]
+[:key_down_raw, 1073741903, 0, 2, 136, 643]
+[:key_down_raw, 1073741903, 0, 2, 137, 645]
+[:key_down_raw, 1073741903, 0, 2, 138, 647]
+[:key_down_raw, 1073741903, 0, 2, 139, 649]
+[:key_down_raw, 1073741903, 0, 2, 140, 651]
+[:key_down_raw, 1073741903, 0, 2, 141, 653]
+[:key_down_raw, 1073741903, 0, 2, 142, 655]
+[:key_down_raw, 1073741903, 0, 2, 143, 656]
+[:key_down_raw, 1073741903, 0, 2, 144, 658]
+[:key_down_raw, 1073741903, 0, 2, 145, 660]
+[:key_down_raw, 1073741903, 0, 2, 146, 662]
+[:key_down_raw, 1073741903, 0, 2, 147, 664]
+[:key_down_raw, 1073741903, 0, 2, 148, 666]
+[:key_down_raw, 1073741903, 0, 2, 149, 668]
+[:key_down_raw, 1073741903, 0, 2, 150, 670]
+[:key_down_raw, 1073741903, 0, 2, 151, 672]
+[:key_down_raw, 1073741903, 0, 2, 152, 674]
+[:key_down_raw, 1073741903, 0, 2, 153, 676]
+[:key_down_raw, 1073741903, 0, 2, 154, 678]
+[:key_down_raw, 1073741903, 0, 2, 155, 680]
+[:key_down_raw, 1073741903, 0, 2, 156, 681]
+[:key_down_raw, 1073741903, 0, 2, 157, 683]
+[:key_down_raw, 32, 0, 2, 158, 684]
+[:key_up_raw, 1073741903, 0, 2, 159, 686]
+[:key_up_raw, 32, 0, 2, 160, 689]
+[:key_down_raw, 1073741904, 0, 2, 161, 692]
+[:key_down_raw, 1073741904, 0, 2, 162, 704]
+[:key_down_raw, 1073741904, 0, 2, 163, 706]
+[:key_down_raw, 1073741904, 0, 2, 164, 707]
+[:key_down_raw, 1073741904, 0, 2, 165, 709]
+[:key_down_raw, 1073741904, 0, 2, 166, 711]
+[:key_down_raw, 1073741904, 0, 2, 167, 713]
+[:key_down_raw, 1073741904, 0, 2, 168, 715]
+[:key_up_raw, 1073741904, 0, 2, 169, 717]
+[:key_down_raw, 32, 0, 2, 170, 769]
+[:key_up_raw, 32, 0, 2, 171, 775]
+[:key_down_raw, 1073741904, 0, 2, 172, 785]
+[:key_down_raw, 1073741904, 0, 2, 173, 799]
+[:key_down_raw, 1073741904, 0, 2, 174, 801]
+[:key_down_raw, 1073741904, 0, 2, 175, 803]
+[:key_down_raw, 1073741904, 0, 2, 176, 805]
+[:key_down_raw, 1073741904, 0, 2, 177, 807]
+[:key_down_raw, 1073741904, 0, 2, 178, 810]
+[:key_down_raw, 1073741904, 0, 2, 179, 812]
+[:key_down_raw, 1073741904, 0, 2, 180, 814]
+[:key_down_raw, 1073741904, 0, 2, 181, 816]
+[:key_down_raw, 1073741904, 0, 2, 182, 818]
+[:key_down_raw, 1073741904, 0, 2, 183, 820]
+[:key_down_raw, 1073741904, 0, 2, 184, 822]
+[:key_down_raw, 1073741904, 0, 2, 185, 824]
+[:key_down_raw, 1073741904, 0, 2, 186, 826]
+[:key_down_raw, 1073741904, 0, 2, 187, 828]
+[:key_down_raw, 1073741904, 0, 2, 188, 830]
+[:key_down_raw, 1073741904, 0, 2, 189, 832]
+[:key_down_raw, 1073741904, 0, 2, 190, 834]
+[:key_down_raw, 1073741904, 0, 2, 191, 836]
+[:key_down_raw, 1073741904, 0, 2, 192, 838]
+[:key_down_raw, 1073741904, 0, 2, 193, 840]
+[:key_down_raw, 1073741904, 0, 2, 194, 841]
+[:key_down_raw, 1073741904, 0, 2, 195, 843]
+[:key_down_raw, 1073741904, 0, 2, 196, 845]
+[:key_down_raw, 1073741904, 0, 2, 197, 847]
+[:key_down_raw, 1073741904, 0, 2, 198, 849]
+[:key_down_raw, 1073741904, 0, 2, 199, 851]
+[:key_down_raw, 1073741904, 0, 2, 200, 853]
+[:key_down_raw, 1073741904, 0, 2, 201, 855]
+[:key_down_raw, 1073741904, 0, 2, 202, 857]
+[:key_down_raw, 1073741904, 0, 2, 203, 859]
+[:key_down_raw, 1073741904, 0, 2, 204, 861]
+[:key_down_raw, 1073741904, 0, 2, 205, 863]
+[:key_down_raw, 1073741904, 0, 2, 206, 864]
+[:key_down_raw, 1073741904, 0, 2, 207, 866]
+[:key_down_raw, 1073741904, 0, 2, 208, 868]
+[:key_down_raw, 1073741904, 0, 2, 209, 870]
+[:key_down_raw, 1073741904, 0, 2, 210, 872]
+[:key_down_raw, 1073741904, 0, 2, 211, 874]
+[:key_down_raw, 1073741904, 0, 2, 212, 876]
+[:key_down_raw, 1073741904, 0, 2, 213, 878]
+[:key_down_raw, 1073741904, 0, 2, 214, 880]
+[:key_down_raw, 1073741904, 0, 2, 215, 882]
+[:key_down_raw, 1073741904, 0, 2, 216, 884]
+[:key_down_raw, 1073741904, 0, 2, 217, 886]
+[:key_down_raw, 1073741904, 0, 2, 218, 887]
+[:key_down_raw, 1073741904, 0, 2, 219, 889]
+[:key_down_raw, 1073741904, 0, 2, 220, 891]
+[:key_down_raw, 1073741904, 0, 2, 221, 893]
+[:key_down_raw, 1073741904, 0, 2, 222, 895]
+[:key_down_raw, 1073741904, 0, 2, 223, 897]
+[:key_down_raw, 1073741904, 0, 2, 224, 899]
+[:key_down_raw, 1073741904, 0, 2, 225, 901]
+[:key_down_raw, 1073741904, 0, 2, 226, 903]
+[:key_down_raw, 1073741904, 0, 2, 227, 905]
+[:key_down_raw, 1073741904, 0, 2, 228, 907]
+[:key_down_raw, 1073741904, 0, 2, 229, 909]
+[:key_down_raw, 1073741904, 0, 2, 230, 911]
+[:key_down_raw, 1073741904, 0, 2, 231, 913]
+[:key_down_raw, 1073741904, 0, 2, 232, 915]
+[:key_down_raw, 1073741904, 0, 2, 233, 917]
+[:key_down_raw, 1073741904, 0, 2, 234, 919]
+[:key_down_raw, 1073741904, 0, 2, 235, 921]
+[:key_down_raw, 1073741904, 0, 2, 236, 923]
+[:key_down_raw, 1073741904, 0, 2, 237, 925]
+[:key_down_raw, 1073741904, 0, 2, 238, 927]
+[:key_down_raw, 1073741904, 0, 2, 239, 929]
+[:key_up_raw, 1073741904, 0, 2, 240, 930]
+[:key_down_raw, 1073741904, 0, 2, 241, 1024]
+[:key_up_raw, 1073741904, 0, 2, 242, 1036]
+[:key_down_raw, 96, 0, 2, 243, 1046]
+[:key_up_raw, 96, 0, 2, 244, 1050]
+[:key_down_raw, 13, 0, 2, 245, 1097]
diff --git a/samples/99_genre_platformer/the_little_probe/app/main.rb b/samples/99_genre_platformer/the_little_probe/app/main.rb
index 8fcf279..9d43ce6 100644
--- a/samples/99_genre_platformer/the_little_probe/app/main.rb
+++ b/samples/99_genre_platformer/the_little_probe/app/main.rb
@@ -394,6 +394,7 @@ class FallingCircle
end
def load_lines file
+ return unless state.snaps
data = gtk.read_file(file) || ""
data.each_line
.reject { |l| l.strip.length == 0 }
@@ -452,10 +453,10 @@ class FallingCircle
results[:point] = { x: x, y: y }
results[:rect] = { x: x - radius, y: y - radius, w: radius * 2, h: radius * 2 }
results[:trajectory] = trajectory(results)
- results[:impacts] = terrain.find_all { |t| line_near_rect? results[:rect], t }.map do |t|
+ results[:impacts] = terrain.find_all { |t| t && (line_near_rect? results[:rect], t) }.map do |t|
{
terrain: t,
- point: geometry.line_intersect(results[:trajectory], t),
+ point: geometry.line_intersect(results[:trajectory], t, replace_infinity: 1000),
type: :terrain
}
end.reject { |t| !point_within_line? t[:point], t[:terrain] }
@@ -463,10 +464,10 @@ class FallingCircle
results[:impacts] += lava.find_all { |t| line_near_rect? results[:rect], t }.map do |t|
{
terrain: t,
- point: geometry.line_intersect(results[:trajectory], t),
+ point: geometry.line_intersect(results[:trajectory], t, replace_infinity: 1000),
type: :lava
}
- end.reject { |t| !point_within_line? t[:point], t[:terrain] }
+ end.reject { |t| !t || (!point_within_line? t[:point], t[:terrain]) }
results
end
@@ -479,6 +480,7 @@ class FallingCircle
end
def calc_terrains_to_monitor
+ return unless circle.impacts
circle.impact = nil
circle.impacts.each do |i|
circle.terrains_to_monitor[i[:terrain]] ||= {
diff --git a/samples/99_genre_platformer/the_little_probe/bug-replay.txt b/samples/99_genre_platformer/the_little_probe/bug-replay.txt
new file mode 100644
index 0000000..378d3c3
--- /dev/null
+++ b/samples/99_genre_platformer/the_little_probe/bug-replay.txt
@@ -0,0 +1,205 @@
+replay_version 2.0
+stopped_at 2085
+seed 100
+recorded_at 2021-11-20 11:34:07 -0600
+[:mouse_button_up, 1, 0, 1, 1, 1]
+[:mouse_move, 803, 93, 2, 2, 31]
+[:mouse_move, 811, 93, 2, 3, 32]
+[:key_down_raw, 1073741903, 0, 2, 4, 123]
+[:key_down_raw, 1073741903, 0, 2, 5, 137]
+[:key_down_raw, 1073741903, 0, 2, 6, 139]
+[:key_down_raw, 1073741903, 0, 2, 7, 141]
+[:key_down_raw, 1073741903, 0, 2, 8, 143]
+[:key_down_raw, 1073741903, 0, 2, 9, 145]
+[:key_down_raw, 1073741903, 0, 2, 10, 147]
+[:key_down_raw, 1073741903, 0, 2, 11, 149]
+[:key_up_raw, 1073741903, 0, 2, 12, 150]
+[:key_down_raw, 32, 0, 2, 13, 171]
+[:key_down_raw, 32, 0, 2, 14, 186]
+[:key_down_raw, 32, 0, 2, 15, 189]
+[:key_down_raw, 32, 0, 2, 16, 190]
+[:key_down_raw, 32, 0, 2, 17, 192]
+[:key_down_raw, 32, 0, 2, 18, 194]
+[:key_down_raw, 32, 0, 2, 19, 196]
+[:key_down_raw, 32, 0, 2, 20, 198]
+[:key_down_raw, 32, 0, 2, 21, 200]
+[:key_down_raw, 32, 0, 2, 22, 202]
+[:key_down_raw, 32, 0, 2, 23, 204]
+[:key_down_raw, 32, 0, 2, 24, 206]
+[:key_down_raw, 32, 0, 2, 25, 208]
+[:key_down_raw, 32, 0, 2, 26, 210]
+[:key_down_raw, 32, 0, 2, 27, 212]
+[:key_down_raw, 32, 0, 2, 28, 214]
+[:key_down_raw, 32, 0, 2, 29, 216]
+[:key_down_raw, 32, 0, 2, 30, 218]
+[:key_down_raw, 32, 0, 2, 31, 221]
+[:key_down_raw, 32, 0, 2, 32, 222]
+[:key_down_raw, 32, 0, 2, 33, 224]
+[:key_down_raw, 32, 0, 2, 34, 227]
+[:key_down_raw, 32, 0, 2, 35, 229]
+[:key_down_raw, 32, 0, 2, 36, 231]
+[:key_down_raw, 32, 0, 2, 37, 233]
+[:key_down_raw, 32, 0, 2, 38, 235]
+[:key_down_raw, 32, 0, 2, 39, 237]
+[:key_down_raw, 32, 0, 2, 40, 239]
+[:key_down_raw, 32, 0, 2, 41, 241]
+[:key_down_raw, 32, 0, 2, 42, 243]
+[:key_down_raw, 32, 0, 2, 43, 245]
+[:key_down_raw, 32, 0, 2, 44, 247]
+[:key_down_raw, 32, 0, 2, 45, 249]
+[:key_down_raw, 32, 0, 2, 46, 251]
+[:key_down_raw, 32, 0, 2, 47, 253]
+[:key_down_raw, 32, 0, 2, 48, 255]
+[:key_down_raw, 32, 0, 2, 49, 257]
+[:key_down_raw, 32, 0, 2, 50, 259]
+[:key_down_raw, 32, 0, 2, 51, 261]
+[:key_down_raw, 32, 0, 2, 52, 263]
+[:key_down_raw, 32, 0, 2, 53, 265]
+[:key_down_raw, 32, 0, 2, 54, 267]
+[:key_down_raw, 32, 0, 2, 55, 269]
+[:key_down_raw, 32, 0, 2, 56, 271]
+[:key_down_raw, 1073741903, 0, 2, 57, 272]
+[:key_up_raw, 1073741903, 0, 2, 58, 284]
+[:key_up_raw, 32, 0, 2, 59, 350]
+[:key_down_raw, 1073741904, 0, 2, 60, 611]
+[:key_down_raw, 1073741904, 0, 2, 61, 626]
+[:key_down_raw, 1073741904, 0, 2, 62, 628]
+[:key_down_raw, 1073741904, 0, 2, 63, 630]
+[:key_down_raw, 1073741904, 0, 2, 64, 632]
+[:key_down_raw, 1073741904, 0, 2, 65, 634]
+[:key_down_raw, 1073741904, 0, 2, 66, 636]
+[:key_up_raw, 1073741904, 0, 2, 67, 636]
+[:key_down_raw, 32, 0, 2, 68, 640]
+[:key_down_raw, 32, 0, 2, 69, 655]
+[:key_down_raw, 32, 0, 2, 70, 657]
+[:key_down_raw, 32, 0, 2, 71, 659]
+[:key_down_raw, 32, 0, 2, 72, 661]
+[:key_down_raw, 32, 0, 2, 73, 663]
+[:key_down_raw, 32, 0, 2, 74, 665]
+[:key_down_raw, 1073741903, 0, 2, 75, 666]
+[:key_up_raw, 1073741903, 0, 2, 76, 672]
+[:key_down_raw, 1073741903, 0, 2, 77, 703]
+[:key_down_raw, 1073741903, 0, 2, 78, 717]
+[:key_up_raw, 1073741903, 0, 2, 79, 717]
+[:key_down_raw, 1073741903, 0, 2, 80, 736]
+[:key_up_raw, 1073741903, 0, 2, 81, 741]
+[:key_up_raw, 32, 0, 2, 82, 798]
+[:key_down_raw, 1073741903, 0, 2, 83, 861]
+[:key_down_raw, 1073741903, 0, 2, 84, 876]
+[:key_down_raw, 1073741903, 0, 2, 85, 878]
+[:key_down_raw, 1073741903, 0, 2, 86, 880]
+[:key_down_raw, 1073741903, 0, 2, 87, 882]
+[:key_down_raw, 1073741903, 0, 2, 88, 884]
+[:key_up_raw, 1073741903, 0, 2, 89, 886]
+[:key_down_raw, 1073741903, 0, 2, 90, 1063]
+[:key_down_raw, 1073741903, 0, 2, 91, 1079]
+[:key_down_raw, 1073741903, 0, 2, 92, 1081]
+[:key_down_raw, 1073741903, 0, 2, 93, 1083]
+[:key_down_raw, 1073741903, 0, 2, 94, 1085]
+[:key_down_raw, 1073741903, 0, 2, 95, 1086]
+[:key_down_raw, 1073741903, 0, 2, 96, 1088]
+[:key_down_raw, 1073741903, 0, 2, 97, 1090]
+[:key_down_raw, 1073741903, 0, 2, 98, 1092]
+[:key_down_raw, 1073741903, 0, 2, 99, 1094]
+[:key_down_raw, 1073741903, 0, 2, 100, 1096]
+[:key_down_raw, 1073741903, 0, 2, 101, 1098]
+[:key_down_raw, 1073741903, 0, 2, 102, 1100]
+[:key_down_raw, 1073741903, 0, 2, 103, 1102]
+[:key_down_raw, 1073741903, 0, 2, 104, 1104]
+[:key_down_raw, 1073741903, 0, 2, 105, 1106]
+[:key_down_raw, 1073741903, 0, 2, 106, 1109]
+[:key_down_raw, 1073741903, 0, 2, 107, 1111]
+[:key_down_raw, 1073741903, 0, 2, 108, 1113]
+[:key_down_raw, 1073741903, 0, 2, 109, 1115]
+[:key_down_raw, 1073741903, 0, 2, 110, 1117]
+[:key_down_raw, 1073741903, 0, 2, 111, 1119]
+[:key_down_raw, 1073741903, 0, 2, 112, 1121]
+[:key_down_raw, 1073741903, 0, 2, 113, 1122]
+[:key_down_raw, 1073741903, 0, 2, 114, 1125]
+[:key_down_raw, 1073741903, 0, 2, 115, 1127]
+[:key_down_raw, 1073741903, 0, 2, 116, 1128]
+[:key_down_raw, 1073741903, 0, 2, 117, 1131]
+[:key_down_raw, 1073741903, 0, 2, 118, 1132]
+[:key_down_raw, 1073741903, 0, 2, 119, 1134]
+[:key_down_raw, 1073741903, 0, 2, 120, 1136]
+[:key_down_raw, 1073741903, 0, 2, 121, 1138]
+[:key_down_raw, 1073741903, 0, 2, 122, 1140]
+[:key_down_raw, 1073741903, 0, 2, 123, 1142]
+[:key_up_raw, 1073741903, 0, 2, 124, 1142]
+[:key_down_raw, 32, 0, 2, 125, 1208]
+[:key_down_raw, 32, 0, 2, 126, 1223]
+[:key_down_raw, 32, 0, 2, 127, 1225]
+[:key_down_raw, 1073741903, 0, 2, 128, 1226]
+[:key_up_raw, 1073741903, 0, 2, 129, 1236]
+[:key_down_raw, 1073741904, 0, 2, 130, 1253]
+[:key_up_raw, 1073741904, 0, 2, 131, 1266]
+[:key_down_raw, 1073741903, 0, 2, 132, 1324]
+[:key_up_raw, 1073741903, 0, 2, 133, 1330]
+[:key_down_raw, 1073741903, 0, 2, 134, 1414]
+[:key_up_raw, 1073741903, 0, 2, 135, 1417]
+[:key_up_raw, 32, 0, 2, 136, 1441]
+[:mouse_move, 812, 92, 2, 137, 1607]
+[:mouse_move, 818, 92, 2, 138, 1608]
+[:mouse_move, 818, 91, 2, 139, 1614]
+[:mouse_move, 818, 90, 2, 140, 1622]
+[:mouse_move, 813, 89, 2, 141, 1623]
+[:mouse_move, 801, 86, 2, 142, 1624]
+[:mouse_move, 786, 83, 2, 143, 1625]
+[:mouse_move, 770, 82, 2, 144, 1626]
+[:mouse_move, 756, 82, 2, 145, 1627]
+[:mouse_move, 745, 82, 2, 146, 1628]
+[:mouse_move, 738, 82, 2, 147, 1629]
+[:mouse_move, 731, 83, 2, 148, 1630]
+[:mouse_move, 724, 84, 2, 149, 1631]
+[:mouse_move, 712, 85, 2, 150, 1632]
+[:mouse_move, 707, 87, 2, 151, 1633]
+[:mouse_move, 702, 89, 2, 152, 1634]
+[:mouse_move, 699, 95, 2, 153, 1635]
+[:mouse_move, 693, 102, 2, 154, 1636]
+[:mouse_move, 687, 110, 2, 155, 1637]
+[:mouse_move, 680, 118, 2, 156, 1638]
+[:mouse_move, 671, 125, 2, 157, 1639]
+[:mouse_move, 659, 132, 2, 158, 1640]
+[:mouse_move, 645, 142, 2, 159, 1641]
+[:mouse_move, 632, 153, 2, 160, 1642]
+[:mouse_move, 616, 164, 2, 161, 1643]
+[:mouse_move, 583, 184, 2, 162, 1644]
+[:mouse_move, 554, 198, 2, 163, 1645]
+[:mouse_move, 519, 212, 2, 164, 1646]
+[:mouse_move, 480, 224, 2, 165, 1647]
+[:mouse_move, 445, 234, 2, 166, 1648]
+[:mouse_move, 414, 246, 2, 167, 1649]
+[:mouse_move, 393, 265, 2, 168, 1650]
+[:mouse_move, 388, 276, 2, 169, 1651]
+[:mouse_move, 386, 272, 2, 170, 1665]
+[:mouse_move, 380, 272, 2, 171, 1666]
+[:mouse_move, 366, 272, 2, 172, 1667]
+[:mouse_move, 336, 266, 2, 173, 1668]
+[:mouse_move, 313, 262, 2, 174, 1669]
+[:mouse_move, 294, 258, 2, 175, 1670]
+[:mouse_move, 278, 255, 2, 176, 1671]
+[:mouse_move, 268, 254, 2, 177, 1672]
+[:mouse_move, 263, 253, 2, 178, 1673]
+[:mouse_move, 261, 252, 2, 179, 1674]
+[:mouse_move, 260, 251, 2, 180, 1675]
+[:mouse_move, 258, 250, 2, 181, 1676]
+[:mouse_move, 256, 249, 2, 182, 1677]
+[:mouse_move, 252, 249, 2, 183, 1678]
+[:mouse_move, 251, 249, 2, 184, 1679]
+[:mouse_move, 248, 249, 2, 185, 1680]
+[:mouse_move, 246, 248, 2, 186, 1681]
+[:mouse_move, 242, 247, 2, 187, 1682]
+[:mouse_move, 234, 247, 2, 188, 1683]
+[:mouse_move, 231, 247, 2, 189, 1684]
+[:mouse_move, 230, 247, 2, 190, 1685]
+[:mouse_move, 230, 246, 2, 191, 1688]
+[:mouse_move, 229, 246, 2, 192, 1691]
+[:mouse_move, 228, 246, 2, 193, 1692]
+[:mouse_move, 227, 246, 2, 194, 1702]
+[:mouse_move, 228, 246, 2, 195, 1834]
+[:mouse_move, 229, 246, 2, 196, 1898]
+[:mouse_move, 229, 245, 2, 197, 1968]
+[:key_down_raw, 96, 0, 2, 198, 2024]
+[:mouse_move, 230, 245, 2, 199, 2027]
+[:key_up_raw, 96, 0, 2, 200, 2028]
+[:key_down_raw, 13, 0, 2, 201, 2085]
diff --git a/samples/99_genre_rpg_roguelike/01_roguelike_starting_point/replay.txt b/samples/99_genre_rpg_roguelike/01_roguelike_starting_point/replay.txt
new file mode 100644
index 0000000..d75d454
--- /dev/null
+++ b/samples/99_genre_rpg_roguelike/01_roguelike_starting_point/replay.txt
@@ -0,0 +1,196 @@
+replay_version 2.0
+stopped_at 697
+seed 100
+recorded_at 2021-11-20 11:36:12 -0600
+[:mouse_button_up, 1, 0, 1, 1, 4]
+[:mouse_move, 793, 90, 2, 2, 24]
+[:mouse_move, 799, 95, 2, 3, 25]
+[:mouse_move, 809, 104, 2, 4, 26]
+[:mouse_move, 818, 111, 2, 5, 27]
+[:mouse_move, 832, 118, 2, 6, 28]
+[:mouse_move, 843, 123, 2, 7, 29]
+[:mouse_move, 849, 126, 2, 8, 30]
+[:key_down_raw, 1073741903, 0, 2, 9, 89]
+[:key_up_raw, 1073741903, 0, 2, 10, 94]
+[:key_down_raw, 1073741903, 0, 2, 11, 98]
+[:key_up_raw, 1073741903, 0, 2, 12, 105]
+[:key_down_raw, 1073741903, 0, 2, 13, 108]
+[:key_down_raw, 1073741906, 0, 2, 14, 116]
+[:key_up_raw, 1073741903, 0, 2, 15, 117]
+[:key_up_raw, 1073741906, 0, 2, 16, 121]
+[:key_down_raw, 1073741906, 0, 2, 17, 126]
+[:key_up_raw, 1073741906, 0, 2, 18, 128]
+[:key_down_raw, 1073741906, 0, 2, 19, 135]
+[:key_up_raw, 1073741906, 0, 2, 20, 138]
+[:key_down_raw, 1073741906, 0, 2, 21, 143]
+[:key_up_raw, 1073741906, 0, 2, 22, 147]
+[:key_down_raw, 1073741906, 0, 2, 23, 152]
+[:key_up_raw, 1073741906, 0, 2, 24, 156]
+[:key_down_raw, 1073741906, 0, 2, 25, 162]
+[:key_up_raw, 1073741906, 0, 2, 26, 167]
+[:key_down_raw, 1073741903, 0, 2, 27, 171]
+[:key_up_raw, 1073741903, 0, 2, 28, 177]
+[:key_down_raw, 1073741903, 0, 2, 29, 181]
+[:key_up_raw, 1073741903, 0, 2, 30, 187]
+[:key_down_raw, 1073741903, 0, 2, 31, 190]
+[:key_up_raw, 1073741903, 0, 2, 32, 197]
+[:key_down_raw, 1073741903, 0, 2, 33, 200]
+[:key_up_raw, 1073741903, 0, 2, 34, 212]
+[:key_down_raw, 1073741906, 0, 2, 35, 214]
+[:key_up_raw, 1073741906, 0, 2, 36, 218]
+[:key_down_raw, 1073741906, 0, 2, 37, 224]
+[:key_up_raw, 1073741906, 0, 2, 38, 227]
+[:key_down_raw, 1073741906, 0, 2, 39, 233]
+[:key_up_raw, 1073741906, 0, 2, 40, 238]
+[:key_down_raw, 1073741906, 0, 2, 41, 243]
+[:key_up_raw, 1073741906, 0, 2, 42, 247]
+[:key_down_raw, 1073741903, 0, 2, 43, 252]
+[:key_up_raw, 1073741903, 0, 2, 44, 259]
+[:key_down_raw, 1073741903, 0, 2, 45, 264]
+[:key_up_raw, 1073741903, 0, 2, 46, 269]
+[:key_down_raw, 1073741903, 0, 2, 47, 274]
+[:key_up_raw, 1073741903, 0, 2, 48, 279]
+[:key_down_raw, 1073741903, 0, 2, 49, 283]
+[:key_up_raw, 1073741903, 0, 2, 50, 289]
+[:key_down_raw, 1073741903, 0, 2, 51, 294]
+[:key_up_raw, 1073741903, 0, 2, 52, 300]
+[:key_down_raw, 1073741905, 0, 2, 53, 308]
+[:key_up_raw, 1073741905, 0, 2, 54, 313]
+[:key_down_raw, 1073741903, 0, 2, 55, 323]
+[:key_up_raw, 1073741903, 0, 2, 56, 333]
+[:key_down_raw, 1073741906, 0, 2, 57, 360]
+[:key_up_raw, 1073741906, 0, 2, 58, 364]
+[:key_down_raw, 1073741906, 0, 2, 59, 369]
+[:key_up_raw, 1073741906, 0, 2, 60, 374]
+[:key_down_raw, 1073741906, 0, 2, 61, 379]
+[:key_up_raw, 1073741906, 0, 2, 62, 383]
+[:mouse_move, 868, 122, 2, 63, 418]
+[:mouse_move, 879, 121, 2, 64, 419]
+[:mouse_move, 882, 120, 2, 65, 420]
+[:mouse_move, 876, 120, 2, 66, 426]
+[:mouse_move, 853, 119, 2, 67, 427]
+[:mouse_move, 830, 117, 2, 68, 428]
+[:mouse_move, 799, 112, 2, 69, 429]
+[:mouse_move, 750, 105, 2, 70, 430]
+[:mouse_move, 659, 100, 2, 71, 431]
+[:mouse_move, 544, 100, 2, 72, 432]
+[:mouse_move, 447, 100, 2, 73, 433]
+[:mouse_move, 383, 100, 2, 74, 434]
+[:mouse_move, 336, 100, 2, 75, 435]
+[:mouse_move, 290, 100, 2, 76, 436]
+[:mouse_move, 251, 100, 2, 77, 437]
+[:mouse_move, 205, 100, 2, 78, 438]
+[:mouse_move, 181, 100, 2, 79, 439]
+[:mouse_move, 159, 102, 2, 80, 440]
+[:mouse_move, 137, 106, 2, 81, 441]
+[:mouse_move, 124, 111, 2, 82, 442]
+[:mouse_move, 120, 113, 2, 83, 443]
+[:mouse_move, 134, 117, 2, 84, 446]
+[:mouse_move, 167, 127, 2, 85, 447]
+[:mouse_move, 208, 137, 2, 86, 448]
+[:mouse_move, 255, 142, 2, 87, 449]
+[:mouse_move, 356, 155, 2, 88, 450]
+[:mouse_move, 439, 159, 2, 89, 451]
+[:mouse_move, 522, 159, 2, 90, 452]
+[:mouse_move, 576, 151, 2, 91, 453]
+[:mouse_move, 606, 139, 2, 92, 454]
+[:mouse_move, 622, 128, 2, 93, 455]
+[:mouse_move, 630, 120, 2, 94, 456]
+[:mouse_move, 630, 117, 2, 95, 457]
+[:mouse_move, 620, 104, 2, 96, 458]
+[:mouse_move, 592, 85, 2, 97, 459]
+[:mouse_move, 544, 64, 2, 98, 460]
+[:mouse_move, 465, 35, 2, 99, 461]
+[:mouse_move, 377, 15, 2, 100, 462]
+[:mouse_move, 209, 0, 2, 101, 463]
+[:mouse_move, 10, 66, 2, 102, 473]
+[:mouse_move, 39, 76, 2, 103, 474]
+[:mouse_move, 66, 80, 2, 104, 475]
+[:mouse_move, 96, 81, 2, 105, 476]
+[:mouse_move, 125, 81, 2, 106, 477]
+[:mouse_move, 149, 80, 2, 107, 478]
+[:mouse_move, 173, 76, 2, 108, 479]
+[:mouse_move, 192, 74, 2, 109, 480]
+[:mouse_move, 209, 71, 2, 110, 481]
+[:mouse_move, 213, 71, 2, 111, 482]
+[:mouse_move, 212, 72, 2, 112, 486]
+[:mouse_move, 212, 75, 2, 113, 487]
+[:mouse_move, 217, 79, 2, 114, 488]
+[:mouse_move, 218, 80, 2, 115, 489]
+[:key_down_raw, 1073741905, 0, 2, 116, 517]
+[:key_up_raw, 1073741905, 0, 2, 117, 522]
+[:key_down_raw, 1073741905, 0, 2, 118, 526]
+[:key_up_raw, 1073741905, 0, 2, 119, 530]
+[:key_down_raw, 1073741905, 0, 2, 120, 535]
+[:key_up_raw, 1073741905, 0, 2, 121, 539]
+[:key_down_raw, 1073741905, 0, 2, 122, 544]
+[:key_up_raw, 1073741905, 0, 2, 123, 549]
+[:mouse_move, 217, 80, 2, 124, 582]
+[:mouse_move, 214, 80, 2, 125, 583]
+[:mouse_move, 205, 80, 2, 126, 584]
+[:mouse_move, 190, 80, 2, 127, 585]
+[:mouse_move, 168, 80, 2, 128, 586]
+[:mouse_move, 145, 80, 2, 129, 587]
+[:mouse_move, 123, 80, 2, 130, 588]
+[:mouse_move, 95, 80, 2, 131, 589]
+[:mouse_move, 64, 80, 2, 132, 590]
+[:mouse_move, 43, 82, 2, 133, 591]
+[:mouse_move, 29, 82, 2, 134, 592]
+[:mouse_move, 22, 83, 2, 135, 593]
+[:mouse_move, 19, 83, 2, 136, 594]
+[:mouse_move, 19, 85, 2, 137, 596]
+[:mouse_move, 22, 98, 2, 138, 597]
+[:mouse_move, 35, 116, 2, 139, 598]
+[:mouse_move, 55, 135, 2, 140, 599]
+[:mouse_move, 79, 147, 2, 141, 600]
+[:mouse_move, 106, 152, 2, 142, 601]
+[:mouse_move, 140, 153, 2, 143, 602]
+[:mouse_move, 182, 151, 2, 144, 603]
+[:mouse_move, 220, 141, 2, 145, 604]
+[:mouse_move, 247, 127, 2, 146, 605]
+[:mouse_move, 272, 103, 2, 147, 606]
+[:mouse_move, 274, 90, 2, 148, 607]
+[:mouse_move, 271, 77, 2, 149, 608]
+[:mouse_move, 254, 64, 2, 150, 609]
+[:mouse_move, 222, 50, 2, 151, 610]
+[:mouse_move, 181, 37, 2, 152, 611]
+[:mouse_move, 141, 32, 2, 153, 612]
+[:mouse_move, 102, 30, 2, 154, 613]
+[:mouse_move, 69, 30, 2, 155, 614]
+[:mouse_move, 40, 34, 2, 156, 615]
+[:mouse_move, 20, 43, 2, 157, 616]
+[:mouse_move, 5, 54, 2, 158, 617]
+[:mouse_move, 0, 77, 2, 159, 618]
+[:mouse_move, 6, 99, 2, 160, 619]
+[:mouse_move, 25, 120, 2, 161, 620]
+[:mouse_move, 51, 134, 2, 162, 621]
+[:mouse_move, 83, 139, 2, 163, 622]
+[:mouse_move, 119, 142, 2, 164, 623]
+[:mouse_move, 156, 142, 2, 165, 624]
+[:mouse_move, 189, 142, 2, 166, 625]
+[:mouse_move, 209, 138, 2, 167, 626]
+[:mouse_move, 222, 132, 2, 168, 627]
+[:mouse_move, 227, 126, 2, 169, 628]
+[:mouse_move, 229, 120, 2, 170, 629]
+[:mouse_move, 231, 113, 2, 171, 630]
+[:mouse_move, 232, 113, 2, 172, 631]
+[:mouse_move, 235, 113, 2, 173, 651]
+[:mouse_move, 236, 113, 2, 174, 652]
+[:mouse_move, 237, 113, 2, 175, 653]
+[:mouse_move, 242, 113, 2, 176, 654]
+[:mouse_move, 252, 115, 2, 177, 655]
+[:mouse_move, 277, 116, 2, 178, 656]
+[:key_down_raw, 96, 0, 2, 179, 656]
+[:mouse_move, 316, 116, 2, 180, 657]
+[:mouse_move, 372, 116, 2, 181, 658]
+[:mouse_move, 445, 117, 2, 182, 659]
+[:mouse_move, 513, 123, 2, 183, 660]
+[:key_up_raw, 96, 0, 2, 184, 661]
+[:mouse_move, 572, 131, 2, 185, 661]
+[:mouse_move, 622, 135, 2, 186, 662]
+[:mouse_move, 669, 135, 2, 187, 663]
+[:mouse_move, 704, 135, 2, 188, 664]
+[:mouse_move, 724, 135, 2, 189, 665]
+[:mouse_move, 728, 135, 2, 190, 666]
+[:mouse_move, 727, 135, 2, 191, 670]
+[:key_down_raw, 13, 0, 2, 192, 697]
diff --git a/samples/99_genre_rpg_topdown/topdown_casino/app/main.rb b/samples/99_genre_rpg_topdown/topdown_casino/app/main.rb
new file mode 100644
index 0000000..eccf744
--- /dev/null
+++ b/samples/99_genre_rpg_topdown/topdown_casino/app/main.rb
@@ -0,0 +1,139 @@
+$gtk.reset
+
+def coinflip
+ rand < 0.5
+end
+
+class Game
+ attr_accessor :args
+
+ def text_font
+ return nil #"rpg.ttf"
+ end
+
+ def text_color
+ [ 255, 255, 255, 255 ]
+ end
+
+ def set_gem_values
+ @args.state.gem0 = ((coinflip) ? 100 : 20)
+ @args.state.gem1 = ((coinflip) ? -10 : -50)
+ @args.state.gem2 = ((coinflip) ? -10 : -30)
+ if coinflip
+ tmp = @args.state.gem0
+ @args.state.gem0 = @args.state.gem1
+ @args.state.gem1 = tmp
+ end
+ if coinflip
+ tmp = @args.state.gem1
+ @args.state.gem1 = @args.state.gem2
+ @args.state.gem2 = tmp
+ end
+ if coinflip
+ tmp = @args.state.gem0
+ @args.state.gem0 = @args.state.gem2
+ @args.state.gem2 = tmp
+ end
+ end
+
+ def initialize args
+ @args = args
+ @args.state.animticks = 0
+ @args.state.score = 0
+ @args.state.gem_chosen = false
+ @args.state.round_finished = false
+ @args.state.gem0_x = 197
+ @args.state.gem0_y = 720-274
+ @args.state.gem1_x = 623
+ @args.state.gem1_y = 720-274
+ @args.state.gem2_x = 1049
+ @args.state.gem2_y = 720-274
+ @args.state.hero_sprite = "sprites/herodown100.png"
+ @args.state.hero_x = 608
+ @args.state.hero_y = 720-656
+ set_gem_values
+ end
+
+ def render_gem_value x, y, gem
+ if @args.state.gem_chosen
+ @args.outputs.labels << [ x, y + 96, gem.to_s, 1, 1, *text_color, text_font ]
+ end
+ end
+
+ def render
+ gemsprite = ((@args.state.animticks % 400) < 200) ? 'sprites/gem200.png' : 'sprites/gem400.png'
+ @args.outputs.background_color = [ 0, 0, 0, 255 ]
+ @args.outputs.sprites << [608, 720-150, 64, 64, 'sprites/oldman.png']
+ @args.outputs.sprites << [300, 720-150, 64, 64, 'sprites/fire.png']
+ @args.outputs.sprites << [900, 720-150, 64, 64, 'sprites/fire.png']
+ @args.outputs.sprites << [@args.state.gem0_x, @args.state.gem0_y, 32, 64, gemsprite]
+ @args.outputs.sprites << [@args.state.gem1_x, @args.state.gem1_y, 32, 64, gemsprite]
+ @args.outputs.sprites << [@args.state.gem2_x, @args.state.gem2_y, 32, 64, gemsprite]
+ @args.outputs.sprites << [@args.state.hero_x, @args.state.hero_y, 64, 64, @args.state.hero_sprite]
+
+ @args.outputs.labels << [ 630, 720-30, "IT'S A SECRET TO EVERYONE.", 1, 1, *text_color, text_font ]
+ @args.outputs.labels << [ 50, 720-85, @args.state.score.to_s, 1, 1, *text_color, text_font ]
+ render_gem_value @args.state.gem0_x, @args.state.gem0_y, @args.state.gem0
+ render_gem_value @args.state.gem1_x, @args.state.gem1_y, @args.state.gem1
+ render_gem_value @args.state.gem2_x, @args.state.gem2_y, @args.state.gem2
+ end
+
+ def calc
+ @args.state.animticks += 16
+
+ return unless @args.state.gem_chosen
+ @args.state.round_finished_debounce ||= 60 * 3
+ @args.state.round_finished_debounce -= 1
+ return if @args.state.round_finished_debounce > 0
+
+ @args.state.gem_chosen = false
+ @args.state.hero.sprite[0] = 'sprites/herodown100.png'
+ @args.state.hero.sprite[1] = 608
+ @args.state.hero.sprite[2] = 656
+ @args.state.round_finished_debounce = nil
+ set_gem_values
+ end
+
+ def walk xdir, ydir, anim
+ @args.state.hero_sprite = "sprites/#{anim}#{(((@args.state.animticks % 200) < 100) ? '100' : '200')}.png"
+ @args.state.hero_x += 5 * xdir
+ @args.state.hero_y += 5 * ydir
+ end
+
+ def check_gem_touching gem_x, gem_y, gem
+ return if @args.state.gem_chosen
+ herorect = [ @args.state.hero_x, @args.state.hero_y, 64, 64 ]
+ return if !herorect.intersect_rect?([gem_x, gem_y, 32, 64])
+ @args.state.gem_chosen = true
+ @args.state.score += gem
+ @args.outputs.sounds << ((gem < 0) ? 'sounds/lose.wav' : 'sounds/win.wav')
+ end
+
+ def input
+ if @args.inputs.keyboard.key_held.left
+ walk(-1.0, 0.0, 'heroleft')
+ elsif @args.inputs.keyboard.key_held.right
+ walk(1.0, 0.0, 'heroright')
+ elsif @args.inputs.keyboard.key_held.up
+ walk(0.0, 1.0, 'heroup')
+ elsif @args.inputs.keyboard.key_held.down
+ walk(0.0, -1.0, 'herodown')
+ end
+
+ check_gem_touching(@args.state.gem0_x, @args.state.gem0_y, @args.state.gem0)
+ check_gem_touching(@args.state.gem1_x, @args.state.gem1_y, @args.state.gem1)
+ check_gem_touching(@args.state.gem2_x, @args.state.gem2_y, @args.state.gem2)
+ end
+
+ def tick
+ input
+ calc
+ render
+ end
+end
+
+def tick args
+ args.state.game ||= Game.new args
+ args.state.game.args = args
+ args.state.game.tick
+end
diff --git a/samples/99_genre_rpg_topdown/topdown_casino/license-for-sample.txt b/samples/99_genre_rpg_topdown/topdown_casino/license-for-sample.txt
new file mode 100644
index 0000000..c25563f
--- /dev/null
+++ b/samples/99_genre_rpg_topdown/topdown_casino/license-for-sample.txt
@@ -0,0 +1,9 @@
+Copyright 2019 DragonRuby LLC (code), Nick Culbertson @mobypixel (art/music)
+
+MIT License
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/samples/99_genre_rpg_topdown/topdown_casino/replay.txt b/samples/99_genre_rpg_topdown/topdown_casino/replay.txt
new file mode 100644
index 0000000..e4d52d7
--- /dev/null
+++ b/samples/99_genre_rpg_topdown/topdown_casino/replay.txt
@@ -0,0 +1,123 @@
+replay_version 2.0
+stopped_at 871
+seed 100
+recorded_at 2021-11-20 11:37:50 -0600
+[:mouse_button_up, 1, 0, 1, 1, 4]
+[:mouse_move, 802, 86, 2, 2, 21]
+[:key_down_raw, 1073741906, 0, 2, 3, 105]
+[:key_down_raw, 1073741906, 0, 2, 4, 119]
+[:key_down_raw, 1073741906, 0, 2, 5, 121]
+[:key_down_raw, 1073741906, 0, 2, 6, 123]
+[:key_down_raw, 1073741906, 0, 2, 7, 125]
+[:key_down_raw, 1073741906, 0, 2, 8, 127]
+[:key_down_raw, 1073741906, 0, 2, 9, 129]
+[:key_down_raw, 1073741906, 0, 2, 10, 131]
+[:key_down_raw, 1073741906, 0, 2, 11, 133]
+[:key_down_raw, 1073741906, 0, 2, 12, 135]
+[:key_down_raw, 1073741906, 0, 2, 13, 137]
+[:key_down_raw, 1073741906, 0, 2, 14, 139]
+[:key_up_raw, 1073741906, 0, 2, 15, 140]
+[:key_down_raw, 1073741903, 0, 2, 16, 141]
+[:key_down_raw, 1073741906, 0, 2, 17, 153]
+[:key_up_raw, 1073741903, 0, 2, 18, 160]
+[:key_down_raw, 1073741906, 0, 2, 19, 168]
+[:key_down_raw, 1073741906, 0, 2, 20, 170]
+[:key_down_raw, 1073741906, 0, 2, 21, 172]
+[:key_down_raw, 1073741906, 0, 2, 22, 174]
+[:key_down_raw, 1073741906, 0, 2, 23, 176]
+[:key_down_raw, 1073741906, 0, 2, 24, 178]
+[:key_down_raw, 1073741906, 0, 2, 25, 180]
+[:key_down_raw, 1073741906, 0, 2, 26, 182]
+[:key_down_raw, 1073741906, 0, 2, 27, 184]
+[:key_down_raw, 1073741906, 0, 2, 28, 186]
+[:key_down_raw, 1073741906, 0, 2, 29, 188]
+[:key_down_raw, 1073741906, 0, 2, 30, 190]
+[:key_down_raw, 1073741906, 0, 2, 31, 192]
+[:key_down_raw, 1073741906, 0, 2, 32, 194]
+[:key_down_raw, 1073741906, 0, 2, 33, 196]
+[:key_up_raw, 1073741906, 0, 2, 34, 196]
+[:key_down_raw, 1073741904, 0, 2, 35, 225]
+[:key_down_raw, 1073741904, 0, 2, 36, 240]
+[:key_down_raw, 1073741904, 0, 2, 37, 242]
+[:key_down_raw, 1073741904, 0, 2, 38, 244]
+[:key_up_raw, 1073741904, 0, 2, 39, 244]
+[:key_down_raw, 1073741905, 0, 2, 40, 297]
+[:key_down_raw, 1073741905, 0, 2, 41, 312]
+[:key_down_raw, 1073741905, 0, 2, 42, 314]
+[:key_down_raw, 1073741905, 0, 2, 43, 316]
+[:key_down_raw, 1073741905, 0, 2, 44, 318]
+[:key_down_raw, 1073741905, 0, 2, 45, 320]
+[:key_down_raw, 1073741905, 0, 2, 46, 322]
+[:key_down_raw, 1073741905, 0, 2, 47, 324]
+[:key_up_raw, 1073741905, 0, 2, 48, 326]
+[:key_down_raw, 1073741904, 0, 2, 49, 355]
+[:key_down_raw, 1073741904, 0, 2, 50, 370]
+[:key_down_raw, 1073741904, 0, 2, 51, 372]
+[:key_down_raw, 1073741904, 0, 2, 52, 374]
+[:key_down_raw, 1073741904, 0, 2, 53, 376]
+[:key_down_raw, 1073741904, 0, 2, 54, 378]
+[:key_up_raw, 1073741904, 0, 2, 55, 379]
+[:key_down_raw, 1073741906, 0, 2, 56, 393]
+[:key_down_raw, 1073741906, 0, 2, 57, 408]
+[:key_down_raw, 1073741906, 0, 2, 58, 410]
+[:key_down_raw, 1073741906, 0, 2, 59, 412]
+[:key_down_raw, 1073741906, 0, 2, 60, 414]
+[:key_down_raw, 1073741906, 0, 2, 61, 416]
+[:key_down_raw, 1073741906, 0, 2, 62, 418]
+[:key_down_raw, 1073741906, 0, 2, 63, 421]
+[:key_up_raw, 1073741906, 0, 2, 64, 421]
+[:key_down_raw, 1073741906, 0, 2, 65, 454]
+[:key_down_raw, 1073741906, 0, 2, 66, 468]
+[:key_down_raw, 1073741906, 0, 2, 67, 470]
+[:key_down_raw, 1073741906, 0, 2, 68, 472]
+[:key_down_raw, 1073741906, 0, 2, 69, 474]
+[:key_up_raw, 1073741906, 0, 2, 70, 475]
+[:key_down_raw, 1073741904, 0, 2, 71, 476]
+[:key_down_raw, 1073741904, 0, 2, 72, 491]
+[:key_down_raw, 1073741904, 0, 2, 73, 493]
+[:key_down_raw, 1073741904, 0, 2, 74, 495]
+[:key_down_raw, 1073741906, 0, 2, 75, 496]
+[:key_down_raw, 1073741906, 0, 2, 76, 511]
+[:key_down_raw, 1073741906, 0, 2, 77, 513]
+[:key_down_raw, 1073741906, 0, 2, 78, 515]
+[:key_up_raw, 1073741906, 0, 2, 79, 515]
+[:key_down_raw, 1073741905, 0, 2, 80, 524]
+[:key_up_raw, 1073741904, 0, 2, 81, 526]
+[:key_up_raw, 1073741905, 0, 2, 82, 532]
+[:key_down_raw, 1073741906, 0, 2, 83, 570]
+[:key_down_raw, 1073741906, 0, 2, 84, 585]
+[:key_up_raw, 1073741906, 0, 2, 85, 586]
+[:key_down_raw, 1073741903, 0, 2, 86, 591]
+[:key_up_raw, 1073741903, 0, 2, 87, 605]
+[:key_down_raw, 1073741905, 0, 2, 88, 608]
+[:key_down_raw, 1073741905, 0, 2, 89, 623]
+[:key_down_raw, 1073741904, 0, 2, 90, 625]
+[:key_up_raw, 1073741905, 0, 2, 91, 627]
+[:key_down_raw, 1073741904, 0, 2, 92, 640]
+[:key_down_raw, 1073741904, 0, 2, 93, 642]
+[:key_down_raw, 1073741904, 0, 2, 94, 644]
+[:key_down_raw, 1073741904, 0, 2, 95, 646]
+[:key_down_raw, 1073741904, 0, 2, 96, 648]
+[:key_up_raw, 1073741904, 0, 2, 97, 650]
+[:key_down_raw, 1073741903, 0, 2, 98, 705]
+[:key_down_raw, 1073741903, 0, 2, 99, 720]
+[:key_down_raw, 1073741903, 0, 2, 100, 722]
+[:key_down_raw, 1073741903, 0, 2, 101, 724]
+[:key_down_raw, 1073741903, 0, 2, 102, 726]
+[:key_down_raw, 1073741903, 0, 2, 103, 729]
+[:key_down_raw, 1073741903, 0, 2, 104, 731]
+[:key_down_raw, 1073741903, 0, 2, 105, 733]
+[:key_down_raw, 1073741903, 0, 2, 106, 735]
+[:key_down_raw, 1073741903, 0, 2, 107, 737]
+[:key_down_raw, 1073741903, 0, 2, 108, 739]
+[:key_down_raw, 1073741903, 0, 2, 109, 741]
+[:key_down_raw, 1073741903, 0, 2, 110, 743]
+[:key_down_raw, 1073741903, 0, 2, 111, 745]
+[:key_down_raw, 1073741903, 0, 2, 112, 747]
+[:key_down_raw, 1073741903, 0, 2, 113, 749]
+[:key_down_raw, 1073741903, 0, 2, 114, 751]
+[:key_down_raw, 1073741903, 0, 2, 115, 753]
+[:key_up_raw, 1073741903, 0, 2, 116, 753]
+[:key_down_raw, 96, 0, 2, 117, 818]
+[:key_up_raw, 96, 0, 2, 118, 823]
+[:key_down_raw, 13, 0, 2, 119, 871]
diff --git a/samples/99_genre_rpg_topdown/topdown_casino/sprites/fire.png b/samples/99_genre_rpg_topdown/topdown_casino/sprites/fire.png
new file mode 100644
index 0000000..ed4b2f0
--- /dev/null
+++ b/samples/99_genre_rpg_topdown/topdown_casino/sprites/fire.png
Binary files differ
diff --git a/samples/99_genre_rpg_topdown/topdown_casino/sprites/gem200.png b/samples/99_genre_rpg_topdown/topdown_casino/sprites/gem200.png
new file mode 100644
index 0000000..f643db9
--- /dev/null
+++ b/samples/99_genre_rpg_topdown/topdown_casino/sprites/gem200.png
Binary files differ
diff --git a/samples/99_genre_rpg_topdown/topdown_casino/sprites/gem400.png b/samples/99_genre_rpg_topdown/topdown_casino/sprites/gem400.png
new file mode 100644
index 0000000..f872e06
--- /dev/null
+++ b/samples/99_genre_rpg_topdown/topdown_casino/sprites/gem400.png
Binary files differ
diff --git a/samples/99_genre_rpg_topdown/topdown_casino/sprites/herodown100.png b/samples/99_genre_rpg_topdown/topdown_casino/sprites/herodown100.png
new file mode 100644
index 0000000..116d406
--- /dev/null
+++ b/samples/99_genre_rpg_topdown/topdown_casino/sprites/herodown100.png
Binary files differ
diff --git a/samples/99_genre_rpg_topdown/topdown_casino/sprites/herodown200.png b/samples/99_genre_rpg_topdown/topdown_casino/sprites/herodown200.png
new file mode 100644
index 0000000..116d406
--- /dev/null
+++ b/samples/99_genre_rpg_topdown/topdown_casino/sprites/herodown200.png
Binary files differ
diff --git a/samples/99_genre_rpg_topdown/topdown_casino/sprites/heroleft100.png b/samples/99_genre_rpg_topdown/topdown_casino/sprites/heroleft100.png
new file mode 100644
index 0000000..116d406
--- /dev/null
+++ b/samples/99_genre_rpg_topdown/topdown_casino/sprites/heroleft100.png
Binary files differ
diff --git a/samples/99_genre_rpg_topdown/topdown_casino/sprites/heroleft200.png b/samples/99_genre_rpg_topdown/topdown_casino/sprites/heroleft200.png
new file mode 100644
index 0000000..116d406
--- /dev/null
+++ b/samples/99_genre_rpg_topdown/topdown_casino/sprites/heroleft200.png
Binary files differ
diff --git a/samples/99_genre_rpg_topdown/topdown_casino/sprites/heroright100.png b/samples/99_genre_rpg_topdown/topdown_casino/sprites/heroright100.png
new file mode 100644
index 0000000..116d406
--- /dev/null
+++ b/samples/99_genre_rpg_topdown/topdown_casino/sprites/heroright100.png
Binary files differ
diff --git a/samples/99_genre_rpg_topdown/topdown_casino/sprites/heroright200.png b/samples/99_genre_rpg_topdown/topdown_casino/sprites/heroright200.png
new file mode 100644
index 0000000..116d406
--- /dev/null
+++ b/samples/99_genre_rpg_topdown/topdown_casino/sprites/heroright200.png
Binary files differ
diff --git a/samples/99_genre_rpg_topdown/topdown_casino/sprites/heroup100.png b/samples/99_genre_rpg_topdown/topdown_casino/sprites/heroup100.png
new file mode 100644
index 0000000..116d406
--- /dev/null
+++ b/samples/99_genre_rpg_topdown/topdown_casino/sprites/heroup100.png
Binary files differ
diff --git a/samples/99_genre_rpg_topdown/topdown_casino/sprites/heroup200.png b/samples/99_genre_rpg_topdown/topdown_casino/sprites/heroup200.png
new file mode 100644
index 0000000..116d406
--- /dev/null
+++ b/samples/99_genre_rpg_topdown/topdown_casino/sprites/heroup200.png
Binary files differ
diff --git a/samples/99_genre_rpg_topdown/topdown_casino/sprites/oldman.png b/samples/99_genre_rpg_topdown/topdown_casino/sprites/oldman.png
new file mode 100644
index 0000000..a9bb758
--- /dev/null
+++ b/samples/99_genre_rpg_topdown/topdown_casino/sprites/oldman.png
Binary files differ
diff --git a/samples/99_genre_teenytiny/teenytiny_starting_point/app/main.rb b/samples/99_genre_teenytiny/teenytiny_starting_point/app/main.rb
new file mode 100644
index 0000000..a542a93
--- /dev/null
+++ b/samples/99_genre_teenytiny/teenytiny_starting_point/app/main.rb
@@ -0,0 +1,162 @@
+# full documenation is at http://docs.dragonruby.org
+# be sure to come to the discord if you hit any snags: http://discord.dragonruby.org
+def tick args
+ # ====================================================
+ # initialize default variables
+ # ====================================================
+
+ # ruby has an operator called ||= which means "only initialize this if it's nil"
+ args.state.count_down ||= 20 * 60 # set the count down to 20 seconds
+ # set the initial position of the target
+ args.state.target ||= { x: args.grid.w.half,
+ y: args.grid.h.half,
+ w: 20,
+ h: 20 }
+
+ # set the initial position of the player
+ args.state.player ||= { x: 50,
+ y: 50,
+ w: 20,
+ h: 20 }
+
+ # set the player movement speed
+ args.state.player_speed ||= 5
+
+ # set the score
+ args.state.score ||= 0
+ args.state.teleports ||= 3
+
+ # set the instructions
+ args.state.instructions ||= "Get to the red goal! Use arrow keys to move. Spacebar to teleport (use them carefully)!"
+
+ # ====================================================
+ # render the game
+ # ====================================================
+ args.outputs.labels << { x: args.grid.w.half, y: args.grid.h - 10,
+ text: args.state.instructions,
+ alignment_enum: 1 }
+
+ # check if it's game over. if so, then render game over
+ # otherwise render the current time left
+ if game_over? args
+ args.outputs.labels << { x: args.grid.w.half,
+ y: args.grid.h - 40,
+ text: "game over! (press r to start over)",
+ alignment_enum: 1 }
+ else
+ args.outputs.labels << { x: args.grid.w.half,
+ y: args.grid.h - 40,
+ text: "time left: #{(args.state.count_down.idiv 60) + 1}",
+ alignment_enum: 1 }
+ end
+
+ # render the score
+ args.outputs.labels << { x: args.grid.w.half,
+ y: args.grid.h - 70,
+ text: "score: #{args.state.score}",
+ alignment_enum: 1 }
+
+ # render the player with teleport count
+ args.outputs.sprites << { x: args.state.player.x,
+ y: args.state.player.y,
+ w: args.state.player.w,
+ h: args.state.player.h,
+ path: 'sprites/square-green.png' }
+
+ args.outputs.labels << { x: args.state.player.x + 10,
+ y: args.state.player.y + 40,
+ text: "teleports: #{args.state.teleports}",
+ alignment_enum: 1, size_enum: -2 }
+
+ # render the target
+ args.outputs.sprites << { x: args.state.target.x,
+ y: args.state.target.y,
+ w: args.state.target.w,
+ h: args.state.target.h,
+ path: 'sprites/square-red.png' }
+
+ # ====================================================
+ # run simulation
+ # ====================================================
+
+ # count down calculation
+ args.state.count_down -= 1
+ args.state.count_down = -1 if args.state.count_down < -1
+
+ # ====================================================
+ # process player input
+ # ====================================================
+ # if it isn't game over let them move
+ if !game_over? args
+ dir_y = 0
+ dir_x = 0
+
+ # determine the change horizontally
+ if args.inputs.keyboard.up
+ dir_y += args.state.player_speed
+ elsif args.inputs.keyboard.down
+ dir_y -= args.state.player_speed
+ end
+
+ # determine the change vertically
+ if args.inputs.keyboard.left
+ dir_x -= args.state.player_speed
+ elsif args.inputs.keyboard.right
+ dir_x += args.state.player_speed
+ end
+
+ # determine if teleport can be used
+ if args.inputs.keyboard.key_down.space && args.state.teleports > 0
+ args.state.teleports -= 1
+ dir_x *= 20
+ dir_y *= 20
+ end
+
+ # apply change to player
+ args.state.player.x += dir_x
+ args.state.player.y += dir_y
+ else
+ # if r is pressed, reset the game
+ if args.inputs.keyboard.key_down.r
+ $gtk.reset
+ return
+ end
+ end
+
+ # ====================================================
+ # determine score
+ # ====================================================
+
+ # calculate new score if the player is at goal
+ if !game_over? args
+
+ # if the player is at the goal, then move the goal
+ if args.state.player.intersect_rect? args.state.target
+ # increment the goal
+ args.state.score += 1
+
+ # move the goal to a random location
+ args.state.target = { x: (rand args.grid.w), y: (rand args.grid.h), w: 20, h: 20 }
+
+ # make sure the goal is inside the view area
+ if args.state.target.x < 0
+ args.state.target.x += 20
+ elsif args.state.target.x > 1280
+ args.state.target.x -= 20
+ end
+
+ # make sure the goal is inside the view area
+ if args.state.target.y < 0
+ args.state.target.y += 20
+ elsif args.state.target.y > 720
+ args.state.target.y -= 20
+ end
+ end
+ end
+end
+
+def game_over? args
+ args.state.count_down < 0
+end
+
+$gtk.reset
diff --git a/samples/99_genre_teenytiny/teenytiny_starting_point/license.txt b/samples/99_genre_teenytiny/teenytiny_starting_point/license.txt
new file mode 100644
index 0000000..100dcec
--- /dev/null
+++ b/samples/99_genre_teenytiny/teenytiny_starting_point/license.txt
@@ -0,0 +1,9 @@
+Copyright 2019 DragonRuby LLC
+
+MIT License
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/samples/99_genre_teenytiny/teenytiny_starting_point/sprites/square-green.png b/samples/99_genre_teenytiny/teenytiny_starting_point/sprites/square-green.png
new file mode 100644
index 0000000..5ef7f75
--- /dev/null
+++ b/samples/99_genre_teenytiny/teenytiny_starting_point/sprites/square-green.png
Binary files differ
diff --git a/samples/99_genre_teenytiny/teenytiny_starting_point/sprites/square-red.png b/samples/99_genre_teenytiny/teenytiny_starting_point/sprites/square-red.png
new file mode 100644
index 0000000..3ed5f13
--- /dev/null
+++ b/samples/99_genre_teenytiny/teenytiny_starting_point/sprites/square-red.png
Binary files differ