碰撞形状并使它们彼此反弹

时间:2011-03-05 00:11:23

标签: javascript html5 canvas

我开始自学如何使用HTML5 Canvas,并决定通过制作一个简短的游戏/演示来学习。

我想让一个简单的块在屏幕周围反弹,从墙壁反弹,然后相互反弹。

我坚持要让他们互相反弹。似乎让它反弹的代码让它在之后立即反弹。我看到代码失败的地方,但我不知道如何解决它:(任何人都可以帮忙吗?

(旁边的问题:我知道在这个例子中我没有尽可能干净/有效/专业地工作但是如果我想改进反馈和对这类示例的'最佳'方法的意见,比如代码回顾什么,可以在stackoverflow上问一个问题吗?)

的jsfiddle: http://jsfiddle.net/vdcSv/

HTML:

<canvas id="canvas" Width="400" Height="300"></canvas>

Javscript:

    function CheckBallCollision(BallsArray, index) {
        for (var i = 0; i < BallsArray.length; i++) {
            if (index != i) {
                if (BallsArray[index].Xdir == 1) {
                    if ((BallsArray[index].Xmax >= BallsArray[i].Xmin)) {
                        if ((BallsArray[index].Ymin <= BallsArray[i].Ymin) && (BallsArray[index].Ymax >= BallsArray[i].Ymin) ||
                       ((BallsArray[index].Ymax >= BallsArray[i].Ymax) && (BallsArray[index].Ymin <= BallsArray[i].Ymax))) {
                            BallsArray[index].Xdir = -BallsArray[index].Xdir;
                        }
                    }
                } else if (BallsArray[index].Xdir == -1) {
                    if ((BallsArray[index].Xmin <= BallsArray[i].Xmax)) {
                        if ((BallsArray[index].Ymin <= BallsArray[i].Ymin) && (BallsArray[index].Ymax >= BallsArray[i].Ymin) ||
                       ((BallsArray[index].Ymax >= BallsArray[i].Ymax) && (BallsArray[index].Ymin <= BallsArray[i].Ymax))) {
                            BallsArray[index].Xdir = -BallsArray[index].Xdir;
                        }
                    }
                }


            }
        }
    }

球对象:

function Ball() {
    this.Xmin = 0;//top left X coord
    this.Ymin = 0;//top left y coord
    this.Height = 25; 
    this.Width = 25;
    this.Xmax = this.Xmin + this.Width;
    this.Ymax = this.Ymin + this.Height;
    this.Xdir = 0; // 0 not moving, 1 moving right, -1 moving left
    this.Ydir = 0;
    this.Red = 0;
    this.Green = 0;
    this.Blue = 200;
    this.Opacity = 1;
    this.Speed = 1;
}

3 个答案:

答案 0 :(得分:1)

通过更改&lt; = to ==

来实现它

这很混乱,事情经常会错过一个块的必要反弹:(我确定部分原因是回到==而不是&lt; =。如果有人有更好的解决方案 - 我都是耳朵:)

http://jsfiddle.net/vdcSv/1/

function CheckBallCollision(BallsArray, index) {
        for (var i = 0; i < BallsArray.length; i++) {
            if (index != i) {
                if (BallsArray[index].Xdir == 1) {
                    if ((BallsArray[index].Xmax == BallsArray[i].Xmin)) {
                        if ((BallsArray[index].Ymin <= BallsArray[i].Ymin) && (BallsArray[index].Ymax >= BallsArray[i].Ymin) ||
                       ((BallsArray[index].Ymax >= BallsArray[i].Ymax) && (BallsArray[index].Ymin <= BallsArray[i].Ymax))) {
                            BallsArray[index].Xdir = -BallsArray[index].Xdir;
                        }
                    }
                } else if (BallsArray[index].Xdir == -1) {
                    if ((BallsArray[index].Xmin == BallsArray[i].Xmax)) {
                        if ((BallsArray[index].Ymin <= BallsArray[i].Ymin) && (BallsArray[index].Ymax >= BallsArray[i].Ymin) ||
                       ((BallsArray[index].Ymax >= BallsArray[i].Ymax) && (BallsArray[index].Ymin <= BallsArray[i].Ymax))) {
                            BallsArray[index].Xdir = -BallsArray[index].Xdir;
                        }
                    }
                }

        }
    }
}

答案 1 :(得分:0)

以下是您可能需要查看的几个点击检测片段:

ball.hitTestCircle = function(obj) {
    var dx = this.x - obj.x;
    var dy = this.y - obj.y;
    var distance = (dx * dx) + (dy * dy);

    var area = (this.radius + obj.radius)*(this.radius + obj.radius);
    return (area / distance);
};

如果调用返回1或更高的冲突,您甚至可以使用该信息来修复差异。

这是基本的直击命中检测脚本:

ball.hitTestRect = function(b) {
    var difference = {};
    difference.x = this.x - b.x - b.width;
    difference.y = this.y - b.y - b.height;
    difference.height = this.height + b.height;
    difference.width = this.width + b.width;

    if (difference.x < 0 && difference.y <= 0 && difference.height + difference.y >= 0 && difference.width + difference.x >= 0) return true;
    return false;
};

我会用以下的方式调用其中任何一个:

for(var i=0;i!=balls.length;i++){
    for(var j=0;j!=balls.length;j++){
       if(j!=i){
           if(balls[i].hitTestRect(balls[j])){
               // all your reversing motion code
           }
       }
    }
}

答案 2 :(得分:0)

看起来你忘了检查是否

BallsArray[index].Xmin <= BallsArray[i].Xmax)

如果你添加它,它的工作原理。值得注意的是,对于两个不同的X方向,您不需要不同的代码,因为此行为是对称的。无论从哪个方向开始,你都有逆转方向。它在Y方向也是对称的,所以如果你只是添加:

BallsArray[index].Ydir = -BallsArray[index].Ydir;

if的'then'部分,如果要处理所有四种碰撞,你只需要一个。

你可能还想添加一个break语句,这样如果一个球碰巧同时碰到另外两个球,它只会反转一次。

对于更逼真的模拟,您可以在(0,1)间隔中乘以负数,但是如果您不做其他事情,您的系统将慢慢稳定到稳定状态,直到舍入错误开始并且它吓坏了。