Skip to content

Instantly share code, notes, and snippets.

@amirrajan
Created August 6, 2019 15:43
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save amirrajan/30be700d54d05e102f14653d7871bfa8 to your computer and use it in GitHub Desktop.
Save amirrajan/30be700d54d05e102f14653d7871bfa8 to your computer and use it in GitHub Desktop.
class Game
attr_accessor :args, :state, :inputs, :outputs, :grid
def update_line_of_sight
variations = [-1, 0, 1]
newly_visible = variations.product(variations).flat_map do |rise, run|
thick_line_of_sight state.x, state.y, rise, run, 15,
lambda { |x, y| dungeon_cell_exists? x, y }
end.uniq
state.dungeon.each do |d|
d.is_visible = newly_visible.find { |v| v.x == d.x && v.y == d.y }
end
end
def label text, x, y, color = nil
color ||= white
[x, y, text, 1, 1, *color]
end
def cell_border x, y, color = nil
[left_margin + x * grid_size,
bottom_margin + y * grid_size,
grid_size,
grid_size,
*color]
end
def green
[60, 200, 100]
end
def blue
[50, 50, 210]
end
def white
[255, 255, 255]
end
def red
[230, 80, 80]
end
def orange
[255, 80, 60]
end
def pink
[255, 0, 200]
end
def gray
[75, 75, 75]
end
def recolor_border border, r, g, b
border[4] = r
border[5] = g
border[6] = b
border
end
def left_margin
40
end
def bottom_margin
60
end
def grid_size
40
end
def render_canvas
return
outputs.borders << state.canvas.map do |c|
c.border
end
end
def export_dungeon
state.dungeon.each do |d|
puts "state.dungeon << [#{d.x}, #{d.y}]"
end
end
def print_cell_coordinates
return unless state.debug
state.dungeon.each do |d|
outputs.labels << [grid_x(d.x) + 2,
grid_y(d.y) - 2,
"#{d.x},#{d.y}",
-2, 0, *white]
end
end
def distance_to_cell cell
distance_to state.x, cell.x, state.y, cell.y
end
def distance_to from_x, x, from_y, y
(from_x - x).abs + (from_y - y).abs
end
def render_dungeon
outputs.solids << [0, 0, grid.w, grid.h]
outputs.borders << state.dungeon.map do |d|
d.alpha += if d.is_visible
255.fdiv(30)
else
255.fdiv(600) * -1
end
d.alpha = d.alpha.cap_min_max(0, 255)
cell_border d.x, d.y, [*blue, d.alpha]
end.reject_nil
end
def render_player
outputs.labels << [grid_x(state.x) + 20,
grid_y(state.y) + 35,
"@",
1, 1, *white]
end
def grid_x x
left_margin + x * grid_size
end
def grid_y y
bottom_margin + y * grid_size
end
def render_enemies
state.enemies.map do |e|
alpha = 255
if e.is_dead
alpha = 255 * state.tick_count.perc_to_zero(e.attacked_at, 30)
end
outputs.labels << [
left_margin + 20 + e.x * grid_size,
bottom_margin + 35 + e.y * grid_size,
"r",
1, 1, *white, alpha]
outputs.borders << [grid_x(e.x), grid_y(e.y), grid_size, grid_size, *red]
end
end
def visible? cell
state.visible_cells.find { |c| c.x == cell.x && c.y == cell.y}
end
def calc_canvas
return if state.canvas.length > 0
15.times do |x|
15.times do |y|
state.canvas << state.new_entity(:canvas) do |c|
c.x = x
c.y = y
c.border = [left_margin + x * grid_size,
bottom_margin + y * grid_size,
grid_size,
grid_size,
*white, 30]
end
end
end
end
def input_click_map
return unless inputs.mouse.click
canvas_entry = state.canvas.find do |c|
inputs.mouse.click.inside_rect? c.border
end
puts canvas_entry
end
def dungeon_cell_exists? x, y
state.dungeon.find { |d| d.x == x && d.y == y }
end
def enemy_at x, y
state.enemies.find { |e| e.x == x && e.y == y && !e.is_dead }
end
def input_target_cell
if inputs.keyboard.key_down.up
[state.x, state.y + 1, 0, 1]
elsif inputs.keyboard.key_down.down
[state.x, state.y - 1, 0, -1]
elsif inputs.keyboard.key_down.left
[state.x - 1, state.y, -1, 0]
elsif inputs.keyboard.key_down.right
[state.x + 1, state.y, 1, 0]
else
nil
end
end
def thick_line_of_sight start_x, start_y, rise, run, distance, cell_exists_lambda
result = []
result += line_of_sight start_x, start_y, rise, run, distance, cell_exists_lambda
result += line_of_sight start_x - 1, start_y, rise, run, distance, cell_exists_lambda
result += line_of_sight start_x + 1, start_y, rise, run, distance, cell_exists_lambda
result
end
def line_of_sight start_x, start_y, rise, run, distance, cell_exists_lambda
result = []
points = points_on_line start_x, start_y, rise, run, distance
points.each do |p|
if cell_exists_lambda.call(p.x, p.y)
result << p
else
return result
end
end
result
end
def points_on_line start_x, start_y, rise, run, distance
distance.times.map do |i|
[start_x + run * i, start_y + rise * i]
end
end
def defaults
state.canvas ||= []
state.dungeon ||= []
state.enemies ||= []
if !state.area
load_area_one
derive_dungeon_from_area
state.x = 7
state.y = 5
state.enemies << state.new_entity(:enemy) do |e|
e.x = 13
e.y = 5
e.previous_hp = 3
e.hp = 3
e.max_hp = 3
e.is_dead = false
end
update_line_of_sight
end
end
def derive_dungeon_from_area
state.dungeon = []
state.area.each do |a|
state.dungeon << state.new_entity(:dungeon_cell) do |d|
d.x = a.x
d.y = a.y
d.is_visible = false
d.alpha = 0
d.border = [left_margin + a.x * grid_size,
bottom_margin + a.y * grid_size,
grid_size,
grid_size,
*blue,
255]
d
end
end
end
def input_move
x, y, x_diff, y_diff = input_target_cell
return unless dungeon_cell_exists? x, y
return if enemy_at x, y
state.x += x_diff
state.y += y_diff
update_line_of_sight
end
def load_area_one
state.area ||= []
state.area << [8, 6]
state.area << [7, 6]
state.area << [7, 7]
state.area << [8, 9]
state.area << [7, 8]
state.area << [7, 9]
state.area << [6, 4]
state.area << [7, 3]
state.area << [7, 4]
state.area << [6, 5]
state.area << [7, 5]
state.area << [8, 5]
state.area << [8, 4]
state.area << [1, 1]
state.area << [0, 1]
state.area << [0, 2]
state.area << [1, 2]
state.area << [2, 2]
state.area << [2, 1]
state.area << [2, 3]
state.area << [1, 3]
state.area << [1, 4]
state.area << [2, 4]
state.area << [2, 5]
state.area << [1, 5]
state.area << [2, 6]
state.area << [3, 6]
state.area << [4, 6]
state.area << [4, 7]
state.area << [4, 8]
state.area << [5, 8]
state.area << [5, 9]
state.area << [6, 9]
state.area << [7, 10]
state.area << [7, 11]
state.area << [7, 12]
state.area << [7, 12]
state.area << [7, 13]
state.area << [8, 13]
state.area << [9, 13]
state.area << [10, 13]
state.area << [11, 13]
state.area << [12, 13]
state.area << [12, 12]
state.area << [8, 12]
state.area << [9, 12]
state.area << [10, 12]
state.area << [11, 12]
state.area << [12, 11]
state.area << [13, 11]
state.area << [13, 10]
state.area << [13, 9]
state.area << [13, 8]
state.area << [13, 7]
state.area << [13, 6]
state.area << [12, 6]
state.area << [14, 6]
state.area << [14, 5]
state.area << [13, 5]
state.area << [12, 5]
state.area << [12, 4]
state.area << [13, 4]
state.area << [14, 4]
state.area << [1, 6]
state.area << [6, 6]
end
def tick
defaults
render_canvas
render_dungeon
render_player
render_enemies
print_cell_coordinates
calc_canvas
input_move
input_click_map
end
end
$game = Game.new
def tick args
$game.args = args
$game.state = args.state
$game.inputs = args.inputs
$game.outputs = args.outputs
$game.grid = args.grid
$game.tick
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment