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