如果一个对象不在屏幕中并且它被用于其他对象的光线投射器,如何删除它?

How to delete an object if its out of screen and it was used in raycasters of other objects?

提问人:Vololodymyr 提问时间:10/2/2023 最后编辑:winner_joinerVololodymyr 更新时间:10/5/2023 访问量:39

问:

在我的主游戏类中,我有一种方法,它可以动态地创建一辆汽车并遍历其他汽车,并在彼此之间映射光线投射(因此汽车可以检测彼此之间的距离):createCar

  createCar(scene, x, y, angle, speed, name) {
    const car = new Car(scene, x, y, angle, speed);
    car.name = name; // for debug
    this.carsGroup.children.iterate((c) => {
      c.raycaster.mapGameObjects(car, true);
      car.raycaster.mapGameObjects(c, true);
    });
    this.carsGroup.add(car);
  }

它有效,除非我想删除一辆车:

  update() {
    this.carsGroup.children.iterate((car) => {
      // Car is out of screen
      if (!this.cameras.main.worldView.contains(car.x, car.y)) {
        this.carsGroup.remove(car);
        this.carsGroup.children.iterate((c) => {
          c.raycaster.removeMappedObjects(car);
          car.raycaster.removeMappedObjects(c);
        });
        car.destroy();
      } else {
        car.update();
        car.debug();
      }
    });
  }

然后,当它在内部尝试检索“raycasterMap”并销毁它时,它在这里失败了:

object.data.get('raycasterMap').destroy();

raycaster-core.js:396 未捕获的类型错误:无法读取未定义的属性(读取“销毁”) 在 Raycaster.removeMappedObjects (raycaster-core.js:396:48) 在游戏.js:51:23

我不知道如何正确地从场景和内存中删除汽车。 如果我只是调用其他汽车,则会引发异常,因为光线投射仍然有参考。car.destroy()

完整的 codepen 示例:https://codepen.io/vvyshko/pen/bGOxpbG

JavaScript Phaser-框架 光线投射 phaserjs

评论

0赞 winner_joiner 10/4/2023
我的解决方案,你在哪里寻找什么?还是遗漏了什么?
0赞 Vololodymyr 10/5/2023
嘿@winner_joiner,谢谢你的帮助,但不幸的是,你的解决方案也抛出了同样的异常:另一辆车抛出的异常,而不是那辆车被删除。cast.js:72 Uncaught TypeError: Cannot read properties of undefined (reading 'get') at Ray.cast (cast.js:72:31) at Car.update (car.js:47:33)
0赞 Vololodymyr 10/5/2023
我想我会发布一个问题给 github.com/wiserim/phaser-raycaster
0赞 winner_joiner 10/5/2023
代码不应抛出任何错误,但它会以某种方式停止。如果删除 ray / raycast 函数调用,它将起作用。也许你不被允许摧毁它们。创建问题可能会有所帮助。destroy
0赞 winner_joiner 10/5/2023
顺便说一句:我用函数调用更新了我的答案,注释掉了,因为我正在测试它。destroy

答:

1赞 winner_joiner 10/3/2023 #1

我认为问题是,清理不是最佳的。我建议,将清理放入 - 类的函数中,并在场景的函数中添加验证,检查 - 子项是否为有效对象,destroycarupdatecar

以下是改动:

class Car extends Phaser.Physics.Arcade.Sprite {
  // ...
  destroy(){
    super.destroy();
    // Cleanup data
    this.ray.destroy();
    this.raycaster.destroy();
  }
  // ...
}

class Example extends Phaser.Scene {
  //...
  update() {
    this.carsGroup.children.iterate((car) => {
      // Check if the list item is valid
      if (!car) {
        return;
      }

      if (!this.cameras.main.worldView.contains(car.x, car.y)) {
        // Remove Car from Group and destroy Object
        this.carsGroup.remove(car, true, true);
      } else {
        car.update();
        car.debug();
      }
    });
  }
}

代码复制和改编自 Codepen:

class Car extends Phaser.Physics.Arcade.Sprite {
    constructor(scene, x, y, rotation, speed) {
      super(scene, x, y, "car");
      this.debugGraphics = scene.add.graphics();
      this.speed = speed;
      this.initialSpeed = speed;
      this.rayLength = 100;
      this.rayColor = 0xffffff;
      this.rotation = rotation;
      this.setDisplaySize(130, 80);
  
      this.debugColor = new Phaser.Display.Color();
      // Set the color to a random value
      this.debugColor.random();

      // Create a raycaster for the car
      this.raycaster = scene.raycasterPlugin.createRaycaster();
      // Create a ray for the car
      this.ray = this.raycaster.createRay();
      // Set the ray origin to the car position
      this.ray.setOrigin(this.x, this.y);
      // Set the ray angle to the car angle
      this.ray.setAngle(this.rotation);
  
      scene.physics.world.enable(this); // Enable physics for the car
      scene.add.existing(this); // Add the car to the scene
  
      //this.raycaster.mapGameObjects(scene.rectangle);
    }
  
