0
votes

I have been working on a tower defense game. So basically I have a loop that makes a table of display objects that are tanks and adds physics bodies to them. Then it "gives the tanks" to a function called moveTank to actually move them.

However to conserve memory I want to remove the physics body and display obejct itself once it is offscreen. The code for that stars at line 234. In the simulator, if you test just removing the physics body everything works fine. However, if I remove the display object (maybe I'm doing it wrong?) it removes the image, but some other functions that use it give an error saying that I'm trying to compare a number with a nil value@ line 229. The nil value is the object is removed and I set its property isMoving and isAlive to false so why is it even trying to perform the operation??

Can anyone help me finish this part of trying to remove the display object with no errors?

local storyboard = require( "storyboard" )
local scene = storyboard.newScene()


local physics = require "physics"
physics.start()
physics.setGravity( 0, 0)
physics.setDrawMode("hybrid")


local screenW, screenH, halfW, halfH = display.contentWidth, display.contentHeight,      display.contentWidth*0.5, display.contentHeight*0.5

local tanks = {}
local tickCnt = 0
local TOTAL_TANKS = 2
local tankCnt = 1

function AddCommas( number, maxPos )

    local s = tostring( number )
    local len = string.len( s )

    if len > maxPos then
            -- Add comma to the string
            local s2 = string.sub( s, -maxPos )             
            local s1 = string.sub( s, 1, len - maxPos )             
            s = (s1 .. "," .. s2)
    end

    maxPos = maxPos - 3             -- next comma position

    if maxPos > 0 then
            return AddCommas( s, maxPos )
    else
            return s
    end

end

function tickCntFunct()
if tickCnt <= 2000 then
tickCnt = tickCnt + 25
print("tick count", tickCnt)
else
tickCnt = 0
end
end
timer.performWithDelay(10, tickCntFunct, 0)

function moveTank(aTank)

local mSpeed = 150
rSpeed = 6



if aTank.isAlive == true and aTank.isKilled == false then
print("aTank.x = ", aTank.x)
print("aTank.y = ", aTank.y)
print("tank rotation = ", aTank.rotation)

local disP1 = math.sqrt((math.abs(aTank.x - pointer1.x))^2 + (math.abs(aTank.y - pointer1.y))^2)
local disP2 = math.sqrt((math.abs(aTank.x - pointer2.x))^2 + (math.abs(aTank.y - pointer2.y))^2)
local disP3 = math.sqrt((math.abs(aTank.x - pointer3.x))^2 + (math.abs(aTank.y - pointer3.y))^2)
local disP4 = math.sqrt((math.abs(aTank.x - pointer4.x))^2 + (math.abs(aTank.y - pointer4.y))^2)

removeTanknumber = 0

if aTank.x < 0 then
aTank.rotation = 90
aTank:setLinearVelocity( mSpeed, 0)
end
if aTank.rotation < 180 and disP1 < 1 then
aTank:setLinearVelocity( 0, 0)
aTank.rotation = aTank.rotation + rSpeed
end 
if aTank.rotation >= 180 and disP1 < 1 then
aTank.rotation = 180
aTank:setLinearVelocity( 0, mSpeed)
end
if aTank.rotation > 90 and disP2 < 1 then
aTank:setLinearVelocity( 0, 0)
aTank.rotation = aTank.rotation - rSpeed
end 
if aTank.rotation <= 90 and disP2 < 1 then
aTank.rotation = 90
aTank:setLinearVelocity( mSpeed, 0)
end 
if aTank.rotation > 0 and disP3 < 1 then
aTank:setLinearVelocity( 0, 0)
aTank.rotation = aTank.rotation - rSpeed
end 
if aTank.rotation <= 0 and disP3 < 1 then
aTank.rotation = 0
aTank:setLinearVelocity( 0, -1*mSpeed)
end 
if aTank.rotation < 90 and disP4 < 1 then
aTank:setLinearVelocity( 0, 0)
aTank.rotation = aTank.rotation + rSpeed
end 
if aTank.rotation >= 90 and disP4 < 1 then
aTank.rotation = 90
aTank:setLinearVelocity( mSpeed, 0)
end 
end
end
timer.performWithDelay(1, moveTank, 0)


function scene:createScene( event )
local group = self.view

pointersGroup = display.newGroup()
mapGroup = display.newGroup()

-- create a grey rectangle as the backdrop
map = display.newImage( "map1.png" )
map:setReferencePoint(display.TopLeftReferencePoint)
map.x = 0
map.y = 0

spawner = display.newImage("pointer.png")
spawner:setReferencePoint(display.CenterReferencePoint)
spawner.y = 210
spawner.x = -40

pointer1 = display.newImage("pointer.png")
pointer1:setReferencePoint(display.CenterReferencePoint)
pointer1.x = 210
pointer1.y = 210

pointer2 = display.newImage("pointer.png")
pointer2:setReferencePoint(display.CenterReferencePoint)
pointer2.x = 210
pointer2.y = 390

pointer3 = display.newImage("pointer.png")
pointer3:setReferencePoint(display.CenterReferencePoint)
pointer3.x = 510
pointer3.y = 390

pointer4 = display.newImage("pointer.png")
pointer4:setReferencePoint(display.CenterReferencePoint)
pointer4.x = 510
pointer4.y = 90

sideBlock = display.newImage("side_block.png")
physics.addBody( sideBlock, "static", { friction=0.5, bounce=0.3 } )
sideBlock:setReferencePoint(display.CenterReferencePoint)
sideBlock.x = screenW - 100
sideBlock.y = screenH/2


-- all display objects must be inserted into group

pointersGroup:insert( spawner )
pointersGroup:insert( pointer1 )
pointersGroup:insert( pointer2 )
pointersGroup:insert( pointer3 )
pointersGroup:insert( pointer4 )
pointersGroup:insert( sideBlock )
mapGroup:insert( map )
group:insert( pointersGroup )
group:insert( mapGroup )

end


function scene:enterScene( event )
local group = self.view


for i = 1, TOTAL_TANKS do
-- create 5 tanks, place them off screen, set their status to isAlive and not isMoving
table.insert(tanks, display.newImage("tank.png"))
print("memory (all spawned): ", AddCommas( system.getInfo("textureMemoryUsed"), 9 ) .. " bytes" )
tanks[i]:setReferencePoint(display.CenterReferencePoint)
tanks[i]:scale(0.75, 0.75)
tanks[i].x = spawner.x
tanks[i].y = spawner.y
tanks[i].isAlive = true
tanks[i].isMoving = false
tanks[i].isKilled = false
end


local function gameLoop(event)

-- normally should not have loops inside the game loop, because
-- if there is too much going on during each frame call it can cause issues
-- but for moving only 5 tanks, this is how you can do it.
-- each tank will call the same function above (moveTank)

-- have a variable that you would check here, to see if 'so many ticks or seconds'
-- has passed, and if so, set the isMoving to true for the next tank .. will just use
-- a simple incremented variable 'tickCnt'


    if tickCnt > 2000 and tankCnt <= TOTAL_TANKS then
    physics.addBody( tanks[tankCnt], { density=3.0, friction=0.5, bounce=0.3 } )
    tanks[tankCnt].isMoving = true
    print("tankCnt= ", tankCnt)
    tankCnt = tankCnt + 1
    print("memory (moving): ", AddCommas( system.getInfo("textureMemoryUsed"), 9 ) .. " bytes" )        
    end


    for i=1, TOTAL_TANKS do
        if tanks[i].isMoving == true and tanks[i].isAlive == true and tanks[i].isKilled == false then
        moveTank(tanks[i])
        end
    end

    for i = 1, TOTAL_TANKS do
        if tanks[i].x >= 40 and tanks[i].isKilled == false then
        tanks[i].isKilled = true
        tanks[i].isMoving = false
        tanks[i].isAlive = false
        physics.removeBody( tanks[i] )
        display.remove(tanks[i])
        tanks[i] = nil
        end
    end

end

Runtime:addEventListener("enterFrame", gameLoop)

physics.start()

end


function scene:exitScene( event )
local group = self.view

physics.stop()

end


function scene:destroyScene( event )
local group = self.view

package.loaded[physics] = nil
physics = nil
end

---------------------------------------------------------------------------------------   --
-- END OF YOUR IMPLEMENTATION
-----------------------------------------------------------------------------------------

-- "createScene" event is dispatched if scene's view does not exist
scene:addEventListener( "createScene", scene )

-- "enterScene" event is dispatched whenever scene transition has finished
scene:addEventListener( "enterScene", scene )

-- "exitScene" event is dispatched whenever before next scene's transition begins
scene:addEventListener( "exitScene", scene )

-- "destroyScene" event is dispatched before view is unloaded, which can be
-- automatically unloaded in low memory situations, or explicitly via a call to
-- storyboard.purgeScene() or storyboard.removeScene().
scene:addEventListener( "destroyScene", scene )

-----------------------------------------------------------------------------------------

return scene
1

1 Answers

0
votes

Try to loop from last tank to first.