Last active
October 30, 2022 22:22
-
-
Save amirrajan/757bf21ba6f8908cdfa98a4d2923fa2e to your computer and use it in GitHub Desktop.
DragonRuby Game Toolkit - Tech Demo Source Code
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
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