简体   繁体   English

p5.j​​s对象碰撞和对象纠缠

[英]p5.js object collision and objects entangling

I wrote some code in p5.js to see if i can properly make a collision detection system but when i put more than 2 squares in, squares seem to bump each other inside of other squares. 我在p5.js中编写了一些代码,以查看是否可以正确地创建碰撞检测系统,但是当我放置2个以上的正方形时,正方形似乎在其他正方形内部相互碰撞。 I'd like to know if there's anyway to stop this plus, if you have any good pointers on how to do tidy/shorten my code id like to hear them. 我想知道是否还有其他方法可以阻止这种加号,如果您有关于如何进行整洁/缩短我的代码ID的好指针,比如想听听他们的话。

My code: 我的代码:

var r; //later defined as an array for the squares
var num; //number of squares
function setup(){
    r = [];
    num = 10;
    createCanvas(windowWidth,windowHeight- 4);
    for(var i = 0;i < num; i++){

        r[i] = new Box(random(width-40),random(height-40),40,40);

    }

}

function draw(){
    background(40);
    for(var i = 0;i < num; i++)    {
        r[i].show();
        for(var j = 0;j<num; j++){

            //this is the if statement evaluating if the left and right of the square is touching each other. i is one square and j is the other. you see in each if statement i have the acceleration being added, this is because if it wasn't then they would be true if the squares were touching each other on any side
            if(r[i].right+r[i].xa >= r[j].left && r[i].bottom >= r[j].top && r[i].top <= r[j].bottom && r[i].left + r[i].xa <= r[j].right){
                r[i].xa *= -1;
                r[j].xa *= -1;

            }
            //this is also just as confusing just read through it carefully
            if(r[i].bottom + r[i].ya >= r[j].top && r[i].right >=r[j].left && r[i].left <= r[j].right && r[i].top + r[i].ya <= r[j].bottom){
                r[i].ya *= -1;
                r[j].ya *= -1;
            }
        }    
    }


}
function Box(x, y, wid, hei){

    this.x = x;//input for square shape
    this.y = y;//ditto
    this.width = wid;//ditto
    this.height= hei;//ditto
    this.xa = random(2,5);//xa is the x acceleration
    this.ya = random(2,5);//ya is the y acceleration
    this.left;
    this.right;
    this.top;
    this.bottom;
    this.show = function(){
        this.left = this.x;     //i define left,right,top,bottom in show function so they get updated
        this.right = this.x +this.width;
        this.top = this.y;
        this.bottom = this.y +this.height;
        push();
        fill(255);
        noStroke();
        rect(this.x,this.y,this.width,this.height);
        pop();//push pop just in case i want to change square colors individually in the future
        this.x += this.xa;//adding acceleration to the squares
        this.y += this.ya;//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        if(this.x > width-this.width||this.x <0){//bouncing off the right and left wall
            this.xa *= -1;
            if(this.x > width/2){// making sure if the square spawns or glitches on the other side of the wall it doesn't get stuck, this checks which side the square is on when it touches the wall then moves it directly on the wall
                this.x = width-this.width;
            }else{
                this.x = 0;
            }
        }
        if(this.y > height-this.height||this.y <0){// same as above but for the y axis
            this.ya *= -1;
            if(this.y > height/2){
                this.y = height-this.height;
            }else{
                this.y = 0;
            }

        }

    }
}
function windowResized(){
    createCanvas(windowWidth,windowHeight- 4);//window resizing adjustment
}

you can view it using this . 您可以使用this查看它。 just copy and paste. 只需复制并粘贴。

The solution to the unsolvable 解决无法解决的问题

Sorry no such thing 对不起没有这样的事

Collision solutions are not easy when you have many moving objects in the scene. 当场景中有许多移动物体时,碰撞解决方案并不容易。

Your immediate problem 您的直接问题

Your problem if mainly because you are making an assumption on the box's direction of travel when they collide. 您的问题主要是因为您正在对盒子碰撞时盒子的行进方向做出假设。 You multiply the direction by -1 to reverse direction. 您将方向乘以-1即可反向。

All good for 2 objects, but add a 3rd and you will end up with the 3 coming together. 都适合2个对象,但是添加第3个对象,最后将3个对象放在一起。 Each in turn you change the direction, box1 hits box2 both move away from each other, then in the same frame box1 hits box3 and now box1 and box3 are moving apart.Your speeds are constant so after a three way collision there will always be 2 boxes traveling in the same direction but overlapping. 依次改变方向,box1击中box2彼此远离,然后在同一帧中box1击中box3,现在box1和box3分开移动。您的速度是恒定的,因此在三向碰撞之后始终为2盒子沿相同方向但重叠。