    update() {
      // console.log('update', this.name, this.speed);
      window.lastUpdatedCar = this;
      this.raycaster.update();
      // Move the car forward
      this.scene.physics.velocityFromRotation(
        this.rotation,
        this.speed,
        this.body.velocity
      );
      // Update the ray origin and angle
      this.ray.setOrigin(this.x, this.y);
      this.ray.setAngle(this.rotation);
      // Cast the ray and get the intersection
     // console.log(this.name, 'removed=', this.removed)

      let intersection ;
      try {
        intersection = this.ray.cast()
      } catch (e) {}
      this.intersection = intersection;
      // If there is an intersection, reduce the speed or stop
      if (intersection) {
      //  console.log('!!!', intersection)
      }
      if (this.crashed) {
          this.setTint(0x555888);
        this.speed = 0;
      } else if (intersection && intersection.object) {
       // console.log('!!!', intersection)
        let distance = Phaser.Math.Distance.BetweenPoints(this, intersection);
        if (distance < this.rayLength) {
          // Determine a deceleration rate (you can adjust this value)
          const decelerationRate = 1; // Adjust as needed
  
          // Calculate the new speed with deceleration
          this.speed -= decelerationRate;
  
          // Ensure the speed doesn't become negative
          if (this.speed < 0) {
            this.speed = 0;
          }
        } else {
          if (this.speed < this.initialSpeed) {
            this.speed++;
          }
        }
      }
    }

  
  
  
    handleCollision(o1, o2) {
      console.log('CRASH', o1, o2)
      o1.crashed = true;
      o2.crashed = true;
    }
  
    debug() {
      this.debugGraphics.clear();
      this.debugGraphics.setDepth(this.depth + 1); // Set the depth
      
      this.debugGraphics.lineStyle(1, this.debugColor.color);
      this.debugGraphics.beginPath();
      this.debugGraphics.moveTo(this.x, this.y);
      this.debugGraphics.lineTo(
        this.x + Math.cos(this.rotation) * this.rayLength,
        this.y + Math.sin(this.rotation) * this.rayLength
      );
      this.debugGraphics.closePath();
      this.debugGraphics.strokePath();
  
      if (this.intersection) {
        this.debugGraphics.fillStyle(0xff0000, 0.5);
        this.debugGraphics.strokeCircle(
          this.intersection.x,
          this.intersection.y,
          5
        );
      }
  
      if (this.crashed) {
          // Draw a red cross
          this.debugGraphics.lineStyle(2, 0xff0000);
          this.debugGraphics.beginPath();
          this.debugGraphics.moveTo(this.x - 10, this.y - 10);
          this.debugGraphics.lineTo(this.x + 10, this.y + 10);
          this.debugGraphics.moveTo(this.x + 10, this.y - 10);
          this.debugGraphics.lineTo(this.x - 10, this.y + 10);
          this.debugGraphics.closePath();
          this.debugGraphics.strokePath();
      }
    }
  
    destroy(){
      super.destroy();
      // Cleanup data
      //this.ray.destroy();
      //this.raycaster.destroy();
    }
  }


class Example extends Phaser.Scene {
  constructor() {
    super();
  }

  preload() {
    this.load.setBaseURL("https://labs.phaser.io");
    this.load.image("bg", "assets/skies/space2.png");
    this.load.image("car", "assets/sprites/car-yellow.png");
    window.scene = this;
  }

  create() {
    const bg = this.add.image(0, 0, "bg");
    bg.setOrigin(0, 0); // Set the origin to the top-left corner
    bg.displayWidth = this.sys.game.config.width; // Stretch width to match canvas width
    bg.displayHeight = this.sys.game.config.height;

    // //create game object
    // this.rectangle = this.add
    //   .rectangle(1000, 300, 50, 200)
    //   .setStrokeStyle(1, 0xff0000);

    this.carsGroup = this.physics.add.group();
    window.carsGroup = this.carsGroup;
    this.createCar(this, 100, 300, 0, 10, "A");
    this.createCar(this, 600, 600, -1, 270, "B");
    this.createCar(this, 400, 300, -0.44, 10, "C");
    this.createCar(this, 600, 700, 0, 170, "D");
    // this.createCar(this, 700, 600, -1.44, 120);
  }

  createCar(scene, x, y, angle, speed, name) {
    const car = new Car(scene, x, y, angle, speed);
    car.name = name; // for debug
    this.carsGroup.children.iterate((c) => {
      c.raycaster.mapGameObjects(car, true);
      car.raycaster.mapGameObjects(c, true);
      c.scene.physics.add.collider(c, car, c.handleCollision);
      car.scene.physics.add.collider(car, c, car.handleCollision);
    });
    this.carsGroup.add(car);
  }

  update() {
    this.carsGroup.children.iterate((car) => {
       // Check if the list item is valid
      if (!car) {
        return;
      }

      if (!this.cameras.main.worldView.contains(car.x, car.y)) {
        // Remove Car from Group and destroy Object
        this.carsGroup.remove(car, true, true);
      } else {
        car.update();
        car.debug();
      }
    });
  }
}

const config = {
  type: Phaser.WEBGL,
  width: 1280,
  height: 1024,
  parent: "phaser-example",
  physics: {
    default: "arcade",
  },
  plugins: {
    scene: [
      {
        key: "PhaserRaycaster",
        plugin: PhaserRaycaster,
        mapping: "raycasterPlugin",
      },
    ],
  },
  scene: Example,
};

const game = new Phaser.Game(config);
 <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/phaser-arcade-physics.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/phaser-raycaster.js"></script>