diff options
| author | Amir Rajan <[email protected]> | 2021-01-18 12:08:34 -0600 |
|---|---|---|
| committer | Amir Rajan <[email protected]> | 2021-01-18 12:08:34 -0600 |
| commit | a4b9c048a1d751f5226833bb0c527ba1a8ac5d09 (patch) | |
| tree | 3f2535e7a6272e796d50e7f07c906d4c9eb1b14a /samples/04_physics_and_collisions/06_box_collision_3/app | |
| parent | a24a71805b1924ae7f80776c736f94575c171d2c (diff) | |
| download | dragonruby-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.rb | 255 |
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 |
