I am developing Game of Life using React.js. Everything works so far, but I would like to add extra feature which would allow to stop the game (cycle) and resume it if needed. And I don't know how can I do it. So inside the main class I have a method / function that starts the game and which is triggered after clicking a button defined in render():
constructor(props) {
super(props);
this.state = {cellStates: Array(TOTAL_FIELDS).fill(0), cellID: Array(TOTAL_FIELDS), gameRunning: false, counter: 0}; //set and fill initial states
this.changeState = this.changeState.bind(this);
this.resetGame = this.resetGame.bind(this);
this.startGame = this.startGame.bind(this);
this.stopGame = this.stopGame.bind(this);
this.showGameStatus = this.showGameStatus.bind(this);
for (let o = 1; o <= TOTAL_FIELDS; o++)
{
this.state.cellID[o-1] = o;
}
}
startGame() {
function checkZeros(arr) { //check if board is blank
return arr === 0;
}
if (!this.state.cellStates.every(checkZeros)) {
alert ('Game starts!');
let cycle = this.state.counter; //define number of life cycle
this.setState(() => {
return {
gameRunning: true //game is on
};
});
$('#reset-button').attr("disabled", "disabled");
$('#start-button').attr("disabled", "disabled");
$('#stop-button').removeAttr("disabled"); //handle buttons
let goGame = setInterval(() => {
const newStates = [];
for (let x = 0; x < TOTAL_FIELDS; x++) {
if (this.state.cellStates[x] === 0) { //cell is dead
if (this.calculateCellsAround(x) === 3)
{
newStates.push(1);
}
else {
newStates.push(this.state.cellStates[x]);
}
}
else { //cell is alive
if (this.calculateCellsAround(x) === 3 || this.calculateCellsAround(x) === 2)
{
newStates.push(this.state.cellStates[x]);
}
else {
newStates.push(0);
}
}
}
this.setState(() => {
return {cellStates: newStates, counter: cycle++};
});
}, 50);
}
else {
alert ("Please fill at least one cell to launch a game.")
}
}
render() {
return (
<div style={{marginTop:0+"px"}} key="wrap-it-all">
<Header />
<Grid>
<Row>
<Col md={12}>
<div className="board-outline">
{this.createMap(140, TOTAL_FIELDS)}
</div>
</Col>
</Row>
<Row>
<Col md={12}>
<button id="start-button" onClick={() => this.startGame()}>Start</button>
<button id="stop-button" onClick={() => this.stopGame()}>Stop</button>
<button id="reset-button" onClick={() => this.resetGame()}>Reset</button>
<p style={{color:`#fff`}}>Lifecycle: <span className="lifecycle">{this.state.counter}</span>. Game is <span className="gamerun">{this.showGameStatus()}</span>.</p>
<Alert className="disclaimer" bsStyle="warning">
<strong>Instruction:</strong> Select the initial state of cells and press the [Start] button.
</Alert>
</Col>
</Row>
</Grid>
</div>
);
}
I assume it all has something to do with mount/unmount built in functions but I have no idea how to use them in order to make it all working.
You need to cancel the interval using clearInterval(handle)
on stop.
If you would like to resume just use setInterval(callback, tick)
again.
In addition, just change your anonymous function (aka setInterval(() => {...}
) to
function onTimerTick() {
//copy everything marked as "..." here
}
and use setInterval(onTimerTick, 50)
.