Collisione con oggetti (muri) [duplicato]

Oct 27 2020

Che buona pratica per rilevare la collisione di 2 oggetti (muri). Sì, non solo rilevamento, ma ulteriore spostamento in modo che gli oggetti non entrino tra loro. Cioè, in modo che quando si scontrano, si appoggiano l'uno contro l'altro, ma non entrano.

CODICE

class WallObj {
    constructor(obj) {//x, y, w, h, bern ,thru) {
        this.x = obj.x
        this.y = obj.y
        this.w = obj.w
        this.h = obj.h
        this.bern = obj.bern
        this.thru = obj.thru
        this.hide = obj.hide
        this.id = obj.id
    }

    collusionWall(startPosition, endPosition) {
        var xS = startPosition[0]
        var x = endPosition[0]

        if (xS - x > 0)
            if (x)
                // if wall behind point
                if (this.x < startPosition[0])
                    return endPosition
                else if (this.x + this.w < x)
                    return endPosition

        return endPosition

        // return [this.x, endPosition[1]]
    }

}

Risposte

2 codeanjero Oct 27 2020 at 16:10

un approccio ingenuo sarebbe controllare x e y:

let ctx = mycan.getContext("2d");
let objects = [];

class player 
{
  constructor()
  {
    this.position = {x:50,y:50};
   this.color = "blue";
    this.size = 32;
    this.stop= false;
    this.prevpos=this.position;
    window.addEventListener("keydown",(e)=>{
      if(this.stop) this.position=this.prevpos;
      else this.displacement(e);
    });
  }
  
   displacement(e)
   {
      this.prevpos = this.position;
      this.position.x+=(e.key=="ArrowRight");
      this.position.x-=(e.key=="ArrowLeft");
      this.position.y+=(e.key=="ArrowDown");
      this.position.y-=(e.key=="ArrowUp");
   }
  
  draw()
  {
    ctx.fillStyle = this.color;  ctx.fillRect(this.position.x,this.position.y,this.size,this.size);
  }
};

class wall
{
  constructor(posx,posy)
  {
   this.position = {x:posx,y:posy};
   this.color = "red";
   this.size = 32;
   }
   
   draw(){
    ctx.fillStyle = this.color;
    ctx.fillRect(this.position.x,this.position.y,this.size,this.size);
   }
};

for(let i = 0; i<mycan.width;i+=32)
{
  objects.push(new wall(i,0));
  objects.push(new wall(i,mycan.height-32));
}

for(let j = 0; j<mycan.height;j+=32)
{
  objects.push(new wall(0,j));
  objects.push(new wall(mycan.width-32,j));
}

let playr=new player;


let collision = (colider)=>{
let colx = false;
let coly = false;
/*******************************************************
here we check if the top left point from our current
wall object is inferior to the top left point of our
player and if the top rignt point of the wall object is
superior to the player top left point.
we need to repeat this for the player top right point 
(so we compare the player top right point is superior
to the wall top left point and inferior to the wall 
top right point)
then we repeat this for y
*******************************************************/
  for(let object of objects)
  {
    colx = (
    (
    (object.position.x<=colider.position.x) && 
    (
    (object.position.x+object.size)>=
    (colider.position.x)
    )
    )||(
 (
 (colider.position.x+colider.size)>=object.position.x) && 
 (
 (colider.position.x+object.size)<=(object.position.x+object.size)
 )
 )
 )
    coly = (
    (
    (object.position.y<=colider.position.y) && 
    (
    (object.position.y+object.size)>=
    (colider.position.y)
    )
    )||(
 (
 (colider.position.y+colider.size)>=object.position.y) && 
 (
 (colider.position.y+object.size)<=(object.position.y+object.size)
 )
 )
 )
 if(colx&&coly) return true;
  }
  return false;
};

setInterval(()=>{
  ctx.clearRect(0,0,mycan.width,mycan.height);
  playr.stop = collision(playr);
  playr.draw();
  for(let obj of objects)
    obj.draw();
},1000/30);
<canvas id="mycan" width=400 height=250></canvas>

Un approccio migliore sarebbe tagliare il tuo mondo 2d in zone in cui la densità degli oggetti che possono entrare in collisione è più o meno importante (un quadtree).

così :

e un modo più semplice sarebbe guardare se l'oggetto freddo è in una sfera (ciò significherebbe che i muri hanno una collisione sferica e difficilmente potrebbero essere rappresentati come un quadrato) ma potremmo semplicemente dire che il giocatore è una sfera e controllare se qualcosa è entrato nel suo raggio.

https://studiofreya.com/3d-math-and-physics/sphere-vs-aabb-collision-detection-test/