英文:
Attempt to index a nil value in TIC-80
问题
我有两个物体正在发生碰撞,当它们碰撞时,会导致一个错误。以下是错误信息:
[string "function _init()..."]:178:
attempt to index a nil value (local 'sprite1')
我每一帧都在检查玩家和敌人列表(每个敌人的索引)之间是否发生碰撞。
for I=1,#enemy_weak do
if collision(enemy_weak[I],player)==true then
playerattack(I)
end
end
以下是代码的其余部分:(请注意,这部分是HTML和JavaScript代码,不需要翻译)
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-html -->
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
<details>
<summary>英文:</summary>
I have two objects that are colliding, and when they do collide, it causes an error. Here is the error:
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:
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-html -->
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
<!-- end snippet -->
I think it might be that the collision code is wrong somehow, although I am not sure.
</details>
# 答案1
**得分**: 1
不要在迭代过程中移除敌人。如果你杀死了某人,它会崩溃,因为最后一个敌人已经不存在。
而是要么
* 倒序迭代,`for #enemy_weak, 1, -1 do`,因为这样你只会移动已经处理过的敌人。
* 使用表和 `pairs`。在遍历表时,将现有条目设置为 `nil` 而不是使用 `table.remove` 是可以的,不会导致任何位移。
顺便说一下,`true` 的值就是 `true`,因此在大多数情况下不需要在你的条件中使用 `== true`。
<details>
<summary>英文:</summary>
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.
</details>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论