Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/tfs/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Lua 卢阿:用一个简单的射手制造一个碰撞系统,我在移除敌人物体方面遇到了问题_Lua_Collision Detection_Love2d - Fatal编程技术网

Lua 卢阿:用一个简单的射手制造一个碰撞系统,我在移除敌人物体方面遇到了问题

Lua 卢阿:用一个简单的射手制造一个碰撞系统,我在移除敌人物体方面遇到了问题,lua,collision-detection,love2d,Lua,Collision Detection,Love2d,我正在用love2d在lua制作一个简单的射击游戏。由于某种原因,当我启动游戏时,程序会认为敌人已经被射杀,而不会产生它。我想第80行有个问题。它似乎认为无论发生什么,敌人在任何时候都是零。我没有收到任何错误。我将使用代码链接到粘贴箱 编辑:我已经更新了我的代码,解决了上面的问题。我想我检查的碰撞使用边界框不正确。无论子弹从何处经过,敌人都不会被置为零。我认为这是因为它用shollet.x而不是o.x进行检查,但我不能用o.x进行检查,因为它是代码前面for循环中的一个局部变量 目前,您的代码

我正在用love2d在lua制作一个简单的射击游戏。由于某种原因,当我启动游戏时,程序会认为敌人已经被射杀,而不会产生它。我想第80行有个问题。它似乎认为无论发生什么,敌人在任何时候都是零。我没有收到任何错误。我将使用代码链接到粘贴箱

编辑:我已经更新了我的代码,解决了上面的问题。我想我检查的碰撞使用边界框不正确。无论子弹从何处经过,敌人都不会被置为零。我认为这是因为它用shollet.x而不是o.x进行检查,但我不能用o.x进行检查,因为它是代码前面for循环中的一个局部变量


目前,您的代码

if (CheckCollision) then
如果不提供任何参数,它将检查变量“CheckCollision”是否存在。在本例中,之所以如此,是因为您已在第53行将其声明为函数,因此每次更新“敌人”都将设置为零

if CheckCollision(x3,y3,x2,y2,w2,h2) then
使用此行,但将变量替换为相应实体的变量。
使用这个,你可以使用

if enemy then
在你的抽签呼叫中,它将检查“敌人”是否存在

顺便说一下,在lua中,if语句不需要在括号内

if (x > 3) then
功能与

if x > 3 then
编辑: 在您提供的新代码中,当您声明函数时,您将其参数命名为已经存在的变量。通常,您会输入一些未用作参数的任意变量。例如

function test(a, b)
    print(a + b)
end
然后使用它

test(1, 2)
或者如果你想使用变量

var1 = 1
var2 = 2
test(var1, var2)
使用已经存在的变量并不是很糟糕,它只是意味着你不能使用它们。使用表中的变量,lua可能不太满意

那么你在哪里

function CheckCollision(o.x,o.y,o.w,o.h, enemy.x,enemy.y,enemy.w,enemy.h)
    return o.x < enemy.x+enemy.w and
     enemy.x < o.x+o.w and
     o.y < enemy.y+enemy.h and
     enemy.y < o.y+o.h
end
功能检查碰撞(o.x,o.y,o.w,o.h,敌方.x,敌方.y,敌方.w,敌方.h)
返回o.x<敌人.x+敌人.w和
敌人x
用这样的东西代替

function CheckCollision(x1,y1,w1,h1, x2,y2,w2,h2)
    return x1 < x2+w2 and
     x2 < x1+w1 and
     y1 < y2+h2 and
     y2 < y1+h1
 end
函数检查冲突(x1、y1、w1、h1、x2、y2、w2、h2)
返回x1
或者,您可以跳过参数并将其硬编码

function CheckCollision()
    return o.x < enemy.x+enemy.w and
     enemy.x < o.x+o.w and
     o.y < enemy.y+enemy.h and
     enemy.y < o.y+o.h
end
函数CheckCollision()
返回o.x<敌人.x+敌人.w和
敌人x

我不确定这是否是您错误的根源,因为我无法访问适当的计算机来尝试它,但无论如何它都是有用的信息。

当您在Lua中加载/运行一个文件时,Lua会按顺序查看整个文件一次,因此检查冲突的行仅在加载
main.Lua
时出现,再也不会被人看见了

现在,你的代码只检查敌人和子弹的碰撞一次

if CheckCollision(enemy.x,enemy.y,enemy.w,enemy.h,bullets.x,bullets.y,bullets.w,bullets.h) then enemy = nil
end
如果你把它放到
love.update(dt)
方法中,它会达到你想要的效果

我想指出的是,一旦
敌方
设置为
nil
(发生冲突),您将抛出一个关于尝试索引nil值的错误,因为您的
敌方
变量不再是表

