Created
March 28, 2015 04:29
-
-
Save dermotbalson/4062c09be05e2c4d4a91 to your computer and use it in GitHub Desktop.
Racing 3
This file contains 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 | |
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