簡體   English   中英

p5.j​​s對象碰撞和對象糾纏

[英]p5.js object collision and objects entangling

我在p5.js中編寫了一些代碼,以查看是否可以正確地創建碰撞檢測系統,但是當我放置2個以上的正方形時,正方形似乎在其他正方形內部相互碰撞。 我想知道是否還有其他方法可以阻止這種加號,如果您有關於如何進行整潔/縮短我的代碼ID的好指針,比如想聽聽他們的話。

我的代碼:

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
}

您可以使用this查看它。 只需復制並粘貼。

解決無法解決的問題

對不起沒有這樣的事

當場景中有許多移動物體時,碰撞解決方案並不容易。

您的直接問題

您的問題主要是因為您正在對盒子碰撞時盒子的行進方向做出假設。 您將方向乘以-1即可反向。

都適合2個對象,但是添加第3個對象,最后將3個對象放在一起。 依次改變方向,box1擊中box2彼此遠離,然后在同一幀中box1擊中box3,現在box1和box3分開移動。您的速度是恆定的,因此在三向碰撞之后始終為2盒子沿相同方向但重疊。

下幀上的重疊框會檢測到重疊和反向,因為它們已經沿相同的方向行進,因此方向開關無法幫助它們分開。

前進的一步

相距僅一步之遙,對代碼的以下修改僅確保在可能的情況下,碰撞導致包裝箱彼此遠離。

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

但這只會使問題遠離重疊,現在有很多碰撞是錯誤的,因為沒有測試來確定碰撞點

在上面的代碼中,您嘗試從一個無法解決的位置解決問題。 現實生活中的盒子永遠不會重疊。 現實生活中的盒子會減速並加速。 完美平整的側面不會一次碰撞超過側面。

為此,您將需要使用集成。 它並不那么困難,而只是將時間分成較小步驟的過程。 碰撞,移動,檢查是否重疊,分開然后再碰撞。

Verlet整合

Verlet集成也將使其更容易。 而不是將箱速存儲為向量,而是存儲當前位置和先前位置。

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

您如下移動一個框

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;

當您碰到某些東西時,您需要更改舊位置,以便為下一次迭代提供正確的方向

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

分組進行。 一次移動所有物體,然后一次測試碰撞。 不要一次移動並測試一個。

Verlet集成更具寬容性,因為它可以使移動速度吸收一些錯誤。 而不是像標准矢量方法那樣處在適當位置。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM