0

I have two objects that are colliding, and when they do collide, it causes an error. Here is the error:

[string "function _init()..."]:178: 
attempt to index a nil value (local 'sprite1')

I am checking every single frame for a collision between the player and the list of enemies (index of each one).

for I=1,#enemy_weak do
 if collision(enemy_weak[I],player)==true then
  playerattack(I)
 end
end

Here is the rest of the code:

function _init()
    --essential_variables
    mp=5
    ap=3
    turn=1
    kills=0
    dir=nil
    
    --nonessential_variables
    end_turn_text=false
    mspr=272
    
    --tables
    player={
        x=120,
     y=48,
        hp=3,
        sprite=256,
    }
    
    enemy_weak={
        x=-5,
        y=-5,
        hp=1,
        sprite=288,
 }
 
end

--initialize game
_init()

function TIC()
--update    
    --turn_control
    if mp==0 then
        end_turn_text=true
    end
    
    if btnp(4) then
            end_turn_text=false
            turn=turn+1
            mp=3
    end
    
    --misc
    mx,my,md=mouse()
    if md==true then
        mspr=273
    else
        mspr=272
    end
    
    player_mouse={
    x=mx-7,
  y=my-4,
  down=md,
  sprite=mspr
    }
    
    if btnp(2) then
        dir="left"
    end
    if btnp(3) then
        dir="right"
    end
    if btnp(0) then
        dir="up"
    end
    if btnp(1) then
        dir="down"
    end
--draw/print
    
    cls(0)
    poke(0x3FFB,1)
    --map
    map(0,0,30,17,0,0,0)
    
    --enemy
    
    spawnenemy(120,80)

    --player
    
    playermove()
    spr(player.sprite,player.x,player.y,0)
    playerloop()
    
    --mouse
    spr(mspr,grid(mx-2),grid(my-2),0)
    for I=1,#enemy_weak do
        if collision(enemy_weak[I],player_mouse)==true then
            mspr=274
        else
            mspr=272
        end
    end
    
        --player_attack
    for I=1,#enemy_weak do
        if collision(enemy_weak[I],player)==true then
            --playerattack(I)
        end
    end
    
    --text
    
    print("KILLS: "..kills,10,20,12)
    print("TURN: "..turn,100,10,12)
    print("MP: "..mp,10,30,12)
    print("AP: "..ap,10,40,12)
    print(detect_wall_collision(),5,5)
    print(dir,50,10)
    print(player.x,150,10)
    print(player.y,150,20)
    if end_turn_text==true then
        print("Press z to end turn",63,120,12)
    end 
end

--player functions

function playermove()
    if mp>0 then
        if btnp(2)and not detect_wall_collision() then
            player.x=player.x-8
            mp=mp-1
        end
        if btnp(3)and detect_wall_collision()==false then
            player.x=player.x+8
            mp=mp-1
        end
        if btnp(0)and detect_wall_collision()==false  then
            player.y=player.y-8
            mp=mp-1
        end
        if btnp(1)and  detect_wall_collision()==false then
            player.y=player.y+8
            mp=mp-1
        end
    end
end

function playerloop()
    if player.y>144 then
        player.y=-8
    elseif player.y<-8 then
        player.y=144
    elseif player.x>248 then
        player.x=-8
    elseif player.x<-8 then
        player.x=248
    end
end

function playerattack(enemyid)
    kills=kills+1
    table.remove(enemy_weak,enemyid)    
end

function inventory()

end

function detect_wall_collision()
    if dir=="left" then
        if mget(player.x-7,player.y)==112 then
            return true
        else
         return false
        end
    end 
    if dir=="right" then
        if mget(player.x+9,player.y)==112 then
            return true
        else
        return false
        end
    end 
    if dir=="up" then
        if mget(player.x,player.y-9)==112 then
            return true
        else
        return false
        end
    end
    if dir=="down" then
        if mget(player.x,player.y+9)==112 then
            return true
        else
        return false
        end
    end
end

--enemy
function spawnenemy(x,y)
    local enemy={}
    enemy.hp=1
    enemy.sprite=288
    enemy.x=grid(x)
    enemy.y=grid(y)
    spr(enemy.sprite,enemy.x,enemy.y,0)
    table.insert(enemy_weak,enemy)
end

--other
function grid(x)
    return math.floor((x)/8)*8
end

function collision(sprite1, sprite2)
-- Calculate the bounding boxes for each sprite
 local sprite1Left = sprite1.x
 local sprite1Right = sprite1.x+4
 local sprite1Top = sprite1.y
 local sprite1Bottom = sprite1.y+4

 local sprite2Left = sprite2.x
 local sprite2Right = sprite2.x+5
 local sprite2Top = sprite2.y
 local sprite2Bottom = sprite2.y+4

 -- Check for overlap
 if sprite1Right >= sprite2Left and sprite1Left <= sprite2Right and sprite1Bottom >= sprite2Top and sprite1Top <= sprite2Bottom then
  return true
 else
  return false
 end
end

I think it might be that the collision code is wrong somehow, although I am not sure.

Sam Cao
  • 1
  • 2
  • Why do you expect `sprite1` to be available? Where is it defined and where is it used? The code you have shown us does not seem to relate to the error you posted. The error means that you access e.g., `sprite1.something` while `sprite1` is `nil`. – Aki Jun 19 '23 at 09:13

1 Answers1

1

Do not remove enemies while iterating. If you kill someone, it will crash because the last enemy no longer exists.

Instead either

  • Iterate backwards, for #enemy_weak, 1, -1 do, because then you only shift enemies who are already processed.
  • Use tables and pairs. Setting an existing entry to nil instead of table.remove while traversing a table is fine and will not shift anything.

Btw, true evaluates to true, thus == true in your condition is in most cases not required.

Luke100000
  • 1,395
  • 2
  • 6
  • 18