0

Tululoo Game Maker API を使用してゲームをプログラミングしているときに、x と y がラジアンから計算されているため、衝突を正確に計算するのに問題があります。

以下の x と y の計算では、多数の小数点が生成されており、衝突をチェックするのが難しいと感じています。

image_angle は、弾丸が最初に使用するピストルの最終的な角度です。

セットアップ中:

x = instance_list(pistol)[0].x;
y = instance_list(pistol)[0].y;
startAng = instance_list(pistol)[0].image_angle;

this.travelX = cos(degtorad(instance_list(pistol)[0].image_angle)) * 5;
this.travelY = sin(degtorad(instance_list(pistol)[0].image_angle)) * 5;

更新フレーム:

x+=this.travelX;
y+=this.travelY;

ボールが壁から跳ね返る角度を計算するのは面倒です。

for(var i = 0; i < instance_number(bounce_barrier);i++){

    if(place_meeting(x,y,instance_list(bounce_barrier)[i])){

            if(Math.round(x*10)/10 > instance_list(bounce_barrier)[i].x ){
                newAng = 180 - startAng;
                this.travelX = +cos(degtorad(newAng)) * 15;
                this.travelY = +sin(degtorad(newAng)) * 15;
                startAng = newAng;
            }

            else if(y > instance_list(bounce_barrier)[i].y - 5 && y <= instance_list(bounce_barrier)[i].y + 10){

                newAng = 180 - startAng;
                this.travelX = -cos(degtorad(newAng)) * 15;
                this.travelY = -sin(degtorad(newAng)) * 15;
                startAng = newAng;
            }

            else if(y <= instance_list(bounce_barrier)[i].y - 5 + bounce_spr.height && y >= instance_list(bounce_barrier)[i].y + bounce_spr.height - 10){

                newAng = 180 - startAng;
                this.travelX = -cos(degtorad(newAng)) * 15;
                this.travelY = -sin(degtorad(newAng)) * 15;
                startAng = newAng;
            }

            else if(x < instance_list(bounce_barrier)[i].x){

                newAng = 180 - startAng;
                this.travelX = +cos(degtorad(newAng)) * 15;
                this.travelY = +sin(degtorad(newAng)) * 15;
                startAng = newAng;
            }
                    else{}

    }

}

place_meeting は Tululoo Game API の一部です:

 function __place_meeting__(nx, ny, what, many) {
        this.other = null;
        var i, l,
            // sprite, scale:
            ts = this.sprite_index,
            tsx, tsy, tfx, tfy, tst,
            // circle:
            tcx, tcy, tcr,
            // bbox:
            tbl, tbr, tbt, tbb,
            // instances, multiple, output, types:
            tz, tm, ct, ch, ra,
            // other:
            o, ox, oy, os, ost, osx, osy, ofx, ofy, ofr;
        if (ts == null) return false;
        tfx = ts.xoffset;
        tfy = ts.yoffset;
        tsx = this.image_xscale;
        tsy = this.image_yscale;
        tst = ts.collision_shape;
        // bbox:
        if (tst == 2) {
            tbl = nx + tsx * (ts.collision_left - tfx);
            tbr = nx + tsx * (ts.collision_right - tfx);
            tbt = ny + tsy * (ts.collision_top - tfy);
            tbb = ny + tsy * (ts.collision_bottom - tfy);
        }
        // circle:
        if (tst == 3) {
            tcr = ts.collision_radius * (tsx > tsy ? tsx : tsy);
            tcx = nx + tsx * (ts.width / 2 - tfx);
            tcy = ny + tsy * (ts.height / 2 - tfy);
        }
        //
        tz = (what.__instance ? [what] : instance_list(what));
        tm = many ? true : false;
        if (tm) ra = [];
        l = tz.length;
        for (i = 0; i < l; i++) {
            o = tz[i];
            if (!o.collision_checking) continue;
            os = o.sprite_index;
            if (os == null) continue;
            ox = o.x; osx = o.image_xscale;
            oy = o.y; osy = o.image_yscale;
            ost = os.collision_shape;
            ct = (tst << 4) | ost;
            ch = false;
            switch(ct) {
            case 0x22:
                if (osx == 1 && osy == 1) {
                    ofx = os.xoffset; ofy = os.yoffset;
                    if (!collide_bbox_bbox(tbl, tbt, tbr, tbb,
                    ox + os.collision_left - ofx, oy + os.collision_top - ofy,
                    ox + os.collision_right - ofx, oy + os.collision_bottom - ofy)) break;
                } else if (!collide_bbox_sbox(tbl, tbt, tbr, tbb, ox, oy, osx, osy, os)) break;
                ch = true;
                break;
            case 0x23:
                ofr = os.collision_radius * (osx > osy ? osx : osy);
                ofx = ox + osx * (os.width / 2 - os.xoffset);
                ofy = oy + osy * (os.height / 2 - os.yoffset);
                if (!collide_bbox_circle(tbl, tbt, tbr, tbb, ofx, ofy, ofr)) break;
                ch = true;
                break;
            case 0x32:
                if (osx == 1 && osy == 1) {
                    ofx = os.xoffset; ofy = os.yoffset;
                    if (!collide_bbox_circle(
                    ox + os.collision_left - ofx, oy + os.collision_top - ofy,
                    ox + os.collision_right - ofx, oy + os.collision_bottom - ofy,
                    tcx, tcy, tcr)) break;
                } else if (!collide_sbox_circle(ox, oy, osx, osy, os, tcx, tcy, tcr)) break;
                ch = true;
                break;
            case 0x33:
                ofr = os.collision_radius * (osx > osy ? osx : osy);
                ofx = ox + osx * (os.width / 2 - os.xoffset);
                ofy = oy + osy * (os.height / 2 - os.yoffset);
                if (!collide_circle_circle(tcx, tcy, tcr, ofx, ofy, ofr)) break;
                ch = true;
                break;
            } if (!ch) continue;
            this.other = o;
            o.other = this;
            if (!tm) return (o);
            ra.push(o);
        } return ra;
    }

