计算与Radians递增的碰撞

时间:2013-11-04 00:03:34

标签: trigonometry game-physics collision radians

使用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;
    }

我已经设法让一颗子弹从墙上弹开,其角度与射击的位置成比例,但是碰撞检测非常糟糕,因为它会反射一些子弹但不是全部,有些直接穿过墙壁。

刚刚添加了Line Collision Detection,我做了子弹线,所以我可以看到

this.oldTravelX,this.oldTravelY到this.travelX,this.travelY。它肯定有所改善,但有些子弹仍然在经历。

一些子弹似乎粘在弹跳区域内或滑动弹跳区左侧,然后决定是向左还是向右。

Added Line Collision Detection

更新代码:

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;          
    }
}

提前致谢。

1 个答案:

答案 0 :(得分:1)

看起来place_meeting函数应该确定子弹和障碍物之间是否存在碰撞。但是,此功能仅占用子弹的新位置。鉴于子弹每次更新移动5个单位,子弹可能会在一个框架内从障碍的一侧移动到另一侧。 e.g:

     |
   . |
    \|  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循环组合成一个,因为您没有重复使用数组中的值。只需计算您的测试点,然后立即进行测试。
  • 尝试使用console.log在程序运行时输出调试信息,以便更好地了解正在发生的事情。
  • 在变量之前使用var(例如pntdisnoPoints),以避免意外创建全局变量。