Two part question regarding RayCasting

First, here is a short video of what I’ve got going on:
video (video quality is HD when downloaded)

It’s weird how it only throws an error once I’m “in range” or “in sight” of the enemy’s ray.
I’m not sure what is happening when I destroy just one tank that is causing an error when I try to go destroy the second. I am not removing the ray or anything.

As far as the second issues goes -
When I drove the user_tank into the area where both radars overlap, the rays from both tanks were registering a collision with each others radar. And when I destroy both tanks, the rays are still being cast and it doesn’t call my onLevelCompletion function (which is nothing more than an overlay window with a level complete banner and a next button)
Is there a way to add my ray/s to a collision filter?

Here is a link to horacebury’s code -
link
* You can look at the firingsolutions.lua there.

Here is my entire fire function as well as an example of how I setup a radar:

[lua]
ET02radar = display.newCircle(enemyT02.x,enemyT02.y, 10)
ET02radar.isVisible = false      
physics.addBody(ET02radar,{radius = 400,isSensor = true, filter = RadarCollisionFilter})
ET02radar.class = “Radar”

– detect a target entering Etank02’s area and fire at it
local onET02radarCollision = function( self, event )
    
     if (event.phase == “began” and event.other.class == “PlayerTank”) then
         print(“began”)
        EnemyFiringTimer = timer.performWithDelay(500, function()
            ETfire( enemyT02, event.other )
        end, -1)

elseif (event.phase == “ended” and event.other.class == “PlayerTank”) then
        print(“collision with ET02radar ended.”)
        if EnemyFiringTimer then timer.cancel(EnemyFiringTimer) end
    end
    
    return true
    
end
ET02radar.collision = onET02radarCollision
ET02radar:addEventListener(“collision”, ET02radar)
[/lua]

Fire function:
[lua]
– fires enemy bullet
function ETfire( self, user_tank )
    
    EDray = physics.rayCast( self.x, self.y, user_tank.x, user_tank.y, “sorted” )
        
    local hitFirst = EDray[1]
    local hitX, hitY = hitFirst.position.x, hitFirst.position.y
    
    if EDray then
        – There’s at least one hit.
        print( "Hit count: " … tostring( #EDray ) )

        – Output all the results.
         for i,v in ipairs(EDray)  do
            print( "Hit: ", i, v.object.class, " Position: ", v.position.x, v.position.y, " Surface normal: ", v.normal.x, v.normal.y )
    end
        print( "The first object hit is: ",
        EDray[1].object.class, " at position: ", EDray[1].position.x, EDray[1].position.y, " where the surface normal is: ", EDray[1].normal.x, EDray[1].normal.y )

        else
        – There’s no hit.
    end
    if ( EDray[1].object.class == “PlayerTank” or EDray[1].object.class == “Uturret” or EDray[1].object.class == “bullet”) then
        
        print(“PlayerTank in range! Fire!”)
        timer.performWithDelay( 40, ShootEnemyBullet )
        
        function ShootEnemyBullet()
        – solution: “firing solution” - the collision point between the tower’s bullet and the target
        – success: true if the tower can successfully fire on the target, false if the target will escape
        local solution, success = intercept( self, user_tank, bulletSpeed )
                    –   
                local math_deg = math.deg  – localize ‘math.deg’ for better performance
                local math_atan2 = math.atan2  – localize ‘math.atan2’ for better performance
 
                – Calculates the angle between specified points A & B
                local function angleBetween( selfX, selfY, user_tankX, user_tankY )
                local angle = ( math_deg( math_atan2( user_tankY-selfY, user_tankX-selfX ) )+180) --; return angle
                    if ( angle < 0 ) then angle = angle + 360 end ; return angle % 360
                end

                local ang = angleBetween( self.x, self.y, user_tank.x, user_tank.y )
                self.rotation = ang
        
        – only fire if the firing solution is successful
        if (success) then
                – calculate vx and vy
                local angle = angleOf( self, solution )
                local pt = rotateTo( {x=bulletSpeed + 50, y=0}, angle)
                local pt2 = mathapi.rotateAboutPoint( {x=self.x,y=self.y -65}, self, self.rotation - 90 )
                
                – create bullet
                Enemybullet = loader:createSpriteFromSHDocument(“Weapon5ex”, “GameFX”, “LevelAssets.pshs”);
                Enemybullet.x, Enemybullet.y, Enemybullet.solution = pt2.x, pt2.y, solution
                physics.addBody(Enemybullet,{friction = 0, bounce = 1.0, density = 1.5, radius=10, isSensor = false, filter = bulletCollisionFilter})
                Enemybullet:scale(.6,.6)
                Enemybullet.class = “bullet”
                Enemybullet.isBulet = true
                Enemybullet.rotation = self.rotation + 90
                
                – fire bullet
                Enemybullet:setLinearVelocity(pt.x, pt.y)
                
                bullets:insert( Enemybullet )            
                Enemybullet.collision = onBulletCollision
                Enemybullet:addEventListener( “collision”, Enemybullet )
            end                
        end            
    end
end
[/lua]

[/lua]

Any help would be greatly appreciated. :slight_smile:

Edit: I changed a few things in the fire function. – code edited –

– bump –
      :ph34r:

Anyone have an idea why I’m getting an error?

I notice in your original post, the line that would call onLevelCompletion() is commented out (labeled line 78).  So that would explain why it’s not being called…

More generally though, I think you should invest some time learning about how to use tables and object oriented design.  Right now you repeat a lot of the same code for your first enemy tank and your second enemy tank.  If you only ever plan to have two enemy tanks, that might be OK, but it’s not scalable if you ever plan to have more than two.

  • Andrew

Thanks for the reply.

I have resolved the problem.

Well that has to do with the enemy fire function. Right now nothing happens when an enemy fires a bullet at the user_tank, other than the bullet getting removed upon collision with the user or wall etc…

  • I may or may not make it to where the enemy bullets collide with and destroy other enemies, which if I did then that would mean I would need to check the current count of enemies via that function.

My function that allows the user to fire is where I am currently calling the onLevelCompletion, every time an enemy is destroyed. As seen in the video, once I get within ‘range’ and the enemy’s ray hits me it throws an error.
One thing I forgot to show in the video is if I destroy the first tank and then without colliding with the second enemy’s ray I shoot the second tank, it works just fine… no error and it calls my onLevelCompletion function.

In regards to my code, yes I’m sure I could greatly benefit from using tables etc…
But this is my first attempt at programming of any kind, so while some portions of my code are what you might call inefficient and can at times can be quite tedious to work with, it’s what I know how to do and it works.
*That being said, I am going to try to better optimize my code as I learn.  :slight_smile:

Edit: As far as tables go - I have done some research into them… however the problem I kept facing is that since my tanks are made up of two separate objects (base, turret) I couldn’t define a single table value that includes both objects of a single tank.
From some articles I read, it doesn’t look like it’s possible; whether that’s true or not I don’t know. 
If there is a way to add displayGroups to a table and then, when checking for collisions, cycle through the table of displayGroups and then if needed remove an entire group rather than manually checking for specific collisions and then based on those results removing a specific displayGroup… that would be wonderful lol.
With the help of a generous Corona user, I’ve successfully incorporated tables in my code. Everything is much more efficient and works better.

Well, it’s hard to say whether the issues you’re facing relate to your code or not.  Probably yes.  In general, code that’s not well organized or structured will have subtle bugs that can be hard to pin down.

In your case, the error says you’re attempting to do arithmetic on a variable ‘x’ that is nil.  It refers to line 52 in firingsolution.lua, which is being called from line 767 in level2.lua.  So, you need to look at those and see if you can figure out why ‘x’ is nil.

As for tables, they are an extremely versatile data structure, so it’s definitely possible to do whatever .  As a start, you might consider putting your enemy tanks in an array (which is one way to use a table), so that you can loop through them one at a time without needing separate variable references for each.  And you can definitely define a table value to include both a base and a turret.  As a simple start, you could do something like this:

[lua]

– Array to hold all of the enemy tanks

local enemyTanks = {}

– Function to create and return an enemy tank

local newEnemyTank = function()

   – An enemy tank is a display group

   local enemyTank = display.newGroup()

    – Create the base and turret as part of the display group, and add them as custom properties of the displayGroup so that we can access them easily

   enemyTank.base = display.newImage(enemyTank, “base.png”)

   enemyTank.turret = display.newImage(enemyTank, “turrent.png”)

   return enemyTank

end

– Create five enemy tanks and add them to the array

for i=1,5 do

   enemyTanks[#enemyTanks+1] = newEnemyTank()

end

[/lua]

  • Andrew

Yeah. With the exception of Some of my collision-detection functions and a few others, most of my functions are optimized so that multiple objects can call the same function if needed.
I would say my code is actually organized pretty well… certain parts of it are just not structured in an efficient way. :wink:

I’m guessing it’s referring to the ‘src.x’ which is “@param Object src position of shooter”…

but I don’t understand why it can’t find the location of the source?
Regardless of the order (Etank01/02) in which I do the following, I get an error - enter tank’s radar, shoot tank, enter second tank’s radar and upon collison with the enemy’s ray I get an error.
If I enter a tank’s radar, shoot the tank, and then without entering the second tank’s radar shoot the tank, I don’t get an error…?

Initially my thought was that something is happening when I call my function/s for removing an Etank, but I don’t know what that would be…?
The first thing I do in my removeEtank function/s is 'if EnemyFiringTimer then timer.cancel(EnemyFiringTimer) end’ then I remove the tank, the tank’s radar, the bullet and play an explosion.
As far as I can tell, there isn’t anything there that would cause a conflict between my functions…

On the subject of tables -
Just to clarify, I completely understand the Concept of tables and arrays; I just couldn’t figure out how to set a single table value as being equal to two objects - again like a defined displayGroup containing multiple objects.

Thanks for the information. I’ll try to incorporate what you suggested.  :slight_smile:
I use LevelHelper, so all my tanks are already created/positioned. Using a specific line of code I can reference a specific tank if I need to make changes to it or add some attribute that will be unique to that tank.

Example:
[lua]
local enemyB02 = loader:spriteWithUniqueName(“Ebase02”)
physics.addBody( enemyB02, {filter = EnemyCollisionFilter } )
enemyB02.class = “Etank02” 

— The ‘B’ represents the tank’s ‘base’ object, and as would be expected the ‘T’ reps the turret object.

local enemyT02 = loader:spriteWithUniqueName(“Eturret02”)
physics.addBody( enemyT02, {filter = EnemyCollisionFilter } )
enemyT02.class = “Etank02”
enemyT02.isSensor = true
enemyT02.isFixedRotation = true
[/lua]

As you can see I give each object a .class of, in this case, ‘Etank02’. Then as you’ve seen, I check to see if the object hit has a .class of ‘Etank02’ and if so then it removes the displayGroup containing those objects… tedious, yes. Using your method however, it should make things much cleaner/more efficient. :slight_smile:

-Saer

An easy way to figure out which x is the problem is to put a print statement just before that line that prints out all of the x’s.  Like this: print(dst.x, src.x).  You’ll immediately see which one is nil.  Then consider where the src object being passed to this function came from.  Go there, insert more print statements, etc.  This is a ‘manual’ debugging approach that I find extremely useful (as opposed to using an IDE with breakpoints and variable inspection, which can also be useful).

It’s hard to say exactly why you’re error is occurring though, since it’s a lot of code for me to inspect detail.

Glad the suggestion on tables was helpful.  I haven’t used LevelHelper, but I have to imagine that there’s a way to use it that doesn’t require you to set up separate variables and functions for each element.

  • Andrew

Thanks for all your help and advice, Andrew.

Ah yes, I forgot I was able to print things like that. :slight_smile:

After doing what you suggested, I was somewhat able to figure out why it couldn’t locate the ‘src.x’… though in the end the answer was incredibly simple. All I had to do was isolate my RayCast function, and that solved it!
Actually upon further inspection, I wasn’t isolating the entire function, just the ‘if’ statement that checks what object/s the ray has hit. :smiley:

if ( EDray[1].object.class and EDray[1].object.class == "PlayerTank" or EDray[1].object.class == "Uturret" or EDray[1].object.class == "bullet") then

[lua]
– Casts a ray towards the user_tank to determine whether or not the enemy should fire.
function ETfire( self, user_tank )
    
    EDray = physics.rayCast( self.x, self.y, user_tank.x, user_tank.y, “unsorted” )
        
    local hitFirst = EDray[1]
    local hitX, hitY = hitFirst.position.x, hitFirst.position.y
    
    if EDray then
        – There’s at least one hit.
        print( "Hit count: " … tostring( #EDray ) )

        – Output all the results.
         for i,v in ipairs(EDray)  do
            print( "Hit: ", i, v.object.class, " Position: ", v.position.x, v.position.y, " Surface normal: ", v.normal.x, v.normal.y )
    end
        print( "The first object hit is: ",
        EDray[1].object.class, " at position: ", EDray[1].position.x, EDray[1].position.y, " where the surface normal is: ", EDray[1].normal.x, EDray[1].normal.y )

        else
        – There’s no hit.
    end
    
    if ( EDray[1].object.class and EDray[1].object.class == “PlayerTank” or EDray[1].object.class == “Uturret” or EDray[1].object.class == “bullet”) then
        
        print(“PlayerTank in range! Fire!”)
        timer.performWithDelay( 10, ShootEnemyBullet)
end

–[[
I  closed/ended the ‘if’ statement right after the statement’s conditional logic,
rather than putting the ‘end’ at the very end - after all the code/functions
that deal with creating the bullet, calculating angle the right angle to shoot the bullet,
collision-detection for the bullet etc… etc…

I’m not completely sure why ending the ray’s ‘if’ statement  solved it, I have an idea,
but regardless I’m happy it works.
–]]
[/lua]

Now all that’s left is figuring out a way to add the ray to some sort of collision filter… or at least figure out how to specify an object I don’t want to interact with the ray - in my case the radars.
As seen in the video, when the user_tank is in the area where both radars overlap, the rays register a collision when they hit the rim of the other tank’s radar.

-Saer

*I was able to solve the issue :slight_smile:

Well unfortunately my reaction was premature. :\
It only works under certain circumstances - video

:sigh: lol well, I’ll figure it out.
I also noticed that a possible cause of my troubles could be that I have both radars assigning a value to the ‘EnemyFiringTimer
(I have a foward declaration at the top of my code - local EnemyFiringTimer )

e.g. as seen in my original post when a tank’s radar it hit ( in the example above it’s the second tank’s radar) the EnemyFiringTimer is assigned a value -
[lua] EnemyFiringTimer = timer.performWithDelay(500, function() ETfire( enemyT02, event.other ) end, -1)
– enemyT02 is defined so it knows where to fire the bullet from 'n such.
[/lua]

but when I shoot a tank, this is called in addition to the code that removes the tank:
[lua] if EnemyFiringTimer then timer.cancel(EnemyFiringTimer) end [/lua]
Which obviously cancels both out.

So yeahhh… haha I’m at a loss for words. I’ll just keep experimenting and eventually get it. :slight_smile:

Hi there,
first to say I didn’t read all the prev posts, so this is more a genereal advice for raycasting and class like interaction of objects (tank turret and tank body)

First thing I don’t understand is why you cast a ray with the property “unsorted” and than take the first result out of the hit table. I mean that’s completly random, you could cast the ray with “any” and it would give you nearly same results.

In my actual project my maincharacter has a flashlight and I want the light to get shorter if it hits a wall, but not if it hits an enemy. So I cast a “sorted” ray and loop through the results from nearest to farest. If one of them is a wall I break the loop and return the hit object and the actual cordinates of the hit. To identify if hit an enemy or a wall all objects got an so called objectType. A string that tells what kind of object the ray hit. With that it’s possible to “mask” the results, as you could ignore specific objectTypes.

As Andrew mentioned before it would be nice to create something like a tank object, a table that contains all parts of a tank. The different parts could refer to there parent table, so it’s possible to link from one part to all of the others. That should solve the problem, that you don’t know which part of the tank has been hit and how to get the others.

local tank ={} tank.turret = display.newImage("tank\_turret.png") tank.turret.parent\_obj = tank tank.body = display.newImage("tank\_body.png") tank.body.parent\_obj = tank

One important thing is that this is a circular reference which can cause memory leaks if not handles correctly. Before destroying a part of the tank you have to nil out all the it.

display.remove(tank.turret) tank.turret.parent\_obj = nil tank.turret = nil

Maybe my suggestions help you, if not it’s ok too.

Greetings Torben

Thanks for weighing in, Torben.

I didn’t really think about that… As you say, it yields the same result, but according to the documentation using ‘Any’ is faster so I guess I might as well change it. actually, as stated in the docs,
unsorted : Return all results, in no particular order.
Any : Return one result, not necessarily the closest one. – “returns *one result” this would not work because the one result I’m checking for is the first hit.

Yeah, for my project I only need raycasting for my enemy tanks - as a form of environmental awareness sensing whether or not an object is in the enemy’s “firing path”, if you will.
As far as “masking” the results go, how would I do that?
As seen above, I use this:

&nbsp;&nbsp;&nbsp; EDray = physics.rayCast( self.x, self.y, user\_tank.x, user\_tank.y, "any" ) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; &nbsp;&nbsp;&nbsp; local hitFirst = EDray[1] &nbsp;&nbsp;&nbsp; local hitX, hitY = hitFirst.position.x, hitFirst.position.y &nbsp;&nbsp; &nbsp; &nbsp;&nbsp;&nbsp; if EDray then &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -- There's at least one hit. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print( "Hit count: " .. tostring( #EDray ) ) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -- Output all the results. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for i,v in ipairs(EDray)&nbsp; do &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print( "Hit: ", i, v.object.class, " Position: ", v.position.x, v.position.y, " Surface normal: ", v.normal.x, v.normal.y ) &nbsp;&nbsp;&nbsp; end &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print( "The first object hit is: ", &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; EDray[1].object.class, " at position: ", EDray[1].position.x, EDray[1].position.y, " where the surface normal is: ", EDray[1].normal.x, EDray[1].normal.y ) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -- There's no hit. &nbsp;&nbsp;&nbsp; end &nbsp;&nbsp;&nbsp; if ( EDray[1].object.class == "PlayerTank" or EDray[1].object.class == "Uturret" or EDray[1].object.class == "bullet") then &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print("PlayerTank in range! Fire!") &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; timer.performWithDelay( 40, ShootEnemyBullet ) &nbsp;

Every object that is hit, I get its information printed in the terminal.
So here’s an example of a condition where I need the ray to ignore certain objects -
I have metal-barriers/obstacles that the tank can’t drive over, but it can still shoot over.
Now when I place an object inside LevelHelper, I can assign it a custom tag and using the following code I can access every object that shares the defined tag:
 

-- Every object that has the tag 'WALLS' is rotated 90º -- local walls = loader:spritesWithTag(LevelHelper\_TAG.WALLS) for i = 1, #walls do &nbsp;local curSpr = walls[i]; &nbsp;&nbsp;&nbsp; curSpr.rotation = 90 &nbsp;&nbsp;&nbsp; print( curSpr.rotation ) end

It grabs every object that has the tag ‘WALLS’ assigned to it and rotates each one 90º.
(If I were to show you in the simulator, every wall would appear to have been rotated 90º)

Now my question would be, how could I tell the ray to ignore ‘curSpr’?

Yes, your suggestion was helpful. I’m always open to opinions. :slight_smile:

Edit: Sorry if the code came out weird, it wasn’t rendering quite right in the preview window. :mellow:

Edit: As far as tables/creating objects etc…
Since my objects are already created and positioned via LevelHelper, wouldn’t it be possible to simply use code similar to what I just showed, for adding them to a table?
Another example of how I use ‘tags’, is for my IGmines (in -ground) which can only be destroyed if a tank runs over one:
 

lol sorry for the long post. :wink:

I will post some rearanged code from my project, to show how ignoring some objects work. Don’t be to confused by the information about raycasting in the docs. It states that “sorted” rays have the slowest performance, but it’s not a big deal in most cases. I shoot like 10 “sorted” rays in an enter frame loop and there’s nearly no hit on performance.

Here is a little shoot function I use, that only returns the first valid hit and ignores the others.
The problem with raycasting is that the rays interact mit every physic shape, even if you set isBodyActive=false for it.

local function shoot\_ray(start\_x, start\_y, end\_x, end\_y) local hits = physics.rayCast( start\_x, start\_y, end\_x, end\_y, "sorted" ) local ray\_hit={} if hits then for i=1, #hits do local hit = hits[i] local object = hit.object if object.object\_type == "tank" or object.object\_type == "wall" then ray\_hit.x, ray\_hit.y = hit.position.x, hit.position.y ray\_hit.object = object break end end end return ray\_hit end

Shoots a ray from one point to another and returns the first valid hit. If there is no hit it returns an empty table.

lol I don’t know why I’m having trouble with this (maybe because it’s after 5:00 A.M. ) :wink:

I threw together a simple little ‘demo project’ to try your method, but I can’t get the ray to ignore the middle box:

link

– bump –
      :ph34r:

Anyone have an idea why I’m getting an error?

I notice in your original post, the line that would call onLevelCompletion() is commented out (labeled line 78).  So that would explain why it’s not being called…

More generally though, I think you should invest some time learning about how to use tables and object oriented design.  Right now you repeat a lot of the same code for your first enemy tank and your second enemy tank.  If you only ever plan to have two enemy tanks, that might be OK, but it’s not scalable if you ever plan to have more than two.

  • Andrew

Thanks for the reply.

I have resolved the problem.

Well that has to do with the enemy fire function. Right now nothing happens when an enemy fires a bullet at the user_tank, other than the bullet getting removed upon collision with the user or wall etc…

  • I may or may not make it to where the enemy bullets collide with and destroy other enemies, which if I did then that would mean I would need to check the current count of enemies via that function.

My function that allows the user to fire is where I am currently calling the onLevelCompletion, every time an enemy is destroyed. As seen in the video, once I get within ‘range’ and the enemy’s ray hits me it throws an error.
One thing I forgot to show in the video is if I destroy the first tank and then without colliding with the second enemy’s ray I shoot the second tank, it works just fine… no error and it calls my onLevelCompletion function.

In regards to my code, yes I’m sure I could greatly benefit from using tables etc…
But this is my first attempt at programming of any kind, so while some portions of my code are what you might call inefficient and can at times can be quite tedious to work with, it’s what I know how to do and it works.
*That being said, I am going to try to better optimize my code as I learn.  :slight_smile:

Edit: As far as tables go - I have done some research into them… however the problem I kept facing is that since my tanks are made up of two separate objects (base, turret) I couldn’t define a single table value that includes both objects of a single tank.
From some articles I read, it doesn’t look like it’s possible; whether that’s true or not I don’t know. 
If there is a way to add displayGroups to a table and then, when checking for collisions, cycle through the table of displayGroups and then if needed remove an entire group rather than manually checking for specific collisions and then based on those results removing a specific displayGroup… that would be wonderful lol.
With the help of a generous Corona user, I’ve successfully incorporated tables in my code. Everything is much more efficient and works better.

Well, it’s hard to say whether the issues you’re facing relate to your code or not.  Probably yes.  In general, code that’s not well organized or structured will have subtle bugs that can be hard to pin down.

In your case, the error says you’re attempting to do arithmetic on a variable ‘x’ that is nil.  It refers to line 52 in firingsolution.lua, which is being called from line 767 in level2.lua.  So, you need to look at those and see if you can figure out why ‘x’ is nil.

As for tables, they are an extremely versatile data structure, so it’s definitely possible to do whatever .  As a start, you might consider putting your enemy tanks in an array (which is one way to use a table), so that you can loop through them one at a time without needing separate variable references for each.  And you can definitely define a table value to include both a base and a turret.  As a simple start, you could do something like this:

[lua]

– Array to hold all of the enemy tanks

local enemyTanks = {}

– Function to create and return an enemy tank

local newEnemyTank = function()

   – An enemy tank is a display group

   local enemyTank = display.newGroup()

    – Create the base and turret as part of the display group, and add them as custom properties of the displayGroup so that we can access them easily

   enemyTank.base = display.newImage(enemyTank, “base.png”)

   enemyTank.turret = display.newImage(enemyTank, “turrent.png”)

   return enemyTank

end

– Create five enemy tanks and add them to the array

for i=1,5 do

   enemyTanks[#enemyTanks+1] = newEnemyTank()

end

[/lua]

  • Andrew

Yeah. With the exception of Some of my collision-detection functions and a few others, most of my functions are optimized so that multiple objects can call the same function if needed.
I would say my code is actually organized pretty well… certain parts of it are just not structured in an efficient way. :wink:

I’m guessing it’s referring to the ‘src.x’ which is “@param Object src position of shooter”…

but I don’t understand why it can’t find the location of the source?
Regardless of the order (Etank01/02) in which I do the following, I get an error - enter tank’s radar, shoot tank, enter second tank’s radar and upon collison with the enemy’s ray I get an error.
If I enter a tank’s radar, shoot the tank, and then without entering the second tank’s radar shoot the tank, I don’t get an error…?

Initially my thought was that something is happening when I call my function/s for removing an Etank, but I don’t know what that would be…?
The first thing I do in my removeEtank function/s is 'if EnemyFiringTimer then timer.cancel(EnemyFiringTimer) end’ then I remove the tank, the tank’s radar, the bullet and play an explosion.
As far as I can tell, there isn’t anything there that would cause a conflict between my functions…

On the subject of tables -
Just to clarify, I completely understand the Concept of tables and arrays; I just couldn’t figure out how to set a single table value as being equal to two objects - again like a defined displayGroup containing multiple objects.

Thanks for the information. I’ll try to incorporate what you suggested.  :slight_smile:
I use LevelHelper, so all my tanks are already created/positioned. Using a specific line of code I can reference a specific tank if I need to make changes to it or add some attribute that will be unique to that tank.

Example:
[lua]
local enemyB02 = loader:spriteWithUniqueName(“Ebase02”)
physics.addBody( enemyB02, {filter = EnemyCollisionFilter } )
enemyB02.class = “Etank02” 

— The ‘B’ represents the tank’s ‘base’ object, and as would be expected the ‘T’ reps the turret object.

local enemyT02 = loader:spriteWithUniqueName(“Eturret02”)
physics.addBody( enemyT02, {filter = EnemyCollisionFilter } )
enemyT02.class = “Etank02”
enemyT02.isSensor = true
enemyT02.isFixedRotation = true
[/lua]

As you can see I give each object a .class of, in this case, ‘Etank02’. Then as you’ve seen, I check to see if the object hit has a .class of ‘Etank02’ and if so then it removes the displayGroup containing those objects… tedious, yes. Using your method however, it should make things much cleaner/more efficient. :slight_smile:

-Saer