Luaでファイルをロード/実行すると、Luaはファイル全体を一度連続して調べますので、ラインのチェックはmain.lua
のロード時にのみ行われます。
あなたのコードが今立っているとして、それはあなたがlove.update(dt)
メソッドにこれを入れた場合、それはあなたの所望の効果を達成する
if CheckCollision(enemy.x,enemy.y,enemy.w,enemy.h,bullets.x,bullets.y,bullets.w,bullets.h) then enemy = nil
end
一度敵と弾丸の衝突をチェックします。
私はenemy
は(衝突が発生した)nil
に設定されると、あなたがインデックスにあなたのenemy
変数はもはやテーブルであるので、nilの値をしようというエラーがスローされることに注意したいと思います。
また、注目すべきは、これらの行が不適切に動作するためにあなたの弾丸原因ループの中
bullets.x = o.x
bullets.y = o.y
for i, o in ipairs(bullets) do
(少なくとも、私はあなたが彼らが持っている行動のためにしたくないと仮定します)新しい弾丸が発砲されるたびに、コードは
table.insert(bullets, {
x = player.x,
y = player.y,
dir = direction,
speed = 400
})
のコードでテーブルに追加されますこれは、新しいテーブルを
#bullets + 1
(テーブルの最後のインデックス+1)インデックス
bullets
に置きます。 forループは
bullets
テーブル内の各箇条書きオブジェクトを繰り返し処理するため、最後の割り当ては常にテーブルの最後の箇条書きに表示されます。
これを簡単に説明しよう。
プレイヤーが2つの弾丸を発射したとします。最初の弾丸発射は私が前に述べたtable.insert(...)
呼び出しを呼び出すでしょう。スマートな思考 - だから、私たちのbullets
表は今、この
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
}
}
のようになります、あなたは私たちのforループだけbullets
内のテーブルを見てみましょうことを意味しipairs(...)
コールを使用していました。しかし、実装には問題があります。
-- 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
ここで、1つの新しい箇条書きについては、正常に動作します。新しい各弾丸が移動すると、各アップデートはbullets.x
とbullets.y
を正しく更新します。しかし、今度は、我々のプレーヤーが発射した2番目の弾丸とみなされます。
は
bullets
の新しい外観は、これはまだ起こっている場所を参照してください。この
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
}
}
のようなものですか?最初の反復で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
しかし、次に2番目の箇条書きに進みます。
-- 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
これが問題です。ループが現在書かれている方法では、プログラムは最後にbullets
テーブルに置かれるため、最後に実行された箇条書きのみを扱います。チェックされ、最後にbullets.x
とbullets.y
に割り当てられます。これにより、直前に発射された弾丸が敵に触れている場合にのみ衝突チェックが行われ、他のものには触れません。
これを解決するには2通りの方法があります。別々の衝突に各弾丸の位置を評価し、この
-- 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
のように、彼らのテーブルにあなただけのループの内側に衝突チェッカーの位置を移動し、そのパラメータを変更するには、この方法を幅と高さを追加します。
もう1つの方法は、オブジェクトのメタデータがクラスのようなテーブルを指し示す「インスタンス化」できるクラスのような表を作成することです。より困難ではありますが、練習が良く、メソッドを書くのがはるかに簡単です。複数のプレイヤー、敵、弾などの一般的な点検と評価をはるかに容易にします。
返信いただきありがとうございます!私はlua構文に慣れていないので、if文の大括弧についてはわかりませんでした。私はC++とJavaでもっと経験豊かです。私は自分のコードを少し更新しましたが、今ではエラーが発生しています。それは間違いなく構文の問題です。エラーは:main.lua:57: ')'の近くに ''があります。更新されたコード:http://pastebin.com/RDCmYj11 – user3103529