Created
November 21, 2023 07:13
-
-
Save amirrajan/606db1e18454ad0c33ddb67795a5df3c to your computer and use it in GitHub Desktop.
DragonRuby Game Toolkit - Lowrez Kenobi Source
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'app/lowrez.rb' | |
class Game | |
attr_gtk | |
def request_action name, at: nil | |
at ||= state.tick_count | |
state.player.requested_action = name | |
state.player.requested_action_at = at | |
end | |
def defaults | |
state.player.x ||= 32 | |
state.player.y ||= 0 | |
state.player.dx ||= 0 | |
state.player.dy ||= 0 | |
state.player.action ||= :standing | |
state.player.action_at ||= 0 | |
state.player.next_action_queue ||= {} | |
state.player.facing ||= 1 | |
state.player.jump_at ||= 0 | |
state.player.jump_count ||= 0 | |
state.player.max_speed ||= 0.7 | |
state.enemies ||= create_enemies | |
state.dead_enemies ||= [] | |
state.explosions ||= [] | |
state.enemy_lasers ||= [] | |
state.sabre.x ||= state.player.x | |
state.sabre.y ||= state.player.y | |
state.camera.x ||= 0 | |
state.camera.y ||= 0 | |
state.actions_lookup ||= new_actions_lookup | |
end | |
def lowrez | |
args.lowrez | |
end | |
def render | |
# background | |
lowrez.background_color = [0, 0, 0] | |
# letter box | |
args.outputs.background_color = [32, 32, 32] | |
if state.is_game_over && state.game_over_at.elapsed_time > 30 | |
lowrez.labels << { x: 32, y: 32, text: "Press ENTER", alignment_enum: 1, size_enum: LOWREZ_FONT_SM, font: LOWREZ_FONT_PATH, r: 255, g: 255, b: 255 } | |
lowrez.labels << { x: 32, y: 26, text: "to go again", alignment_enum: 1, size_enum: LOWREZ_FONT_SM, font: LOWREZ_FONT_PATH, r: 255, g: 255, b: 255 } | |
else | |
lowrez.labels << { x: vx(32), y: vy(32), text: "Go that way ->", alignment_enum: 1, size_enum: LOWREZ_FONT_SM, font: LOWREZ_FONT_PATH, r: 255, g: 255, b: 255 } | |
lowrez.labels << { x: vx(108), y: vy(10), text: "JUMP!", alignment_enum: 0, size_enum: LOWREZ_FONT_SM, font: LOWREZ_FONT_PATH, r: 255, g: 255, b: 255 } | |
lowrez.labels << { x: vx(190), y: vy(32), text: "ATTACK!", alignment_enum: 0, size_enum: LOWREZ_FONT_SM, font: LOWREZ_FONT_PATH, r: 255, g: 255, b: 255 } | |
lowrez.labels << { x: vx(300), y: vy(50), text: "Help me LOWREZ Kenobi! You're my only hope!", alignment_enum: 0, size_enum: LOWREZ_FONT_SM, font: LOWREZ_FONT_PATH, r: 255, g: 255, b: 255 } | |
end | |
if state.player.x > 256 | |
lowrez.labels << { x: vx(512), y: vy(50), text: "TODO: Make more enemies and stuff...", alignment_enum: 0, size_enum: LOWREZ_FONT_SM, font: LOWREZ_FONT_PATH, r: 255, g: 255, b: 255 } | |
lowrez.labels << { x: vx(724), y: vy(50), text: "This is all I was able to get done...", alignment_enum: 0, size_enum: LOWREZ_FONT_SM, font: LOWREZ_FONT_PATH, r: 255, g: 255, b: 255 } | |
lowrez.labels << { x: vx(934), y: vy(50), text: "Would you like me to toast some bread for you?", alignment_enum: 0, size_enum: LOWREZ_FONT_SM, font: LOWREZ_FONT_PATH, r: 255, g: 255, b: 255 } | |
lowrez.labels << { x: vx(1168), y: vy(50), text: "It might be a bit on the dark side though...", alignment_enum: 0, size_enum: LOWREZ_FONT_SM, font: LOWREZ_FONT_PATH, r: 255, g: 255, b: 255 } | |
lowrez.labels << { x: vx(1430), y: vy(50), text: "Why are you still here? There isn't anything else >_>", alignment_enum: 0, size_enum: LOWREZ_FONT_SM, font: LOWREZ_FONT_PATH, r: 255, g: 255, b: 255 } | |
lowrez.labels << { x: vx(1780), y: vy(60), text: "Never gonna ", alignment_enum: 0, size_enum: LOWREZ_FONT_SM, font: LOWREZ_FONT_PATH, r: 255, g: 255, b: 255 } | |
lowrez.labels << { x: vx(1780), y: vy(55), text: "give you up.", alignment_enum: 0, size_enum: LOWREZ_FONT_SM, font: LOWREZ_FONT_PATH, r: 255, g: 255, b: 255 } | |
lowrez.labels << { x: vx(1780), y: vy(45), text: "Never gonna", alignment_enum: 0, size_enum: LOWREZ_FONT_SM, font: LOWREZ_FONT_PATH, r: 255, g: 255, b: 255 } | |
lowrez.labels << { x: vx(1780), y: vy(40), text: "let you down.", alignment_enum: 0, size_enum: LOWREZ_FONT_SM, font: LOWREZ_FONT_PATH, r: 255, g: 255, b: 255 } | |
lowrez.labels << { x: vx(1780), y: vy(30), text: "Never gonna ", alignment_enum: 0, size_enum: LOWREZ_FONT_SM, font: LOWREZ_FONT_PATH, r: 255, g: 255, b: 255 } | |
lowrez.labels << { x: vx(1780), y: vy(25), text: "run around and", alignment_enum: 0, size_enum: LOWREZ_FONT_SM, font: LOWREZ_FONT_PATH, r: 255, g: 255, b: 255 } | |
lowrez.labels << { x: vx(1780), y: vy(20), text: "desert you.", alignment_enum: 0, size_enum: LOWREZ_FONT_SM, font: LOWREZ_FONT_PATH, r: 255, g: 255, b: 255 } | |
end | |
# lines | |
lowrez.lines << { x: vx(-1280), y: vy(2), x2: 2560, y2: 2, r: 255, g: 255, b: 255 } | |
lowrez.lines << { x: vx(0 - 8), y: vy(0), x2: vx(0 - 8), y2: (64), r: 255, g: 255, b: 255 } | |
render_player | |
render_sabre | |
render_enemies | |
render_enemy_lasers | |
end | |
def render_enemy_lasers | |
lowrez.sprites << state.enemy_lasers.map do |e| | |
e.merge x: vx(e.x), y: vy(e.y), path: :pixel, w: 3, h: 1, angle: state.tick_count * 15 | |
end | |
end | |
def render_enemies | |
lowrez.sprites << state.enemies.map do |e| | |
e.merge x: vx(e.x), y: vy(e.y) | |
end | |
state.dead_enemies.each do |e| | |
e.a ||= 255 | |
e.a -= 4 | |
end | |
state.dead_enemies.reject! { |e| e.a < 0 } | |
lowrez.sprites << state.dead_enemies.map do |e| | |
e.merge x: vx(e.x), y: vy(e.y) | |
end | |
state.explosions.each do |e| | |
e.path ||= :pixel | |
e.lifetime ||= 15 | |
e.a ||= 255 | |
e.lifetime -= 1 | |
e.scale_d ||= 0.1 | |
if e.lifetime < 7 | |
e.a -= 2 | |
end | |
e.x -= e.scale_d | |
e.y -= e.scale_d | |
e.w += e.scale_d * 3 | |
e.h += e.scale_d * 3 | |
e.scale_d *= 1.2 | |
end | |
state.explosions.reject! { |e| e.lifetime < 0 } | |
lowrez.sprites << state.explosions.map do |e| | |
e.merge x: vx(e.x), y: vy(e.y) | |
end | |
end | |
def queue_explosion rect | |
state.explosions << { x: rect.x, y: rect.y, w: 1, h: 1 } | |
end | |
def render_sabre | |
return if !state.sabre.is_active | |
sabre_index = 0.frame_index count: 4, | |
hold_for: 2, | |
repeat: true | |
offset = 0 | |
offset = -8 if state.player.facing == -1 | |
lowrez.sprites << { x: vx(state.sabre.x) + offset, | |
y: vy(state.sabre.y), w: 16, h: 16, path: "sprites/sabre-throw/#{sabre_index}.png" } | |
end | |
def new_actions_lookup | |
r = { | |
slash_0: { | |
frame_count: 6, | |
interrupt_count: 4, | |
path: "sprites/kenobi/slash-0/:index.png" | |
}, | |
slash_1: { | |
frame_count: 6, | |
interrupt_count: 4, | |
path: "sprites/kenobi/slash-1/:index.png" | |
}, | |
slash_2: { | |
frame_count: 8, | |
throw_frame: 2, | |
catch_frame: 6, | |
path: "sprites/kenobi/slash-2/:index.png" | |
}, | |
slash_3: { | |
frame_count: 9, | |
throw_frame: 2, | |
catch_frame: 7, | |
path: "sprites/kenobi/slash-3/:index.png" | |
}, | |
slash_4: { | |
frame_count: 9, | |
throw_frame: 2, | |
catch_frame: 7, | |
path: "sprites/kenobi/slash-4/:index.png" | |
}, | |
slash_5: { | |
frame_count: 11, | |
path: "sprites/kenobi/slash-5/:index.png" | |
}, | |
slash_6: { | |
frame_count: 8, | |
interrupt_count: 6, | |
path: "sprites/kenobi/slash-6/:index.png" | |
} | |
} | |
r.each.with_index do |(k, v), i| | |
v.name ||= k | |
v.index ||= i | |
v.hold_for ||= 5 | |
v.duration ||= v.frame_count * v.hold_for | |
v.last_index ||= v.frame_count - 1 | |
v.interrupt_count ||= v.frame_count | |
v.interrupt_duration ||= v.interrupt_count * v.hold_for | |
v.repeat ||= false | |
v.next_action ||= r[r.keys[i + 1]] | |
end | |
r | |
end | |
def render_player | |
flip_horizontally = if state.player.facing == -1 | |
true | |
else | |
false | |
end | |
player_sprite = { x: vx(state.player.x + 1 - 8), | |
y: vy(state.player.y), | |
w: 16, | |
h: 16, | |
flip_horizontally: flip_horizontally } | |
if state.is_game_over | |
player_sprite.flip_horizontally = false | |
player_sprite.angle = 90 | |
player_sprite.y -= 2 | |
lowrez.sprites << { **player_sprite, path: "sprites/kenobi/standing.png" } | |
elsif state.player.action == :standing | |
if state.player.y != 0 | |
if state.player.jump_count <= 1 | |
lowrez.sprites << { **player_sprite, path: "sprites/kenobi/jumping.png" } | |
else | |
index = state.player.jump_at.frame_index count: 8, hold_for: 5, repeat: false | |
index ||= 7 | |
lowrez.sprites << { **player_sprite, path: "sprites/kenobi/second-jump/#{index}.png" } | |
end | |
elsif state.player.dx != 0 | |
index = state.player.action_at.frame_index count: 4, hold_for: 5, repeat: true | |
lowrez.sprites << { **player_sprite, path: "sprites/kenobi/run/#{index}.png" } | |
else | |
lowrez.sprites << { **player_sprite, path: 'sprites/kenobi/standing.png'} | |
end | |
else | |
v = state.actions_lookup[state.player.action] | |
slash_frame_index = state.player.action_at.frame_index count: v.frame_count, | |
hold_for: v.hold_for, | |
repeat: v.repeat | |
slash_frame_index ||= v.last_index | |
slash_path = v.path.sub ":index", slash_frame_index.to_s | |
lowrez.sprites << { **player_sprite, path: slash_path } | |
end | |
end | |
def calc_input | |
if state.is_game_over | |
enter_pressed = inputs.keyboard.key_down.enter || | |
inputs.keyboard.key_down.j || | |
inputs.keyboard.key_down.f || | |
inputs.keyboard.key_down.space || | |
inputs.mouse.button_left || | |
inputs.mouse.button_right || | |
inputs.controller_one.key_down.a || | |
inputs.controller_one.key_down.b | |
if enter_pressed && state.game_over_at.elapsed_time > 30 | |
state.game_over_count_down ||= 120 | |
state.game_over_count_down = -1 | |
end | |
return | |
end | |
if state.player.next_action_queue.length > 2 | |
raise "Code in calc assums that key length of state.player.next_action_queue will never be greater than 2." | |
end | |
if inputs.controller_one.key_down.a || | |
inputs.mouse.button_left || | |
inputs.keyboard.key_down.j || | |
inputs.keyboard.key_down.f | |
request_action :attack | |
end | |
should_update_facing = false | |
if state.player.action == :standing | |
should_update_facing = true | |
else | |
key_0 = state.player.next_action_queue.keys[0] | |
key_1 = state.player.next_action_queue.keys[1] | |
if state.tick_count == key_0 | |
should_update_facing = true | |
elsif state.tick_count == key_1 | |
should_update_facing = true | |
elsif key_0 && key_1 && state.tick_count.between?(key_0, key_1) | |
should_update_facing = true | |
end | |
end | |
if should_update_facing && inputs.left_right.sign != state.player.facing.sign | |
state.player.dx = 0 | |
if inputs.left | |
state.player.facing = -1 | |
elsif inputs.right | |
state.player.facing = 1 | |
end | |
state.player.dx += state.player.max_speed * inputs.left_right | |
end | |
if state.player.action == :standing | |
state.player.dx += 0.1 * inputs.left_right | |
if state.player.dx.abs > state.player.max_speed | |
state.player.dx = state.player.max_speed * state.player.dx.sign | |
end | |
end | |
was_jump_requested = inputs.keyboard.key_down.up || | |
inputs.keyboard.key_down.w || | |
inputs.mouse.button_right || | |
inputs.controller_one.key_down.up || | |
inputs.controller_one.key_down.b || | |
inputs.keyboard.key_down.space | |
can_jump = state.player.jump_at.elapsed_time > 20 | |
if state.player.jump_count <= 1 | |
can_jump = state.player.jump_at.elapsed_time > 10 | |
end | |
if was_jump_requested && can_jump | |
if state.player.action == :slash_6 | |
state.player.action = :standing | |
end | |
state.player.dy = 1 | |
state.player.jump_count += 1 | |
state.player.jump_at = state.tick_count | |
end | |
end | |
def calc | |
calc_input | |
calc_requested_action | |
calc_next_action | |
calc_sabre | |
calc_player_boxes | |
calc_player_movement | |
calc_player_attack | |
calc_camera | |
calc_enemies | |
calc_enemy_lasers | |
if state.player.y <= 0 && state.player.dy < 0 | |
state.player.y = 0 | |
state.player.dy = 0 | |
state.player.jump_at = 0 | |
state.player.jump_count = 0 | |
end | |
end | |
def calc_player_attack | |
# lowrez.sprites << vsprite(state.player.hurt_box.merge(path: :pixel, a: 80)) | |
if state.player.action != :standing | |
# lowrez.sprites << vsprite(state.player.hit_box.merge(path: :pixel, a: 80)) | |
lasers = state.enemy_lasers.find_all do |l| | |
l.intersect_rect? state.player.hit_box | |
end.each do |l| | |
away = geometry.angle_from(l, state.player.hurt_box_center).vector | |
l.dx = away.x * 2 | |
l.dy = away.y * 2 | |
end | |
shooters = state.enemies.find_all do |e| | |
e.type == :shooter && e.intersect_rect?(state.player.hit_box) | |
end | |
state.enemies -= shooters | |
state.dead_enemies += shooters | |
shooters.each do |s| | |
queue_explosion s | |
end | |
end | |
end | |
def calc_enemy_lasers | |
state.enemy_lasers.each do |l| | |
l.x += l.dx | |
l.y += l.dy | |
l.lifetime ||= 600 | |
l.lifetime -= 1 | |
end | |
state.enemy_lasers.reject! { |l| l.lifetime < 0 } | |
end | |
def create_enemies | |
[ | |
{ x: 160, y: 3, w: 1, h: 10, path: :pixel, dx: 0, mode: :activated, type: :wall }, | |
{ x: 256, | |
y: 8, | |
w: 3, | |
h: 3, | |
path: :pixel, | |
dx: 0, | |
mode: :activated, | |
type: :shooter, | |
cool_down: 60, | |
current_cool_down: 0 }, | |
{ x: 260, | |
y: 15, | |
w: 3, | |
h: 3, | |
path: :pixel, | |
dx: 0, | |
mode: :activated, | |
type: :shooter, | |
cool_down: 60, | |
current_cool_down: 0 } | |
] | |
end | |
def calc_wall_enemy e | |
if (e.x - state.player.x).between?(0, 60) && e.mode == :activated | |
e.dx -= 0.05 | |
e.x += e.dx | |
elsif (e.x - state.player.x) < 0 | |
e.dx -= 0.05 | |
e.x += e.dx | |
e.mode = :deactivated | |
elsif (e.x - state.player.x).abs > 45 | |
e.mode = :activated | |
end | |
e.dx = -2 if e.dx.abs > 2 | |
end | |
def calc_shooter_enemy e | |
if (e.x - state.player.x).abs.between?(5, 60) && e.mode == :activated | |
e.current_cool_down -= 1 | |
if e.current_cool_down < 0 | |
to_player = geometry.angle_to(e, state.player.hurt_box_center).vector | |
state.enemy_lasers << { x: e.x + 1, y: e.y + 1, dx: to_player.x, dy: to_player.y, w: 3, h: 3 } | |
e.current_cool_down = e.cool_down | |
end | |
end | |
end | |
def calc_enemies | |
return if state.is_game_over | |
return if state.tick_count < 60 | |
state.enemies.each do |e| | |
if e.type == :wall | |
calc_wall_enemy e | |
elsif e.type == :shooter | |
calc_shooter_enemy e | |
end | |
end | |
collision = state.enemies.find do |e| | |
if e.type == :wall | |
e.intersect_rect? state.player.hurt_box | |
end | |
end | |
collision ||= state.enemy_lasers.find do |e| | |
e.intersect_rect? state.player.hurt_box | |
end | |
if collision | |
state.is_game_over = true | |
state.game_over_at = state.tick_count | |
state.player.dx = collision.dx * 2 | |
state.player.x += state.player.dx | |
state.player.facing = collision.dx.sign | |
if collision.type == :wall | |
state.player.dy = 2 | |
elsif state.player.y == 0 | |
state.player.dy = 0.5 | |
end | |
end | |
end | |
def vsprite s | |
s.merge x: vx(s.x), y: vy(s.y) | |
end | |
def vx x | |
(x - state.camera.x).round | |
end | |
def vy y | |
(y - state.camera.y).round | |
end | |
def vw w | |
w | |
end | |
def vh h | |
h | |
end | |
def calc_camera | |
percentage = 0.03 | |
target_x = state.player.x | |
target_y = state.player.y | |
if state.sabre.is_active | |
target_x = state.sabre.x + 16 * state.player.facing | |
else | |
if state.player.dx.abs > 0.2 | |
target_x += 40 * state.player.facing | |
end | |
end | |
distance_x = target_x - (state.camera.x + 32) | |
distance_y = target_y - (state.camera.y + 32) | |
state.camera.x += distance_x * percentage if distance_x.abs > 5 | |
state.camera.y += distance_y * percentage if distance_y.abs > 5 | |
# state.camera.x = 0 if state.camera.x < 0 | |
state.camera.y = 0 if state.camera.y < 0 | |
end | |
def calc_player_boxes | |
if state.player.facing == 1 | |
state.player.hurt_box = { x: state.player.x - 1, y: state.player.y + 5, w: 2, h: 4 } | |
else | |
state.player.hurt_box = { x: state.player.x + 1, y: state.player.y + 5, w: 2, h: 4 } | |
end | |
state.player.hurt_box_center = { x: state.player.x - 2 + 2, y: state.player.y + 2 + 4 } | |
if state.sabre.is_active | |
state.player.hit_box = { x: state.sabre.x + 1, y: state.sabre.y + 7, w: 14, h: 3 } | |
else | |
if state.player.facing == 1 | |
state.player.hit_box = { x: state.player.x + 4, y: state.player.y + 4, w: 5, h: 8 } | |
else | |
state.player.hit_box = { x: state.player.x - 7, y: state.player.y + 4, w: 5, h: 8 } | |
end | |
if state.player.action == :slash_5 | |
state.player.hit_box = { x: state.player.x - 8, y: state.player.y + 4, w: 16, h: 8 } | |
end | |
if state.player.action == :slash_6 | |
state.player.hit_box = { x: state.player.x - 8, y: state.player.y, w: 16, h: 16 } | |
end | |
end | |
end | |
def calc_player_movement | |
state.player.x += state.player.dx | |
state.player.y += state.player.dy | |
state.player.dy -= 0.05 | |
if state.player.y <= 0 | |
state.player.y = 0 | |
state.player.dy = 0 | |
state.player.jump_at = 0 | |
state.player.jump_count = 0 | |
end | |
if state.is_game_over | |
state.player.dx *= 0.97 | |
else | |
state.player.dx *= 0.95 | |
end | |
if state.player.dx.abs < 0.09 | |
state.player.dx = 0 | |
end | |
state.player.x = 0 if state.player.x < 0 | |
state.player.x = 1800 if state.player.x > 1800 | |
end | |
def calc_requested_action | |
return if !state.player.requested_action | |
return if state.player.requested_action_at > state.tick_count | |
player_action = state.player.action | |
player_action_at = state.player.action_at | |
# first attack | |
if state.player.requested_action == :attack | |
if player_action == :standing | |
state.player.next_action_queue.clear | |
state.player.next_action_queue[state.tick_count] = :slash_0 | |
state.player.next_action_queue[state.tick_count + state.actions_lookup.slash_0.duration] = :standing | |
else | |
current_action = state.actions_lookup[state.player.action] | |
state.player.next_action_queue.clear | |
queue_at = player_action_at + current_action.interrupt_duration | |
queue_at = state.tick_count if queue_at < state.tick_count | |
next_action = current_action.next_action | |
next_action ||= { name: :standing, | |
duration: 4 } | |
if next_action | |
state.player.next_action_queue[queue_at] = next_action.name | |
state.player.next_action_queue[player_action_at + | |
current_action.interrupt_duration + | |
next_action.duration] = :standing | |
end | |
end | |
end | |
state.player.requested_action = nil | |
state.player.requested_action_at = nil | |
end | |
def calc_sabre | |
can_throw_sabre = true | |
sabre_throws = [:slash_2, :slash_3, :slash_4] | |
if !sabre_throws.include? state.player.action | |
state.sabre.facing = nil | |
state.sabre.is_active = false | |
return | |
end | |
current_action = state.actions_lookup[state.player.action] | |
throw_at = state.player.action_at + (current_action.throw_frame) * 5 | |
catch_at = state.player.action_at + (current_action.catch_frame) * 5 | |
if !state.tick_count.between? throw_at, catch_at | |
state.sabre.facing = nil | |
state.sabre.is_active = false | |
return | |
end | |
state.sabre.facing ||= state.player.facing | |
state.sabre.is_active = true | |
spline = [ | |
[ 0, 0.25, 0.75, 1.0], | |
[1.0, 0.75, 0.25, 0] | |
] | |
throw_duration = catch_at - throw_at | |
current_progress = args.easing.ease_spline throw_at, | |
state.tick_count, | |
throw_duration, | |
spline | |
farthest_sabre_x = 32 | |
state.sabre.y = state.player.y | |
state.sabre.x = state.player.x + farthest_sabre_x * current_progress * state.sabre.facing | |
end | |
def calc_next_action | |
return if state.is_game_over | |
return if !state.player.next_action_queue[state.tick_count] | |
state.player.previous_action = state.player.action | |
state.player.previous_action_at = state.player.action_at | |
state.player.previous_action_ended_at = state.tick_count | |
state.player.action = state.player.next_action_queue[state.tick_count] | |
state.player.action_at = state.tick_count | |
is_air_born = state.player.y != 0 | |
if state.player.action == :slash_0 | |
state.player.dy = 0 if state.player.dy > 0 | |
if is_air_born | |
state.player.dy = 0.5 | |
else | |
state.player.dx += 1.5 * state.player.facing | |
end | |
elsif state.player.action == :slash_1 | |
state.player.dy = 0 if state.player.dy > 0 | |
if is_air_born | |
state.player.dy = 0.5 | |
else | |
state.player.dx += 1.5 * state.player.facing | |
end | |
elsif state.player.action == :slash_2 | |
if is_air_born | |
state.player.dy = 1.0 | |
end | |
state.player.dx += 0.25 * state.player.facing | |
elsif state.player.action == :slash_3 | |
if is_air_born | |
state.player.dy = 1.0 | |
end | |
state.player.dx += 0.25 * state.player.facing | |
elsif state.player.action == :slash_4 | |
if is_air_born | |
state.player.dy = 1.2 | |
end | |
state.player.dx += 0.25 * state.player.facing | |
elsif state.player.action == :slash_5 | |
state.player.dy = 0 if state.player.dy < 0 | |
if is_air_born | |
state.player.dy += 1.5 | |
else | |
state.player.dy += 0.5 | |
end | |
state.player.dx += 3 * state.player.facing | |
elsif state.player.action == :slash_6 | |
state.player.dy = 0 if state.player.dy > 0 | |
if is_air_born | |
state.player.dy = -1.5 | |
end | |
state.player.dx += 1.5 * state.player.facing | |
end | |
end | |
def tick | |
if state.is_game_over | |
if state.game_over_count_down && state.game_over_count_down < 0 | |
$gtk.reset | |
else | |
if state.player.y == 0 | |
state.game_over_count_down ||= 120 | |
state.game_over_count_down -= 1 | |
if state.game_over_count_down < 0 | |
$gtk.reset | |
end | |
end | |
end | |
end | |
defaults | |
calc | |
render | |
args.outputs.labels << { x: 10, y: 10.from_top, text: "Controls:", r: 255, g: 255, b: 255, size_enum: -1 } | |
args.outputs.labels << { x: 10, y: 33.from_top, text: "Move: left/right", r: 255, g: 255, b: 255, size_enum: -1 } | |
args.outputs.labels << { x: 10, y: 56.from_top, text: "Jump: space | up | right click", r: 255, g: 255, b: 255, size_enum: -1 } | |
args.outputs.labels << { x: 10, y: 79.from_top, text: "Attack: f | j | left click", r: 255, g: 255, b: 255, size_enum: -1 } | |
end | |
def lsprites | |
lowrez.sprites | |
end | |
end | |
$game = Game.new | |
def tick args | |
if !args.inputs.keyboard.has_focus && args.gtk.production && args.state.tick_count != 0 | |
args.outputs.background_color = [0, 0, 0] | |
args.outputs.labels << { x: 640, y: 360, text: "Game Paused (click to resume).", alignment_enum: 1, r: 255, g: 255, b: 255 } | |
else | |
$game.args = args | |
$game.tick | |
end | |
end | |
# $gtk.reset |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment