2016-06-22 5 views
-1

私はlove2dを使って簡単なシューティングゲームを作っています。何らかの理由で私がゲームを開始したときに、プログラムは敵が射殺されたと判断し、それを召喚しません。私は80番目の問題だと思っています。何があっても敵は何時も無神経だと思えるようです。私は何の誤りもありません。コード付きのペーストビンへのリンク。ルア:シンプルなシューティングゲームで衝突システムを作って、敵オブジェクトを取り除く際に問題が発生する

編集:コードをかなり更新し、上記の問題を解決しました。私は間違ってバウンディングボックスを使用して衝突をチェックしていると思う。弾丸がどこを通過しても、敵は決してゼロに設定されません。私は、それはo.xの代わりにbullets.xでチェックするためだと思うが、コードの前のforループのローカル変数のためo.xでチェックできない。

http://pastebin.com/iwL0QHsc

答えて

3

パラメータを指定しない場合は変数 'CheckCollision' は存在する場合、現在、あなたのコードは、それが

if (CheckCollision) then 

チェックしますありません。この場合、53行目の関数として宣言しているため、 '敵'の更新はすべてnilに設定されます。

if CheckCollision(x3,y3,x2,y2,w2,h2) then 

この行を使用しますが、変数をそれぞれのエンティティの変数に置き換えてください。これを使用して
、あなたは「敵」は存在するかどうかを確認しますあなたのドローコールで

if enemy then 

を、使用することができます。

ちょうど、ちなみに、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 

使用して、代わりにこのような何かを持っています。

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 

また、パラメータをスキップしてハードコードすることもできます。

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 

私はそれをしようとする適切なコンピュータへのアクセスを持っていないが、それはとにかく有用な情報であるとして、これはあなたのエラーの原因であるかはわかりません。

+0

返信いただきありがとうございます!私はlua構文に慣れていないので、if文の大括弧についてはわかりませんでした。私はC++とJavaでもっと経験豊かです。私は自分のコードを少し更新しましたが、今ではエラーが発生しています。それは間違いなく構文の問題です。エラーは:main.lua:57: ')'の近くに ''があります。更新されたコード:http://pastebin.com/RDCmYj11 – user3103529

1

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.xbullets.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.xbullets.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つの方法は、オブジェクトのメタデータがクラスのようなテーブルを指し示す「インスタンス化」できるクラスのような表を作成することです。より困難ではありますが、練習が良く、メソッドを書くのがはるかに簡単です。複数のプレイヤー、敵、弾などの一般的な点検と評価をはるかに容易にします。

+0

返信いただきありがとうございます。私はあなたが示唆した変更を行い、あなたが言ったように敵との間違いに遭遇しましたが、私は敵のコードを書き直し、どのように削除して今は正常に動作するのですか?あなたの返信がどれほど助けになったか分かりません。再度、感謝します! – user3103529

関連する問題