Help with enemy-tank firing behavior

Okay, so here is what I got going on -

I have my enemy tank, which is stationary, and I’m trying to get it to fire at the user_tank.
One method that was suggested to me was to fire a continuous stream of invisible bullets towards the user and if one hits the user, then call a function to fire a real bullet - that way the enemies won’t be firing all over the place, hitting the walls&barriers etc…

The problem is that my invisible bullets aren’t reacting to the physical environment (walls, barriers etc…) they are going straight through everything until they hit the user_tank and are removed.

You’ll see that my Ebullet1 is a sensor, that is because every time one of the enemy-tank’s bullets would collide with my user_tank it would cause it to jump a little.

This is the code I am currently using to fire a bullet from the enemy tank:
[lua] function shootEbullet()
    local pt = mathapi.rotateAboutPoint( {x=enemyT01.x,y=enemyT01.y-65}, enemyT01, enemyT01.rotation - 90 )
            
           
            local Ebullet1 = loader:createSpriteFromSHDocument(“FireBall”, “GameFX”, “LevelAssets.pshs”);
           – Ebullet1:scale(,);
            Ebullet1.x = pt.x; Ebullet1.y = pt.y;
            physics.addBody( Ebullet1 , “dynamic”, { friction= 0, bounce= 1.0, density= .6, radius= 7 } );
            Ebullet1.class = “bullet”
            Ebullet1.isBullet = true
            Ebullet1.myName = “Ebullet”
            Ebullet1.isSensor = true
            Ebullet1.rotation = enemyT01.rotation
            Ebullet1.isVisible = false
            
            
            Ebullet1:applyForce( pt.x - enemyT01.x, pt.y - enemyT01.y, enemyT01.x, enemyT01.y )
            level1group:insert( Ebullet1 )
           
            transition.to( Ebullet1, {
            time = 800,
            x = user_tank.x,
            y = user_tank.y,
            onComplete = shootEbullet } );
            
            
–==================== ‘removeSelf’ functions for various objects–====================

function fireRealBullet()
    ----
    ----
    print(" Fired Real Bullet ")
 end
 
 

–==================== Collision Handling–====================

        local onEbullet1Collision = function( self, event )
          if event.phase == “began” then
               
              if event.other.myName == “Ubase”
              or event.other.myName == “Uturret”
                
             then
                    print(" Hit PlayerTank ")
                    self:removeSelf()
                    self = nil
                    timer.performWithDelay( 10, fireRealBullet)
          end
       end
    end
    Ebullet1.collision = onEbullet1Collision
    Ebullet1:addEventListener( “collision”, Ebullet1 )
end
Runtime:addEventListener( “enterframe”, shootEbullet )
tmr = timer.performWithDelay(2000, shootEbullet, -1); [/lua]

I’d appreciate any tips someone might have. :smiley:

I removed the isSensor = true from the Ebullet.

I think the reason the Ebullet1 isn’t reacting to my physical objects is
because I am using transition.to to move my bullet… I’m guessing it
overrides the physics to get the defined object to the specified
point/s?

I am using this bit of code to make the enemy turret aim towards the user_tank when it calls the function to fire a real bullet:
[lua] 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 objects
local function angleBetween( enemyB01X, enemyB01Y, user_tankX, user_tankY )
      local angle = ( math_deg( math_atan2( user_tankY-enemyB01Y, user_tankX-enemyB01X ) )+180) --; return angle
         if ( angle < 0 ) then angle = angle + 360 end ; return angle % 360
end

function fireRealBullet()
    print(" Fired Real Bullet ")
    local ang = angleBetween( enemyB01.x, enemyB01.y, user_tank.x, user_tank.y )
      enemyT01.rotation = ang
 end [/lua]

It works how I want it to - when one of the “invisible” bullets hit the user it calls the function fireRealBullet and the turret aims towards the user_tank.
Only one issue, when I got to shoot the enemy tank, it gets removed and plays an animation I have defined, but halfway through the animation I get an error
"Line: 237

Attempt to perform arithmetic on field ‘y’ (a nil value)"

  • Line #2 in the shootEbullet function -
     

Anyone have a suggestion?

Hi @Saerothir,

At a glance, this is probably a scoping issue. If you “print ( enemyT01 )” on line #2, before the call to “mathapi.rotateAboutPoint”, does it return nil? If so, you need to figure out why that variable/object isn’t in the scope when Lua tries to do some math on its y value.

Brent

Thanks for the response Brent.

I tried what you suggested and it printed fine.

I could be wrong, but might it have something to do with this:
[lua] 

  • tmr = timer.performWithDelay(2000, shootEbullet, -1);

[/lua]
My thinking is since it is outside the function, even when the enemy tank is destroyed/removed, it continues to try to do all the math on an object that is no longer present…
I tried putting the timer inside the function, but when I do nothing happens… I don’t get any errors but the shootEbullet function does not start.

If you want, I can post both functions I use for shooting the player bullet and the enemy tank bullet (they also deal with collision detection).

Hi @Saerothir,

Just curious, is there a reason you’re using a transition for this instead of just pure physics on the bullet? It’s not fair to say that transitions “don’t play well” with physics, but a transition will keep trying to resolve itself after a collision occurs, so you need to cancel a transitioning object on collision. Generally I try to avoid them when using physics, but maybe that’s just me…

Brent

Well, for my user_tank I’m using an angleBetween function (provided by you actually) applying force to the bullet and using an invisible touch-sensitive-rect that acts as a sensor for when the user touches the display - which is how the user fires bullets.

I used the same appleForce bit of code for the enemy tank, but since the Etank isn’t controlled by a real person (no touch events) I wasn’t sure how to fire the Ebullet, so I just used transitions.

Hi @Saerothir,

Yes, I remember this project somewhat. :slight_smile:

Going back a few steps, you’re firing “invisible bullets”, I assume for the purpose of tracking the user? Sort of a predictive method whether the user tank is within range? If so, would you be interested in an actual, proven method of mathematically predicting the collision point of a moving object, i.e. fire a bullet from a stationary point (enemy tank) and have it hit the user tank, assuming the user tank is going in a straight line at the same speed?

This is the method commonly used in tower defense games, and the formula is proven many times over. It’s not “perfect”, i.e. it can’t predict if the user tank is going to slow down, speed up, or adjust its path post-fire, but it’s accurate if the target moving object continues on its normal vector path.

If you want that code, I can supply it for you. I didn’t write it myself… instead, credit Corona physics veteran @horacebury (Matt Webster)… but I have the code, and can supply it to you.

Brent

Yes, that’s exactly right. Whether the enemy tank is moving or stationary, it would constantly be firing ( the bullets would react to the physics objects wall, obstacles etc… ) and upon collision with the user it would trigger the enemy to then fire a real bullet.

  • It is the same concept used by the devs of TinyTanks -

I’d be very interested if you think it would be a better solution.
My tank is controlled by a virtual-joystick and the speed is fairly consistent - technically you could slow it down by only slightly moving the stick, but who would want to do that? :wink:

To give you a better idea of the type of game environment, here is a picture of a muckup level I’ve been using to test various things such as animations, effects, mechanics etc… etc…
link

Eventually I’ll be implementing the ‘Perspective’ camera module because I’ll be adding much bigger arenas.

Hi @Saerothir,

The main question now is, how are you dealing with the “range” of the enemies vs. the player? Do the enemies fire constantly no matter where the player is? Or do they have a certain radial range that the player must cross before they start firing? If so, how are you sensing this range? As a radial sensor (physics body) that’s larger than the enemy, or do you simply loop and do the distance math for the enemy depending on the location of the player?

Basically, there are a lot of factors involved which determine the best solution for this. The predictive aiming method I mention can work in various ways, but you’ll need to figure out the basic structure before you implement that part.

Brent

I haven’t started working with range yet. :] I’ve been focusing on trying to get the firing behavior working.
Eventually that is probably what I would do though, create an invisible radial sensor. <-- I assume no matter what method I end up using, the radial sensor concept will work? Or is there some math for working with/calculating range in the code from @horacebury?

The basic structure I had in mind was the following:
Firing - Like how I described in my previous posts.
Movement - Some enemies will move along bezier paths while others will move randomly within specified x,y coordinate “zones”.

I know there are quite a few variables to take into account when deciding what method to use, and I trust you to know what method would work best. I’m up for trying anything. :smiley:

 

Any thoughts?
Can the code you mentioned be found in the Code-Exchange? I searched “horacebury” but i didn’t find anything relating to what we’re discussing…

Hi @Saerothir,

I have an update for you! I asked Matt to post these functions on the Code Exchange, and he did, just yesterday:

http://developer.coronalabs.com/code/predictive-aiming-tower-defense

As I mentioned, I’ve briefly tested these and they work great. But you’ll have to work them into your code, and figure out the various settings and parameters that make it function as you wish.

Brent

Awesome!! Thanks for asking him Brent! :smiley:

The included example looks to be just what I need.
Adapting the code to my project is turning out to be a bit tricky, but I’ll get it.

Thanks for all your help and advice.

I removed the isSensor = true from the Ebullet.

I think the reason the Ebullet1 isn’t reacting to my physical objects is
because I am using transition.to to move my bullet… I’m guessing it
overrides the physics to get the defined object to the specified
point/s?

I am using this bit of code to make the enemy turret aim towards the user_tank when it calls the function to fire a real bullet:
[lua] 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 objects
local function angleBetween( enemyB01X, enemyB01Y, user_tankX, user_tankY )
      local angle = ( math_deg( math_atan2( user_tankY-enemyB01Y, user_tankX-enemyB01X ) )+180) --; return angle
         if ( angle < 0 ) then angle = angle + 360 end ; return angle % 360
end

function fireRealBullet()
    print(" Fired Real Bullet ")
    local ang = angleBetween( enemyB01.x, enemyB01.y, user_tank.x, user_tank.y )
      enemyT01.rotation = ang
 end [/lua]

It works how I want it to - when one of the “invisible” bullets hit the user it calls the function fireRealBullet and the turret aims towards the user_tank.
Only one issue, when I got to shoot the enemy tank, it gets removed and plays an animation I have defined, but halfway through the animation I get an error
"Line: 237

Attempt to perform arithmetic on field ‘y’ (a nil value)"

  • Line #2 in the shootEbullet function -
     

Anyone have a suggestion?

Hi @Saerothir,

At a glance, this is probably a scoping issue. If you “print ( enemyT01 )” on line #2, before the call to “mathapi.rotateAboutPoint”, does it return nil? If so, you need to figure out why that variable/object isn’t in the scope when Lua tries to do some math on its y value.

Brent

Thanks for the response Brent.

I tried what you suggested and it printed fine.

I could be wrong, but might it have something to do with this:
[lua] 

  • tmr = timer.performWithDelay(2000, shootEbullet, -1);

[/lua]
My thinking is since it is outside the function, even when the enemy tank is destroyed/removed, it continues to try to do all the math on an object that is no longer present…
I tried putting the timer inside the function, but when I do nothing happens… I don’t get any errors but the shootEbullet function does not start.

If you want, I can post both functions I use for shooting the player bullet and the enemy tank bullet (they also deal with collision detection).

Hi @Saerothir,

Just curious, is there a reason you’re using a transition for this instead of just pure physics on the bullet? It’s not fair to say that transitions “don’t play well” with physics, but a transition will keep trying to resolve itself after a collision occurs, so you need to cancel a transitioning object on collision. Generally I try to avoid them when using physics, but maybe that’s just me…

Brent

Well, for my user_tank I’m using an angleBetween function (provided by you actually) applying force to the bullet and using an invisible touch-sensitive-rect that acts as a sensor for when the user touches the display - which is how the user fires bullets.

I used the same appleForce bit of code for the enemy tank, but since the Etank isn’t controlled by a real person (no touch events) I wasn’t sure how to fire the Ebullet, so I just used transitions.