Two player tank game (old school style)

Written in 2011 for an iPad 2.

There are separate controls for rotating the turrets and the tank so you can get tricky with strafing.

The tanks are hidden while in the trees (unless you fire, of course).
Tanks get trapped if they drive into the mudpits (but you can still rotate the turret and fire)

One problem I remember is Codea could not handle that many simultaneous inputs, perhaps there is a way to overcome that now.

function setup()
  -- tunables
  numMudpits = 4 -- tanks get stuck in mud
  numWoods = 6  -- tanks hidden in trees

-- game setup  
  touches = {}    
  shells1={}
  shells2={}

  lastFireTime1 = 0
  lastFireTime2 = 0

  mud={} -- mudpits to get stuck in    
  woods={}
  init()  
  explosionSize=1
  displayMode(FULLSCREEN_NO_BUTTONS)

end

function clearTable(table)  
  for k in pairs(table) do
      table[k]=nil
  end
end

function init()
  moving1 = 0
  firing1 = 0 
  dx=0
  dy=0
  gunrot1=0
  dxx=0
  dyy=0
  rot=0  
  clearTable(mud)
  mud={}
  for i =0,numMudpits-1 do
      x=math.random(WIDTH)
      y=math.random(HEIGHT-200)+100
      w=math.random(200)+2
      h=math.random(300)+2
      if y+h > HEIGHT-100 then
          h=HEIGHT-100-y
      end
      table.insert(mud, {x,y,x+w,y+h})
  end

  clearTable(woods)
  woods={}
  for i =0,numWoods-1 do
      x=math.random(WIDTH)
      y=math.random(HEIGHT-200)+100
      w=math.random(200)+2
      h=math.random(300)+2
      if y+h > HEIGHT-100 then
          h=HEIGHT-100-y
      end
      table.insert(woods, {x,y,x+w,y+h})
  end

  tankx1=math.random(WIDTH-100)+50
  tanky1=HEIGHT-200
  while inMud(tankx1,tanky1)==1 or inWoods(tankx1, tanky1)==1 do
      print("getting tank1 out of mud/woods")
      tankx1=math.random(WIDTH-100)+50
      tanky1=HEIGHT-200
  end    

  tankx2=math.random(WIDTH-100)+50
  tanky2=200
  while inMud(tankx2,tanky2)==1 or inWoods(tankx2, tanky2)==1 do
      print("getting tank2 out of mud/woods")
      tankx2=math.random(WIDTH-100)+50
      tanky2=200
  end  

  rot2=90
  gunrot2=90

  ended=0
  winner=0
end

function touched(touch)
  if touch.state == ENDED then
      touches[touch.id] = nil
  else
      touches[touch.id] = touch
  end
end

function inMud(x,y)  
  for i,v in ipairs(mud) do
      mx=v[1]
      my=v[2] 
      mx2=v[3]  
      my2=v[4]
      if x > mx-3 and x<mx2+3 and y>my-3 and y<my2+3 then
          return 1
      end      
  end  
  return 0  
end

function inWoods(x,y)  
  for i,v in ipairs(woods) do
      mx=v[1]
      my=v[2] 
      mx2=v[3]  
      my2=v[4]
      if x > mx-3 and x<mx2+3 and y>my-3 and y<my2+3 then
          return 1
      end      
  end  
  return 0  
end

function drawTank(tankX, tankY, rot, gunRot, bodyColor, turretColor)
    pushMatrix()    
-- draw tank body
  strokeWidth(0)
--    stroke(255, 255, 255, 255)    
  translate(tankX,tankY)
  rotate(rot)      
  fill(bodyColor)
--    stroke(bodyColor)        
  rect(-6,-8,12,18)    
  popMatrix()
  pushMatrix()

  -- draw the turret
  translate(tankX,tankY)
  rotate(gunRot)    
  strokeWidth(1)
  fill(turretColor)
  stroke(turretColor)    
  line(0,0,0,12) 
  stroke(turretColor)
  fill(bodyColor)
  ellipseMode(CENTER)
  ellipse(0,0,10)

  popMatrix()
end  