同样值得注意的是,这些行

bullets.x = o.x
bullets.y = o.y
在for循环中

for i, o in ipairs(bullets) do
导致您的项目符号行为不正常(至少,我假设您不希望它们有这样的行为)每次发射新项目符号时,它都会与代码一起添加到
项目符号
表中

table.insert(bullets, {
        x = player.x,
        y = player.y,

        dir = direction,
        speed = 400
    })
这会将每个新表放入
项目符号的
项目符号+1
(表的最后一个索引+1)索引中。由于for循环迭代
项目符号
表中的每个项目符号对象,因此发生的最后一个赋值始终在表中的最后一个项目符号上

让我试着更简单地解释一下

假设一个玩家发射两颗子弹。第一次子弹射击将调用我前面提到的
表.insert(…)
调用。因此,我们的
项目符号
表将如下所示

bullets = {
    x = 100,
    y = 100, -- This is what you set player.x and player.y to in the start.
    w = 15,
    h = 15,

    -- This is that new table we added - the 1st bullet fired.
    {
        -- This will all be inside it according to the table.insert(...) call.
        x = 100, -- What player.x is equal to
        y = 100, -- What player.y is equal to

        dir = ... -- Who knows what it is, just some radians that you calculated.
        speed = 400
    }
}
bullets = {
    x = 150, -- These are equal to the first bullet's values - for now, at least.
    y = 150,
    w = 15,
    h = 15,

    -- This 1st bullet is still here.
    {
        x = 150, -- Lets say the bullet has moved 50 pixels in both directions.
        y = 150,

        dir = ...
        speed = 400
    },

    -- This is the new second bullet.
    {
       x = 100, -- Remember player.x and player.y are both 100
       y = 100,

       dir = ...
       speed = 400
    }
}
-- When you add a bullet
table.insert(bullets, {
    x = player.x,
    y = player.y,
    w = bullets.w,
    h = bullets.h,

    dir = direction,
    speed = 400
})

-- When looking for collisions
local i, o
for i, o in ipairs(bullets) do
    o.x = o.x + math.cos(o.dir) * o.speed * dt
    o.y = o.y + math.sin(o.dir) * o.speed * dt

    -- This will destroy an enemy correctly
    if CheckCollision(enemy.x,enemy.y,enemy.w,enemy.h, o.x, o.y, o.w, o.h) then enemy = nil end

    if (o.x < -10) or (o.x > love.graphics.getWidth() + 10)
    or (o.y < -10) or (o.y > love.graphics.getHeight() + 10) then
        table.remove(bullets, i)
    end
end
现在,您使用了一个
ipairs(…)
调用,这意味着我们的for循环将只查看
项目符号中的表。但它的实施存在一个问题

-- With our new table inside bullets, we will only have that table to look at for the entire loop. So, lets jump right into the loop implementation.
local i, o
for i, o in ipairs(bullets) do
    -- This is fine. These lines look at the new table's x and y values and move them correctly.
    o.x = o.x + math.cos(o.dir) * o.speed * dt
    o.y = o.y + math.sin(o.dir) * o.speed * dt

    -- This is the problem.
    bullets.x = o.x  -- Now, those x and y values in the bullets table are set to the new table's x and y values.
    bullets.y = o.y

    -- The rest of the loop works fine.
    ...
end
现在,对于一个新的子弹,它工作得很好。每次更新都会在新的项目符号移动时正确更新
bollets.x
bollets.y
。但是现在让我们考虑一下我们的玩家发射的第二颗子弹

子弹头的新外观是这样的

bullets = {
    x = 100,
    y = 100, -- This is what you set player.x and player.y to in the start.
    w = 15,
    h = 15,

    -- This is that new table we added - the 1st bullet fired.
    {
        -- This will all be inside it according to the table.insert(...) call.
        x = 100, -- What player.x is equal to
        y = 100, -- What player.y is equal to

        dir = ... -- Who knows what it is, just some radians that you calculated.
        speed = 400
    }
}
bullets = {
    x = 150, -- These are equal to the first bullet's values - for now, at least.
    y = 150,
    w = 15,
    h = 15,

    -- This 1st bullet is still here.
    {
        x = 150, -- Lets say the bullet has moved 50 pixels in both directions.
        y = 150,

        dir = ...
        speed = 400
    },

    -- This is the new second bullet.
    {
       x = 100, -- Remember player.x and player.y are both 100
       y = 100,

       dir = ...
       speed = 400
    }
}
-- When you add a bullet
table.insert(bullets, {
    x = player.x,
    y = player.y,
    w = bullets.w,
    h = bullets.h,

    dir = direction,
    speed = 400
})

