I have an auto attack set up for my game. When the characters reach a specific X and Y location they start to attack. The goal is for the auto attack to run every 3 seconds.
to do this, I have a runtime event listener that controls the movement and also tracks the X and Y in order to trigger the attacking.
the problem that I have seemed to realize is that due to the frame rate, this actually triggers many times.
So if I make a single attack do 10 damage, it actually attacks for 10 damage multiplied by whatever the frame rate is.
I’ve tried using a timer.performWithDelay, but that was not a good solution.
anyone have an Idea of how I can make the character attack once they reach a certain point and from then on, attack only once every 3 seconds?
Well timer.performWithDelay() may still be your best option, but you’re going to need a flag to know when to fire off the timer.
local needToStartAttackTimer = true local attackTimer = nil local function yourRunTimeListener( event ) if (code to determine you're in range to attack) then if needToStartAttackTimer then needToStartAttackTimer = false attackTimer = timer.performWithDelay( 3000, doAttack, 0 ) end end if (code to stop the attack) then timer.cancel( attackTimer ) needToStartAttackTimer = true end end
thanks Rob, I tried what you have suggested and it still does not seem to work
I have the following code
if self.frame == 6 then if self.attackingTF == true then self.attackingTF = false self.attackTimer = timer.performWithDelay( 10000, self:attack(self.target), 1 ) end end
I have noticed that there seems to be something wrong with the timer itself. I have adjusted the delay time from 3000 all the way up to 10000 as you can see in my code, but it does not actually create any delay. both 3000 and 10000 seem to fire off instantly. I even specified that the iteration only be 1 to try and ensure that this only triggers once, but that does not work either.
I will say that before your suggestion, the function was firing off like 10 times, by using this chunk of code I have it tracked that it only fires off 3 times. It has been cut down, but I cant for the life of me figure out why it wont fire just once and why it seems as if the parameters I put into the timer delay dont seem to matter.
I did forget to mention that I did put in the timer.cancel, but that as well does not seem to produce anything
if self.frame == 6 then if self.attackingTF == true then self.attackingTF = false self.attackTimer = timer.performWithDelay( 10000, self:attack(self.target), 1 ) elseif self.attackingTF == false then timer.cancel( self.attackTimer ) end end
The 2nd parameter to timer.performWithDelay is an “address to a function”, not the return value from a function. When you put the () (in this case (self.target), you’re telling Lua to execute self:attack(self.target) and with the return value from that function, telling timer.performDelay() to execute that function in 10 seconds.
Normally, if you didn’t need the parameter, you would write:
sure, I used a template for OOP I believe I got from develephant. I’ll try and post a simple version of what I have to help keep it clean.
local function Enemy(name, image, class) enemy.class = class enemy.image = image enemy.name = name enemy.maxHealth = 100 enemy.health = 100 enemy.strength = 5 enemy.armor = 10 enemy.target = Hero1 enemy.attackingTF = false function enemyFollow(self, event) transition.moveTo (self, x, y, time = 1000) if self.x == target.x and self.y == target.y then self.attackingTF = true end if self.attackingTF == true then self:play() -- starts attack animation end if self.frame == 6 then if self.attackingTF == true then self.attackingTF = false self.attackTimer = timer.performWithDelay( 1000, function () self:attack(self.target); end, 1 ) elseif self.attackingTF == false then timer.cancel( self.attackTimer ) end end end enemy.enterFrame = enemyFollow -- moves enemies allows function to recognize self attributes Runtime:addEventListener("enterFrame", enemy) -- moves enemies function enemy:takeDamage( forHp, newTarget ) forHp = forHp or 0 self.health = math.max( 0, (self.health - forHp)) end function enemy:attack( character ) print("enemy attacks") if ( character ) then character:takeDamage (self.strength, self.armor, self.name) end end end return Enemy
This is just a quick and dirty example of what I have, not exact word for word. I hope this helps
How often is self.frame = 6? Your enterFrame listener is firing 30 or 60 times per second. If you’re value of self.frame isn’t updating fast enough that codes going to execute multiple times.
this is the animation info used, so I figure about 1/10th of a second is spent on frame 6.
I would not think that if I take self.frame 6 out for being a requirement I would think that it would only make the issue worse, because I would assume time spent on self.attackingTF = true would be a lot longer than the time spent on frame 6.
Well timer.performWithDelay() may still be your best option, but you’re going to need a flag to know when to fire off the timer.
local needToStartAttackTimer = true local attackTimer = nil local function yourRunTimeListener( event ) if (code to determine you're in range to attack) then if needToStartAttackTimer then needToStartAttackTimer = false attackTimer = timer.performWithDelay( 3000, doAttack, 0 ) end end if (code to stop the attack) then timer.cancel( attackTimer ) needToStartAttackTimer = true end end
thanks Rob, I tried what you have suggested and it still does not seem to work
I have the following code
if self.frame == 6 then if self.attackingTF == true then self.attackingTF = false self.attackTimer = timer.performWithDelay( 10000, self:attack(self.target), 1 ) end end
I have noticed that there seems to be something wrong with the timer itself. I have adjusted the delay time from 3000 all the way up to 10000 as you can see in my code, but it does not actually create any delay. both 3000 and 10000 seem to fire off instantly. I even specified that the iteration only be 1 to try and ensure that this only triggers once, but that does not work either.
I will say that before your suggestion, the function was firing off like 10 times, by using this chunk of code I have it tracked that it only fires off 3 times. It has been cut down, but I cant for the life of me figure out why it wont fire just once and why it seems as if the parameters I put into the timer delay dont seem to matter.
I did forget to mention that I did put in the timer.cancel, but that as well does not seem to produce anything
if self.frame == 6 then if self.attackingTF == true then self.attackingTF = false self.attackTimer = timer.performWithDelay( 10000, self:attack(self.target), 1 ) elseif self.attackingTF == false then timer.cancel( self.attackTimer ) end end
The 2nd parameter to timer.performWithDelay is an “address to a function”, not the return value from a function. When you put the () (in this case (self.target), you’re telling Lua to execute self:attack(self.target) and with the return value from that function, telling timer.performDelay() to execute that function in 10 seconds.
Normally, if you didn’t need the parameter, you would write:
sure, I used a template for OOP I believe I got from develephant. I’ll try and post a simple version of what I have to help keep it clean.
local function Enemy(name, image, class) enemy.class = class enemy.image = image enemy.name = name enemy.maxHealth = 100 enemy.health = 100 enemy.strength = 5 enemy.armor = 10 enemy.target = Hero1 enemy.attackingTF = false function enemyFollow(self, event) transition.moveTo (self, x, y, time = 1000) if self.x == target.x and self.y == target.y then self.attackingTF = true end if self.attackingTF == true then self:play() -- starts attack animation end if self.frame == 6 then if self.attackingTF == true then self.attackingTF = false self.attackTimer = timer.performWithDelay( 1000, function () self:attack(self.target); end, 1 ) elseif self.attackingTF == false then timer.cancel( self.attackTimer ) end end end enemy.enterFrame = enemyFollow -- moves enemies allows function to recognize self attributes Runtime:addEventListener("enterFrame", enemy) -- moves enemies function enemy:takeDamage( forHp, newTarget ) forHp = forHp or 0 self.health = math.max( 0, (self.health - forHp)) end function enemy:attack( character ) print("enemy attacks") if ( character ) then character:takeDamage (self.strength, self.armor, self.name) end end end return Enemy
This is just a quick and dirty example of what I have, not exact word for word. I hope this helps
How often is self.frame = 6? Your enterFrame listener is firing 30 or 60 times per second. If you’re value of self.frame isn’t updating fast enough that codes going to execute multiple times.
this is the animation info used, so I figure about 1/10th of a second is spent on frame 6.
I would not think that if I take self.frame 6 out for being a requirement I would think that it would only make the issue worse, because I would assume time spent on self.attackingTF = true would be a lot longer than the time spent on frame 6.