Skip to content

Instantly share code, notes, and snippets.

@xenobrain
Last active August 9, 2024 13:12
Show Gist options
  • Save xenobrain/2b398d8789fc9077187025d50aa0d111 to your computer and use it in GitHub Desktop.
Save xenobrain/2b398d8789fc9077187025d50aa0d111 to your computer and use it in GitHub Desktop.
Shadowcasting in ruby
def tick(args)
grid_w = 16
grid_h = 16
args.state.grid ||= [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1,
]
if args.state.tick_count.zero? # flip grid y-axis
y = 0
while y < grid_h >> 1
x = 0
while x < grid_w
i = grid_w * y + x
j = grid_w * (grid_h - 1 - y) + x
temp = args.state.grid[i]
args.state.grid[i] = args.state.grid[j]
args.state.grid[j] = temp
x += 1
end
y += 1
end
end
args.state.start_x ||= 5
args.state.start_y ||= 5
radius = 5
args.state.start_x += args.inputs.left_right
args.state.start_y += args.inputs.up_down
visible_tiles = Array.new(grid_w * grid_h, 0)
compute_fov(args.state.grid, args.state.start_x, args.state.start_y, radius, visible_tiles)
# draw map
grid_w.times do |y|
grid_h.times do |x|
color = args.state.grid[y * grid_w + x] == 1 ? [100, 100, 100] : [0, 0, 0]
args.outputs.solids << [x * 32, y * 32, 32, 32, *color, 255]
end
end
# draw visible tiles
grid_w.times do |y|
grid_h.times do |x|
if visible_tiles[y * grid_w + x] == 1
args.outputs.solids << [x * 32, y * 32, 32, 32, 0, 255, 0, 128]
end
end
end
args.outputs.solids << [args.state.start_x * 32, args.state.start_y * 32, 32, 32, 255, 0, 0, 255]
end
MULT = [
1, 0, 0, -1, -1, 0, 0, 1,
0, 1, -1, 0, 0, -1, 1, 0,
0, 1, 1, 0, 0, -1, -1, 0,
1, 0, 0, 1, -1, 0, 0, -1
]
def compute_fov grid, grid_w, grid_h, x, y, radius, visible_tiles
visible_tiles[y * grid_w + x] = 1
radius2 = radius * radius
octant = 0
while octant < 8
row = 1
start_slope = 1.0
end_slope = 0.0
xx = MULT[octant]
xy = MULT[octant + 8]
yx = MULT[octant + 16]
yy = MULT[octant + 24]
while row <= radius
dx = -row - 1
dy = -row
blocked = false
new_start = 0.0
while dx <= 0
dx += 1
cell_x = x + dx * xx + dy * xy
cell_y = y + dx * yx + dy * yy
l_slope = (dx - 0.5) / (dy + 0.5)
r_slope = (dx + 0.5) / (dy - 0.5)
break if end_slope > l_slope
next if start_slope < r_slope
cell_index = cell_y * grid_w + cell_x
if dx * dx + dy * dy < radius2 && cell_x >= 0 && cell_y >= 0 && cell_x < grid_w && cell_y < grid_h
visible_tiles[cell_index] = 1
end
if blocked
if cell_x >= 0 && cell_y >= 0 && cell_x < grid_w && cell_y < grid_h && grid[cell_index] == 1
new_start = r_slope
else
blocked = false
start_slope = new_start
end
elsif cell_x >= 0 && cell_y >= 0 && cell_x < grid_w && cell_y < grid_h && grid[cell_index] == 1 && row < radius
blocked = true
new_start = r_slope
end
end
break if blocked
row += 1
end
octant += 1
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment