You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

2D平台游戏水平移动方块左侧碰撞玩家穿模Bug排查

2D平台游戏水平移动方块单侧碰撞失效问题

更新:我使用p5.js重写了最小可复现示例,核心逻辑如下:

let keyInput = []
let player
let block

function setup() {
  createCanvas(600, 600)
  
  player = new Player(0, height/2)
  block = new Block(200, height-100, 100, 1000)
}


function draw() {
  background(220);
  
  player.draw()
  block.draw()
  
  player.moveX()
  block.checkCollisionsX()
  player.moveY()
  block.checkCollisionsY()
}

function keyPressed() {
  keyInput[keyCode] = true;
}

function keyReleased() {
  keyInput[keyCode] = false;
}

function rectCollide(x1, y1, w1, h1, x2, y2, w2, h2) {
    return x1 + w1 > x2 && x1 < x2 + w2 && y1 + h1 > y2 && y1 < y2 + h2;
}

// 方块构造类
class Block {
  constructor(x, y, w, h) {
    this.x = x;
    this.y = y;
    this.w = w;
    this.h = h;
    
    this.movingSpeed = 3;
    this.start = 200
    this.stop = 400
  }
  draw() {
    fill(255)
    rect(this.x, this.y, this.w, this.h)
    this.x += this.movingSpeed;
    if (this.x > this.stop) {
        this.movingSpeed = -this.movingSpeed;
    }
    if (this.x < this.start) {
        this.movingSpeed = abs(this.movingSpeed);
    }
  }
  checkCollisionsX() {
    if (rectCollide(player.pos.x, player.pos.y, player.width, player.height, this.x, this.y, this.w, this.h)) {
        if (player.vel.x < 0) { // 玩家左移碰撞方块右侧
            player.pos.x = this.x + this.w;
        } else { // 玩家右移碰撞方块左侧(该侧逻辑失效)
            player.pos.x = this.x - player.width;
        }
        player.vel.x = 0;
    }
  }
  checkCollisionsY() {
    if (rectCollide(player.pos.x, player.pos.y, player.width, player.height, this.x, this.y, this.w, this.h)) {
        if (player.vel.y < 0) {
            player.pos.y = this.y + this.h;
            player.vel.y *= -yRebound; // 非完全弹性碰撞,回弹系数不为-1
        } else {
            //player.pos.x += movingSpeed; // 平台移动时将玩家同步固定在平台上
            player.jumps = player.numJumps;
            player.pos.y = this.y - player.height;
            player.vel.y = 0;
            player.acc.y = 0;
        }
    }
  }
}

// 玩家构造类
class Player {
  constructor(x, y) {    
    this.width = 50
    this.height = 100

    this.pos = new p5.Vector(x, y);
    this.vel = new p5.Vector(0, 0);
    this.acc = new p5.Vector(0, 0);

    this.accSpeed = 0.05;
    this.gravity = 0.5;
    this.maxVel = 10;
    this.jumpForce = 15;
    this.friction = 0.15;
    this.numJumps = 1;
    this.jumps = this.numJumps;

    this.isGrounded = false;
    this.canMove = true;

    this.dir = "DOWN"
  }
  draw() {
    fill(255, 0, 0)
    rect(this.pos.x, this.pos.y, this.width, this.height)
  }
  moveX() {
    // X轴移动逻辑
    if (keyInput[LEFT_ARROW] && this.vel.x > -this.maxVel && this.canMove) {
        this.acc.x = -this.accSpeed;
    } else if (keyInput[RIGHT_ARROW] && this.vel.x < this.maxVel && this.canMove) {
        this.acc.x = this.accSpeed;
    } else if (abs(this.vel.x) > 0.2) {
        this.acc.x = (this.vel.x < 0) ? this.friction : -this.friction;
    } else {
        this.vel.x = 0;
        this.acc.x = 0;
    }
    this.vel.x += this.acc.x; // 速度累加加速度
    this.pos.x += this.vel.x; // 位置累加速度
  }
  moveY() {
    // Y轴移动逻辑
    if (keyInput[UP_ARROW] && this.jumps > 0 && this.canMove) {
      this.jumps--;
      this.vel.y = -this.jumpForce;
    }
    this.acc.y += this.gravity;
    this.vel.y += this.acc.y;
    this.pos.y += this.vel.y;
    this.acc.y = 0; // 重置加速度
    
    if (this.pos.y >= height - this.height) {
      this.pos.y = height-this.height
      this.jumps = this.numJumps;
    }
  }
}

对应示例的HTML代码:

<!DOCTYPE html>
<html lang="en">
  <head>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.1/p5.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.1/addons/p5.sound.min.js"></script>
    <link rel="stylesheet" type="text/css" href="style.css">
    <meta charset="utf-8" />
  </head>
  <body>
    <main>
    </main>
  </body>
</html>

我正在开发一款2D平台游戏,目前除水平移动方块的左侧碰撞外,其余所有方块的碰撞逻辑均运行正常。
运行效果演示
水平移动方块的实现代码如下:

if (type.equals("moving-horizontal-2x1")) {
    image(img2x1, pos.x, pos.y, 200, 100);
    pos.x += movingSpeed;
    if (pos.x > stop) {
        movingSpeed = -movingSpeed;
    }
    if (pos.x < start) {
        movingSpeed = abs(movingSpeed);
    }
}

玩家与方块碰撞时,除X轴方向的方块左侧外,其余各面碰撞均正常,异常效果如下图:
异常效果示意图
另有演示视频展示了玩家与移动方块碰撞时的异常表现。
从演示内容可以看到,玩家会被错误移位到方块另一侧。我不清楚该问题的产生原因,当前使用的碰撞检测/解算代码与其他静态方块的逻辑完全一致,仅单侧碰撞会失效。
当前X轴方向的碰撞检测代码如下:

if (rectCollide(player.pos.x, player.pos.y, player.width, player.height, pos.x, pos.y, width, height)) {
    if (player.vel.x < 0) { // 玩家向左移动,碰撞方块右侧
        player.pos.x = pos.x + width;
    } else { // 玩家向右移动,碰撞方块左侧(该侧为故障侧)
        player.pos.x = pos.x - player.width;
    }
    player.vel.x = 0;
}

我曾尝试在玩家碰撞方块左侧时调整玩家x坐标修复问题,例如执行player.pos.x += movingSpeed,但该方案并未生效。
我推测该Bug与移动方块的更新逻辑有关,这套碰撞检测/解算代码在所有其他静态方块上都能完美运行。
恳请各位提供排查思路与解决方案,感谢!


内容的提问来源于stack exchange,提问作者Scollier

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 09:45:37