Phaser添加角色行走动画后Hitbox位置异常问题求助
俯视角Phaser游戏角色Hitbox位置异常问题解决
我是Phaser新手,开发俯视角游戏时遇到Hitbox位置异常问题:角色向下移动时Hitbox位置正常,但向上、向左、向右移动时,Hitbox固定在角色左上角。
问题表现
- 向下移动:Hitbox位置正常
- 向上/向左/向右移动:Hitbox固定在角色左上角
尝试过硬编码设置this.player.body.setOffset(28,24)(上/左/右方向)和setOffset(0,0)(向下方向)临时解决,但这种方式不够优雅,希望得到更合理的方案。
项目相关代码
main.js
import Phaser from "./lib/phaser.js"; import Game from "./scenes/Game.js"; export default new Phaser.Game({ type: Phaser.AUTO, scene: Game, width: 750, height: 500, autoCenter: Phaser.Scale.CENTER_BOTH, physics: { default: "arcade", arcade: { debug: true } } });
Game.js
import Phaser from "../lib/phaser.js"; export default class Game extends Phaser.Scene { constructor() { super("game"); } preload() { this.load.image("tiles", "assets/MasterSimple.png"); this.load.image("character", "../../assets/Player/idle/idle down1.png"); // 行走动画资源 this.load.image("wd1", "../../assets/Player/walk/walk down1.png"); this.load.image("wd2", "../../assets/Player/walk/walk down2.png"); this.load.image("wd3", "../../assets/Player/walk/walk down3.png"); this.load.image("wd4", "../../assets/Player/walk/walk down4.png"); this.load.image("wu1", "../../assets/Player/walk/walk up1.png"); this.load.image("wu2", "../../assets/Player/walk/walk up2.png"); this.load.image("wu3", "../../assets/Player/walk/walk up3.png"); this.load.image("wu4", "../../assets/Player/walk/walk up4.png"); this.load.image("wl1", "../../assets/Player/walk/walk left1.png"); this.load.image("wl2", "../../assets/Player/walk/walk left2.png"); this.load.image("wl3", "../../assets/Player/walk/walk left3.png"); this.load.image("wl4", "../../assets/Player/walk/walk left4.png"); this.load.image("wr1", "../../assets/Player/walk/walk right1.png"); this.load.image("wr2", "../../assets/Player/walk/walk right2.png"); this.load.image("wr3", "../../assets/Player/walk/walk right3.png"); this.load.image("wr4", "../../assets/Player/walk/walk right4.png"); this.load.tilemapTiledJSON("level1", "assets/level1.json"); } create() { const level1 = this.make.tilemap({ key: "level1", tileWidth: 16, tileHeight: 16, }); const tileset = level1.addTilesetImage("MasterSimple", "tiles"); // 图层 const eauLayer = level1.createLayer("eau", tileset, 0, 0); eauLayer.scale = 3; const solLayer = level1.createLayer("sol", tileset, 0, 0); solLayer.scale = 3; const murLayer = level1.createLayer("mur", tileset, 0, 0); murLayer.scale = 3; // 角色创建 this.player = this.physics.add.sprite(500, 300, "character").setScale(3.5); this.cursors = this.input.keyboard.createCursorKeys(); this.physics.add.collider(this.player, eauLayer); eauLayer.setCollisionBetween(81, 82); this.physics.add.collider(this.player, murLayer); murLayer.setCollisionBetween(110, 140); // 动画创建 // 向下行走 const walkDownFrames = [ { key: "wd1" }, { key: "wd2" }, { key: "wd3" }, { key: "wd4" }, ]; this.anims.create({ key: "walkDown", frames: walkDownFrames, frameRate: 10, repeat: -1, }); // 向上行走 const walkUpFrames = [ { key: "wu1" }, { key: "wu2" }, { key: "wu3" }, { key: "wu4" }, ]; this.anims.create({ key: "walkUp", frames: walkUpFrames, frameRate: 10, repeat: -1, }); // 向左行走 const walkLeftFrames = [ { key: "wl1" }, { key: "wl2" }, { key: "wl3" }, { key: "wl4" }, ]; this.anims.create({ key: "walkLeft", frames: walkLeftFrames, frameRate: 10, repeat: -1, }); // 向右行走 const walkRightFrames = [ { key: "wr1" }, { key: "wr2" }, { key: "wr3" }, { key: "wr4" }, ]; this.anims.create({ key: "walkRight", frames: walkRightFrames, frameRate: 10, repeat: -1, }); // 相机跟随 this.cameras.main.startFollow(this.player); } update() { this.player.setVelocityY(0); this.player.setVelocityX(0); const speed = 300; if (this.cursors.up.isDown) { this.player.setVelocityY(-speed); this.player.anims.play("walkUp", true); } else if (this.cursors.down.isDown) { this.player.setVelocityY(speed); this.player.anims.play("walkDown", true); } else if (this.cursors.left.isDown) { this.player.setVelocityX(-speed); this.player.anims.play("walkLeft", true); } else if (this.cursors.right.isDown) { this.player.setVelocityX(speed); this.player.anims.play("walkRight", true); } else { this.player.anims.stop(); } } }
解决方案
核心问题是不同方向的动画帧没有统一的原点(origin),Phaser中物理体位置基于精灵原点计算,帧原点不一致会导致Hitbox偏移。推荐两种根源解决方法:
1. 统一所有角色帧的原点
在创建角色时设置统一原点(比如中心原点),确保所有行走帧的视觉中心与原点对齐:
this.player = this.physics.add.sprite(500, 300, "character") .setScale(3.5) .setOrigin(0.5, 0.5); // 设置中心为原点
可根据你的资源调整原点坐标(比如(0.4, 0.6)),确保所有方向帧的角色位置对应同一个原点。
2. 使用精灵表(Sprite Sheet)替代单独加载图片
单独加载单张图片容易出现帧尺寸、原点不一致的问题,建议将所有行走帧整合到一张精灵表中,用load.spritesheet加载:
// preload中替换单独图片加载 this.load.spritesheet('playerWalk', '../../assets/Player/walk/walk_sheet.png', { frameWidth: 32, // 替换为你的单帧宽度 frameHeight: 48 // 替换为你的单帧高度 });
然后从精灵表生成动画帧:
// 向下行走动画示例 this.anims.create({ key: "walkDown", frames: this.anims.generateFrameNumbers('playerWalk', { start: 0, end: 3 }), frameRate: 10, repeat: -1 }); // 向上行走动画示例(假设帧索引4-7) this.anims.create({ key: "walkUp", frames: this.anims.generateFrameNumbers('playerWalk', { start: 4, end: 7 }), frameRate: 10, repeat: -1 });
精灵表的所有帧尺寸、原点完全统一,物理体不会出现偏移问题。
3. 临时优化(不推荐)
如果暂时无法使用精灵表,可在切换动画时统一设置物理体偏移,避免硬编码分支:
// 在update的方向判断中添加统一偏移 if (this.cursors.up.isDown) { this.player.setVelocityY(-speed); this.player.anims.play("walkUp", true); this.player.body.setOffset(28,24); } else if (this.cursors.down.isDown) { this.player.setVelocityY(speed); this.player.anims.play("walkDown", true); this.player.body.setOffset(0,0); } // 其余方向同理
但此方法仍属于临时修复,推荐优先使用前两种方案。
内容的提问来源于stack exchange,提问作者SgO
相关产品推荐
相关产品推荐

