Skip to content

Instantly share code, notes, and snippets.

@icculus
Last active October 9, 2024 10:23
Show Gist options
  • Save icculus/276845a7d22b32c21126866f0b47b7a1 to your computer and use it in GitHub Desktop.
Save icculus/276845a7d22b32c21126866f0b47b7a1 to your computer and use it in GitHub Desktop.
DragonRuby Basic Gorillas
# This is the complete source code to Basic Gorillas:
# https://dragonruby.itch.io/basicgorillas
#
# You can tinker with this by getting a copy of DragonRuby Game Toolkit:
# https://dragonruby.org/
#
# Amir Rajan wrote this game, catch him at https://twitter.com/amirrajan !
class YouSoBasicGorillas
attr_accessor :outputs, :grid, :game, :inputs
def tick
defaults
render
calc
process_inputs
end
def defaults
game.building_spacing = 1
game.building_room_spacing = 15
game.building_room_width = 10
game.building_room_height = 15
game.building_heights = [4, 4, 6, 8, 15, 20, 18]
game.building_room_sizes = [5, 4, 6, 7]
game.gravity = 0.25
game.first_strike ||= :player_1
game.buildings ||= []
game.holes ||= []
game.player_1_score ||= 0
game.player_2_score ||= 0
game.wind ||= 0
end
def render
render_stage
render_value_insertion
render_gorillas
render_holes
render_banana
render_game_over
render_score
render_wind
end
def render_score
outputs.primitives << [:solids, 0, 0, 1280, 31, fancy_white]
outputs.primitives << [:solids, 1, 1, 1279, 29]
outputs.labels << [ 10, 25, "Score: #{game.player_1_score}", 0, 0, fancy_white]
outputs.labels << [1270, 25, "Score: #{game.player_2_score}", 0, 2, fancy_white]
end
def render_wind
outputs.primitives << [:solids, 640, 12, game.wind * 500 + game.wind * 10 * rand, 4, 35, 136, 162]
outputs.lines << [640, 30, 640, 0, fancy_white]
end
def render_game_over
return unless game.over
outputs.primitives << [:solids, grid.rect, 0, 0, 0, 200]
outputs.primitives << [:labels, 640, 370, "Game Over!!", 5, 1, fancy_white]
if game.winner == :player_1
outputs.primitives << [:labels, 640, 340, "Player 1 Wins!!", 5, 1, fancy_white]
else
outputs.primitives << [:labels, 640, 340, "Player 2 Wins!!", 5, 1, fancy_white]
end
end
def render_stage
return unless game.stage_generated
return if game.stage_rendered
outputs.static_solids << [grid.rect, 33, 32, 87]
outputs.static_solids += game.buildings.map(&:solids)
game.stage_rendered = true
end
def render_gorilla gorilla, id
return unless gorilla
if game.banana && game.banana.owner == gorilla
animation_index = game.banana.created_at.frame_index(3, 5, false)
end
if !animation_index
outputs.sprites << [gorilla.solid, "sprites/#{id}-idle.png"]
else
outputs.sprites << [gorilla.solid, "sprites/#{id}-#{animation_index}.png"]
end
end
def render_gorillas
render_gorilla game.player_1, :left
render_gorilla game.player_2, :right
end
def render_value_insertion
return if game.banana
return if game.over
if game.current_turn == :player_1_angle
outputs.labels << [ 10, 710, "Angle: #{game.player_1_angle}_", fancy_white]
elsif game.current_turn == :player_1_velocity
outputs.labels << [ 10, 710, "Angle: #{game.player_1_angle}", fancy_white]
outputs.labels << [ 10, 690, "Velocity: #{game.player_1_velocity}_", fancy_white]
elsif game.current_turn == :player_2_angle
outputs.labels << [1120, 710, "Angle: #{game.player_2_angle}_", fancy_white]
elsif game.current_turn == :player_2_velocity
outputs.labels << [1120, 710, "Angle: #{game.player_2_angle}", fancy_white]
outputs.labels << [1120, 690, "Velocity: #{game.player_2_velocity}_", fancy_white]
end
end
def render_banana
return unless game.banana
rotation = game.tick_count.%(360) * 20
rotation *= -1 if game.banana.dx > 0
outputs.sprites << [game.banana.x, game.banana.y, 15, 15, 'sprites/banana.png', rotation]
end
def render_holes
outputs.sprites += game.holes.map do |s|
animation_index = s.created_at.frame_index(7, 3, false)
if animation_index
[s.sprite, [s.sprite.rect, "sprites/explosion#{animation_index}.png" ]]
else
s.sprite
end
end
end
def calc
calc_generate_stage
calc_current_turn
calc_banana
end
def calc_current_turn
return if game.current_turn
game.current_turn = :player_1_angle
game.current_turn = :player_2_angle if game.first_strike == :player_2
end
def calc_generate_stage
return if game.stage_generated
game.buildings << building_prefab(game.building_spacing + -20, *random_building_size)
8.numbers.inject(game.buildings) do |buildings, i|
buildings <<
building_prefab(game.building_spacing +
game.buildings.last.right,
*random_building_size)
end
building_two = game.buildings[1]
game.player_1 = new_player(building_two.x + building_two.w.fdiv(2),
building_two.h)
building_nine = game.buildings[-3]
game.player_2 = new_player(building_nine.x + building_nine.w.fdiv(2),
building_nine.h)
game.stage_generated = true
game.wind = 1.randomize(:ratio, :sign)
end
def new_player x, y
game.new_entity(:gorilla) do |p|
p.x = x - 25
p.y = y
p.solid = [p.x, p.y, 50, 50]
end
end
def calc_banana
return unless game.banana
game.banana.x += game.banana.dx
game.banana.dx += game.wind.fdiv(10)
game.banana.y += game.banana.dy
game.banana.dy -= game.gravity
banana_collision = [game.banana.x, game.banana.y, 10, 10]
if game.player_1 && banana_collision.intersects_rect?(game.player_1.solid)
game.over = true
if game.banana.owner == game.player_2
game.winner = :player_2
else
game.winner = :player_1
end
game.player_2_score += 1
elsif game.player_2 && banana_collision.intersects_rect?(game.player_2.solid)
game.over = true
if game.banana.owner == game.player_2
game.winner = :player_1
else
game.winner = :player_2
end
game.player_1_score += 1
end
if game.over
place_hole
return
end
return if game.holes.any? do |h|
h.sprite.scale_rect(0.8, 0.5, 0.5).intersects_rect? [game.banana.x, game.banana.y, 10, 10]
end
return unless game.banana.y < 0 || game.buildings.any? do |b|
b.rect.intersects_rect? [game.banana.x, game.banana.y, 1, 1]
end
place_hole
end
def place_hole
return unless game.banana
game.holes << game.new_entity(:banana) do |b|
b.sprite = [game.banana.x - 20, game.banana.y - 20, 40, 40, 'sprites/hole.png']
end
game.banana = nil
end
def process_inputs_main
return if game.banana
return if game.over
if inputs.keyboard.key_down.enter
input_execute_turn
elsif inputs.keyboard.key_down.backspace
game.hash[game.current_turn] ||= ""
game.hash[game.current_turn] = game.hash[game.current_turn][0..-2]
elsif inputs.keyboard.key_down.char
game.hash[game.current_turn] ||= ""
game.hash[game.current_turn] += inputs.keyboard.key_down.char
end
end
def process_inputs_game_over
return unless game.over
return unless inputs.keyboard.key_down.truthy_keys.any?
game.over = false
outputs.static_solids.clear
game.buildings.clear
game.holes.clear
game.stage_generated = false
game.stage_rendered = false
if game.first_strike == :player_1
game.first_strike = :player_2
else
game.first_strike = :player_1
end
end
def process_inputs
process_inputs_main
process_inputs_game_over
end
def input_execute_turn
return if game.banana
if game.current_turn == :player_1_angle && parse_or_clear!(:player_1_angle)
game.current_turn = :player_1_velocity
elsif game.current_turn == :player_1_velocity && parse_or_clear!(:player_1_velocity)
game.current_turn = :player_2_angle
game.banana =
new_banana(game.player_1,
game.player_1.x + 25,
game.player_1.y + 60,
game.player_1_angle,
game.player_1_velocity)
elsif game.current_turn == :player_2_angle && parse_or_clear!(:player_2_angle)
game.current_turn = :player_2_velocity
elsif game.current_turn == :player_2_velocity && parse_or_clear!(:player_2_velocity)
game.current_turn = :player_1_angle
game.banana =
new_banana(game.player_2,
game.player_2.x + 25,
game.player_2.y + 60,
180 - game.player_2_angle,
game.player_2_velocity)
end
if game.banana
game.player_1_angle = nil
game.player_1_velocity = nil
game.player_2_angle = nil
game.player_2_velocity = nil
end
end
def random_building_size
[game.building_heights.sample, game.building_room_sizes.sample]
end
def int? v
v.to_i.to_s == v.to_s
end
def random_building_color
[[ 99, 0, 107],
[ 35, 64, 124],
[ 35, 136, 162],
].sample
end
def random_window_color
[[ 88, 62, 104],
[253, 224, 187]].sample
end
def windows_for_building starting_x, floors, rooms
floors.-(1).combinations(rooms - 1).map do |floor, room|
[starting_x +
game.building_room_width.*(room) +
game.building_room_spacing.*(room + 1),
game.building_room_height.*(floor) +
game.building_room_spacing.*(floor + 1),
game.building_room_width,
game.building_room_height,
random_window_color]
end
end
def building_prefab starting_x, floors, rooms
game.new_entity(:building) do |b|
b.x = starting_x
b.y = 0
b.w = game.building_room_width.*(rooms) +
game.building_room_spacing.*(rooms + 1)
b.h = game.building_room_height.*(floors) +
game.building_room_spacing.*(floors + 1)
b.right = b.x + b.w
b.rect = [b.x, b.y, b.w, b.h]
b.solids = [[b.x - 1, b.y, b.w + 2, b.h + 1, fancy_white],
[b.x, b.y, b.w, b.h, random_building_color],
windows_for_building(b.x, floors, rooms)]
end
end
def parse_or_clear! game_prop
if int? game.hash[game_prop]
game.hash[game_prop] = game.hash[game_prop].to_i
return true
end
game.hash[game_prop] = nil
return false
end
def new_banana owner, x, y, angle, velocity
game.new_entity(:banana) do |b|
b.owner = owner
b.x = x
b.y = y
b.angle = angle % 360
b.velocity = velocity / 5
b.dx = b.angle.vector_x(b.velocity)
b.dy = b.angle.vector_y(b.velocity)
end
end
def fancy_white
[253, 252, 253]
end
end
$you_so_basic_gorillas = YouSoBasicGorillas.new
def tick args
$you_so_basic_gorillas.outputs = args.outputs
$you_so_basic_gorillas.grid = args.grid
$you_so_basic_gorillas.game = args.game
$you_so_basic_gorillas.inputs = args.inputs
$you_so_basic_gorillas.tick
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment