This is a little tank game I wrote about a week ago. The tanks correctly pitch/roll on the hills. Also, the aiming turrets does some nifty little transformations to convert a global aim direction into the angles the turret needs to point at no matter what sort of hill it is on. The enemy tanks have a basic AI that tells them to circle the closest tank (randomly circle left or right), which looks pretty smart on screen for the simplicity of the actual logic. Also, the tank handling is very Halo-like in that you use WASD to control the direction of the tank relative to the camera, and rotate the camera view to see where you are looking. The pseudo-physics isn't as realistic as I'd like, but the movement still feels pretty natural. I was playing with the idea of turning this into a complete, media-less, tank shoot em up but right now I have my hands full with the 2d physics simulation challenge.
Controls: WASD - move, mouselook, spacebar - shoot, and left/right mouse click for camera zoom.
Anyway, here's the code, just copy, paste, run:
set display mode 1024,768,32
ink rgb(0,255,0),0
box 0,0,100,100
ink 0,0
box 2,2,98,98
sync
get image 1,0,0,100,100
sync on
sync rate 0
autocam off
cls
hide mouse
set ambient light 55
type entity_type
shoot_rate as float
shoot_power as float
heal_rate as float
upgrade_rate as float
upgrade_speed as float
research_amount as float
weapon as float
body
turret
cannon
exist
anglex as float
anglez as float
angley as float
targetangley as float
speed as float
direction
hull
top
endpiece
last_shot
aimanglex as float
aimangley as float
accel
lastdirchange
circledir
endtype
dim entity(100) as entity_type
set camera range 0.01,200
make matrix 1,100,100,40,40
randomize matrix 1,80
smooth_matrix(1,40,40,3,60)
prepare matrix texture 1,1,1,1
color backdrop 0
global camdist#=0.2
position camera -4,2,-4
make object box 2000,0.1,0.1,100
ink -1,0
for n=1 to 20
make_entity(n)
position object entity(n).body,rnd(60)+20,0,rnd(60)+20
entity(n).angley=rnd(360)
yrotate object entity(n).turret,rnd(90)-45
next n
type bullet_type
vx as float
vy as float
vz as float
object
exist
shotfrom
endtype
dim bullet(1000) as bullet_type
hide object 2000
global time#
lasttime=timer()
time#=(timer()-lasttime)*0.001
do
time#=(timer()-lasttime)*0.001
if time#<0.001 then time#=0.001
lasttime=timer()
set cursor 0,0
keep_entities_on_matrix()
control_entity(1)
update_camera(1)
update_bullets()
update_tanks()
bullet_collisions()
tank_collisions()
ai(1)
sync
loop
function update_camera(n)
obj=entity(n).body
x#=object position x(obj)
y#=object position y(obj)
z#=object position z(obj)
position camera x#,y#,z#
rotate camera 0,0,0
turn camera right entity(n).aimangley
pitch camera down entity(n).aimanglex
pitch camera up 90
move camera 0.5
pitch camera down 90
pitch camera down 15
move camera -camdist#
pitch camera up 15
if mouseclick()=1
camdist#=camdist#/1.01
endif
if mouseclick()=2
camdist#=camdist#*1.01
show object entity(n).body
show object entity(n).hull
show object entity(n).turret
show object entity(n).top
show object entity(n).cannon
show object entity(n).endpiece
endif
if camdist#<1
camdist#=1
hide object entity(n).body
hide object entity(n).hull
hide object entity(n).turret
hide object entity(n).top
hide object entity(n).cannon
hide object entity(n).endpiece
endif
if camdist#>100 then camdist#=100
entity(n).aimangley=entity(n).aimangley+mousemovex()
entity(n).aimanglex=entity(n).aimanglex+mousemovey()
endfunction
function control_entity(n)
obj=entity(n).body
move_entity(n,keystate(17)-keystate(31),keystate(32)-keystate(30))
x#=object position x(obj)
y#=object position y(obj)
z#=object position z(obj)
cx#=camera position x()
cy#=camera position y()
cz#=camera position z()
q=0
while camera position y()<get ground height(1,camera position x(),camera position z())
inc q
move camera 1
if q>100 then exit
endwhile
q=0
while camera position y()>get ground height(1,camera position x(),camera position z())
inc q
move camera 1
if q>10000 then exit
endwhile
hitx#=camera position x()
hity#=camera position y()
hitz#=camera position z()
position camera cx#,cy#,cz#
aimx#=hitx#-x#
aimy#=hity#-y#
aimz#=hitz#-z#
aim_tank(n,aimx#,aimy#,aimz#,1.0)
entity(n).upgrade_speed=entity(n).upgrade_speed+entity(n).upgrade_rate*time#
entity(n).research_amount=entity(n).research_amount+entity(n).upgrade_speed*time#
if returnkey()=1
entity(n).weapon=entity(n).weapon+entity(n).research_amount
entity(n).research_amount=0
entity(n).upgrade_speed=0
endif
print "Weapon:",entity(n).weapon
print "Research amount:",entity(n).research_amount
if spacekey()=1 then shoot_bullet(n)
endfunction
function keep_entities_on_matrix()
for n=1 to 100
if entity(n).exist=1
obj=entity(n).body
x#=object position x(obj)
z#=object position z(obj)
position object obj,x#,get ground height(1,x#,z#),z#
rotate object obj,0,0,0
rotate object obj,0,0,0
turn object right obj,entity(n).angley
move object obj,0.1
yf#=get ground height(1,object position x(obj),object position z(obj))
move object obj,-0.2
yb#=get ground height(1,object position x(obj),object position z(obj))
move object obj,0.1
move object right obj,0.1
yr#=get ground height(1,object position x(obj),object position z(obj))
move object right obj,-0.2
yl#=get ground height(1,object position x(obj),object position z(obj))
move object right obj,0.1
xangle#=wrapvalue(atanfull((yf#-yb#),0.2))
zangle#=wrapvalue(atanfull((yr#-yl#),0.2))
entity(n).anglex=curveangle(xangle#,entity(n).anglex,4)
entity(n).anglez=curveangle(zangle#,entity(n).anglez,4)
pitch object up obj,entity(n).anglex
roll object left obj,entity(n).anglez
endif
next n
endfunction
function make_entity(num)
entity(num).exist=1
o0=freeobject()
make object cube o0,0
o1=freeobject()
make object box o1,0.8,0.3,1
position object o1,0,0.15,0
glue object to limb o1,o0,0,1
o2=freeobject()
make object cylinder o2,1
scale object o2,50,30,50
glue object to limb o2,o1,0,1
position object o2,0,0.2,0
entity(num).body=o0
entity(num).hull=o1
entity(num).turret=o2
o3=freeobject()
make object sphere o3,1
scale object o3,100,60,100
glue object to limb o3,o2,0,1
position object o3,0,0.5,0
o4=freeobject()
make object cylinder o4,0.4
scale object o4,50,300,100
xrotate object o4,90
fix object pivot o4
glue object to limb o4,o2,0,1
position object o4,0,0.3,1
o5=freeobject()
make object sphere o5,0.4
scale object o5,100,10,100
position object o5,0,0.20,0
glue object to limb o5,o4,0,1
entity(num).top=o3
entity(num).cannon=o4
entity(num).endpiece=o5
entity(num).shoot_rate=0.3333
entity(num).shoot_power=0.3333
entity(num).upgrade_rate=1.0-0.6666
entity(num).upgrade_speed=0.0
entity(num).weapon=3.0
entity(num).research_amount=0.0
color object entity(num).hull,rgb(0,0,255)
endfunction
function freeobject()
i=1:while object exist(i):inc i:endwhile
endfunction i
function smooth_matrix(num,xtile,ztile,times,edge_height#)
dim temp#(xtile,ztile)
for looop=1 to times
for x=0 to xtile
for z=0 to ztile
temp#(x,z)=get matrix height(num,x,z)
if (x=0 or z=0 or x=xtile or z=ztile) then temp#(x,z)=edge_height#
next z
next x
for x=0 to xtile
for z=0 to ztile
x1=x-2
if x1<0 then x1=0
x2=x+2
if x2>xtile then x2=xtile
z1=z-2
if z1<0 then z1=0
z2=z+2
if z2>ztile then z2=ztile
count=0
total#=0
for x3=x1 to x2
for z3=z1 to z2
inc count
total#=total#+temp#(x3,z3)
next z3
next x3
set matrix height num,x,z,total#/count
next z
next x
update matrix num
next looop
undim temp#(0,0)
endfunction
function update_bullets()
for b=1 to 1000
if bullet(b).exist=1
obj=bullet(b).object
position object obj,object position x(obj)+bullet(b).vx, object position y(obj)+bullet(b).vy, object position z(obj)+bullet(b).vz
bullet(b).vy=bullet(b).vy-0.00
if object position y(obj)<get ground height(1,object position x(obj),object position z(obj)) or object position x(obj)<-100 or object position x(obj)>200 or object position z(obj)<-100 or object position z(obj)>200 or object position y(obj)>150
delete object obj
bullet(b).exist=0
endif
endif
next b
endfunction
function update_tanks()
for e=1 to 100
if entity(e).exist=1
while entity(e).targetangley-entity(e).angley<-180
entity(e).targetangley=entity(e).targetangley+360
endwhile
while entity(e).targetangley-entity(e).angley>180
entity(e).targetangley=entity(e).targetangley-360
endwhile
if abs(entity(e).angley-entity(e).targetangley)>110
entity(e).direction=-1
else
entity(e).direction=1
endif
if entity(e).direction=-1 then entity(e).targetangley=180+entity(e).targetangley
while entity(e).targetangley-entity(e).angley<-180
entity(e).targetangley=entity(e).targetangley+360
endwhile
while entity(e).targetangley-entity(e).angley>180
entity(e).targetangley=entity(e).targetangley-360
endwhile
if entity(e).accel=1
if entity(e).targetangley<entity(e).angley-360*time#
entity(e).angley=entity(e).angley-360*time#
endif
if entity(e).targetangley>entity(e).angley+360*time#
entity(e).angley=entity(e).angley+360*time#
endif
endif
entity(e).speed=entity(e).speed-0.1*sin(entity(e).anglex)*time#
move object entity(e).body,entity(e).speed
entity(e).speed=entity(e).speed*0.98
endif
next e
endfunction
function shoot_bullet(n)
if timer()>entity(n).last_shot+1000.0/(entity(n).shoot_rate*entity(n).weapon)
entity(n).last_shot=timer()
b=1
while bullet(b).exist=1
inc b
endwhile
bullet(b).exist=1
obj=freeobject()
bullet(b).object=obj
make object sphere bullet(b).object,0.2
color object obj,rgb(255,0,0)
position object obj,object position x(entity(n).body),object position y(entity(n).body),object position z(entity(n).body)
set object to object orientation obj,entity(n).body
move object right obj,object position x(entity(n).hull)
move object up obj,object position y(entity(n).hull)
move object obj,object position z(entity(n).hull)
move object right obj,object position x(entity(n).turret)
move object up obj,object position y(entity(n).turret)
move object obj,object position z(entity(n).turret)
turn object right obj,object angle y(entity(n).turret)
pitch object down obj,object angle x(entity(n).cannon)
x#=object position x(obj)
y#=object position y(obj)
z#=object position z(obj)
move object obj,1
bullet(b).vx=(object position x(obj)-x#)*0.5
bullet(b).vy=(object position y(obj)-y#)*0.5
bullet(b).vz=(object position z(obj)-z#)*0.5
x#=object position x(entity(n).body)
y#=object position y(entity(n).body)
z#=object position z(entity(n).body)
move object entity(n).body,1
bullet(b).vx=bullet(b).vx+(object position x(entity(n).body)-x#)*entity(n).speed*0.5
bullet(b).vy=bullet(b).vy+(object position y(entity(n).body)-y#)*entity(n).speed*0.5
bullet(b).vz=bullet(b).vz+(object position z(entity(n).body)-z#)*entity(n).speed*0.5
move object entity(n).body,-1
bullet(b).shotfrom=n
endif
endfunction
function bullet_collisions()
for e=1 to 100
if entity(e).exist=1
for b=1 to 1000
if bullet(b).exist=1 and e<>bullet(b).shotfrom
d2#=(object position x(entity(e).body)-object position x(bullet(b).object))^2+(object position y(entity(e).body)-object position y(bullet(b).object))^2+(object position z(entity(e).body)-object position z(bullet(b).object))^2
if d2#<1
bullet(b).exist=0
delete object bullet(b).object
endif
endif
next b
endif
next e
endfunction
function tank_collisions()
for e1=1 to 99
if entity(e1).exist=1
for e2=e+1 to 100
if entity(e2).exist=1
dx#=object position x(entity(e1).body)-object position x(entity(e2).body)
dy#=object position y(entity(e1).body)-object position y(entity(e2).body)
dz#=object position z(entity(e1).body)-object position z(entity(e2).body)
d2#=dx#^2+dy#^2+dz#^2
if d2#<1.5^2
d#=sqrt(d2#)
move#=(1.5-d#)*0.5
dx#=dx#/d#
dy#=dy#/d#
dz#=dz#/d#
position object entity(e1).body,object position x(entity(e1).body)+move#*dx#,object position y(entity(e1).body)+move#*dy#,object position z(entity(e1).body)+move#*dz#
position object entity(e2).body,object position x(entity(e2).body)-move#*dx#,object position y(entity(e2).body)-move#*dy#,object position z(entity(e2).body)-move#*dz#
endif
endif
next e2
endif
next e1
endfunction
function ai(player)
for e=1 to 100
if entity(e).exist=1 and e<>player
closeste=-1
closestdist2#=10000^2
obj=entity(e).body
for e2=1 to 100
if entity(e2).exist=1 and e2<>e
dx#=object position x(obj)-object position x(entity(e2).body)
dy#=object position y(obj)-object position y(entity(e2).body)
dz#=object position z(obj)-object position z(entity(e2).body)
d2#=dx#^2+dy#^2+dz#^2
if d2#<closestdist2#
closestdist2#=d2#
closeste=e2
endif
endif
next e2
dx#=object position x(entity(closeste).body)-object position x(obj)
dy#=object position y(entity(closeste).body)-object position y(obj)
dz#=object position z(entity(closeste).body)-object position z(obj)
aim_tank(e,dx#,dy#,dz#,10.0)
dist#=sqrt(closestdist2#)
fd=0
if dist#>10 then fd=1
if dist#<3 then fd=-1
entity(e).aimangley=atanfull(dx#,dz#)
if timer()>entity(e).lastdirchange+1000
entity(e).lastdirchange=timer()+rnd(1000)
entity(e).circledir=rnd(2)-1
endif
move_entity(e,fd,entity(e).circledir)
if rnd(10)=1 then shoot_bullet(e)
endif
next e
endfunction
function aim_tank(n,aimx#,aimy#,aimz#,c#)
l#=sqrt(aimx#^2+aimy#^2+aimz#^2)
aimx#=aimx#/l#
aimy#=aimy#/l#
aimz#=aimz#/l#
rem transform into tank coordinates :)
` print "global aim:",aimx#,",",aimy#,",",aimz#
obj=entity(n).body
x#=object position x(obj)
y#=object position y(obj)
z#=object position z(obj)
move object right obj,1
xx#=object position x(obj)-x#
xy#=object position y(obj)-y#
xz#=object position z(obj)-z#
move object left obj,1
move object up obj,1
yx#=object position x(obj)-x#
yy#=object position y(obj)-y#
yz#=object position z(obj)-z#
move object down obj,1
move object obj,1
zx#=object position x(obj)-x#
zy#=object position y(obj)-y#
zz#=object position z(obj)-z#
move object obj,-1
rem nice 3d space transformations :)
taimx#=aimx#*xx#+aimy#*xy#+aimz#*xz#
taimy#=aimx#*yx#+aimy#*yy#+aimz#*yz#
taimz#=aimx#*zx#+aimy#*zy#+aimz#*zz#
move object entity(n).cannon,-1
xa#=atanfull(-taimy#,sqrt(taimx#^2+taimz#^2))
if xa#>20 then xa#=20
xrotate object entity(n).cannon,curveangle(xa#,object angle x(entity(n).cannon),c#)
move object entity(n).cannon,1
yrotate object entity(n).turret,curveangle(atanfull(taimx#,taimz#),object angle y(entity(n).turret),c#)
endfunction
function move_entity(n,fbaccel#,rlaccel#)
entity(n).accel=0
if fbaccel#<>0 or rlaccel#<>0
entity(n).targetangley=atanfull(rlaccel#,fbaccel#)+entity(n).aimangley
if entity(n).direction=1
entity(n).speed=entity(n).speed+0.3*time#
else
entity(n).speed=entity(n).speed-0.15*time#
endif
entity(n).accel=1
endif
endfunction