-- This function gets called once every frame
function draw()    
  background(59, 84, 57, 121)
  noSmooth()

  bc = 75/2 -- button center

  pushStyle() -- controls 1
  strokeWidth(2) 
  stroke(218, 217, 217, 255)
  fill(128, 122, 122, 255)
  line(75,bc,102,bc)    
  ellipse(bc,bc,75)
  ellipse(100+bc,bc,75)
  line(275,bc,302,bc)
  ellipse(200+bc,bc,75)
  ellipse(300+bc,bc,75)  

  fill(189, 32, 18, 255)
  ellipse(WIDTH-175+ bc, bc, 75)

  fill(53, 131, 35, 255)  
  ellipse(WIDTH-75+bc,bc,75)    

  hd=75/2
  bcy=HEIGHT-hd

  fill(128, 122, 122, 255)  -- controls 2 
  line(WIDTH-75,bcy,WIDTH-102,bcy)
  ellipse(WIDTH-0-hd,bcy,75)              
  ellipse(WIDTH-100-hd,bcy,75)
  line(WIDTH-275,bcy,WIDTH-302,bcy)
  ellipse(WIDTH-200-hd,bcy,75)    
  ellipse(WIDTH-300-hd,bcy,75)
  fill(189, 32, 18, 255)
  ellipse(100+hd,bcy,75)
  fill(53, 131, 35, 255)        
  ellipse(hd,bcy,75) 

  -- mudpits
  strokeWidth(0)
  fill(97, 100, 132, 255)
  for i,v in ipairs(mud) do
      rect(v[1],v[2],v[3]-v[1],v[4]-v[2])    
  end    

  popStyle()    

  strokeWidth(1)  
  line(0,100,WIDTH, 100)
  line(0,HEIGHT-100,WIDTH,HEIGHT-100)

--tank 1 touches    
  moving1=0
  moving2=0

  for k,touch in pairs(touches) do    
      x=touch.x
      y=touch.y        
      if ended==0 then        
          if x < 75 and y< 75 then
              rot = rot + 3
              gunrot1=gunrot1 +3
          end

          if x > 100 and x < 175 and y< 75 then
              rot=rot-3
              gunrot1=gunrot1-3
          end

          if x>200 and x<275 and y<75 then
              gunrot1=gunrot1-3
          end

          if x>300 and x< 375 and y< 75 then
              gunrot1=gunrot1+3
          end

          if x>WIDTH-175 and x< WIDTH-100 and y< 75 then
              if ElapsedTime > lastFireTime1 + 1 then -- throttle fire rate to 1 sec
                  lastFireTime1 = ElapsedTime
                  sx1 = -math.sin(math.rad(gunrot1))*2            
                  sy1 = math.cos(math.rad(gunrot1))*2
                  table.insert(shells1, {tankx1, tanky1, sx1, sy1} )  -- x, y and delta for shell
              end
          end        

          if x>WIDTH-75 and y<75 then
              moving1 = 1
          end

--tank2 touches      
          if x > WIDTH-75 and y>HEIGHT- 75 then
              rot2=rot2+3
              gunrot2 = gunrot2+3
          end

          if x > WIDTH-175 and x < WIDTH-100 and y> HEIGHT- 75 then
              rot2=rot2-3
              gunrot2=gunrot2-3
          end

          if x>WIDTH-275 and x<WIDTH-200 and y>HEIGHT- 75 then
              gunrot2=gunrot2-3
          end

          if x>WIDTH-375 and x<WIDTH- 300 and y> HEIGHT- 75 then
              gunrot2=gunrot2+3
          end

          if x>100 and x<175 and y> HEIGHT- 75 then
              if ElapsedTime > lastFireTime2 + 1 then -- throttle fire rate to 1 per sec
                  lastFireTime2 = ElapsedTime
                  sx2 = -math.sin(math.rad(gunrot2))*2            
                  sy2 = math.cos(math.rad(gunrot2))*2
                  table.insert(shells2, {tankx2, tanky2, sx2, sy2} )  -- x, y and delta for shell
              end
          end        

          if x<75 and y>HEIGHT- 75 then
              moving2 = 1
          end 
      elseif x>WIDTH/2-100 and x<WIDTH/2+100 and y>HEIGHT/2+-75 and y<HEIGHT/2+75 then 
          init()
      end          
  end -- for

  if ended == 1 then
      pushStyle()
      fill(232, 236, 34, 255)
      stroke(232, 236, 34, 255)
      ellipseMode(CENTER)    
      if winner==1 then
          ellipse(tankx2,tanky2,explosionSize)
      else
          ellipse(tankx1,tanky1, explosionSize)      
      end
      if explosionSize <100 then
          explosionSize = explosionSize + 1
      end
      popStyle() 
  end

  dyy = math.cos(math.rad(rot))
  dxx = math.sin(math.rad(rot))

  if moving1 == 1 and ended == 0 then
      if inMud(tankx1,tanky1)==1 then

      else      
          if tankx1>1 and tankx1<WIDTH and tanky1>101 and tanky1<HEIGHT-99 then
              tankx1 = tankx1 - 1*dxx
              tanky1 = tanky1 + 1*dyy  
          end  
      end  
  end

