Last active
October 9, 2024 10:23
-
-
Save icculus/276845a7d22b32c21126866f0b47b7a1 to your computer and use it in GitHub Desktop.
DragonRuby Basic Gorillas
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
# 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