Created
April 9, 2013 14:49
-
-
Save dermotbalson/5346310 to your computer and use it in GitHub Desktop.
24. Raytracing
This file contains hidden or 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
--# 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