setInterval参数值更新后clearInterval不清除
clearInterval not clearing after setInterval parameter value is updated
在这个游戏中(从 Youtube 上获得)蛇在进食时会长大,而且速度也会加快。一切正常,直到蛇至少吃了一顿饭。此时暂停、播放按钮根本不起作用,新游戏按钮重置蛇的位置和食物位置,但游戏不会停止,速度也不会重置。
我知道问题出在哪里 (increaseSpeed()) 但我不知道如何修复它。如果我从此函数中删除 setInterval return,游戏的每个部分都可以正常工作,除了速度永远不会改变
const getRandomCoordinates = () => {
let min = 1
let max = 98
let x = Math.floor((Math.random()*(max-min+1)+min)/2)*2
let y = Math.floor((Math.random()*(max-min+1)+min)/2)*2
return [x,y]
}
const initialState = {
direction: 'RIGHT',
speed: 200,
food: getRandomCoordinates(),
snakeDots: [
[0,0],
[2,0]
],
message: ""
}
// GAMEBOARD COMPONENT
class GameBoard extends Component {
state = initialState
componentDidMount() {
document.onkeydown = this.onKeyDown
}
componentDidUpdate() {
this.checkIfOutOfBorders()
this.checkIfCollapsed()
this.checkIfEat()
}
playButton = () => {
clearInterval(this.intervalId)
this.intervalId = setInterval(this.moveSnake, this.state.speed)
}
pauseButton = () => {
clearInterval(this.intervalId)
}
newGameButton = () => {
this.setState(initialState)
clearInterval(this.intervalId)
}
onKeyDown = (e) => {
e = e || window.event;
switch(e.keyCode) {
case 38:
this.setState({ direction: 'UP'})
break
case 40:
this.setState({ direction: 'DOWN'})
break
case 37:
this.setState({ direction: 'LEFT'})
break
case 39:
this.setState({ direction: 'RIGHT'})
break
default:
}
}
moveSnake = () => {
let dots = [...this.state.snakeDots]
let head = dots[dots.length - 1]
switch (this.state.direction) {
case 'RIGHT':
head = [head[0] + 2, head[1]]
break
case 'LEFT':
head = [head[0] - 2, head[1]]
break
case 'UP':
head = [head[0], head[1] - 2]
break
case 'DOWN':
head = [head[0], head[1] + 2]
break
default:
}
dots.push(head)
dots.shift()
this.setState({
snakeDots: dots
})
}
checkIfOutOfBorders = () => {
let head = this.state.snakeDots[this.state.snakeDots.length - 1]
if (head[0] >= 100 || head[1] >= 100 || head[0] < 0 || head[1] < 0) {
this.onGameOver()
}
}
checkIfCollapsed = () => {
let snake = [...this.state.snakeDots]
let head = snake[this.state.snakeDots.length - 1]
snake.pop()
snake.forEach(dot => {
if (head[0] === dot[0] && head[1] === dot[1]) {
this.onGameOver()
}
})
}
checkIfEat = () => {
let head = this.state.snakeDots[this.state.snakeDots.length - 1]
let food = this.state.food
if (head[0] === food[0] && head[1] === food[1]) {
this.setState({
food: getRandomCoordinates()
})
this.growSnake()
this.increaseSpeed()
}
}
growSnake = () => {
let newSnake = [...this.state.snakeDots]
newSnake.unshift([])
this.setState({
snakeDots: newSnake
})
}
increaseSpeed = () => {
let speed = this.state.speed
if (this.state.speed > 10) {
this.setState({
speed: speed - 10
})
}
setInterval(this.moveSnake, this.state.speed)
}
onGameOver = () => {
// alert(`Game over! You're snake length is ${this.state.snakeDots.length}`)
this.newGameButton()
console.log('over')
}
render () {
return (
<div className="console-container">
<div className="game-area">
<Snake snakeDots={ this.state.snakeDots } />
<Food food={ this.state.food } />
</div>
<ControlPanel
playButton={this.playButton}
pauseButton={this.pauseButton}
newGameButton={this.newGameButton}
scoreboardMessage={this.scoreboardMessage}
/>
</div>
)
}
}
export default GameBoard
这一行的 increaseSpeed
方法有 3 个问题:
setInterval(this.moveSnake, this.state.speed)
;
- 您没有保存新的间隔 ID
- 您使用旧状态值(因为
setState
是异步的)
- 您没有清除之前的区间
这应该有效:
increaseSpeed = () => {
let speed = this.state.speed
if (this.state.speed > 10) {
speed -= 10;
this.setState({
speed
})
}
clearInterval(this.intervalId);
this.intervalId = setInterval(this.moveSnake, speed);
}
在这个游戏中(从 Youtube 上获得)蛇在进食时会长大,而且速度也会加快。一切正常,直到蛇至少吃了一顿饭。此时暂停、播放按钮根本不起作用,新游戏按钮重置蛇的位置和食物位置,但游戏不会停止,速度也不会重置。
我知道问题出在哪里 (increaseSpeed()) 但我不知道如何修复它。如果我从此函数中删除 setInterval return,游戏的每个部分都可以正常工作,除了速度永远不会改变
const getRandomCoordinates = () => {
let min = 1
let max = 98
let x = Math.floor((Math.random()*(max-min+1)+min)/2)*2
let y = Math.floor((Math.random()*(max-min+1)+min)/2)*2
return [x,y]
}
const initialState = {
direction: 'RIGHT',
speed: 200,
food: getRandomCoordinates(),
snakeDots: [
[0,0],
[2,0]
],
message: ""
}
// GAMEBOARD COMPONENT
class GameBoard extends Component {
state = initialState
componentDidMount() {
document.onkeydown = this.onKeyDown
}
componentDidUpdate() {
this.checkIfOutOfBorders()
this.checkIfCollapsed()
this.checkIfEat()
}
playButton = () => {
clearInterval(this.intervalId)
this.intervalId = setInterval(this.moveSnake, this.state.speed)
}
pauseButton = () => {
clearInterval(this.intervalId)
}
newGameButton = () => {
this.setState(initialState)
clearInterval(this.intervalId)
}
onKeyDown = (e) => {
e = e || window.event;
switch(e.keyCode) {
case 38:
this.setState({ direction: 'UP'})
break
case 40:
this.setState({ direction: 'DOWN'})
break
case 37:
this.setState({ direction: 'LEFT'})
break
case 39:
this.setState({ direction: 'RIGHT'})
break
default:
}
}
moveSnake = () => {
let dots = [...this.state.snakeDots]
let head = dots[dots.length - 1]
switch (this.state.direction) {
case 'RIGHT':
head = [head[0] + 2, head[1]]
break
case 'LEFT':
head = [head[0] - 2, head[1]]
break
case 'UP':
head = [head[0], head[1] - 2]
break
case 'DOWN':
head = [head[0], head[1] + 2]
break
default:
}
dots.push(head)
dots.shift()
this.setState({
snakeDots: dots
})
}
checkIfOutOfBorders = () => {
let head = this.state.snakeDots[this.state.snakeDots.length - 1]
if (head[0] >= 100 || head[1] >= 100 || head[0] < 0 || head[1] < 0) {
this.onGameOver()
}
}
checkIfCollapsed = () => {
let snake = [...this.state.snakeDots]
let head = snake[this.state.snakeDots.length - 1]
snake.pop()
snake.forEach(dot => {
if (head[0] === dot[0] && head[1] === dot[1]) {
this.onGameOver()
}
})
}
checkIfEat = () => {
let head = this.state.snakeDots[this.state.snakeDots.length - 1]
let food = this.state.food
if (head[0] === food[0] && head[1] === food[1]) {
this.setState({
food: getRandomCoordinates()
})
this.growSnake()
this.increaseSpeed()
}
}
growSnake = () => {
let newSnake = [...this.state.snakeDots]
newSnake.unshift([])
this.setState({
snakeDots: newSnake
})
}
increaseSpeed = () => {
let speed = this.state.speed
if (this.state.speed > 10) {
this.setState({
speed: speed - 10
})
}
setInterval(this.moveSnake, this.state.speed)
}
onGameOver = () => {
// alert(`Game over! You're snake length is ${this.state.snakeDots.length}`)
this.newGameButton()
console.log('over')
}
render () {
return (
<div className="console-container">
<div className="game-area">
<Snake snakeDots={ this.state.snakeDots } />
<Food food={ this.state.food } />
</div>
<ControlPanel
playButton={this.playButton}
pauseButton={this.pauseButton}
newGameButton={this.newGameButton}
scoreboardMessage={this.scoreboardMessage}
/>
</div>
)
}
}
export default GameBoard
这一行的 increaseSpeed
方法有 3 个问题:
setInterval(this.moveSnake, this.state.speed)
;
- 您没有保存新的间隔 ID
- 您使用旧状态值(因为
setState
是异步的) - 您没有清除之前的区间
这应该有效:
increaseSpeed = () => {
let speed = this.state.speed
if (this.state.speed > 10) {
speed -= 10;
this.setState({
speed
})
}
clearInterval(this.intervalId);
this.intervalId = setInterval(this.moveSnake, speed);
}