P5.js 图像碰撞

P5.js Image Collision

我最近发现 p5.js 中的图像碰撞与常规矩形碰撞有很大不同。如果您想在 image() 函数中不手动设置高度和宽度参数而保持图像的纵横比,则可以使用 scale() 函数缩放图像。但是,这不会改变图像的区域,因此要检测碰撞,我必须将图像乘以我设置的图像比例。例如,如果在构造函数中设置,要获取播放器宽度将是 playerImage.width * player.scale.

所以我已经完成了所有这些,甚至还制作了一个函数来显示图像的area/hitbox。然后,当我用我的碰撞函数设置它时,底部和右侧检测到碰撞很好,但顶部和左侧似乎表现得很奇怪。

你可以在这里看到发生了什么:https://image-colliding.stcollier.repl.co/

有谁知道为什么左侧和顶部边缘的碰撞关闭?

这是我针对该问题的代码:

let debug = true;

function preload() {

  playerImg = loadImage("https://image-colliding.stcollier.repl.co/Player.png")
  brickImg = loadImage("https://image-colliding.stcollier.repl.co/brick.jpeg")

}

function setup() {

  createCanvas(windowWidth, windowHeight)

  player = new Player(windowWidth/2, windowHeight/2, 0.5)
  brick = new Brick(windowWidth/10, windowHeight/3, 0.1)

  speed = 3;

}

function draw() {

  background(200, 200, 200)

  push();
  brick.display();
  pop();

  push();
  player.display();
  pop();

if (debug) {
  showRectCollider(player.x, player.y, playerImg.width * player.s, playerImg.height * player.s)

  showRectCollider(brick.x, brick.y, brickImg.width * brick.s, brickImg.height * brick.s)

  if (player.collidesImg(brick.x, brick.y, brickImg.width, brickImg.height, brick.s)) {
    collidingColor = 'green';
  } else {
    collidingColor = 'red'
  }
}

if (keyIsPressed && keyCode === UP_ARROW) {
  moveY(player, -speed)
}
if (keyIsPressed && keyCode === DOWN_ARROW) {
  moveY(player, speed)
}
if (keyIsPressed && keyCode === LEFT_ARROW) {
  moveX(player, -speed)
}
if (keyIsPressed && keyCode === RIGHT_ARROW) {
  moveX(player, speed)
}

}

class Player {
  constructor(x, y, s) {
    this.x = x;
    this.y = y;
    this.s = s;
  }
  display() {
    translate(this.x, this.y)
    scale(this.s)
    image(playerImg, 0, 0)
  }
  collidesFunc1(x, y, w, h) {
  if (
    this.x - w/2 <= x + w/2 &&
    this.x + w/2 >= x - w/2 && 
    this.y - h/2 <= y + h/2 && 
    this.y + h/2 >= y - h/2) {
    return true;
  }
  else {
    return false;
    }
  }
  collidesFunc2(x, y, w, h) {
    if (
      this.x >= x - w &&
      this.x <= x + w &&
      this.y >= y - h &&
      this.y <= y + h) {
      return true;
    }
    else {
      return false;
    }
  }
  collidesImg(x, y, w, h, s) {
    if (
      this.x >= x - (w * s) &&
      this.x <= x + (w * s) &&
      this.y >= y - (h * s) &&
      this.y <= y + (h * s)) {
      return true;
    }
    else {
      return false;
    }
  }
}

class Brick {
  constructor(x, y, s) {
    this.x = x;
    this.y = y;
    this.s = s;
  }
  display() {
    translate(this.x, this.y)
    scale(this.s)
    image(brickImg, 0, 0)
  }
}

//Other functions

var collidingColor = 'red';

function showRectCollider(x, y, w, h) {
  noFill();
  stroke(collidingColor);
  strokeWeight(3);
  rect(x, y, w, h)
}

function moveX(object, speed) {
  object.x += speed;
}

function moveY(object, speed) {
  object.y += speed;
}
html, body {
  margin: 0;
  padding: 0;
  overflow: hidden;
}
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width">
    <title>repl.it</title>
    <link href="style.css" rel="stylesheet" type="text/css" />
    <script src="https://cdn.jsdelivr.net/npm/p5@1.3.1/lib/p5.js"></script>
  </head>
  <body>
    <script src="script.js"></script>
  </body>