The overlapping boxes on the next frame detect the overlap and both reverse direction, as they are already traveling in the same direction the direction switch does not help them move apart. 下帧上的重叠框会检测到重叠和反向,因为它们已经沿相同的方向行进,因此方向开关无法帮助它们分开。

A step forward 前进的一步

Well a step apart, The following modification to the code just ensures that when possible a collision results in the box move away from each other. 相距仅一步之遥,对代码的以下修改仅确保在可能的情况下,碰撞导致包装箱彼此远离。

function draw() {
    background(40);
    for (var i = 0; i < num; i++) {
        const bx1 = r[i];
        r[i].show();
        for (var j = 0; j < num; j++) {
            if (j !== i) {
                // t for top, b for bottom, r for right and l for left. 1 for first box 2 for second
                // bx for box
                const bx2 = r[j];
                const t1 = bx1.top + bx1.ya;
                const b1 = bx1.bottom + bx1.ya;
                const l1 = bx1.left + bx1.xa;
                const r1 = bx1.right + bx1.xa;
                const t2 = bx2.top + bx2.ya;
                const b2 = bx2.bottom + bx2.ya;
                const l2 = bx2.left + bx2.xa;
                const r2 = bx2.right + bx2.xa;
                // the or's mean that the condition will complete at the first passed clause
                // If not (not over lapping)  AKA is overlapping
                if (!(t1 > b2 || b1 < t2 || l1 > r2 || r1 < l2)) {
                    if (r1 >= l2) {
                        bx1.xa = -Math.abs(bx1.xa);
                        bx2.xa = Math.abs(bx2.xa);
                    }
                    if (l1 <= r2) {
                        bx1.xa = Math.abs(bx1.xa);
                        bx2.xa = -Math.abs(bx2.xa);
                    }

                    if (b1 >= t2) {
                        bx1.ya = -Math.abs(bx1.ya);
                        bx2.ya = Math.abs(bx2.ya);
                    }
                    if (t1 <= b2) {
                        bx1.ya = Math.abs(bx1.ya);
                        bx2.ya = -Math.abs(bx2.ya);
                    }
                }
            }
        }
    }
}

But that only moves the problem away from overlapping, now there are many collision that are wrong as there is no test to determine the point of collision 但这只会使问题远离重叠,现在有很多碰撞是错误的,因为没有测试来确定碰撞点

In the above code you are trying to solve from an unsolvable position. 在上面的代码中,您尝试从一个无法解决的位置解决问题。 Boxes in real life never overlap. 现实生活中的盒子永远不会重叠。 Boxes in real life will slow down and speed up. 现实生活中的盒子会减速并加速。 perfectly flat sides will never collide with more than on side at a time. 完美平整的侧面不会一次碰撞超过侧面。

To do this you will need to use integration. 为此,您将需要使用集成。 Its not that hard and is just a process of dividing time into smaller steps. 它并不那么困难,而只是将时间分成较小步骤的过程。 Collide, move, check for overlap, move apart then back to collide. 碰撞,移动,检查是否重叠,分开然后再碰撞。

Verlet integration Verlet整合

Also verlet integration will make it easier. Verlet集成也将使其更容易。 Rather than store a boxes speed as a vector you store the current position and the previous position. 而不是将箱速存储为向量,而是存储当前位置和先前位置。

box.x = 10;
box.y = 10;
box.ox = 8;  // the boxes old position
box.oy = 8;

You move a box as follows 您如下移动一个框

sx = box.x - box.ox;
sy = box.y - box.oy;
box.ox = box.x;
box.oy = box.y;
box.x += sx;  // the boxes old position
box.y += sy;

When you hit something you need to change the old position so as to give the next iteration the correct direction 当您碰到某些东西时,您需要更改旧位置,以便为下一次迭代提供正确的方向

if(box.y > ground){
   box.y = ground - (box.y - ground); // move away from ground same dist as moved into ground
   box.oy = box.y -sy;
}

Do them all in groups. 分组进行。 Move all at once, then test for collision at once. 一次移动所有物体,然后一次测试碰撞。 Dont move and test one at a time. 不要一次移动并测试一个。

Verlet integration is much more forgiving as it lets speed of movement absorb some of the error. Verlet集成更具宽容性,因为它可以使移动速度吸收一些错误。 Rather than be all in position as the standard vector method does. 而不是像标准矢量方法那样处在适当位置。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM