Skip to content

Instantly share code, notes, and snippets.

@dermotbalson
Created March 28, 2015 04:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dermotbalson/4062c09be05e2c4d4a91 to your computer and use it in GitHub Desktop.
Save dermotbalson/4062c09be05e2c4d4a91 to your computer and use it in GitHub Desktop.
Racing 3
--# Main
-- Main
supportedOrientations(LANDSCAPE_ANY)
displayMode(OVERLAY)
function setup()
radius,points,trackWidth,wallHeight=250,100,40,10
centre=vec2(WIDTH/2,HEIGHT/2)
track=CreateTemplate(radius,points)
maxSpeed=200
camHeight=5
crashMargin=3
AddInnerTrack()
sensPos=vec2(WIDTH/2,50)
smoothness=4 --1-7
miniSize=200
draw=drawEditor
skyColor=color(162, 192, 203, 255)
lightDirection=vec3(0,5,-1):normalize()
ambient=color(255*0.3)
diffuse=color(255*0.6)
FPS=60
parameter.integer("Smoothness",1,5,3)
parameter.action("Done editing",DoneEditing)
end
function drawEditor()
background(220)
DrawTrackEditor()
end
function DrawTrackEditor()
pushStyle()
stroke(0,0,255)
strokeWidth(2)
for i=1,points do
line(track[i].x+centre.x,track[i].y+centre.y,track[i+1].x+centre.x,track[i+1].y+centre.y)
line(track2[i].x+centre.x,track2[i].y+centre.y,track2[i+1].x+centre.x,track2[i+1].y+centre.y)
end
strokeWidth(2)
fill(255, 0, 248, 255)
line(track[1].x+centre.x,track[1].y+centre.y,track2[1].x+centre.x,track2[1].y+centre.y)
strokeWidth(0)
if CurrentTouch.state~=ENDED then
fill(255,0,0)
ellipse(CurrentTouch.x,CurrentTouch.y,20)
end
popStyle()
end
function CreateTemplate(r,p)
--create unit circular track first
local sin,cos,rad=math.sin,math.cos,math.pi*2/p
v={}
for i=1,p do
v[i]=vec2(cos(rad*(i-1)),sin(rad*(i-1)))*r
end
v[p+1]=v[1]
v[0]=v[p]
return v
end
function touched(t)
if draw==drawEditor and t.state==ENDED then DistortTrack(vec2(t.x,t.y)-centre) end
end
function DistortTrack(d)
local dn=d:normalize()
local dLen=d:len()
local max,maxi=0,0
for i=1,points do
local ti=track[i]:normalize()
local a=dn:dot(ti)
if a>0 then
a=a^(16-Smoothness*3)
track[i]=ti*(dLen*a+track[i]:len()*(1-a))
if i==1 then track[points+1]=track[i] end
if i==points then track[0]=track[i] end
end
end
AddInnerTrack()
end
function AddInnerTrack()
--create inner set of points
track2={}
for i=1,points do
track2[i]=track[i]*(1-trackWidth/track[i]:len())
end
track2[points+1]=track2[1]
track2[0]=track2[points]
end
function DoneEditing()
CreateTrack()
AddPeople()
miniTrack=CreateMiniTrack()
car=MakeCarFrontImage()
draw=DrawRacing
pos=vec3((track[1].x+track2[1].x)/2,5,(track[1].y+track2[1].y)/2)
local pos2=vec3((track[2].x+track2[2].x)/2,camHeight,(track[2].y+track2[2].y)/2)
currSquare=1
local d=(pos2-pos):normalize()
local d=-vec3(-(track[2].y-track2[2].y),pos.y,track[2].x-track2[2].x):normalize()
angle=math.rad(math.atan2(d.y/d.x))
speed=0
lastSquare=1
displayMode(FULLSCREEN)
end
function CreateMiniTrack()
local img=image(WIDTH,HEIGHT)
setContext(img)
DrawTrackEditor()
setContext()
local x1,x2,y1,y2=math.floor(centre.x+minX),math.floor(centre.x+maxX),
math.floor(centre.y+minY),math.floor(centre.y+maxY)
local img2=img:copy(x1,y1,x2-x1,y2-y1)
miniScale=miniSize/math.max(maxX-minX,maxY-minY)
miniPos=vec2(WIDTH-miniScale*img2.width-2,HEIGHT-2)
miniWidth=img2.width*miniScale
miniHeight=img2.height*miniScale
return img2
end
function MakeCarFrontImage()
local img=image(280,250)
setContext(img)
pushStyle()
pushMatrix()
fill(0)
rect(20,0,50,60)
rect(220,0,50,60)
strokeWidth(0)
fill(255,0,0)
rect(103,0,84,232)
popMatrix() pushMatrix()
translate(40,0)
rotate(-15)
rect(0,0,80,240)
popMatrix() pushMatrix()
translate(170,-20)
rotate(15)
rect(0,0,80,240)
popMatrix() pushMatrix()
fill(255)
ellipse(145,150,100)
fontSize(64)
fill(0)
text("1",145,150)
popMatrix()
setContext()
popStyle()
local img2=image(img.width*1.5,img.height*0.5)
setContext(img2)
sprite(img,img2.width/2,img2.height/2,img2.width,img2.height)
setContext()
return img2
end
function SetupLighting(m)
m.shader=shader(TileShader.vertexShader,TileShader.fragmentShader)
--m.shader=shader(SurfaceShader.vertexShader,SurfaceShader.fragmentShader)
--m.shader.lightDirection=lightDirection
--m.shader.ambient=ambient
--m.shader.diffuse=diffuse
return m
end
function CreateTrack()
local img=DrawTrackImage(100,100,8)
--calculate bounds of track
minX,maxX,minY,maxY=9999,-9999,9999,-9999
for i=1,points do
minX=math.min(track[i].x,minX)
minY=math.min(track[i].y,minY)
maxX=math.max(track[i].x,maxX)
maxY=math.max(track[i].y,maxY)
end
local v,t,n={},{},{}
local k=0.25
local tw,th=1/img.width/k,1/img.height/k
local cw,ch=minX*tw,minY*th
for i=1,points do
local v11=vec3(track[i].x,0,track[i].y)
local v21=vec3(track2[i].x,0,track2[i].y)
local v22=vec3(track2[i+1].x,0,track2[i+1].y)
local v12=vec3(track[i+1].x,0,track[i+1].y)
local t11=vec2(v11.x*tw-cw,v11.z*th-ch)
local t21=vec2(v21.x*tw-cw,v21.z*th-ch)
local t22=vec2(v22.x*tw-cw,v22.z*th-ch)
local t12=vec2(v12.x*tw-cw,v12.z*th-ch)
v[#v+1]=v11 t[#t+1]=t11
v[#v+1]=v21 t[#t+1]=t21
v[#v+1]=v22 t[#t+1]=t22
v[#v+1]=v22 t[#t+1]=t22
v[#v+1]=v12 t[#t+1]=t12
v[#v+1]=v11 t[#t+1]=t11
end
for i=1,#v do n[i]=vec3(0,1,0) end
local m=mesh()
m.vertices=v
m.texCoords=t
m.normals=n
m.texture=img
m:setColors(color(255))
m.shader=shader(TileShader.vertexShader,TileShader.fragmentShader)
m=SetupLighting(m)
trackMesh=m
--calculate centre point of each square
trackCentre,trackAve={},{}
for i=1,points do
local a=(track[i]+track2[i]+track[i+1]+track2[i+1])/4
trackCentre[i]=vec3(a.x,camHeight,a.y)
trackAve[i]=(a:dist(track[i])+a:dist(track[i+1])+a:dist(track2[i])+a:dist(track2[i+1]))/4
end
trackCentre[0]=trackCentre[points]
trackCentre[points+1]=trackCentre[1]
trackAve[0]=trackAve[points]
trackAve[points+1]=trackAve[1]
--create side walls
local img=DrawCrowdImage()
local Scale=1
local ww,hh=img.width*Scale,img.height*Scale
local v,t,n={},{},{}
--local f=wallHeight/img.height
local cw,ch=0,0
local cw2,ch2=0,0
for i=1,points do
--outer wall
local v11=vec3(track[i].x,0,track[i].y)
local v21=vec3(track[i+1].x,0,track[i+1].y)
local v22=vec3(track[i+1].x,hh,track[i+1].y)
local v12=vec3(track[i].x,hh,track[i].y)
cw1=cw+track[i]:dist(track[i+1])/ww
local t11=vec2(cw,0)
local t21=vec2(cw1,0)
local t22=vec2(cw1,1)
local t12=vec2(cw,1)
cw=cw1
v[#v+1]=v11 t[#t+1]=t11
v[#v+1]=v21 t[#t+1]=t21
v[#v+1]=v22 t[#t+1]=t22
v[#v+1]=v22 t[#t+1]=t22
v[#v+1]=v12 t[#t+1]=t12
v[#v+1]=v11 t[#t+1]=t11
--normals
local v1,v2=(v21-v11):normalize(),(v22-v11):normalize()
local nn=v1:cross(v2)
for j=1,6 do n[#n+1]=nn end
--inner wall
local v11=vec3(track2[i].x,0,track2[i].y)
local v21=vec3(track2[i+1].x,0,track2[i+1].y)
local v22=vec3(track2[i+1].x,hh,track2[i+1].y)
local v12=vec3(track2[i].x,hh,track2[i].y)
cw1=cw2-track2[i]:dist(track2[i+1])/ww
local t11=vec2(cw2,0)
local t21=vec2(cw1,0)
local t22=vec2(cw1,1)
local t12=vec2(cw2,1)
cw2=cw1
v[#v+1]=v11 t[#t+1]=t11
v[#v+1]=v21 t[#t+1]=t21
v[#v+1]=v22 t[#t+1]=t22
v[#v+1]=v22 t[#t+1]=t22
v[#v+1]=v12 t[#t+1]=t12
v[#v+1]=v11 t[#t+1]=t11
--normals
local v1,v2=(v21-v11):normalize(),(v22-v11):normalize()
local nn=v1:cross(v2)
for j=1,6 do n[#n+1]=nn end
end
local m=mesh()
m.vertices=v
m.texCoords=t
m.normals=n
m.texture=img
m:setColors(color(255))
m.shader=shader(TileShader.vertexShader,TileShader.fragmentShader)
m=SetupLighting(m)
sideMesh=m
end
function AddPeople()
local img={readImage("Planet Cute:Character Boy"),readImage("Planet Cute:Character Pink Girl"),
readImage("Planet Cute:Character Horn Girl"),readImage("Planet Cute:Character Cat Girl"),
readImage("Planet Cute:Character Princess Girl")}
people={}
scale=0.1
for i=1,#img do
local w,h=img[i].width*0.1,img[i].height*0.1
local m=mesh()
m.vertices={vec2(-w/2,-h/2),vec2(w/2,-h/2),vec2(w/2,h/2),vec2(w/2,h/2),vec2(-w/2,h/2),vec2(-w/2,-h/2)}
m.texCoords={vec2(0,0),vec2(1,0),vec2(1,1),vec2(1,1),vec2(0,1),vec2(0,0)}
m.texture=img[i]
people[i]=m
end
crowd={}
for i=1,points*2 do
local r=math.random(1,#img)
local p,rot,d
if i<=points then
d=(track[i]-track2[i]):normalize() --direction of this tile
p=vec3(track[i].x,wallHeight+1.5,track[i].y)+vec3(d.x,0,d.y)*10
else
local j=i-points
d=(track[j]-track2[j]):normalize() --direction of this tile
p=vec3(track2[j].x,wallHeight+1.5,track2[j].y)-vec3(d.x,0,d.y)*10
end
local rot=math.deg(math.atan(-d.y/d.x))
local e=math.random()
local h=math.random()*0.4
crowd[i]={r,p,e,h,rot}
end
end
function DrawRacing()
background(skyColor)
FPS=FPS*0.9+.1/DeltaTime
perspective()
AdjustDriving()
camera(pos.x,pos.y,pos.z,pos.x+math.sin(angle),pos.y,pos.z-math.cos(angle))
DrawMesh(trackMesh)
DrawCrowd()
DrawMesh(sideMesh)
DrawHUD()
end
function DrawMesh(m)
--m.shader.mModel=modelMatrix()
m:draw()
end
function AdjustDriving()
speed=math.max(0,math.min(maxSpeed,speed+Gravity.y))
if speed>0 and not startTime then startTime=ElapsedTime end
angle=angle+Gravity.x/100
local p=pos+speed*vec3(math.sin(angle),0,-math.cos(angle))*DeltaTime
--check we are on the track
--first get the square we are in
--check if we have moved to the next square, if so, adjust
local mind,currSquare=999999,0
for i=1,points do
local d=pos:dist(trackCentre[i])
if d<mind then mind,currSquare=d,i end
end
if p:dist(trackCentre[currSquare])>trackAve[currSquare]-crashMargin then
speed=0
pos=trackCentre[currSquare]
crashing=true
crashDetails={currSquare,trackAve[currSquare],pos:dist(trackCentre[currSquare]),
pos,trackCentre[currSquare]}
else
pos=p
crashing=nil
end
if currSquare<lastSquare and ElapsedTime-startTime>20 then
lapTime=ElapsedTime-startTime
startTime=ElapsedTime
end
lastSquare=currSquare
end
function DrawCrowd()
local p
for i=1,#crowd do
local c=crowd[i]
local p=c[2]
p.y=p.y+math.sin(ElapsedTime*15+c[3])*c[4]
pushMatrix()
translate(p:unpack())
rotate(c[5],0,1,0)
people[c[1]]:draw()
popMatrix()
end
end
function DrawHUD()
ortho()
viewMatrix(matrix())
pushStyle()
spriteMode(CORNER)
sprite(miniTrack,miniPos.x,miniPos.y,miniWidth,-miniHeight)
fill(255,255,0)
local p=miniPos+vec2(pos.x-minX,-(pos.z-minY))*miniScale
ellipse(p.x,p.y,10)
local b=vec2(math.random()-0.5,math.random()-0.5)*speed/10
sprite(car,WIDTH/2-car.width/2+b.x,b.y)
fill(255)
fontSize(18)
textMode(CORNER)
text("Speed: "..math.floor(speed),550,HEIGHT-50)
if startTime then text("Time: "..string.format("%0.1f",ElapsedTime-startTime),550,HEIGHT-75) end
if lapTime then text("Lap time: "..string.format("%0.1f",lapTime),550,HEIGHT-100) end
text("FPS: "..math.floor(FPS),25,HEIGHT-25)
if crashing then
text("square="..crashDetails[1],500,HEIGHT-50)
text("limit="..crashDetails[2],500,HEIGHT-75)
text("dist="..crashDetails[3],500,HEIGHT-100)
text("pos="..tostring(crashDetails[4]),500,HEIGHT-125)
text("ave pos="..tostring(crashDetails[5]),500,HEIGHT-150)
end
popStyle()
end
function DrawTrackImage()
local img=readImage("SpaceCute:Background")
setContext(img)
fill(90, 77, 77, 150)
rect(-3,-3,img.width+6,img.height+6)
setContext()
return img
end
function DrawCrowdImage()
local img=image(100,wallHeight)
fill(178, 122, 91, 255)
stroke(74, 58, 52, 255)
strokeWidth(1)
pushStyle()
noSmooth()
setContext(img)
rect(0,0,img.width+1,img.height-2)
fill(74,58,52,150)
fontSize(4)
text("Codea rules",img.width/2,img.height*0.4)
setContext()
popStyle()
return img
end
function LookAtMatrix(source,target,up)
local Z=(source-target):normalize()
up=up or vec3(0,1,0)
local X=(up:cross(Z)):normalize()
local Y=(Z:cross(X)):normalize()
return matrix(X.x,X.y,X.z,0,Y.x,Y.y,Y.z,0,Z.x,Z.y,Z.z,0,source.x,source.y,source.z,1)
end
--# Shader
TileShader = {
vertexShader = [[
uniform mat4 modelViewProjection;
attribute vec4 position;
attribute vec4 color;
attribute vec2 texCoord;
varying lowp vec4 vColor;
varying highp vec2 vTexCoord;
void main()
{
vColor=color;
vTexCoord = texCoord;
gl_Position = modelViewProjection * position;
}
]],
fragmentShader = [[
precision highp float;
uniform lowp sampler2D texture;
varying lowp vec4 vColor;
varying highp vec2 vTexCoord;
void main()
{
lowp vec4 col = texture2D( texture, vec2(mod(vTexCoord.x,1.0), mod(vTexCoord.y,1.0)));
gl_FragColor = col;
}
]]}
SurfaceShader = {
vertexShader = [[
uniform mat4 modelViewProjection;
uniform mat4 mModel;
uniform vec3 lightDirection;
uniform vec4 diffuse;
attribute vec4 position;
attribute vec4 color;
attribute vec2 texCoord;
attribute vec3 normal;
varying lowp vec4 vColor;
varying highp vec2 vTexCoord;
varying lowp vec4 vDiffuse;
void main()
{
vColor=color;
vTexCoord = texCoord;
gl_Position = modelViewProjection * position;
vec4 n=mModel*vec4(normal,0.0);
vDiffuse=diffuse*clamp(dot(normalize(n.xyz),lightDirection), 0.0, 1.0);
}
]],
fragmentShader = [[
precision highp float;
uniform lowp sampler2D texture;
uniform vec4 ambient;
varying lowp vec4 vColor;
varying highp vec2 vTexCoord;
varying lowp vec4 vDiffuse;
void main()
{
lowp vec4 col = texture2D( texture, vec2(mod(vTexCoord.x,1.0), mod(vTexCoord.y,1.0)));
if (col.a==0.0) discard;
else {
col = col * (ambient + vDiffuse);
col.a=1.0;
gl_FragColor = col;
}
}
]]}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment