All Enemies are deleted when one dies

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
Post Reply
Ceresaurs
Prole
Posts: 5
Joined: Sun Nov 24, 2024 3:00 pm

All Enemies are deleted when one dies

Post by Ceresaurs »

Hi! I'm new to love2d and coding in general and only started a couple of months ago. I'm having an issue where attacking one enemy, and it taking damage and running the remove function ends up removing all enemies on screen. I've tried countless of different ways to approach this and I'm not sure if it's my collision that's causing this issue, or something in my enemy code. I'm using box2d world callbacks for my collisions.

Press G while walking left or right (with the arrow keys or WASD) to attack, after selecting the available characters.

Feedback would be greatly appreciated! :awesome:
Attachments
beat em up test .zip
(2.42 MiB) Downloaded 205 times
User avatar
dusoft
Party member
Posts: 654
Joined: Fri Nov 08, 2013 12:07 am
Location: Europe usually
Contact:

Re: All Enemies are deleted when one dies

Post by dusoft »

Can you provide the relevant code, e.g. where the deletion happens? Probably you are creating enemy instances as a reference, not a copy.
Ceresaurs
Prole
Posts: 5
Joined: Sun Nov 24, 2024 3:00 pm

Re: All Enemies are deleted when one dies

Post by Ceresaurs »

Code: Select all

 function Enemy:checkRemove()
    for i, instance in ipairs(ActiveEnemys) do
        
        if instance.health  <= 0 then
         instance.toBeRemoved = true
        end

        if instance.toBeRemoved == true then
            instance:remove()
        end
    end
end

function Enemy:remove()
    for i, instance in ipairs(ActiveEnemys) do

        if instance.health <= 0 then
       
            instance.toSpawnNew = true

            instance.physics.body:destroy()


        table.remove(ActiveEnemys,i)


                
            return true
        else
            return false
   
        end
    end
end
Ceresaurs
Prole
Posts: 5
Joined: Sun Nov 24, 2024 3:00 pm

Re: All Enemies are deleted when one dies

Post by Ceresaurs »

Should probably also include this as well:

Code: Select all

function Hitbox.beginContact_PlayerToEnemy(a,b,collision) 
        for i,instance in ipairs(ActiveHitboxes) do
            if a == instance.physics.fixture or b == instance.physics.fixture then
                for v = 1, #ActiveEnemys do
                    if a == ActiveEnemys[v].physics.fixture or b == ActiveEnemys[v].physics.fixture then
                        return ActiveEnemys[v], true
                    
                    end
                end
            end
        end
    end

function beginContact(a, b, collision) 
    
    if Enemy.beginContact(a,b,collision) then Enemy:getIntent() return end
    if Hitbox.beginContact_PlayerToEnemy(a,b,collision) then --if player's hitbox contacts with enemy returns true then,

        Enemy:takeDamage(Hitbox.beginContact_PlayerToEnemy(a,b,collision))  return end --Enemy takes damage


    Player:beginContact(a, b, collision)
    
   
end

    
 function Enemy:takeDamage()
    for i,instance in ipairs(ActiveEnemys) do
       
        instance.health = instance.health - Player.damageOutput 
        instance:checkRemove()
        
       
    end
end 
MrFariator
Party member
Posts: 559
Joined: Wed Oct 05, 2016 11:53 am

Re: All Enemies are deleted when one dies

Post by MrFariator »

In your posted code, the enemy takeDamage function makes every enemy instance take damage at once, so that's likely your issue.
Ceresaurs
Prole
Posts: 5
Joined: Sun Nov 24, 2024 3:00 pm

Re: All Enemies are deleted when one dies

Post by Ceresaurs »

I originally had a conditional (after the for loop in the take damage function) in hopes that it would make it so that if the Enemy that calls the function is equal to the instance to run the code on the single enemy, but it never passes the check and I don't know why. Using the self keyword returns nil here and I also don't understand why that's the case.

Code: Select all

function Enemy:takeDamage()
    for i,instance in ipairs(ActiveEnemys) do
       if instance == self then -- never passes this check 
        self.health = self.health - Player.damage --"a nil value?"
        instance:checkRemove()
        hoverSFX:play()
       end
    end
end
MrFariator
Party member
Posts: 559
Joined: Wed Oct 05, 2016 11:53 am

Re: All Enemies are deleted when one dies

Post by MrFariator »

Looks like you've got a bit of a fundamental misunderstanding regarding the "self" keyword and instances of your enemy class.

Lets run through this example:

Code: Select all

local myTable = { x = 0 }
function myTable:myFunction ( ) 
  -- just increment table's x value
  self.x = self.x + 1 -- self is inferred from the colon syntax
end
myTable:myFunction ( )

-- is functionally equivalent to
local myTable = { x = 0 }
function myTable.myFunction ( tab ) -- "tab" could be named "self" or whatever you want
  tab.x = tab.x + 1
end
myTable.myFunction ( myTable )  
myTable:myFunction () -- can mix and match too, just need to be careful!
As you see, the colon (":") is just syntactic sugar, that reduces some amount of typing. Because in lua you are decently commonly passing tables around, or calling functions contained in tables (that act on those tables' contents), this kind of shorthand can be helpful -- just at the cost of causing some confusion for beginner programmers.

As such, when you have code like...

Code: Select all

Enemy:takeDamage(...)
That means that you are not passing an enemy instance to the function, but rather the enemy class itself. This is why in your code the "instance == self" check would never equate to true, because your class and its instances are different tables.

So, as you can see, you'll need to modify your "beginContact" function to instead act on your instances, rather than the enemy class itself. You may similarly want to do so on player class too, in case you ever want to spawn more than one copy of the player.

So...

Code: Select all

-- instead of this...
Enemy:takeDamage ( param1, param2, ... )
-- do this
Enemy.takeDamage (instanceOfEnemy, param1, param2, ... )
-- or this, assuming instances of your enemy class contain the takeDamage function
instanceOfEnemy:takeDamage ( param1, param2, ... )
I'll leave fixing up the code as an exercise for you to solve.
Ceresaurs
Prole
Posts: 5
Joined: Sun Nov 24, 2024 3:00 pm

Re: All Enemies are deleted when one dies

Post by Ceresaurs »

What I struggle with understanding is if "self" refers to the entire class of individual instances.

Also thank you for the response, I don't understand it entirely but I think it'll push me in the right direction!
RNavega
Party member
Posts: 385
Joined: Sun Aug 16, 2020 1:28 pm

Re: All Enemies are deleted when one dies

Post by RNavega »

If you're not yet familiar with metatables, trying to simulate classes and instances in Lua using the metatable __index trick can be a lot.
You can perfectly make your game by defining functions outside of any tables, and explicitly writing the table parameter, like with:

Code: Select all

local function enemyCheckRemove(enemy)
    if enemy.health <= 0 then
        (...)
    end
end
Post Reply

Who is online

Users browsing this forum: Ahrefs [Bot] and 3 guests