summaryrefslogtreecommitdiffhomepage
path: root/samples/04_physics_and_collisions/06_box_collision_3/app
diff options
context:
space:
mode:
authorAmir Rajan <[email protected]>2021-01-18 12:08:34 -0600
committerAmir Rajan <[email protected]>2021-01-18 12:08:34 -0600
commita4b9c048a1d751f5226833bb0c527ba1a8ac5d09 (patch)
tree3f2535e7a6272e796d50e7f07c906d4c9eb1b14a /samples/04_physics_and_collisions/06_box_collision_3/app
parenta24a71805b1924ae7f80776c736f94575c171d2c (diff)
downloaddragonruby-game-toolkit-contrib-a4b9c048a1d751f5226833bb0c527ba1a8ac5d09.tar.gz
dragonruby-game-toolkit-contrib-a4b9c048a1d751f5226833bb0c527ba1a8ac5d09.zip
Synced with 2.3.
Diffstat (limited to 'samples/04_physics_and_collisions/06_box_collision_3/app')
-rw-r--r--samples/04_physics_and_collisions/06_box_collision_3/app/main.rb255
1 files changed, 255 insertions, 0 deletions
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
new file mode 100644
index 0000000..2e32eee
--- /dev/null
+++ b/samples/04_physics_and_collisions/06_box_collision_3/app/main.rb
@@ -0,0 +1,255 @@
+class Game
+ attr_gtk
+
+ def tick
+ defaults
+ render
+ input_edit_map
+ input_player
+ calc_player
+ end
+
+ def defaults
+ state.gravity = -0.4
+ state.drag = 0.15
+ state.tile_size = 32
+ state.player.size = 16
+ state.player.jump_power = 12
+
+ state.tiles ||= []
+ state.player.y ||= 800
+ state.player.x ||= 100
+ state.player.dy ||= 0
+ state.player.dx ||= 0
+ state.player.jumped_down_at ||= 0
+ state.player.jumped_at ||= 0
+
+ calc_player_rect if !state.player.rect
+ end
+
+ def render
+ outputs.labels << [10, 10.from_top, "tile: click to add a tile, hold X key and click to delete a tile."]
+ outputs.labels << [10, 35.from_top, "move: use left and right to move, space to jump, down and space to jump down."]
+ outputs.labels << [10, 55.from_top, " You can jump through or jump down through tiles with a height of 1."]
+ outputs.background_color = [80, 80, 80]
+ outputs.sprites << tiles.map(&:sprite)
+ outputs.sprites << (player.rect.merge path: 'sprites/square/green.png')
+
+ mouse_overlay = {
+ x: (inputs.mouse.x.ifloor state.tile_size),
+ y: (inputs.mouse.y.ifloor state.tile_size),
+ w: state.tile_size,
+ h: state.tile_size,
+ a: 100
+ }
+
+ mouse_overlay = mouse_overlay.merge r: 255 if state.delete_mode
+
+ if state.mouse_held
+ outputs.primitives << mouse_overlay.border
+ else
+ outputs.primitives << mouse_overlay.solid
+ end
+ end
+
+ def input_edit_map
+ state.mouse_held = true if inputs.mouse.down
+ state.mouse_held = false if inputs.mouse.up
+
+ if inputs.keyboard.x
+ state.delete_mode = true
+ elsif inputs.keyboard.key_up.x
+ state.delete_mode = false
+ end
+
+ return unless state.mouse_held
+
+ ordinal = { x: (inputs.mouse.x.idiv state.tile_size),
+ y: (inputs.mouse.y.idiv state.tile_size) }
+
+ found = find_tile ordinal
+ if !found && !state.delete_mode
+ tiles << (state.new_entity :tile, ordinal)
+ recompute_tiles
+ elsif found && state.delete_mode
+ tiles.delete found
+ recompute_tiles
+ end
+ end
+
+ def input_player
+ player.dx += inputs.left_right
+
+ if inputs.keyboard.key_down.space && inputs.keyboard.down
+ player.dy = player.jump_power * -1
+ player.jumped_at = 0
+ player.jumped_down_at = state.tick_count
+ elsif inputs.keyboard.key_down.space
+ player.dy = player.jump_power
+ player.jumped_at = state.tick_count
+ player.jumped_down_at = 0
+ end
+ end
+
+ def calc_player
+ calc_player_rect
+ calc_below
+ calc_left
+ calc_right
+ calc_above
+ calc_player_dy
+ calc_player_dx
+ reset_player if player_off_stage?
+ end
+
+ def calc_player_rect
+ player.rect = current_player_rect
+ player.next_rect = player.rect.merge x: player.x + player.dx,
+ y: player.y + player.dy
+ player.prev_rect = player.rect.merge x: player.x - player.dx,
+ y: player.y - player.dy
+ end
+
+ def calc_below
+ return unless player.dy <= 0
+ tiles_below = find_tiles { |t| t.rect.top <= player.y }
+ collision = find_colliding_tile tiles_below, (player.rect.merge y: player.next_rect.y)
+ return unless collision
+ if collision.neighbors.b == :none && player.jumped_down_at.elapsed_time < 10
+ player.dy = -1
+ else
+ player.y = collision.rect.y + state.tile_size
+ player.dy = 0
+ end
+ end
+
+ def calc_left
+ return unless player.dx < 0
+ tiles_left = find_tiles { |t| t.rect.right <= player.prev_rect.left }
+ collision = find_colliding_tile 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
+ tiles_right = find_tiles { |t| t.rect.left >= player.prev_rect.right }
+ collision = find_colliding_tile 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 = find_tiles { |t| t.rect.y >= player.y }
+ collision = find_colliding_tile tiles_above, (player.rect.merge y: player.next_rect.y)
+ return unless collision
+ return if collision.neighbors.t == :none
+ player.dy = 0
+ player.y = collision.rect.bottom - player.rect.h
+ 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 reset_player
+ player.x = 100
+ player.y = 720
+ player.dy = 0
+ end
+
+ def recompute_tiles
+ tiles.each do |t|
+ t.w = state.tile_size
+ t.h = state.tile_size
+ t.neighbors = tile_neighbors t, tiles
+
+ t.rect = [t.x * state.tile_size,
+ t.y * state.tile_size,
+ state.tile_size,
+ state.tile_size].rect.to_hash
+
+ sprite_sub_path = t.neighbors.mask.map { |m| flip_bit m }.join("")
+
+ t.sprite = {
+ x: t.x * state.tile_size,
+ y: t.y * state.tile_size,
+ w: state.tile_size,
+ h: state.tile_size,
+ path: "sprites/tile/wall-#{sprite_sub_path}.png"
+ }
+ end
+ end
+
+ def flip_bit bit
+ return 0 if bit == 1
+ return 1
+ end
+
+ def player
+ state.player
+ end
+
+ def player_off_stage?
+ player.rect.top < grid.bottom ||
+ player.rect.right < grid.left ||
+ player.rect.left > grid.right
+ end
+
+ def current_player_rect
+ { x: player.x, y: player.y, w: player.size, h: player.size }
+ end
+
+ def tiles
+ state.tiles
+ end
+
+ def find_tile ordinal
+ tiles.find { |t| t.x == ordinal.x && t.y == ordinal.y }
+ end
+
+ def find_tiles &block
+ tiles.find_all(&block)
+ end
+
+ def find_colliding_tile tiles, target
+ tiles.find { |t| t.rect.intersect_rect? target }
+ end
+
+ def tile_neighbors tile, other_points
+ t = find_tile x: tile.x + 0, y: tile.y + 1
+ r = find_tile x: tile.x + 1, y: tile.y + 0
+ b = find_tile x: tile.x + 0, y: tile.y - 1
+ l = find_tile x: tile.x - 1, y: tile.y + 0
+
+ tile_t, tile_r, tile_b, tile_l = 0
+
+ tile_t = 1 if t
+ tile_r = 1 if r
+ tile_b = 1 if b
+ tile_l = 1 if l
+
+ state.new_entity :neighbors, mask: [tile_t, tile_r, tile_b, tile_l],
+ t: t ? :some : :none,
+ b: b ? :some : :none,
+ l: l ? :some : :none,
+ r: r ? :some : :none
+ end
+end
+
+def tick args
+ $game ||= Game.new
+ $game.args = args
+ $game.tick
+end