Skip to content

Instantly share code, notes, and snippets.

@amirrajan
Last active March 30, 2025 06:48
Show Gist options
  • Save amirrajan/532cbe1c91602df3e44f72018760f8b6 to your computer and use it in GitHub Desktop.
Save amirrajan/532cbe1c91602df3e44f72018760f8b6 to your computer and use it in GitHub Desktop.
DragonRuby Game Toolkit: Slay the Card Game Example
class Game
attr_gtk
attr :enemy
def tick
defaults
calc
render
end
def calc
@enemy.hp_perc ||= @enemy.hp / @enemy.max_hp
@enemy.hp_perc = @enemy.hp_perc.lerp(@enemy.hp / @enemy.max_hp, 0.2)
@enemy.dead = @enemy.action == :dying || @enemy.action == :dead
if inputs.keyboard.key_down.space && [email protected]
@enemy.hp -= 1
@enemy.hp = @enemy.hp.clamp(0, @enemy.max_hp)
if @enemy.hp <= 0
@enemy.action = :dying
@enemy.action_at = Kernel.tick_count
end
end
if @enemy.action == :dying && @enemy.action_at.elapsed_time > 30
@enemy.action = :dead
@enemy.action_at = Kernel.tick_count
end
end
def defaults
@enemy ||= {
id: :hello_world,
max_hp: 3,
hp: 3,
name: "Hello World",
image: "sprites/square/blue.png",
action: :idle
}
@player ||= {
hp: 20,
max_hp: 20,
draw_pile: [
{
id: :whimpy_punch,
quality: :new,
name: "Whimpy Punch",
desciption: "Just a whimpy punch",
max_hp: 20,
hp: 20,
degrade_description: ""
}
],
hand: []
}
@skip_turn_button_rect ||= Layout.rect(row: 10, col: 20, w: 4, h: 2)
end
def render
outputs.background_color = [0, 0, 0]
outputs.primitives << draw_pile_prefab
outputs.primitives << hand_prefab
outputs.primitives << health_prefab
outputs.primitives << skip_turn_prefab
outputs.primitives << enemy_prefab
outputs.primitives << Layout.rect(row: 6, col: 9, w: 6, h: 2)
.center
.merge(text: "Press space to attack.",
anchor_x: 0.5,
anchor_y: 0.5,
size_px: 30,
r: 255,
g: 255,
b: 255)
# outputs.primitives << Layout.debug_primitives(invert_colors: true)
end
def progress_bar_prefab rect:, perc:;
if perc.round(1) > 0
[
{ x: rect.x, y: rect.y, w: rect.w, h: rect.h, path: :solid },
{ x: rect.x + 4, y: rect.y + 4, w: rect.w * perc - 8, h: rect.h - 8, path: :solid, r: 0, g: 80, b: 0 }
]
else
[
{ x: rect.x, y: rect.y, w: rect.w, h: rect.h, path: :solid },
]
end
end
def enemy_prefab
layout_config = { safe_area: false, origin: :bottom_left }
e = @enemy
return nil if @enemy.action == :dead && @enemy.action_at.elapsed_time > 60
card_rect = Layout.rect(w: 0, col: 0, w: 4, h: 6, include_row_gutter: true, include_col_gutter: true, **layout_config)
name_loc = Layout.rect(row: 0, col: 0, w: 4, h: 1, **layout_config).center
image_rect = Layout.rect(row: 2.25, col: 0.25, w: 3.5, h: 3.5, **layout_config)
hp_rect = Layout.rect(row: 1, col: 0, w: 4, h: 1, **layout_config)
outputs[:enemy].w = card_rect.w
outputs[:enemy].h = card_rect.h
outputs[:enemy].primitives << card_rect.merge(path: :solid, r: 40, g: 40, b: 40)
outputs[:enemy].primitives << name_loc.merge(text: @enemy.name, anchor_x: 0.5, anchor_y: 0.5, size_px: 30, r: 255, g: 255, b: 255)
outputs[:enemy].primitives << image_rect.merge(path: @enemy.image)
outputs[:enemy].primitives << progress_bar_prefab(rect: hp_rect, perc: @enemy.hp_perc)
if @enemy.action == :dead
enemy_a = Easing.smooth_stop(start_at: @enemy.action_at,
duration: 60,
tick_count: Kernel.tick_count,
power: 3,
flip: true) * 255
enemy_angle = @enemy.action_at.elapsed_time * 10
enemy_scale = 1 - @enemy.action_at.elapsed_time / 60
else
enemy_a = 255
enemy_angle = 0
enemy_scale = 1
end
Layout.rect(row: 0, col: 10, w: 4, h: 6, include_row_gutter: true, include_col_gutter: true)
.merge(path: :enemy, a: enemy_a, angle: enemy_angle)
.scale_rect(enemy_scale, enemy_scale)
end
def health_prefab
progress_bar_prefab rect: Layout.rect(row: 8, col: 20, w: 4, h: 1), perc: @player.hp / @player.max_hp
end
def button_prefab rect:, text:;
[
rect.merge(path: :solid, r: 255, g: 255, b: 255),
rect.center.merge(text: text, size_px: 30, r: 0, g: 0, b: 0, anchor_x: 0.5, anchor_y: 0.5)
]
end
def skip_turn_prefab
button_prefab rect: @skip_turn_button_rect, text: "Skip Turn"
end
def hand_prefab
[
Layout.rect(row: 8, col: 4.5, w: 3, h: 4).merge(path: :solid, r: 255, g: 255, b: 255),
Layout.rect(row: 8, col: 7.5, w: 3, h: 4).merge(path: :solid, r: 255, g: 255, b: 255),
Layout.rect(row: 8, col: 10.5, w: 3, h: 4).merge(path: :solid, r: 255, g: 255, b: 255),
Layout.rect(row: 8, col: 13.5, w: 3, h: 4).merge(path: :solid, r: 255, g: 255, b: 255),
Layout.rect(row: 8, col: 16.5, w: 3, h: 4).merge(path: :solid, r: 255, g: 255, b: 255),
]
end
def draw_pile_prefab
[
Layout.rect(row: 8, col: 0, w: 3, h: 4).merge(path: :solid, r: 255, g: 255, b: 255)
]
end
end
def boot args
args.state = {}
end
def tick args
$game ||= Game.new
$game.args = args
$game.tick
end
def reset args
$game = nil
end
GTK.reset
slay-the-card-game-720p.mp4
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment