JavaScript HTML5 Canvas如何实现子弹发射后不跟随玩家位置变化
问题根因
- 全局复用同一个
Bullet实例:你仅在init函数中初始化了一次全局bullet对象,每次调用shootGun都是将同一个对象的引用推入bullets数组,所有已发射的子弹本质上指向同一块内存地址,玩家旋转时修改该全局对象的属性,所有已发射的子弹会同步生效 - 未固化子弹发射时的方向参数:目前子弹速度仅写死了固定的
speedX = 3,没有根据发射瞬间的玩家朝向计算对应独立的速度分量,子弹移动时会读取实时的玩家角度而非发射时的角度 - 存在无效的数组操作逻辑:控制模块中
bullets.slice(bullet, 1)属于错误用法,slice不会修改原数组,反而可能引发索引混乱
修复步骤
- 移除
init函数中全局初始化bullet的逻辑,改为每次射击时新建独立的Bullet实例,避免引用共享 - 每次创建子弹时,基于发射瞬间的玩家朝向计算固定的x、y轴速度分量,存储到当前子弹实例的私有属性中,后续移动仅读取该私有值,不关联实时玩家状态
- 清理无效的数组操作代码,调整超时销毁逻辑的触发时机,避免重复注册计时器
代码修改示例
修改后的shootGun函数
let bullets = []; function shootGun() { // 每次射击新建独立实例 const newBullet = new Bullet({ x: ammo.position.x, y: ammo.position.y, width: ammo.style.width, height: ammo.style.height, color: "black", }); // 替换为你实际存储玩家/枪口朝向角度的变量,若弧度已提前转换可去掉角度转弧度的计算 const fireAngle = 玩家当前朝向角度; // 固化当前发射方向的速度分量 newBullet.speedX = 3 * Math.cos(fireAngle * Math.PI / 180); newBullet.speedY = 3 * Math.sin(fireAngle * Math.PI / 180); // 注册一次超时销毁逻辑,不用放在遍历循环中重复触发 setTimeout(() => { newBullet.alive = false; }, 1000); bullets.push(newBullet); }
修改控制模块代码
// 原有数组清理逻辑保留即可 for (let i = 0; i < bullets.length; i++) { if (bullets[i] === undefined) continue; if (bullets[i].alive === false) { bullets.splice(i, 1); // splice后索引会前移,补充i--避免漏遍历元素 i--; continue; } } if (punching) { arm1.position.x = 60; // 仅保留射击调用,移除无效的slice操作 shootGun(); }
修改遍历更新逻辑
bullets.forEach((bullet) => { bullet.update(); bullet.newPos(); // 移除这里的setTimeout,已移到创建子弹的逻辑中 });
内容的提问来源于stack exchange,提问作者robotosail
相关产品推荐
相关产品推荐