</html>

我有三个用于检测碰撞的函数,目前我正在使用我制作的 collidesImg() 函数。所有三个函数都可以在第 71-106 行找到。

感谢您的帮助。非常感谢。

你的碰撞逻辑有点不对劲,这里附上解释性注释:

    collidesImg(x, y, w, h, s) {
        if (
            // right edge of player to the right of left edge of brick
            this.x + playerImg.width * this.s >= x &&
            // left edge of player to the left of right edge of brick
            this.x <= x + (w * s) &&
            // bottom edge of player below top edge of brick
            this.y + playerImg.height * this.s >= y &&
            // top edge of player above bottom edge of brick
            this.y <= y + (h * s)) {
            return true;
        } else {
            return false;
        }
    }

let debug = true;

function preload() {
    playerImg = loadImage("https://image-colliding.stcollier.repl.co/Player.png")
    brickImg = loadImage("https://image-colliding.stcollier.repl.co/brick.jpeg")
}

function setup() {

    createCanvas(windowWidth, windowHeight)

    player = new Player(windowWidth / 2, windowHeight / 2, 0.5)
    brick = new Brick(windowWidth / 10, windowHeight / 3, 0.1)

    speed = 3;

}

function draw() {

    background(200, 200, 200)

    push();
    brick.display();
    pop();

    push();
    player.display();
    pop();

    if (debug) {
        if (player.collidesImg(brick.x, brick.y, brickImg.width, brickImg.height, brick.s)) {
            collidingColor = 'green';
        } else {
            collidingColor = 'red'
        }

        showRectCollider(player.x, player.y, playerImg.width * player.s, playerImg.height * player.s)
        showRectCollider(brick.x, brick.y, brickImg.width * brick.s, brickImg.height * brick.s)
    }

    if (keyIsPressed && keyCode === UP_ARROW) {
        moveY(player, -speed)
    }
    if (keyIsPressed && keyCode === DOWN_ARROW) {
        moveY(player, speed)
    }
    if (keyIsPressed && keyCode === LEFT_ARROW) {
        moveX(player, -speed)
    }
    if (keyIsPressed && keyCode === RIGHT_ARROW) {
        moveX(player, speed)
    }

}

class Player {
    constructor(x, y, s) {
        this.x = x;
        this.y = y;
        this.s = s;
    }
    display() {
        translate(this.x, this.y)
        scale(this.s)
        image(playerImg, 0, 0)
    }
    collidesFunc1(x, y, w, h) {
        if (
            this.x - w / 2 <= x + w / 2 &&
            this.x + w / 2 >= x - w / 2 &&
            this.y - h / 2 <= y + h / 2 &&
            this.y + h / 2 >= y - h / 2) {
            return true;
        } else {
            return false;
        }
    }
    collidesFunc2(x, y, w, h) {
        if (
            this.x >= x - w &&
            this.x <= x + w &&
            this.y >= y - h &&
            this.y <= y + h) {
            return true;
        } else {
            return false;
        }
    }
    collidesImg(x, y, w, h, s) {
        if (
            // right edge of player to the right of left edge of brick
            this.x + playerImg.width * this.s >= x &&
            // left edge of player to the left of right edge of brick
            this.x <= x + (w * s) &&
            // bottom edge of player below top edge of brick
            this.y + playerImg.height * this.s >= y &&
            // top edge of player above bottom edge of brick
            this.y <= y + (h * s)) {
            return true;
        } else {
            return false;
        }
    }
}

class Brick {
    constructor(x, y, s) {
        this.x = x;
        this.y = y;
        this.s = s;
    }
    display() {
        translate(this.x, this.y)
        scale(this.s)
        image(brickImg, 0, 0)
    }
}

//Other functions

var collidingColor = 'red';

function showRectCollider(x, y, w, h) {
    noFill();
    stroke(collidingColor);
    strokeWeight(3);
    rect(x, y, w, h)
}

function moveX(object, speed) {
    object.x += speed;
}

function moveY(object, speed) {
    object.y += speed;
}
html, body {
  margin: 0;
  padding: 0;
  overflow: hidden;
}
<!DOCTYPE html>
<html>
  <head>
    <script src="https://cdn.jsdelivr.net/npm/p5@1.3.1/lib/p5.js"></script>
  </head>
  <body>
  </body>
</html>