Reputation: 132
I wanted to try out creating a proof-of-concept of actors that have their own independent loops, outside of the main loop - I created something like that, but I'd like to know if there are some glaring issues, or if I am doing it completely wrong.
Basically I'd like to know if the right way to handle the "internal" loop would be using this, or if there is a better way of doing it (inside the live() function): setTimeout(() => {this.live()}, 100);
Second question would be to know the best way of destroying an instantiated class, withing the class, with something like "this.destroy()" - right now I am just removing the connection from the container to the object
Example here: https://codepen.io/tommica/pen/qmNXYL
I'll paste the code itself too:
<ul id="simple-log"></ul>
<script>
// We will store out actors as "id" => "actor"
let actors = {};
// Custom logging functionality for a simple ul list
const sLog = (text) => {
let li = document.createElement('li');
li.innerHTML = text;
document.getElementById('simple-log').appendChild(li);
};
const randomNum = (min,max) => { return Math.floor(Math.random() * max) + min; }
// Actor definition
class Actor {
constructor(name, id) {
this.id = id;
this.name = name;
this.gender = randomNum(1,2) === 1 ? 'male' : 'female'; // Random gender
this.lastTime = null;
}
live() {
// Get the current time, and log every 5 seconds
let now = Date.now();
let difference = now - this.lastTime;
if(difference > 5000) {
sLog(`Actor "${this.name}" Log - Difference: ${difference}`);
this.lastTime = now;
}
// Determine if the actor died of a tragic accident
if(randomNum(1,100000) < 5) {
// Something tragic happened, that caused this actor to die
this.die();
} else {
// I'm pretty sure that this is not the best way, but for some reason just
// setTimeout(this.live, 1); does not work
setTimeout(() => {this.live()}, 100);
}
}
die() {
// Log the death
sLog(`Actor "${this.name}" died`);
// This seems really a wrong way to do this, should not need to rely on an element outside of the scope - something else should do this, but how?
delete actors[this.id];
}
}
// Function to spawn a new actor
let spawnActor = () => {
let id = 'a'+randomNum(1,9000000);
sLog('Spawning an actor');
let actorInstance = new Actor(id, id); // Rejoice!
actorInstance.live();
actors[id] = actorInstance;
}
// Simple loop that simulates the rendering of the screen
let lastTimeAnimated = null;
let mainAnimationLoop = () => {
// Logs every 5 seconds to the log
let now = Date.now();
let difference = now - lastTimeAnimated;
if(difference > 5000) {
sLog(`Main Animation Loop Log - Difference: ${difference}`);
lastTimeAnimated = now;
}
window.requestAnimationFrame(mainAnimationLoop);
}
// Simple loop that simulates a normal game main loop
let lastTime = null;
let mainLoop = () => {
// Mainloop logs every 5 seconds to the log
let now = Date.now();
let difference = now - lastTime;
if(difference > 5000) {
sLog(`Main Loop Log - Difference: ${difference}`);
lastTime = now;
}
// Random actor spawner
if(randomNum(1,10000) < 5) {
spawnActor(); // It truly is a blessed day!
}
setTimeout(mainLoop, 1);
}
// Should be obvious
let init = () => {
mainAnimationLoop();
mainLoop();
}
// Let's get started!
init();
</script>
Upvotes: 0
Views: 50
Reputation: 664599
Basically I'd like to know if the right way to handle the "internal" loop would be using this, or if there is a better way of doing it (inside the live() function):
setTimeout(() => {this.live()}, 100);
There are many other ways to do this (some of them even involving a real while
loop), but none of them is "the one right way".
I'm pretty sure that this is not the best way, but for some reason just
setTimeout(this.live, 1);
does not work
See How to access the correct this
/ context inside a callback? for the why.
Second question would be to know the best way of destroying an instantiated class, withing the class, with something like "this.destroy()" - right now I am just removing the connection from the container to the object:
delete actors[this.id];
This seems really a wrong way to do this, should not need to rely on an element outside of the scope - something else should do this, but how?
You cannot "destroy" anything in javascript. If you want an instance to get garbage-collected, you need to remove all references to it. The right way to let an actor die is to just let it stop living - i.e. don't call .live()
any more, and/or remove all timeouts that are scheduled to call it.
You don't need that container for anything (and in the code you've shown, you're not even using it). For some reason, spawnActor
did store the instances, so it is its job to collect the dead. If you really don't need that collection, just omit it; if you use if for something then each actor should announce its death by setting an own property or by sending a message to the main actor, so that it can be removed from the collection as appropriate.
Upvotes: 1