弾丸が発射された場所に比例した角度で​​壁から跳ね返ることができましたが、すべてではなくいくつかの弾丸を跳ね返すため、衝突検出は非常に悪く、一部は壁をまっすぐ通過します。

ライン衝突検出を追加したところ、箇条書きのラインを作成したので、

this.oldTravelX,this.oldTravelY を this.travelX,this.travelY に移動します。確実に改善されましたが、一部の弾丸はまだ通過しています。

一部の弾丸は、跳ねるブロックの内側にくっついたり、跳ねるブロックの左側を滑り落ちたりして、左に行くか右に行くかを決めているようです。

ライン衝突検出を追加

更新されたコード:

pntdis = point_distance(this.oldTravelX, this.oldTravelY, this.travelX, this.travelY);
noPoints = pntdis/0.01;

for(var i=0; i < pntdis; i+=noPoints)
{
    pointsArrX[i] = this.travelX - (this.oldTravelX * i);
    pointsArrY[i] = this.travelY -  (this.oldTravelY * i);
}

for(var i=0;i<pointsArrX.length;i++){

    if(place_meeting(Math.round(pointsArrX[i]),Math.round(pointsArrY[i]),bounce_barrier) || place_meeting(x,y,bounce_barrier))
    {
            newAng = 180 - startAng;
            this.travelX = +cos(degtorad(newAng)) * 15;
            this.travelY = +sin(degtorad(newAng)) * 15;
            startAng = newAng;          
    }
}

前もって感謝します。

4

1 に答える 1

1

このplace_meeting関数は、弾丸とバリアの間に衝突があるかどうかを判断することになっているようです。ただし、この関数は箇条書きの新しい位置のみを取得します。弾丸が更新ごとに 5 単位移動することを考えると、弾丸が 1 つのフレームでバリアの一方の側から他方の側に移動する可能性があります。例えば:

     |
   . |
    \|  barrier
     \
     |\_______
       \
        .

place_meeting弾丸の古い位置と新しい位置の両方を取得して、中間位置がバリアと衝突したかどうかを判断できるようにする必要があります(たとえば、弾丸のパスとバリアのエッジで線と線の交差テストを行うことにより、おそらく衝突ポイントを返します)。


編集

更新されたコードは、弾丸のパスに沿った多数のポイントの衝突をチェックすることを目的としているようです。これを行うためのより速い方法がありますが、あなたの方法は十分に速く、理解しやすいかもしれません。ただし、チェックするポイントの計算方法にバグがあるようです。

紙の上で手動でコードをステップ実行する:

pntdis = 5  // assume point_distance returns 5
noPoints = 5 / 0.01 = 500
i = 0
pointsArrX[0] = this.travelX
pointsArrY[0] = this.travelY
i = i + noPoints = 500
500 < 5: false, for loop ends

その他の考慮事項:

  • 衝突を検出した後にステートメントが必要breakになる場合があるため、それ以上のポイントをテストし続ける必要はありません。
  • for配列内の値を再利用していないため、2 つのループを 1 つに結合できます。テストポイントを計算して、すぐにテストしてください。
  • console.logプログラムの実行時にデバッグ情報を出力して、何が起こっているのかをよりよく理解できるようにしてください。
  • 誤ってグローバル変数を作成しないvarように、変数 ( や など) の前にpntdis使用します。noPoints
于 2013-11-04T01:16:42.257 に答える