Skip to content

Instantly share code, notes, and snippets.

@dermotbalson
Created April 9, 2013 14:49
Show Gist options
  • Save dermotbalson/5346310 to your computer and use it in GitHub Desktop.
Save dermotbalson/5346310 to your computer and use it in GitHub Desktop.
24. Raytracing
--# Main
-- Main
function setup()
if Backup then Backup("TrackDemo 200") end
t=Track3()
parameter.boolean("Rays",true)
end
function draw()
t:draw()
end
function touched(touch)
t:touched(touch)
end
--# Track1
Track1 = class()
function Track1:init(x)
self.car={x=350,y=100}
self.FOV=75 --degrees each side
self.slice=1 --degrees per view
end
function Track1:draw()
background(128)
spriteMode(CORNER)
--create new shapes every second or sl
if counter==nil then counter=0 end
counter = counter + 1
if counter%60==1 then --every 60 redraws, or about one second
screen=image(WIDTH,HEIGHT) --draw on an image the same size as the screen
setContext(screen)
fill(0,0,255,100)
for i=1,3 do
rect(self.car.x+math.random(-200,200),self.car.y+math.random(100,500),
math.random(10,100),math.random(10,100))
ellipse(self.car.x+math.random(-200,200),self.car.y+math.random(100,500),math.random(10,100))
end
setContext()
views=self:GetRays(screen)
end
sprite(screen,0,0)
fill(255,0,0)
ellipse(self.car.x,self.car.y,20)
stroke(0,100,200,200)
strokeWidth(1)
if views~=nil then
for i,v in ipairs(views) do
line(self.car.x,self.car.y,v.x,v.y)
end
end
end
function Track1:GetRays(s)
local rays={} --to store results
local f=math.pi/180 --to convert degrees to radians
for i=-self.FOV,self.FOV,self.slice do
local d,dy,dy=0,0,0 --distance to object, and x,y position of object
for u=1,1000 do --put a limit ont he looping
local xx=self.car.x+u*math.sin(i*f) --step forward
local yy=self.car.y+u*math.cos(i*f)
--if in bounds, and pixel non blank, we've hit something
if xx>1 and xx<=WIDTH and yy>1 and yy<=HEIGHT then
local r,g,b,a=s:get(xx,yy)
if b~=0 then d=u dx=xx dy=yy break end
else break end
end
--store angle, distance and x,y position of object
if d>0 then table.insert(rays,{angle=i,dist=d,x=dx,y=dy}) end
end
return rays
end
function Track1:touched(touch)
--dummy for now
end
--# Track2
Track2 = class()
function Track2:init(x)
self.car={x=25,y=50,speed=4,angle=0}
self.FOV=75 --degrees each side
self.slice=5 --degrees per view
self.trackOffset={x=50,y=50}
self:CreateTrack()
end
function Track2:draw()
--assign temporary short names just to make code easier to read
local tx,ty=self.trackOffset.x,self.trackOffset.y
background(128)
pushStyle()
spriteMode(CORNER)
sprite(imgTrack,tx,ty)
fill(255,0,0)
ellipse(tx+self.car.x,ty+self.car.y,12)
stroke(0,100,200,200)
strokeWidth(1)
views=self:GetRays(imgTrack)
if views~=nil and Rays then
for i,v in ipairs(views) do
line(tx+self.car.x,ty+self.car.y,tx+v.x,ty+v.y)
end
end
popStyle()
self:SetNewPosition()
end
function Track2:CreateTrack()
imgTrack=image(500,400)
setContext(imgTrack)
pushStyle()
fill(0,0,0,0) --transparent
stroke(201,201,201) --white
self.TrackBlue=201 --define the track colour (blue)
strokeWidth(50)
rect(0,0,500,400)
popStyle()
setContext()
end
function Track2:GetRays(s)
local rays={} --to store results
local f=math.pi/180 --to convert degrees to radians
for i=self.car.angle-self.FOV,self.car.angle+self.FOV,self.slice do --CHANGE
local d,dy,dy=0,0,0 --distance to object, and x,y position of object
for u=1,1000 do --put a limit on the looping
local xx=self.car.x+u*math.sin(i*f) --step forward
local yy=self.car.y+u*math.cos(i*f)
--if in bounds, and pixel non blank, we've hit something
if xx>1 and xx<=WIDTH and yy>1 and yy<=HEIGHT then
local r,g,b,a=s:get(xx,yy)
if b~=self.TrackBlue then d=u dx=xx dy=yy break end
else break end
end
--store angle, distance and x,y position of object
if d>0 then table.insert(rays,{angle=i,dist=d,x=dx,y=dy}) end
end
return rays
end
function Track2:SetNewPosition()
local maxd,maxa=0,0
for i,v in ipairs(views) do
if v.dist>maxd then maxd=v.dist maxa=v.angle end
end
local f=math.pi/180 --to convert degrees to radians
self.car.x=self.car.x+self.car.speed*math.sin(maxa*f)
self.car.y=self.car.y+self.car.speed*math.cos(maxa*f)
self.car.angle=maxa
end
function Track2:touched(touch)
--dummy for now
end
--# Track3
Track3 = class()
function Track3:init(x)
self.car={x=25,y=50,speed=150,angle=0,maxTurn=2,width=6,length=12}
self.FOV=60 --degrees each side
self.slice=5 --degrees per view
self.degToRad=math.pi/180 --to convert degrees to radians
self.trackOffset={x=50,y=50}
self:CreateTrack() --create rectangular track
self:ReadTrack(imgTrack) --read track into a table in memory
end
function Track3:draw()
background(128)
pushStyle()
pushMatrix()
translate(self.trackOffset.x,self.trackOffset.y)
spriteMode(CORNER)
sprite(imgTrack,0,0)
stroke(0,100,200,200)
strokeWidth(1)
views=self:GetRays()
if views~=nil and Rays then
for i,v in ipairs(views) do
line(self.car.x,self.car.y,v.x,v.y)
end
end
rectMode(CENTER)
--draw a rectangular car, rotate and position it first --NEW
translate(self.car.x,self.car.y)
rotate(-self.car.angle)
fill(255,0,0)
stroke(255,0,0)
ellipse(0,0,self.car.width,self.car.length)
popMatrix()
popStyle()
self:SetNewPosition(DeltaTime) --NEW pass through deltatime
end
function Track3:CreateTrack()
imgTrack=image(500,400)
setContext(imgTrack)
pushStyle()
fill(0,0,0,0) --transparent
stroke(201,201,201) --white
strokeWidth(50)
rect(0,0,500,400)
popStyle()
setContext()
--imgTrack=readImage("Documents:track 2")
end
function Track3:ReadTrack(s) --NEW whole function is new
--now copy image contents into a table for faster access
self.track={}
--capture track colour from pixel at car starting position
--we only do this once so we can afford the time to look at all of r,g and b
local r,g,b=s:get(self.car.x,self.car.y)
local trackcolor=r*256*256+g*256+b
for i=1,s.width do
self.track[i]={}
for j=1,s.height do
local r,g,b=s:get(i,j)
--set table value to 1 if pixel is part of track
--otherwise leave table value nil
--this makes for a fairly small table
if r*256*256+g*256+b==trackcolor then self.track[i][j]=1 end
end
end
self.rows,self.cols=s.width,s.height
end
function Track3:GetRays()
local rays={} --to store results
for i=self.car.angle-self.FOV,self.car.angle+self.FOV,self.slice do
--calculate change in x and y for each pixel moved
--this only changes when the angle changes so do it here
local fx,fy=math.sin(i*self.degToRad),math.cos(i*self.degToRad)
local d,dx,dy=0,0,0 --distance to object, and x,y position of object
for u=1,1000 do --put a limit on the looping
local xx=math.floor(self.car.x+u*fx+.5) --step forward
local yy=math.floor(self.car.y+u*fy+.5)
--if in bounds, and table value non blank, we've hit something
if self.track[xx][yy]~=1 then
d=u dx=xx dy=yy break
end
end
--store angle, distance and x,y position of object
if d>0 then table.insert(rays,{angle=i,dist=d,x=dx,y=dy}) end
end
return rays
end
function Track3:SetNewPosition(dt)
local maxd,maxa=0,0
local z,zz=0,0
for i,v in ipairs(views) do
--to smooth turning at corners, use a weighted average of angles
z=z+v.dist --use distance as weight --NEW
zz=zz+v.angle*v.dist
end
local aa=zz/z --weighted average angle
local s=self.car.speed*dt --NEW
self.car.x=self.car.x+s*math.sin(aa*self.degToRad)
self.car.y=self.car.y+s*math.cos(aa*self.degToRad)
local u=aa-self.car.angle --NEW also next couple of lines
if u>0 then
self.car.angle=self.car.angle+math.min(self.car.maxTurn,u)
else
self.car.angle=self.car.angle+math.max(-self.car.maxTurn,u)
end
end
function Track3:touched(touch)
--dummy for now
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment