ray casting test/demo
theory found
herescript mostly ripped from
herechanges from the brain damage version (besides changing functions tween the 2 systems)
- most everything removed out of table structures, tables are slow, luaplayer is slow, this was really slow
- removed redundant math (do we really need to calc "math.pi /180" 7 times a loop?)
- removed multiple colors
- replaced floor and sky rendering with a static image
- changed rendering and ray casting properties
all of the above was done in order to get a decent frame rate, without those changes it ran full screen @ 333mhz at about 1 frame per 1-5 seconds
now @ 333mhz, its still slow, and still bogs down, but its frame rate is almost respectable (maybe 8 fps?)
why?
dunno, i got this stuck in my head over the weekend, today i happened to be up at 6 am nursing a sick cat, which means i was stuck in the spare room with my old compaq and nothing to do most of the morning
all in all it was a amusing learning experience
script:
-------------------------
-------------------------
-- crappy raycast test --
-- for luaplayer 0.20 --
-- 2008 CFDT / OSGELD --
-------------------------
-------------------------
-- basic setup
screen_width = 480
screen_height = 272
feild_of_view = 060 -- degrees
sliver_width = 010 -- thickness of wall sliver in pixels
wall_zoom = 200 -- how much to zoom the walls
ray_resolution = 0.05
slivers_per_screen = math.ceil(screen_width / sliver_width)
ang_per_sliver = feild_of_view / slivers_per_screen
pibt = (math.pi / 180)
fovbt = (feild_of_view / 2)
-- color data
color = Color.new(200, 200, 200)
bg = Image.load("bg.JPG")
-- map data
map_width = 11
map_height = 11
map_start_point_x = 2.5
map_start_point_y = 2.5
map_start_angle = 90
map =
{
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1},
{1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1},
{1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1},
{1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1},
{1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1},
{1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1},
{1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
}
-- player data
player_speed = 0.1
player_turn = 5
player_x = map_start_point_x
player_y = map_start_point_y
player_ang = map_start_angle
function get_map(x, y)
x = math.floor(x)
y = math.floor(y)
if (x < 1 or y < 1) or (x > map_width or y > map_height) then
return 1
end
return map[y][x]
end
function cast_ray(x, y, ang)
local distance = 0
local dx = math.cos(ang * pibt) * ray_resolution
local dy = math.sin(ang * pibt) * ray_resolution
repeat
x = x + dx
y = y + dy
distance = distance + ray_resolution
col = get_map(x, y)
if (col ~= 0) then
break
end
until (false)
return distance, col
end
while true do
local ox = player_x
local oy = player_y
local pad = Controls.read()
screen:clear()
screen:blit(0,0,bg)
-- controls
if pad:up() then
player_x = player_x + math.cos(player_ang * pibt) * player_speed
player_y = player_y + math.sin(player_ang * pibt) * player_speed
elseif pad:down() then
player_x = player_x - math.cos(player_ang * pibt) * player_speed
player_y = player_y - math.sin(player_ang * pibt) * player_speed
end
if pad:right() then
player_ang = (player_ang + player_turn) % 360
elseif pad:left() then
player_ang = (player_ang + 360 - player_turn) % 360
end
--
-- check bounds
if (get_map(player_x, player_y) ~= 0) then
player_x = ox
player_y = oy
end
--
-- cast rays
local sx = 0
local ang = player_ang - fovbt
local ray_len = 0
local col = 0
local height = 0
local start_wall = 0
-- start from the left and cast a ray per sliver
for s = 1, slivers_per_screen do
-- cast the ray
ray_len, col = cast_ray(player_x, player_y, ang)
ray_len = ray_len * math.cos((player_ang - ang) * pibt)
-- calulate wall height
height = math.floor(wall_zoom / ray_len)
start_wall = math.floor(136 - height / 2)
-- clip the wall to the screen
if (start_wall < 0) then
height = height + start_wall
start_wall = 0
end
if (start_wall + height > screen_height) then
height = screen_height - start_wall
end
-- draw the wall
screen:fillRect(sx, start_wall, sliver_width, height, color)
-- increase the sliver pos
sx = sx + sliver_width
-- increase the sliver angle
ang = ang + ang_per_sliver
end
screen.flip()
screen.waitVblankStart()
end
you will need an image named bg.JPG, mine is just a 480x272 image, top half dark blue, bottom half dark grey
EDIT!
i made an optimization which nearly doubled the rendering speed, which about 1/3 of that improvement was used to increase rendering quality (sharp corners vs blobby ones) the above code represents the current version