Skip to content

Instantly share code, notes, and snippets.

@amirrajan
Last active October 30, 2022 22:22
Show Gist options
  • Save amirrajan/757bf21ba6f8908cdfa98a4d2923fa2e to your computer and use it in GitHub Desktop.
Save amirrajan/757bf21ba6f8908cdfa98a4d2923fa2e to your computer and use it in GitHub Desktop.
DragonRuby Game Toolkit - Tech Demo Source Code
the-keeper-iteration-2.mp4
class Game
attr_gtk
def tick
defaults
render
input
calc
end
def defaults
state.keeper.x ||= 659
state.keeper.y ||= 260
state.keeper.w ||= 191
state.keeper.h ||= 156
state.keeper.speed ||= 0
state.keeper.max_speed ||= 3
state.keeper.angle ||= 0
state.keeper.action ||= :idle
state.keeper.sprite_data ||= load_keeper_sprite_data
state.queues.ripples ||= []
state.lilies ||= 30.map { random_lily_pads }
end
def render
outputs.background_color = [0, 0, 0]
outputs.sprites << { x: 0, y: 0, w: 1280, h: 720, path: "sprites/background.png" }
render_moving_clouds
render_land
render_willow_tree
render_ripples
render_lilies
render_keeper
render_horus
outputs.sprites << { x: 0, y: 0, w: 1280, h: 720, path: "sprites/fog.png" }
end
def render_moving_clouds
outputs.sprites << { x: state.tick_count % 1280, y: 0, w: 1280, h: 720, path: "sprites/clouds.png" }
outputs.sprites << { x: -1280 + state.tick_count % 1280, y: 0, w: 1280, h: 720, path: "sprites/clouds.png" }
end
def render_land
outputs.sprites << { x: 0, y: 0, w: 1280, h: 720, path: "sprites/land.png" }
render_frame sprite_directory: "sprites/dock-shadow", frame_count: 11
render_frame sprite_directory: "sprites/grass-land", frame_count: 15
render_frame sprite_directory: "sprites/grass-cliff", frame_count: 16
render_frame sprite_directory: "sprites/dock-water", frame_count: 6
render_frame sprite_directory: "sprites/cliff-water", frame_count: 11
outputs.sprites << { x: 0, y: 0, w: 1280, h: 720, path: "sprites/house.png" }
outputs.sprites << { x: 0, y: 0, w: 1280, h: 720, path: "sprites/vignette.png" }
end
def render_willow_tree
index = 0.frame_index(count: 24, hold_for: 4, repeat: true)
outputs.sprites << { x: 75, y: 455, w: 250 / 1.5, h: 350 / 1.5, path: "sprites/tree_yellow.png" }
outputs.sprites << { x: 30, y: 450, w: 393 / 1.5, h: 409 / 1.5, path: "sprites/willowtree/#{index}.png" }
end
def render_ripples
outputs.sprites << state.queues.ripples
end
def render_lilies
outputs.sprites << state.lilies
end
def render_keeper
keeper_sprite = state.keeper.sprite_data[state.keeper.angle.round]
boat_sprite_path = "sprites/boat/#{keeper_sprite.boat_sprite_path}"
keeper_animation_frame = (state.keeper.move_at || 0).frame_index count: 30, hold_for: 8, repeat: true
outputs.sprites << { x: state.keeper.x,
y: state.keeper.y,
w: state.keeper.w,
h: state.keeper.h,
path: boat_sprite_path,
flip_horizontally: keeper_sprite.boat_sprite_flip,
angle: keeper_sprite.boat_delta_angle,
angle_anchor_x: 0.5,
angle_anchor_y: 0.5 }
outputs.sprites << { x: state.keeper.x,
y: state.keeper.y,
w: 191,
h: 156,
path: "sprites/keeper/#{state.keeper.action}/#{keeper_sprite.keeper_sprite_angle}-#{keeper_animation_frame}.png",
flip_horizontally: keeper_sprite.keeper_sprite_flip,
angle_anchor_x: 0.5,
angle_anchor_y: 0.5 }
end
def render_horus
index = 0.frame_index(count: 15, hold_for: 10, repeat: true)
outputs.sprites << { x: 325, y: 150, w: 134 / 2, h: 163 / 2, path: "sprites/horus/#{index}.png" }
end
def input
if inputs.keyboard.key_down.r
$gtk.reset_next_tick
end
state.keeper.angle -= inputs.left_right
state.keeper.speed *= 0.99
if inputs.up
state.keeper.action = :moving
state.keeper.move_at ||= state.tick_count
state.keeper.speed += 0.05
else
state.keeper.action = :idle
state.keeper.move_at = nil
end
end
def render_frame sprite_directory:, frame_count:;
index = 0.frame_index(count: frame_count, hold_for: 6, repeat: true)
outputs.sprites << { x: 0, y: 0, w: 1280, h: 720, path: "#{sprite_directory}/#{index}.png", a: 255 }
end
def calc
calc_keeper
calc_lilies
calc_ripples
end
def calc_keeper
state.keeper.angle = state.keeper.angle % 360
state.keeper.angle = 360 - state.keeper.angle if state.keeper.angle < 0
state.keeper.speed = state.keeper.speed.clamp 0, state.keeper.max_speed
state.keeper.x += state.keeper.angle.vector_x state.keeper.speed
state.keeper.y += state.keeper.angle.vector_y state.keeper.speed
top_edge = 720
bottom_edge = 0 - state.keeper.w
left_edge = 550
right_edge = 1280 - state.keeper.w
if state.keeper.x > right_edge
state.keeper.x = right_edge
elsif state.keeper.x < left_edge
state.keeper.x = left_edge
end
if state.keeper.y > top_edge
state.keeper.y = bottom_edge
elsif state.keeper.y < bottom_edge
state.keeper.y = top_edge
end
end
def calc_lilies
state.lilies.each do |groups|
groups.each do |l|
g = 100
m1 = 10
m2 = 5
selected_point = { x: state.keeper.x + 96, y: state.keeper.y + 78 }
angle = geometry.angle_to selected_point, l
boat_vector = angle.vector
d = geometry.distance selected_point, l
origin_d = geometry.distance l[:origin], l
origin_angle = geometry.angle_from l[:origin], l
k = 0.03
if d != 0
f = (g * m1 * m2).fdiv(d**2)
if f > 10
f = 5
end
s = origin_d * k
l.x += (boat_vector.x * f) + (origin_angle.vector_x * s)
l.y += (boat_vector.y * f) + (origin_angle.vector_y * s)
end
end
end
end
def calc_ripples
if state.keeper.speed.round > 0 && state.tick_count.zmod?(20)
queue_ripples
end
state.queues.ripples.each do |r|
r.a ||= 255
r.a -= 2
r.w += 2
r.h += 2
r.x -= 1
r.y -= 1
r.x += r.dx
r.y += r.dy
r.dx *= 0.95
r.dy *= 0.95
end
state.queues.ripples.reject! { |r| r.a < 0 }
end
def load_keeper_sprite_data
contents = gtk.read_file "app/keeper-sprites.txt"
sprite_data = {}
contents.each_line do |l|
tokens = l.split ","
angle = tokens[0].strip.to_i
sprite_data[angle] = {
angle: tokens[0].strip.to_i,
keeper_sprite_angle: tokens[1].strip.to_i,
keeper_sprite_flip: tokens[2].strip == "true",
boat_sprite_path: tokens[3].strip,
boat_sprite_flip: tokens[4].strip == "true",
boat_delta_angle: tokens[5].strip.to_i
}
end
sprite_data
end
def random_lily_pads
big_lily = random_big_lily
small_lily_1 = random_small_lily big_lily
small_lily_2 = random_small_lily big_lily
lotus = random_lotus big_lily
[big_lily, small_lily_1, small_lily_2, lotus].reject_nil
end
def random_big_lily
x = 600 * rand + 600
y = 600 * rand + 30
big_lily_1 = { path: 'sprites/lilies/lilypad1.png', w: 30, h: 25 }
big_lily_2 = { path: 'sprites/lilies/lilypad3.png', w: 42, h: 26 }
[big_lily_1, big_lily_2].sample.merge(x: x,
y: y,
origin: [x, y])
end
def random_small_lily big_lily
small_lily_1 = { path: 'sprites/lilies/lilypad2.png', w: 22, h: 17 }
small_lily_2 = { path: 'sprites/lilies/lilypad4.png', w: 26, h: 20 }
small_lily = [small_lily_1, small_lily_2].sample
place_lily_nearby big_lily, small_lily
end
def random_lotus big_lily
if rand > 0.65
flower = { path: 'sprites/lilies/lotus.png', w: 37, h: 33 }
place_lily_nearby big_lily, flower
elsif rand > 0.5
lotuspod1 = { path: 'sprites/lilies/lotuspod1.png', w: 18, h: 63 }
lotuspod2 = { path: 'sprites/lilies/lotuspod2.png', w: 16, h: 32 }
place_lily_nearby big_lily, [lotuspod1, lotuspod2].sample
end
end
def place_lily_nearby big_lily, small_lily
small_lily_distance = -5
coin_flip = rand
small_lily_origin = if coin_flip > 0.75
{ x: big_lily.right + small_lily_distance,
y: big_lily.top + small_lily_distance }
elsif coin_flip > 0.5
{ x: big_lily.right + small_lily_distance,
y: big_lily.bottom - small_lily_distance - small_lily.h }
elsif coin_flip > 0.25
{ x: big_lily.left - small_lily_distance - small_lily.w,
y: big_lily.top }
else
{ x: big_lily.left - small_lily_distance - small_lily.w,
y: big_lily.bottom - small_lily_distance - small_lily.h }
end
small_lily.merge(x: small_lily_origin.x,
y: small_lily_origin.y,
origin: { x: small_lily_origin.x, y: small_lily_origin.y })
end
def queue_ripples
front_ripple_rect = {
x: state.keeper.x,
y: state.keeper.y,
w: 20,
h: 17
}.center_inside_rect(state.keeper)
front_ripple_rect.x += state.keeper.angle.vector_x * (state.keeper.w / 4)
front_ripple_rect.y += state.keeper.angle.vector_y * (state.keeper.h / 4)
state.queues.ripples << front_ripple_rect.merge(path: "sprites/ripples/ripple-0-front.png",
angle_anchor_x: 0.5,
angle_anchor_y: 0.5,
angle: state.keeper.angle,
dx: state.keeper.angle.vector_x * state.keeper.speed,
dy: state.keeper.angle.vector_y * state.keeper.speed)
back_ripple_rect = {
x: state.keeper.x - 10,
y: state.keeper.y,
w: 20,
h: 17
}.center_inside_rect(state.keeper)
back_ripple_rect.x -= state.keeper.angle.vector_x * (state.keeper.w / 4)
back_ripple_rect.y -= state.keeper.angle.vector_y * (state.keeper.h / 4)
state.queues.ripples << back_ripple_rect.merge(path: "sprites/ripples/ripple-0-back.png",
angle_anchor_x: 0.5,
angle_anchor_y: 0.5,
angle: state.keeper.angle,
dx: state.keeper.angle.vector_x * state.keeper.speed,
dy: state.keeper.angle.vector_y * state.keeper.speed)
end
end
$game ||= Game.new
def tick args
$game.args = args
$game.tick
end
$gtk.reset
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment