wiserim / phaser-raycaster

Raycasting plugin for Phaser 3. Documentation:

Home Page:https://wiserim.github.io/phaser-raycaster/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

How to properly unmap and delete object ?

vyshkov opened this issue · comments

In my main game class I have a createCar method, which dynamically creates a car and iterates over other cars and maps raycast between each other (so cars can detect the distance between each other):

  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);
  }

It works unless I want to delete a 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();
      }
    });
  }

Then it fails here when it tries to retrieve the "raycasterMap" and destroy it:

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

raycaster-core.js:396 Uncaught TypeError: Cannot read properties of undefined (reading 'destroy') at Raycaster.removeMappedObjects (raycaster-core.js:396:48) at game.js:51:23

I can't figure out how to properly remove an object from the scene and memory. If I call car.destroy() other cars throw exceptions, because the raycast still has references.

Code sample: https://codepen.io/vvyshko/pen/bGOxpbG

Hello,
The problem was caused by the fact that each Car object had it's own Raycaster object.
Raycaster is responsible for managing rays and maps of objects. Each Ray, Map (and mapped game object by extension) can be assigned to only one Raycaster.

You have to move Raycaster from Car to scene.

Also due to removal of cars from group, iterator tries to go through more items than the group has.
You can fix this by checking if car exist:

this.carsGroup.children.iterate((car) => {
      //if car is undefined (for example if car was removed from group)
      if(!car) {
        return;
      }
     //rest of the code
}

Fixed sample: https://codepen.io/wiserim/pen/ZEVVLqr

Thank you @wiserim. This works!
The minor problem is that the ray now detects its own car, so I have to calculate ray's position to be in front of the car.
Here is the updated version with your fix:
https://codepen.io/vvyshko/pen/JjwwMjz

You can avoid detecting car by it's own ray by:

A. Passing to ray array of objects without current car:

//Inside Car.update() method

//Get all other cars
let self = this;
let cars = scene.carsGroup.getChildren().filter((car) => car !== self);
//Cast the ray and get the intersection
this.intersection = this.ray.cast(cars);

B. Disabling Car's map and enabling it afterwards with Raycaster.disableMap() and Raycaster.enableMap().

//Inside Car.update() method

//Disable Car's map
scene.raycaster.disableMaps(this);
//Cast the ray and get the intersection
this.intersection = this.ray.cast();
//Enable Car's map
scene.raycaster.enableMaps(this);

Docs:
https://wiserim.github.io/phaser-raycaster/Raycaster.html#enableMaps__anchor
https://wiserim.github.io/phaser-raycaster/Raycaster.html#disableMaps__anchor