-- move tank2
  dyy = math.cos(math.rad(rot2))
  dxx = math.sin(math.rad(rot2))

  if moving2 == 1 and ended == 0 then 
      if inMud(tankx2,tanky2)==1 then
      else      
          if tankx2>1 and tankx2<WIDTH and tanky2>101 and tanky2<HEIGHT-99 then
              tankx2 = tankx2 - 1*dxx
              tanky2 = tanky2 + 1*dyy      
          end
      end
  end    

  drawTank(tankx1, tanky1, rot, gunrot1, color(42, 50, 232, 255), color(138, 223, 209, 255))    
  drawTank(tankx2, tanky2, rot2, gunrot2, color(231, 41, 47, 255), color(138, 223, 209, 255))  

  -- trees, draw after tanks/mud so mud could be hidden
  strokeWidth(0)
  fill(108, 192, 64, 255)
  for i,v in ipairs(woods) do
      rect(v[1],v[2],v[3]-v[1],v[4]-v[2])    
  end
  strokeWidth(1)

  -- shells store absolute deltas, no rotation or translation
  -- draw shells for tank1  
  if #shells1 > 0 then
        for i,v in ipairs(shells1) do
      v[1]=v[1]+v[3]
      v[2]=v[2]+v[4]  

      fill(228, 231, 10, 255)
      stroke(208, 225, 84, 255)
      ellipse( v[1], v[2], 5)  

      if v[1] <0 or v[1] > WIDTH or v[2] < 100 or v[2] > HEIGHT-100 then
          rt = table.remove(shells1,i)
      end  

      sx=v[1]
      sy=v[2]

      if sx > tankx2-10 and sx<tankx2+10 and sy>tanky2-10 and sy<tanky2+10 then
          print("Boom!!! Tank1 wins") 
          ended=1
          winner=1
          table.remove(shells1,i)          
      end
  end 
  end

    -- draw shells for tank2 
  if #shells2 > 0 then
      for i,v in ipairs(shells2) do

      v[1]=v[1]+v[3]
      v[2]=v[2]+v[4]  

      fill(228, 231, 10, 255)
      stroke(208, 225, 84, 255)
      ellipse( v[1], v[2], 5)  

      if v[1] <0 or v[1] > WIDTH or v[2] < 100 or v[2] > HEIGHT-100 then
          rt = table.remove(shells2,i)                
      end

      sx=v[1]
      sy=v[2]

      if sx > tankx1-10 and sx<tankx1+10 and sy>tanky1-10 and sy<tanky1+10 and winner == 0 then
          print("Boom!!! Tank2 wins")
          ended=1 
          winner=2
          table.remove(shells2,i)          
      end

      end
  end 

  if ended == 1 and explosionSize>99 then -- restart button
      pushMatrix()
      pushStyle()
      stroke(159, 159, 159, 255)
      fill(53, 131, 35, 255)        
      strokeWidth(2)
      translate(WIDTH/2,HEIGHT/2)
      rect(-100,-75,200,150)
      translate(0,-5)
      clip(0,0,WIDTH, HEIGHT/2)
      ellipse(0,0,100)
      clip(WIDTH/2,HEIGHT/2,200,200)
      ellipse(0,0,100)
      noClip()
      translate(0,48)
      rotate(-5)
      line(0,0,15,15)
      line(0,0,15,-15)
      popStyle()
      popMatrix()
  end

  popMatrix() 
end

@Ophitoxaemia I haven’t tried your code yet, but I just wanted to say that Codea can handle as many simultaneous inputs as you can fit fingers on the screen.