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

p5.play动态精灵相向移动停止不反弹问题求助(仿Age of War游戏)

解决p5.play精灵碰撞反弹问题

你的问题核心在于碰撞检测逻辑的时机和碰撞体状态切换方式:动态碰撞体产生物理交互后再切换为静态已经无法抵消之前的动量,且循环检测会重复修改状态导致异常。以下是针对性修复方案:

核心修复思路

  1. 用停止移动替代切换碰撞体类型:静态碰撞体适用于固定场景物体,动态角色临时停止直接设置speed=0更可靠。
  2. 新增状态标记避免重复触发:给每个单位添加攻击状态锁,防止每一帧重复执行碰撞逻辑和攻击函数。
  3. 修正数组索引错误:队伍数组存储的是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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 03:57:50