Spawning multiple sprites in for loop

Hello! I'm attempting to spawn several instances of a class that derives from Sprite and run some logic on all of them. Basically, I'm having them all spawn and run animation paths. The problem is, it only seems to spawn one instance of the object rather than all 6 that I'm attempting to instantiate.

function SpawnRow(enemiesInRow)
    local rowID = enemyRowsActive + 1

    for i = 1, enemiesInRow, 1 do
        local newEnemy = Enemy(100, 0)
        newEnemy:buildRoute(100, 0, 300, 120, 20, i * 20, 40, 1000, pd.easingFunctions.linear, 200 * i)
    end
end

SpawnRow(6)

When I debug this it counts to 6, but doesn't spawn more than the first sprite object. The one that does spawn behaves exactly as I intend it to. I'm new to Lua so there may be something I just don't know about via behaviors of for loops or how Sprites work in the sdk.

Let me know if you have any ideas!
Kurt

1 Like

When I run your code with my own Enemy class, I see 6 sprites on screen, so the problem doesn't seem to be with the code you've shared. Would you mind sharing your Enemy class?

Interesting! Thanks for looking into it for me. Here's the enemy code

local pd <const> = playdate
local gfx <const> = pd.graphics

local speed = 10

class('Enemy').extends(gfx.sprite)

local parts = {}

local animator = nil

function Enemy:init(x,y)
    local image = gfx.image.new("images/enemy")
    self:setImage(image)
    self:moveTo(x,y)
    self:add()
end

function Enemy:update()
    if animator then
        self:moveTo(animator:currentValue())
    end
end

function Enemy:buildRoute(startX, startY, bottomX, bottomY, endX, endY, arcRadius, duration, easing, delay)
    parts[1] = pd.geometry.lineSegment.new(startX, startY, bottomX, bottomY)
    parts[2] = pd.geometry.arc.new(bottomX, bottomY + arcRadius, arcRadius, 0, 360)
    parts[3] = pd.geometry.lineSegment.new(bottomX,bottomY,endX,endY)

    animator = gfx.animator.new({duration, duration, duration}, parts, {easing, easing, easing}, delay)
end

So, I put this issue on the back burner and started implementing collisions and all 6 of the enemies started colliding/revealing themselves as they did their fly patterns... So they all exist, but for some reason they're not being offset by the math I'm doing with the iterating i variable.

        newEnemy:buildRoute(100, 0, 300, 120, 20, i * 20, 40, 1000, pd.easingFunctions.linear, 200 * i)

After debugging the results of the i multiplications the enemies are all getting the correct offset variables... It's almost as if they're all receiving the same animator even though they're being set as local variables from the class they are instanced from.

Any thoughts on that?
Kurt

Alright, I figured out my issue. It seems to be just a simple misunderstanding of how things work in Lua on my part. I was calling everything on the local variable assuming that it would stay tied to individual instances, but that doesn't seem to be the case unless you reference the variable through self.variable.

Code that works as expected:

class('Enemy').extends(gfx.sprite)

local parts = {}
local partDuration = {}
local animEasing = {}

local animator = nil

function Enemy:init(x,y)
    local image = gfx.image.new("images/enemy")
    self:setImage(image)
    self:moveTo(x,y)
    self:setCollideRect(0,10,32,10)
    self:add()
end


function Enemy:collisionResponse(other)
    if other:isa(Bullet) then
        self:damage()
        other:remove()
        print("hit")
        return "overlap"
    end
    if other:isa(Enemy) then
        return "overlap"
    end
end

function Enemy:update()
    if self.animator then
        self:moveWithCollisions(self.animator:currentValue())
    end
end

function Enemy:buildRoute(startX, startY, bottomX, bottomY, endX, endY, arcRadius, duration, easing, delay)
    print("building new route")
    self.parts = {
        pd.geometry.lineSegment.new(startX, startY, bottomX, bottomY),
        pd.geometry.arc.new(bottomX, bottomY + arcRadius, arcRadius, 0, 360),
        pd.geometry.lineSegment.new(bottomX,bottomY,endX,endY)
    }
    self.partDuration = {duration, duration, duration}
    self.animEasing = {easing, easing, easing}

    self.animator = gfx.animator.new(self.partDuration, self.parts, self.animEasing, delay)
end

Awesome! Glad you figured it out.

You should be able to set the sprite's animator using playdate.graphics.sprite:setAnimator so that you don't have to worry about updating it yourself.

I'm banging my head against this as well. Thank you for your update. Will try to fix my particular issue using the self.property

Cool! Let me know if you still have an issue. It took me a while to understand scoping in Lua and basically every issue I've had developing for PlayDate has just been my misunderstanding of how Lua works!