ウチツクシ

ゲームをしたり作ったり

HSPの物理エンジンOBAQのコリジョン処理でハマったこと

去年OBAQ使ったゲームを作ってる時にコリジョン関係でバグを何度か直して「もう直しきったはず!」と安心しきってたけど、今日やってみたらまだ残っててうんざりしたので、整理がてらメモ残しておきます。今後OBAQ使って同じような処理するゲーム作ることがあったら、あと同じようにうんざりしている人が他にいたら、役に立つかも。

初めに、あるオブジェクトAに他のオブジェクトBが当たったらBが消えてスコアが100入るケース。

#include "obaq.as"

    screen 0, 320, 240

    qreset
    qgravity 0, 0

    ; オブジェクトA設置
    qaddpoly target, 4, 20, 30, 0, 10, 20, , 1, , 2
    qtype target, type_bind

    score = 0
    fcnt = 0

*mainLoop
    redraw 0
    color : boxf

    qexec

    ; 60フレーム毎にオブジェクトB出現
    if ((fcnt \ 60) == 0) {
        qaddpoly obj, 4, 60, 30, , 4, 4, , 2
        qinertia obj, 1
        qspeed obj, -0.2
    }

    ; Aに当たったら消えてスコア加算
    qcollision target
    qgetcol i, x, y
    if (i >= 0) {
        score += 100
        qdel i
    }

    qdraw

    ; 情報表示
    color 255, 255, 255
    pos 30, 20
    mes "score " + score

    redraw 1
    await 15

    fcnt++
    goto *mainLoop

左にある中心点が赤いオブジェAに、中心点が緑のオブジェBが衝突してきてAに当たると消えて100点加算される。これは大丈夫、問題ない。

次に、B が2つ同時に A に当たるケース。
上のスクリプトのB出現の箇所を以下に置き換えて。

    ; 60フレーム毎にオブジェクトB出現
    if ((fcnt \ 60) == 0) {
        repeat 2
            qaddpoly obj, 4, 60, 25 + cnt * 10, , 4, 4, , 2
            qinertia obj, 1
            qspeed obj, -0.2
        loop
    }

同じ大きさ速度のオブジェをY座標だけ変えて同時に出しているから、同時にAに当たって同時に消えて200点入っている…ように見えるけど、よく見ると同時に消えていない。
ウェイト増やして確認すると、当たったとき上が先に消えて次のフレームで下が消えている。

Bを3つに増やしてみる。

    ; 60フレーム毎にオブジェクトB出現
    if ((fcnt \ 60) == 0) {
        repeat 3
            qaddpoly obj, 4, 60, 22 + cnt * 8, , 4, 4, , 2
            qinertia obj, 1
            qspeed obj, -0.2
        loop
    }

3つとも当っているはずなのに一番下だけ消えずに跳ね返ってしまう。

これはコリジョン処理に問題があって、1フレームに1オブジェクトしか処理していないから。そのため3つ消すのに3フレームかかってしまうけど、3フレーム目にはもうAとは接触していないため3つ目のオブジェクトは消えない。

だから1フレームで接触してるオブジェ全部を処理したい。qgetcol 命令は実行するごとにオブジェクトIDを次々と返し、もう返すIDがなくなったときは -1 が返るのでそれを利用する。

コリジョン処理部分を以下に書き換えて。

    ; Aに当たったら消えてスコア加算
    qcollision target
    repeat
        qgetcol i, x, y
        if (i < 0) : break
        score += 100
        qdel i
    loop

if のところは (i = -1) の方が分かりやすいけどHSPTV部門的に…接触しているオブジェを全部処理して、-1 が返ったらループを抜ける。これで1フレームで全部消えてくれるはず。
実行するとちゃんと消えてる。ウェイト増やして見てみても間違いない!

続きを読む