-- When looking for collisions
local i, o
for i, o in ipairs(bullets) do
    o.x = o.x + math.cos(o.dir) * o.speed * dt
    o.y = o.y + math.sin(o.dir) * o.speed * dt

    -- This will destroy an enemy correctly
    if CheckCollision(enemy.x,enemy.y,enemy.w,enemy.h, o.x, o.y, o.w, o.h) then enemy = nil end

    if (o.x < -10) or (o.x > love.graphics.getWidth() + 10)
    or (o.y < -10) or (o.y > love.graphics.getHeight() + 10) then
        table.remove(bullets, i)
    end
end
看到这是怎么回事了吗?让我们在第一次迭代时跳转到for循环

-- First iteration occurs. We're looking at the first bullet.
for i, o in ipairs(bullets) do
    o.x = o.x + math.cos(o.dir) * o.speed * dt -- Lets say o.x = 160 now
    o.y = o.y + math.sin(o.dir) * o.speed * dt -- and o.y = 160

    bullets.x = o.x  -- bullets.x = o.x, so bullets.x = 160
    bullets.y = o.y  -- bullets.y = o.y, so bullets.y = 160

    ...
end
但接下来我们会看到第二颗子弹

-- Second iteration, second bullet.
for i, o in ipairs(bullets) do
     -- Since it's the new table, o.x and o.y start at 100 
     o.x = o.x + math.cos(o.dir) * o.speed * dt  -- Lets say o.x = 110
     o.y = o.y + math.sin(o.dir) * o.speed * dt  -- Lets say o.y = 110 as well

     bullets.x = o.x
     bullets.y = o.y
     -- But now our bullets.x and bullets.y have moved to the new bullet!
     -- The position of the 1st bullet is completely forgotten about!

     ...
end
这就是问题所在。按照当前编写循环的方式,程序只关心最近发射的子弹,因为它将被放在
子弹
表的最后一位-它将被选中并分配给
子弹.x
子弹.y
最后一位。这使得碰撞检查只关心最近发射的子弹是否碰到敌人,而不关心其他子弹

有两种方法可以解决这个问题。或者在碰撞中分别计算每个项目符号的位置,并将宽度和高度添加到它们的表格中,如下所示

bullets = {
    x = 100,
    y = 100, -- This is what you set player.x and player.y to in the start.
    w = 15,
    h = 15,

    -- This is that new table we added - the 1st bullet fired.
    {
        -- This will all be inside it according to the table.insert(...) call.
        x = 100, -- What player.x is equal to
        y = 100, -- What player.y is equal to

        dir = ... -- Who knows what it is, just some radians that you calculated.
        speed = 400
    }
}
bullets = {
    x = 150, -- These are equal to the first bullet's values - for now, at least.
    y = 150,
    w = 15,
    h = 15,

    -- This 1st bullet is still here.
    {
        x = 150, -- Lets say the bullet has moved 50 pixels in both directions.
        y = 150,

        dir = ...
        speed = 400
    },

    -- This is the new second bullet.
    {
       x = 100, -- Remember player.x and player.y are both 100
       y = 100,

       dir = ...
       speed = 400
    }
}
-- When you add a bullet
table.insert(bullets, {
    x = player.x,
    y = player.y,
    w = bullets.w,
    h = bullets.h,

    dir = direction,
    speed = 400
})

-- When looking for collisions
local i, o
for i, o in ipairs(bullets) do
    o.x = o.x + math.cos(o.dir) * o.speed * dt
    o.y = o.y + math.sin(o.dir) * o.speed * dt

    -- This will destroy an enemy correctly
    if CheckCollision(enemy.x,enemy.y,enemy.w,enemy.h, o.x, o.y, o.w, o.h) then enemy = nil end

    if (o.x < -10) or (o.x > love.graphics.getWidth() + 10)
    or (o.y < -10) or (o.y > love.graphics.getHeight() + 10) then
        table.remove(bullets, i)
    end
end
——添加项目符号时
表.插入(项目符号{
x=player.x,
y=player.y,
w=子弹。w,
h=子弹。h,
dir=方向,
速度=400
})
--在寻找碰撞时
本地i,o
对于ipairs(子弹)中的i,o
o、 x=o.x+math.cos(o.dir)*o.speed*dt
o、 y=o.y+math.sin(o.dir)*o.speed*dt
--这将正确地消灭敌人
如果检查碰撞(敌方x,敌方y,敌方w,敌方h,o.x,o.y,o.w,o.h),则敌方=零结束
如果(o.x<-10)或(o.x>love.graphics.getWidth()+10)
或者(o.y<-10)或者(o.y>love.graphics.getHeight()+10)然后
表.删除(项目符号,i)
终止
终止
这样,您只需将碰撞检查器的位置移动到循环内部并更改其参数