As a learning exercise, I’m making a Javascript browser game where when the user presses a button, it simulates rolling several 6-sided dice and then shows images that correspond to the random value rolled on each dice. I have the basic functionality working. However, rather than immediately showing the end result of each dice, I want to have each dice image cycle through several different values before finally stopping on the end result, in the hopes that this will aesthetically feel more like rolling dice.
I’m trying to follow OOP, so I have the relevant objects and methods in a DiceGame class. To asynchronously let the dice images cycle without freezing all other functionality, I was thinking of using the setTimeout function.
Here’s a simplified version of what I’ve tried:
class DiceGame {
constructor() {
this.diceArray = [new Dice('dice01'), new Dice('dice02')]
}
rollAllDice(tumblesRemaining, tumbleDelay) {
for (let index in this.diceArray) {
this.diceArray[index].roll() //this randomizes the value & image of a single Dice object
}
if (tumblesRemaining > 0) {
function nextRecursiveFunction() {
this.rollAllDice(tumblesRemaining-1, tumbleDelay+100);
}
setTimeout(nextRecursiveFunction, tumbleDelay);
}
}
playGame()
{
this.rollAllDice(10, 100);
}
}
const game = new DiceGame()
game.playGame()
The intention is that this would do something like this:
- Set dice image to random value (example: 6).
- Wait for 100 milliseconds.
- Set dice image to random value (example: 2).
- Wait for 200 milliseconds.
- Keep following this pattern until ‘tumblesRemaining’ is 0, at which point that’s the final dice value.
…and while it does this, it wouldn’t be blocking any other functionality that the game has.
However, the actual code fails. My understanding is that when methods are called as callbacks, the callback doesn’t have access to an instantiated object to use as the context for that method, and thus it can’t access members. So when nextRecursiveFunction is called as a callback by setTimeout, it no longer sees itself as being within the scope of game, and because of that there is no this.rollAllDice function to call. This causes the failure.
I’ve tried to find solutions. I’ve found posts that have demonstrated how to call methods with parameters, I’ve found posts that have demonstrated how to call a single method as a callback, and I’ve found posts that demonstrate how to perform recursion with callbacks. However, I haven’t found a way to have an object recursively call its own method via callbacks without losing access to its members.
So I have two questions:
- Is there a way to make recursively calling methods via callbacks function in the way I’m intending?
- Aside from recursively calling methods via callbacks, is there a better way to accomplish the intention of this code (asynchronously cycling the dice images in OOP)?
And in case it helps, I want to clarify that I’m less interested in this specific problem and more interested in learning best practices and growing my understanding of JavaScript problem-solving. I just want to leverage this particular problem as a learning opportunity.