Created
March 21, 2018 19:33
-
-
Save D-Robot-M/8d65fa447442e6092e80fdbd2e4031de to your computer and use it in GitHub Desktop.
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 | |
function setup() | |
displayMode(FULLSCREEN) | |
tree=readImage("Documents:tree") | |
grass=readImage("Documents:grass") | |
gun= readImage("Documents:deagle") | |
imageStatus="Ready" | |
setup2() | |
end | |
function setup2() | |
parameter.integer("Viewpoint",-2000,2000,20) | |
Visibility = 2000 | |
sh=ZombieShader | |
speed,angle=0,0 | |
ds,da=0,0 | |
count=0 | |
FPS=60 | |
posX,posY,posZ=-60,82,205 --starting position | |
posX = math.floor(posX) | |
posY = math.floor(posY) | |
posZ = math.floor(posZ) | |
score=0 | |
health=100 | |
wraiths=25 | |
Joystick.init() | |
minLight=0 | |
meshTable={} | |
meshTable[1],meshTable[2]={},{} | |
--AddLevel(-500,0,0,1000,1000,gravel,.1) | |
HM={} --holds height maps, one for each terrain area we build -- NEW | |
--add a terrain area --NEW | |
AddTerrain({x=-400,y=0.5,z=100,width=800,depth=800,c=color(20,50,20,255), | |
tileSize=50,minY=10,maxY=100,random=false,img=grass, | |
noiseLevel=.2,noiseStep=.5,scaleFactor=.1,heightMaps=HM}) | |
--add trees | |
for i=1,50 do | |
local x=math.random(-375,375) | |
local z=math.random(150,750) | |
local w=math.random(20,60) | |
AddItem(x,0,z,w,tree) --rotating to face us | |
end | |
for i=1,4 do | |
local x=math.random(-375,375) | |
local z=math.random(150,750) | |
local w=math.random(20,60) | |
AddItem(x,0,z,10,gun) | |
end | |
end | |
function draw() | |
count=count+1 | |
ThreeDT.preDraw() | |
background(5, 152, 239, 255) | |
perspective(45,WIDTH/HEIGHT) | |
if Viewpoint<10 then Viewpoint=10 end | |
angle=angle+da*DeltaTime | |
movex = ds*DeltaTime*math.sin(math.rad(angle)) | |
movez = ds*DeltaTime*math.cos(math.rad(angle)) | |
posX,posZ=posX+movex,posZ+ movez | |
if posZ < 101 then | |
posZ = 100 | |
end | |
if posZ > 901 then | |
posZ = 901 | |
end | |
if posX < -391 then | |
posX = -391 | |
end | |
if posX > 401 then | |
posX = 401 | |
end | |
local h0=posY --NEW | |
posY=math.max(Viewpoint,HeightAtPos(posX,posZ)+10) --NEW | |
local h1=posY --NEW | |
--try to look up if climbing or down if descending --NEW | |
if posY==Viewpoint then lookY=20 else lookY=(h1-h0)*100/ds+10 end | |
--look in the same direction as we are facing | |
lookX,lookY,lookZ=posX+1000*math.sin(math.rad(angle)),20,posZ+1000*math.cos(math.rad(angle)) | |
camera(posX,posY,-posZ,lookX,lookY,-lookZ, 0,1,0) | |
if count%61==1 then | |
table.sort(meshTable[2], | |
function(a,b) return | |
vec2(posX,-posZ):dist(vec2(a.pos.x,-a.pos.z))>vec2(posX,-posZ):dist(vec2(b.pos.x,-b.pos.z)) end) | |
end | |
for k=1,2 do | |
for i,m in pairs(meshTable[k]) do | |
--rotate free standing objects if required, so they face us | |
m.shader.dist=Visibility | |
m.shader.minLight=minLight | |
--m.shader.id=0 | |
if m.rotate==true and count%31==1 then | |
pushMatrix() | |
if m.id~=nil then m.pos.y=HeightAtPos(m.pos.x,m.pos.z)+charHeight end | |
translate(m.pos.x,m.pos.y,-m.pos.z) | |
local dx,dz=m.pos.x-posX,-m.pos.z+posZ | |
local ang=math.deg(math.atan(dx/-dz)) | |
rotate(-ang,0,1,0) | |
m.shader.pos=vec2(posX-m.pos.x,m.pos.z-posZ) | |
m.ang=ang | |
ThreeDT.drawMesh(m) | |
--m:draw() | |
popMatrix() | |
elseif m.ang==nil then | |
m.shader.pos=vec2(posX,-posZ) | |
--m:draw() | |
ThreeDT.drawMesh(m) | |
else | |
pushMatrix() | |
translate(m.pos.x,m.pos.y,-m.pos.z) | |
rotate(-m.ang,0,1,0) | |
m.shader.pos=vec2(posX-m.pos.x,m.pos.z-posZ) | |
ThreeDT.drawMesh(m) | |
--m:draw() | |
popMatrix() | |
end | |
end | |
end | |
local hit=ThreeDT.CheckHit() | |
if hit~=nil then | |
print("hit",hit) | |
sound(SOUND_POWERUP, 47963) | |
score = score + 1 | |
DeleteItem(hit) | |
end | |
ortho() --this is needed to get text written on the screen | |
viewMatrix(matrix()) --and this | |
pushStyle() | |
fill(0) fontSize(18) strokeWidth(3) textMode(CORNER) | |
text("Health="..string.format("% d",health),50,HEIGHT-90) | |
text(posX, 100, 200) | |
text(posZ, 100, 250) | |
popStyle() | |
Joystick:draw() | |
end | |
function AddTerrain(...) | |
local x,y,z,w,d,c,p,f,h,r,n,tbl,img,sc,hm,ns=Params( | |
{"x","y","z","width","depth","c","tileSize","minY","maxY","random","noiseLevel", | |
"heightTable","img","scaleFactor","heightMaps","noiseStep"},{...}) | |
local nw,nd=math.floor(w/p),math.floor(d/p) --number of tiles in each direction | |
--if no table of heights provided, generate one with noise | |
if tbl==nil then | |
n=n or 0.2 --default noise level | |
tbl1,tbl2={},{} | |
--noise starts at 0 on the outside, increases by the step as we move inward, max of 1 | |
--noise is nil at edge, increases by 30% per tile inwards, to 100% | |
local min,max=9999,0 | |
--if user wants a random result each time. add a random number to the noise results | |
if r==true then rnd=math.random(1,10000) else rnd=0 end | |
for i=1,nw+1 do | |
tbl1[i],tbl2[i]={},{} | |
for j=1,nd+1 do | |
--noise fraction for this tile, based on how close to the edge it is | |
--this formula counts how many rows in from the edge this tile is | |
tbl1[i][j]=math.min(1,math.min(i-1,j-1,nw+1-i,nd+1-j)*ns) | |
--the noise itself | |
tbl2[i][j]=noise(rnd+i*n, rnd+j*n) | |
--keep track of min and max values of noise | |
if tbl2[i][j]<min then min=tbl2[i][j] end | |
if tbl2[i][j]>max then max=tbl2[i][j] end | |
end | |
end | |
--now go back through the whole array and scale it | |
--we know the user wants values between f and h | |
--we know our noise varies between min and max | |
--so now we pro rate all our values so they vary between f and h, based on the noise values | |
for i=1,nw+1 do | |
for j=1,nd+1 do | |
local f1=y | |
--pro rate | |
local f2=f+(h-f)*(tbl2[i][j]-min)/(max-min) | |
--now apply noise fraction, to reduce noise around the edges | |
tbl2[i][j]=f1*(1-tbl1[i][j])+f2*tbl1[i][j] | |
end | |
end | |
end | |
--store details for later use in determining height | |
table.insert(hm,{x1=x,z1=z,x2=x+w,z2=z+d,p=p,t=tbl2}) | |
--create the vectors and mesh | |
if img==nil then | |
img=image(10,10) | |
setContext(img) | |
background(c) | |
setContext() | |
end | |
local wx,wz=img.width*sc,img.height*sc | |
v,t={},{} | |
for i=1,nw do | |
for j=1,nd do | |
local x1,x2=x+(i-1)*p,x+i*p local x3,x4=x2,x1 | |
local y1,y2,y3,y4=tbl2[i][j],tbl2[i+1][j],tbl2[i+1][j+1],tbl2[i][j+1] | |
local z1,z3=z+(j-1)*p,z+j*p local z2,z4=z1,z3 | |
v[#v+1]=vec3(x1,y1,-z1) t[#t+1]=vec2(x1/wx,z1/wz) --bottom left | |
v[#v+1]=vec3(x2,y2,-z2) t[#t+1]=vec2(x2/wx,z2/wz) --bottom right | |
v[#v+1]=vec3(x3,y3,-z3) t[#t+1]=vec2(x3/wx,z3/wz) --top right | |
v[#v+1]=vec3(x3,y3,-z3) t[#t+1]=vec2(x3/wx,z3/wz) --top right | |
v[#v+1]=vec3(x4,y4,-z4) t[#t+1]=vec2(x4/wx,z4/wz) --top left | |
v[#v+1]=vec3(x1,y1,-z1) t[#t+1]=vec2(x1/wx,z1/wz) --bottom left | |
end | |
end | |
local m=mesh() | |
m.texture=img | |
m.vertices=v | |
m:setColors(color(255)) | |
m.texCoords=t | |
m.pos=vec3(x,y,z) | |
m.shader = shader(sh.vertexShader, sh.fragmentShader) | |
table.insert(meshTable[1],m) | |
end | |
ThreeDT={} | |
function ThreeDT.setShader(m) | |
m.shader=shader(idShader.vertexShader,idShader.fragmentShader) | |
m.shader.id=0 | |
end | |
function ThreeDT.touched(touch) | |
if touch.state==ENDED then | |
ThreeDT.t=vec2(touch.x,touch.y) | |
end | |
end | |
function ThreeDT.preDraw() | |
if ThreeDT.t~=nil then --draw on hidden image if we've had a hit | |
setContext(ThreeDT.img) | |
clip(ThreeDT.t.x-1,ThreeDT.t.y-1,2,2) | |
end | |
--set up hidden image if not done | |
if ThreeDT.img==nil then | |
ThreeDT.img=image(WIDTH,HEIGHT) | |
ThreeDT.t=nil | |
end | |
beingAttacked=false | |
end | |
function ThreeDT.drawMesh(m) | |
--if we have a touch, set pixels with id number | |
if ThreeDT.t~=nil then | |
if m.id~=nil then m.shader.id=m.id/255 end | |
m:draw() | |
m.shader.id=0 | |
else | |
if m.id~=nil then | |
local c=chars[m.id] | |
local u,d | |
d=vec2(posX,posZ):dist(vec2(m.pos.x,m.pos.z)) | |
if d<attackDist then u=3 else u=1 end | |
if u~=c.a then c.a=u c.f=0 end | |
if count%charFrameSpeed==1 or c.f==0 then | |
local a=anim[c.a] | |
c.f=c.f+1 | |
if c.f>#anim[c.a].Left then c.f=1 end | |
m:setRectTex(1,a.Left[c.f],a.Bottom,a.Width,a.Height) | |
end | |
if c.a==3 then | |
if d<5 then | |
health=health-0.2 | |
beingAttacked=true | |
else | |
m.pos.x=m.pos.x+(posX-m.pos.x)*charSpeed/d | |
m.pos.z=m.pos.z+(posZ-m.pos.z)*charSpeed/d | |
end | |
end | |
end | |
m:draw() | |
end | |
end | |
function ThreeDT.CheckHit() | |
if ThreeDT.t==nil then return end | |
sound(SOUND_EXPLODE, 21148) | |
setContext() | |
clip() | |
ThreeDT.t=nil | |
end | |
--calculates height at x,z | |
function HeightAtPos(x,z) | |
--identify the location and calculate height | |
local h=0 --set default as 0 | |
for i,v in pairs(HM) do --look in each terrain area | |
if x>=v.x1 and x<=v.x2 and z>=v.z1 and z<=v.z2 then --if in this area... | |
--calc which square we are in | |
local mx,mz=1+math.floor((x-v.x1)/v.p),1+math.floor((z-v.z1)/v.p) | |
--use bilinear interpolation (most common method) for interpolating 4 corner values | |
local px,pz=1+(x-v.x1)/v.p-mx,1+(z-v.z1)/v.p-mz | |
h=v.t[mx][mz]*(1-px)*(1-pz)+ | |
v.t[mx+1][mz]*px*(1-pz)+ | |
v.t[mx+1][mz+1]*px*pz+ | |
v.t[mx][mz+1]*(1-px)*pz | |
break | |
end | |
end | |
return h | |
end | |
function AddItem(x,y,z,w,i,r,id) --centred on x | |
y=HeightAtPos(x,z) | |
local h=i.height*w/i.width | |
local m=mesh() | |
m.texture=i | |
local v,t={},{} | |
v,t=AddImage(-w/2,0,0,w,h,0,v,t) | |
m.pos=vec3(x,y,z) | |
if r~=nil then m.ang=r else m.rotate=true end | |
m.vertices=v | |
m:setColors(color(255)) | |
m.texCoords=t | |
m.shader = shader(sh.vertexShader, sh.fragmentShader) | |
if id~=nil then m.id=id end | |
table.insert(meshTable[2],m) | |
end | |
function DeleteItem(id) | |
for i,m in pairs(meshTable[2]) do | |
if m.id==id then table.remove(meshTable[2],i) return end | |
end | |
end | |
function AddImage(x,y,z,w,h,d,v,t) | |
v[#v+1]=vec3(x,y,z) t[#t+1]=vec2(0,0) | |
v[#v+1]=vec3(x+w,y,z-d) t[#t+1]=vec2(1,0) | |
v[#v+1]=vec3(x+w,y+h,z-d) t[#t+1]=vec2(1,1) | |
v[#v+1]=vec3(x+w,y+h,z-d) t[#t+1]=vec2(1,1) | |
v[#v+1]=vec3(x,y+h,z) t[#t+1]=vec2(0,1) | |
v[#v+1]=vec3(x,y,z) t[#t+1]=vec2(0,0) | |
return v,t | |
end | |
function AddLevel(x,y,z,w,d,i,s) | |
local m=mesh() | |
m.texture=i | |
local v,t={},{} | |
local nx,nz=w/i.width/s,d/i.height/s | |
v[#v+1]=vec3(x,y,-z) t[#t+1]=vec2(0,0) | |
v[#v+1]=vec3(x+w,y,-z) t[#t+1]=vec2(nx,0) | |
v[#v+1]=vec3(x+w,y,-z-d) t[#t+1]=vec2(nx,nz) | |
v[#v+1]=vec3(x+w,y,-z-d) t[#t+1]=vec2(nx,nz) | |
v[#v+1]=vec3(x,y,-z-d) t[#t+1]=vec2(0,nz) | |
v[#v+1]=vec3(x,y,-z) t[#t+1]=vec2(0,0) | |
m.vertices=v | |
m:setColors(color(255)) | |
m.texCoords=t | |
m.pos=vec3(x,y,z) | |
m.shader = shader(sh.vertexShader, sh.fragmentShader) | |
table.insert(meshTable[1],m) | |
end | |
function touched(touch) | |
if touch.state==BEGAN then return end | |
print(touch.state) | |
local dds,dda=Joystick.touched(touch) | |
if dda~=nil then | |
ds=ds+dds | |
da=da+dda | |
elseif dds==0 then ds,da=0,0 | |
else ThreeDT.touched(touch) end | |
end | |
function Params(list,tbl) --tbl is params | |
if type(tbl[1])=="table" then --was named table | |
local t={} --match the named params with the list provided | |
for n,v in pairs(tbl[1]) do | |
for i=1,#list do | |
if n==list[i] then t[i]=v break end | |
end | |
end | |
return unpack(t) | |
else --was an unnamed list, return it as is | |
return unpack(tbl) | |
end | |
end | |
ZombieShader = { | |
vertexShader = [[ | |
// | |
// A basic vertex shader | |
// | |
//This is the current model * view * projection matrix | |
// Codea sets it automatically | |
uniform mat4 modelViewProjection; | |
uniform vec2 pos; | |
uniform float dist; | |
uniform float mist; | |
uniform float minLight; | |
//This is the current mesh vertex position, color and tex coord | |
// Set automatically | |
attribute vec4 position; | |
attribute vec4 color; | |
attribute vec2 texCoord; | |
//This is an output variable that will be passed to the fragment shader | |
varying lowp vec4 vColor; | |
varying highp vec2 vTexCoord; | |
void main() | |
{ | |
//Pass the mesh color to the fragment shader | |
float d=distance(pos,vec2(position.x,position.z)); | |
float j=clamp(1.-d/dist,0.,1.); | |
float jj=j*j; | |
vec4 c=color; | |
if (mist==0.) {c.rg = c.rg*max(minLight,j); | |
c.b = c.b*jj;} | |
else c=c*j; | |
vColor=c; | |
vTexCoord = texCoord; | |
//Multiply the vertex position by our combined transform | |
gl_Position = modelViewProjection * position; | |
} | |
]], | |
fragmentShader = [[ | |
// | |
// A basic fragment shader | |
// | |
//Default precision qualifier | |
precision highp float; | |
//This represents the current texture on the mesh | |
uniform lowp sampler2D texture; | |
uniform float id; | |
//The interpolated vertex color for this fragment | |
varying lowp vec4 vColor; | |
//The interpolated texture coordinate for this fragment | |
varying highp vec2 vTexCoord; | |
void main() | |
{ | |
//Sample the texture at the interpolated coordinate | |
lowp vec4 col = texture2D( texture, vec2(mod(vTexCoord.x,1.0), mod(vTexCoord.y,1.0))) * vColor; | |
//Set the output color to the texture color | |
if (col.a==0.) discard; | |
else if (id==0. || col.a<0.2) gl_FragColor=col; | |
else gl_FragColor = vec4(id,0.,0.,1.); | |
} | |
]]} | |
--# Joystick | |
--Joystick | |
Joystick={} | |
function Joystick.init(diam,corner,dm,da,sens) | |
Joystick.diam=diam or 150 | |
Joystick.centreDiam=Joystick.diam*.4 | |
Joystick.r=Joystick.diam/2*.707 | |
Joystick.changeLocation(corner or 1) --1 to 4 | |
Joystick.deltaMove=dm or 2 | |
Joystick.deltaAngle=da or 2 | |
Joystick.sensitivity=sens or 3 --1 to 5 | |
Joystick.drawImage() | |
end | |
function Joystick.drawImage() | |
Joystick.img=image(Joystick.diam,Joystick.diam) | |
setContext(Joystick.img) | |
pushStyle() | |
local m=2 | |
local d,r=Joystick.diam,Joystick.r | |
fill(134, 186, 210, 255) | |
ellipse(m+d/2,m+d/2,d) | |
local xc,yc=m+d/2,m+d/2 | |
strokeWidth(4) | |
stroke(0,0,0,20) | |
line(xc-r,yc-r,xc+r,yc+r) | |
line(xc-r,yc+r-2,xc+r,yc-r-2) | |
fill(110, 146, 185, 255) | |
strokeWidth(1) | |
ellipse(m+d/2,m+d/2,Joystick.centreDiam) | |
popStyle() | |
setContext() | |
end | |
function Joystick.changeLocation(c) | |
local a={{0,50},{0,HEIGHT-Joystick.diam},{WIDTH-Joystick.diam,0}, | |
{WIDTH-Joystick.diam,HEIGHT-Joystick.diam}} | |
Joystick.pos=vec2(a[c][1],a[c][2]) | |
--print(a[c][1],a[c][2]) | |
end | |
function Joystick.draw() | |
ortho() --this is needed to get text written on the screen | |
viewMatrix(matrix()) --and this | |
spriteMode(CORNER) | |
sprite(Joystick.img,Joystick.pos.x,Joystick.pos.y) | |
end | |
function Joystick.touched(touch) | |
local d,x,y=Joystick.diam,Joystick.pos.x,Joystick.pos.y | |
local dd=vec2(touch.x,touch.y):dist(vec2(x+d/2,y+d/2)) | |
if dd>Joystick.diam then return | |
elseif dd<Joystick.centreDiam/2 then return 0 end | |
local dMove,dAngle=0,0 | |
local x,y=touch.x-x-d/2,touch.y-y-d/2 --print(x,y) | |
if math.abs(y)>math.abs(x) then --moving forward or backward | |
if y>0 then --forward | |
dMove = Joystick.deltaMove --print("forward") | |
else --backward | |
dMove = -Joystick.deltaMove --print("backward") | |
end | |
else --moving left or right | |
if x>0 then | |
dAngle = Joystick.deltaAngle --print("right") | |
else | |
dAngle = - Joystick.deltaAngle --print("left") | |
end | |
end | |
return dMove,dAngle | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment