Attempt to index a nil value in TIC-80

81 Views Asked by At

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.

1

There are 1 best solutions below

0
On

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.