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

发布于 2024-10-20 13:06:35 字数 2239 浏览 1 评论 0原文

我开始自学如何使用 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;
}

I was starting to teach myself how to work with HTML5 Canvas and decided to learn by making a short game/demo.

I wanted to make a simple blocks bounce around the screen, bounce off the walls, and bounce off each other.

I'm stuck on getting them to bounce off each other. It seems like code that makes it bounce away is making it bounce back immediately after. I see where the code fails but I don't know how to fix it :( Can anyone help?

(Side question: I know I'm not working as clean/efficiently/professionally as possible in this example but if I wanted to improve with feedback and opinions about the 'best' method for this type of example, like a code review or something, is it ok to ask a question on 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;
                        }
                    }
                }


            }
        }
    }

Ball Object:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

囍孤女 2024-10-27 13:06:35

通过将 <= 更改为 == 来使其工作,

这很混乱,而且事情经常会错过从块上必要的反弹:(我确信部分原因是依靠 == 而不是 <=。如果有人有更好的解决方案 - 我洗耳恭听:)

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

        }
    }
}

Got it working by changing the <= to ==

It's messy and things often miss the necessary bounce off a block :( I'm sure part of the reason is falling back on the == instead of <=. If anyone has a better solution - I'm all ears :)

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

        }
    }
}
神魇的王 2024-10-27 13:06:35

以下是您可能需要研究的几个命中检测片段:

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

Here are a couple hit detection snippets you might want to look into:

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

if the call returns 1 or greater your colliding, and you can even use that info to fix the difference.

Here is basic rect hit detections script:

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

I would call either of these with something like :

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
           }
       }
    }
}
我一向站在原地 2024-10-27 13:06:35

看来您忘记检查如果

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

添加此内容是否有效。还值得注意的是,您不需要为两个不同的 X 方向使用不同的代码,因为这种行为是对称的。无论它以哪种方式开始行驶,你都会让它反转方向。它在 Y 方向上也是对称的,因此如果您只需添加:

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

if 的“then”部分,您只需要一个 if 即可处理所有四种碰撞。

您可能还需要添加一个 break 语句,这样如果一个球碰巧同时与其他两个球碰撞,它只会反转方向一次。

为了进行更真实的模拟,您可以乘以 (0, 1) 区间内的负数,但是如果您不做其他事情,您的系统将慢慢进入稳定状态,直到出现舍入误差并崩溃。

It looks like you forgot to check if

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

If you add this in it works. It's also worth noting that you don't need different code for the two different X directions as this behaviour is symmetrical. Regardless of which way it is travelling to begin with you have it reversing direction. It's also symmetrical in the Y direction so if you just add:

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

to the 'then' part of the if you'll only need one if to take care of all four kinds of collisions.

You may also want to add a break statement so that if a ball happens to collide with two other balls at the same time it will only reverse direction once.

For a more realistic simulation you can multiply by a negative number in the (0, 1) interval, however if you don't do something else your system will slowly settle into a steady state until the rounding errors kick in and it freaks out.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文