p5.play动态精灵相向移动停止不反弹问题求助(仿Age of War游戏)
解决p5.play精灵碰撞反弹问题
你的问题核心在于碰撞检测逻辑的时机和碰撞体状态切换方式:动态碰撞体产生物理交互后再切换为静态已经无法抵消之前的动量,且循环检测会重复修改状态导致异常。以下是针对性修复方案:
核心修复思路
- 用停止移动替代切换碰撞体类型:静态碰撞体适用于固定场景物体,动态角色临时停止直接设置
speed=0更可靠。 - 新增状态标记避免重复触发:给每个单位添加攻击状态锁,防止每一帧重复执行碰撞逻辑和攻击函数。
- 修正数组索引错误:队伍数组存储的是
Melee实例而非Sprite对象,需用实例本身获取索引。
修改后的完整代码
class SpriteBuilder { constructor(Type, Team) { if (Type == "Melee") { this.Melee = new Melee(Team); this.ApplyTeam(this.Melee.Sprite, Team); } } ApplyTeam(Sprite, Team) { if (Team == "Left") { Sprite.color = "Blue"; Sprite.pos = { x: 10, y: 480 }; } if (Team == "Right") { Sprite.color = "Red"; Sprite.pos = { x: 690, y: 480 }; } } } class Melee { constructor(Team) { this.Team = Team; this.isAttacking = false; // 标记是否进入攻击状态 this.currentTarget = null; // 锁定当前攻击目标 if (Team == "Left") { this.Sprite = new Sprite(); TeamLeft.push(this); } if (Team == "Right") { this.Sprite = new Sprite(); TeamRight.push(this); } this.Attackinterval; this.life = 200; this.Sprite.width = 20; this.Sprite.height = 20; this.Sprite.text = "Me"; this.Sprite.textColor = "White"; this.Move(); } Move(){ // 初始统一设置动态碰撞体 this.Sprite.collider = "d"; if (this.Team=="Left"){ this.Sprite.direction="Right"; this.Sprite.speed=1; } if (this.Team=="Right"){ this.Sprite.direction="Left"; this.Sprite.speed=1; } } CollideCheck() { // 已进入攻击状态时,仅检测目标是否存活 if (this.isAttacking) { if (!this.currentTarget || this.currentTarget.life <= 0) { this.isAttacking = false; clearInterval(this.Attackinterval); this.Move(); // 目标死亡后恢复移动 } return; } // 检测敌方碰撞 let enemyTeam = this.Team == "Left" ? TeamRight : TeamLeft; for (let enemy of enemyTeam) { if (enemy.Sprite.collides(this.Sprite)) { // 直接停止移动,不修改碰撞体类型 this.Sprite.speed = 0; enemy.Sprite.speed = 0; this.isAttacking = true; this.currentTarget = enemy; this.DealDamage(enemy); console.log(this.Team == "Left" ? "蓝方攻击" : "红方攻击"); break; // 只锁定第一个碰撞到的目标 } } // 友方碰撞处理:停止移动避免重叠 let allyTeam = this.Team == "Left" ? TeamLeft : TeamRight; for (let ally of allyTeam) { if (ally !== this && ally.Sprite.collides(this.Sprite)) { this.Sprite.speed = 0; break; } } } AmIDead() { if (this.life <= 0) { let team = this.Team == "Left" ? TeamLeft : TeamRight; let index = team.indexOf(this); // 修正索引获取逻辑 if (index !== -1) { team.splice(index, 1); } // 通知攻击者目标已死亡 if (this.currentTarget) { this.currentTarget.isAttacking = false; this.currentTarget.currentTarget = null; this.currentTarget.Move(); } this.Sprite.remove(); clearInterval(this.Attackinterval); } } DealDamage(target) { if (this.Attackinterval) clearInterval(this.Attackinterval); this.Attackinterval = setInterval(() => { if (!target || target.life <= 0) { clearInterval(this.Attackinterval); this.isAttacking = false; this.currentTarget = null; this.Move(); } else { target.life -= 10; } }, 1000); } }
关键优化点
- 用
isAttacking状态锁避免重复触发攻击逻辑,每个单位仅锁定一个目标 - 碰撞时直接设置
speed=0停止移动,保留动态碰撞体以维持碰撞检测能力 - 修复队伍数组索引错误,确保死亡单位能被正确移除
- 目标死亡后自动恢复攻击者的移动状态,继续寻找下一个目标
内容的提问来源于stack exchange,提问作者Jacob Hougaard Jørgensen
相关产品推荐
相关产品推荐

