【问题标题】:Why won't requestAnimationFrame() work while nested inside this if statement?为什么 requestAnimationFrame() 嵌套在这个 if 语句中时不起作用?
【发布时间】:2019-08-07 12:41:43
【问题描述】:

我正在制作俄罗斯方块游戏,现在我正在编写每 1 秒(在本例中为每 800 毫秒)丢块的函数。我的函数是这样的

function drop() {
    //grab the current time
    let now = Date.now();
    //create a var to hold the difference of the current time
    let delta = now - dropStart; //------Why can't these be switched
    if(delta > 800) {
        dropStart = Date.now();
        drawPiece(p.activeTetromino, vacant);
        p.y++;
        drawPiece(p.activeTetromino, p.color);
    }
    requestAnimationFrame(drop);
}

drop();

这可以很好地完成工作。但是我还是个新手,因为我是从教程中复制这段代码的,所以我喜欢从一个函数中从上到下读出逻辑,然后重新排列某些行。例如,我移动了 requestAnimationFrame(drop); 并将其放在 if 语句中。所以它看起来像这样

 function drop() {
    //grab the current time
    let now = Date.now();
    //create a var to hold the difference of the current time
    let delta = now - dropStart; //------Why can't these be switched
    if(delta > 800) {
        dropStart = Date.now();
        drawPiece(p.activeTetromino, vacant);
        p.y++;
        drawPiece(p.activeTetromino, p.color);
        requestAnimationFrame(drop);
    }
}

drop();

这将阻止该功能,并且您不会看到 tetromino 棋子每 800 毫秒掉落一次。我查看了调试器并观察了函数的执行。我看着它击中了第一个 drawpiece() 函数,该函数假设删除当前的部分(用黑色在它上面绘画)。然后增加它的位置,然后在它的新位置绘制新的一块。但问题是它不会移除这件作品或在其新位置上绘制一个新作品。然而,当 requestAnimationFrame(drop); 时,所有这些都是固定的。被感动了?为什么?

// //create your globals
// const canvas = document.querySelector('#canvas');
// const ctx = canvas.getContext('2d');
// const row = 20;
// const col = 10;
// const sq = 40;
// const vacant = 'black';

// //-----------------------Why can't I initialize the tetrominos??

// //create and draw board
// let board = [];
// for(let r = 0; r < row; r++) {
// 	board[r] = [];
// 	for(let c = 0; c < col; c++) {
// 		board[r][c] = vacant;
// 		draw(c, r, board[r][c]);
// 	}
// }

// //define a function to draw to the canvas
// function draw(x, y, color) {
// 	ctx.fillStyle = color;
// 	ctx.fillRect(x * sq, y * sq, sq, sq);
// 	ctx.strokeStyle = 'white';
// 	ctx.strokeRect(x * sq, y * sq, sq, sq);
// }

// //create an object for the tetrominos 
// function Tetromino(tetromino, color) {
// 	this.tetromino = tetromino;
// 	this.color = color;
// 	this.tetrominoN = 0;
// 	this.activeTetromino = this.tetromino[this.tetrominoN];
// 	this.x = 0;
// 	this.y = 0;
// }

// //create an array for the pieces
// const pieces = [
// 	[Z, 'red'],
// 	[S, 'limegreen'],
// 	[T, 'yellow'],
// 	[O, 'blue'],
// 	[L, '#b938ff'],
// 	[I, 'cyan'],
// 	[J, 'orange']
// ]

// //create a new instance of Tetromino
// function randomPiece() {
// 	let r = Math.floor(Math.random() * pieces.length);
// 	return new Tetromino(pieces[r][0], pieces[r][1]);
// }
// let p = randomPiece();

// //draw the piece
// function drawPiece(piece) {
// 	//loop through the tetromino
// 	for(let r = 0; r < piece.length; r++) {
// 		for(let c = 0; c < piece.length; c++) {
// 			//if the tetromino index is zero skip it
// 			if(!piece[r][c]) continue;
// 			//else draw it
// 			else draw(p.x + c, p.y + r, p.color);
// 		}
// 	}
// }

// //undrawdraw the piece
// function undrawPiece(piece) {
// 	//loop through the tetromino
// 	for(let r = 0; r < piece.length; r++) {
// 		for(let c = 0; c < piece.length; c++) {
// 			//if the tetromino index is zero skip it
// 			if(!piece[r][c]) continue;
// 			//else draw it
// 			else draw(p.x + c, p.y + r, vacant);
// 		}
// 	}
// }

// drawPiece(p.activeTetromino);

// //control the piece 
// document.addEventListener('keydown', (event) => {
// 	if(event.keyCode === 37) p.moveLeft();

// 	else if (event.keyCode === 38) p.rotate();

//     else if (event.keyCode === 39) p.moveRight();

// 	else if (event.keyCode === 40) p.moveDown();

// });

// Tetromino.prototype.moveDown = function() {
// 	if(!this.collision(0, 1, this.activeTetromino)) {
// 		undrawPiece(this.activeTetromino);
// 		this.y++;
// 		drawPiece(this.activeTetromino);
// 	} else {
// 		//lock piece and generate a new one
// 		this.lock();
// 		p = randomPiece();
// 	}
// }

// Tetromino.prototype.moveLeft = function() {
// 	if(!this.collision(-1, 0, this.activeTetromino)) {
// 		undrawPiece(this.activeTetromino);
// 		this.x--;
// 		drawPiece(this.activeTetromino);
// 	}
// }

// Tetromino.prototype.moveRight = function() {
// 	if(!this.collision(1, 0, this.activeTetromino)) {
// 		undrawPiece(this.activeTetromino);
// 		this.x++;
// 		drawPiece(this.activeTetromino);
// 	}
// }

// Tetromino.prototype.rotate = function() {
// 	let nextPattern = this.tetromino[(this.tetrominoN + 1) % 4];
// 	if(!this.collision(0, 0, nextPattern)) {
// 		if(this.tetromino.length > 1) {
// 			undrawPiece(this.activeTetromino);
// 			this.tetrominoN = (this.tetrominoN + 1) % 4; // take paranthesis off
// 			this.activeTetromino = this.tetromino[this.tetrominoN];
// 			drawPiece(this.activeTetromino);
// 		}
// 	}
// }

// //create a function to check for collisions
// Tetromino.prototype.collision = function(x, y, piece) {
// 	for(let r = 0; r < piece.length; r++) {
// 		for(let c = 0; c < piece.length; c++) {
// 			//skip index if it is 0
// 			if(!piece[r][c]) continue;
// 			//create vars for the future piece position
// 			let newX = this.x + c + x;
// 			let newY = this.y + r + y;
// 			//see if new position collides with border
// 			if(newX < 0 || newX >= col || newY >= row) return true;
// 			//see if there's a locked piece on the board
// 			if(board[newY][newX] !== vacant) return true;
// 		}
// 	}
// 	return false;
// }

// Tetromino.prototype.lock = function() {
// 	for(let r = 0; r < this.activeTetromino.length; r++) {
// 		for(let c = 0; c < this.activeTetromino.length; c++) {
// 			if(!this.activeTetromino[r][c]) continue;
// 			//if piece reaches the top its gameover
// 			if(this.y + r < 0) {
// 				gameover = true;
// 				alert('Game Over!');
// 			}
// 			//lock the piece by updating the board
// 			board[this.y + r][this.x + c] = this.color;
// 		}
// 	}
// }

// let dropStart = Date.now();
// //drop the piece every 1s
// function drop() {
// 	let now = Date.now();
// 	let delta = now - dropStart;
// 	//if delta is greater than 1s drop the piece
// 	if(delta > 800) {
// 		p.moveDown();
// 		dropStart = Date.now();
// 	}
// 	requestAnimationFrame(drop);
// }

// drop();

//declare globals
const col = 10;
const row = 20;
const sq = 40;
const vacant = 'black';
const cvs = document.querySelector('#canvas');
const ctx = cvs.getContext('2d');

//create and draw the board
let board = [];
for(let r = 0; r < row; r++) {
	board[r] = [];
	for(let c = 0; c < col; c++) {
		board[r][c] = vacant;
		draw(c, r, board[r][c]);
	}
}

//create a blueprint function to draw to the board
function draw(x, y, color) {
	//set the drawing specifications
	ctx.fillStyle = color;
	ctx.fillRect(x * sq, y * sq, sq, sq);
	ctx.strokeStyle = 'white';
	ctx.strokeRect(x * sq, y * sq, sq, sq);
}

//create a blueprint object for the tetrominos
function Piece(tetromino, color) {
	//create the properties
	this.tetromino = tetromino;
	this.color = color;
	this.tetrominoN = 0;
	this.activeTetromino = this.tetromino[this.tetrominoN];
	this.x = 0;
	this.y = 0;
}

//create an array to hold all of the tetrominos
const pieces = [
	[Z, 'red'],
	[S, 'limegreen'],
	[T, 'yellow'],
	[O, 'blue'],
	[L, '#b938ff'],
	[I, 'cyan'],
	[J, 'orange']
]

//grab a piece
let p = new Piece(pieces[2][0], pieces[2][1]);

//create a blueprint function to draw tetrominos to the board
function drawPiece(piece, color) {
	for(let r = 0; r < piece.length; r++) {
		for(let c = 0; c < piece.length; c++) {
			if (!piece[r][c]) continue;
			draw(c + p.x, r + p.y, color);
		}
	}
}

//draw a piece to the board
drawPiece(p.activeTetromino, p.color);

//start a time to set as a refrence for the dropstart
let dropStart = Date.now();
//create a blueprint function to drop the piece
function drop() {
	//grab the current time
	let now = Date.now();
	//create a var to hold the difference of the current time
	let delta = now - dropStart; //------Why can't these be switched
	if(delta > 800) {
		dropStart = Date.now();
		drawPiece(p.activeTetromino, vacant);
		p.y++;
		drawPiece(p.activeTetromino, p.color);
		requestAnimationFrame(drop);
	}
}

drop();
<!-- <!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>Tetris</title>
	<link href="https://fonts.googleapis.com/css?family=Orbitron&display=swap" rel="stylesheet">
</head>
<style>
	body {
		background-color: #595959;
		display: flex;
		justify-content: center;
		align-items: center;
		min-height: 100vh;
		overflow-y: hidden;
	}
	canvas {
		outline: 1px solid white;
	}
	.canvas-wrap {
		padding-left: 50px;
		padding-top: 50px;
		position: relative;
	}
	.num-top, .num-bottom {
		position: absolute;
		top: -1px;
		left: 0;
	}

	.num-top {
		width: 100%;
		height: 50px;
	}

	.num-bottom {
		height: 100%;
		width: 50px;
	}
	.nb {
		font-family: 'Orbitron';
		color: white;
	}
	.num-wrap-t {
		display: flex;
		justify-content: space-around;
		margin-left: 50px;
		width: 400px;
	}
	.num-wrap-b {
		display: flex;
		flex-direction: column;
		justify-content: space-around;
		margin-top: 50px;
		height: 800px;
	}
	.num-wrap-b .nb {
		text-align: right;
		margin-right: 3px;
	}

	.num-wrap-t .nb {
		position: relative;
		top: 31px;
	}
</style>
<body>
	<div class="canvas-wrap">
		<div class="num-top">
			<div class="num-wrap-t">
				<div class="nb">0</div>
				<div class="nb">1</div>
				<div class="nb">2</div>
				<div class="nb">3</div>
				<div class="nb">4</div>
				<div class="nb">5</div>
				<div class="nb">6</div>
				<div class="nb">7</div>
				<div class="nb">8</div>
				<div class="nb">9</div>
			</div>
		</div>
		<canvas id="canvas" width="400" height="800"></canvas>
		<div class="num-bottom">
			<div class="num-wrap-b">
				<div class="nb">0</div>
				<div class="nb">1</div>
				<div class="nb">2</div>
				<div class="nb">3</div>
				<div class="nb">4</div>
				<div class="nb">5</div>
				<div class="nb">6</div>
				<div class="nb">7</div>
				<div class="nb">8</div>
				<div class="nb">9</div>
				<div class="nb">10</div>
				<div class="nb">11</div>
				<div class="nb">12</div>
				<div class="nb">13</div>
				<div class="nb">14</div>
				<div class="nb">15</div>
				<div class="nb">16</div>
				<div class="nb">17</div>
				<div class="nb">18</div>
				<div class="nb">19</div>
			</div>
		</div>
    </div>		
	<script src="tetrominos.js"></script>
	<script src="tetris.js"></script>
</body>
</html> -->
<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>Tetris</title>
	<link href="https://fonts.googleapis.com/css?family=Orbitron&display=swap" rel="stylesheet">
</head>
<style>
	body, html {
		padding: 0;
		margin: 0;
	}

	body {
		background-color: #595959;
		min-height: 100vh;
		display: flex;
		justify-content: center;
		align-items: center;
	}

	canvas {
		outline: 1px solid white;
	}
	.canvas-wrap {
		padding-left: 50px;
		padding-top: 50px;
		position: relative;
	}
	.num-top, .num-bottom {
		position: absolute;
		top: -1px;
		left: 0;
	}

	.num-top {
		width: 100%;
		height: 50px;
	}

	.num-bottom {
		height: 100%;
		width: 50px;
	}
	.nb {
		font-family: 'Orbitron';
		color: white;
	}
	.num-wrap-t {
		display: flex;
		justify-content: space-around;
		margin-left: 50px;
		width: 400px;
	}
	.num-wrap-b {
		display: flex;
		flex-direction: column;
		justify-content: space-around;
		margin-top: 50px;
		height: 800px;
	}
	.num-wrap-b .nb {
		text-align: right;
		margin-right: 3px;
	}

	.num-wrap-t .nb {
		position: relative;
		top: 31px;
	}
</style>
<body>
	<div class="canvas-wrap">
		<div class="num-top">
			<div class="num-wrap-t">
				<div class="nb">0</div>
				<div class="nb">1</div>
				<div class="nb">2</div>
				<div class="nb">3</div>
				<div class="nb">4</div>
				<div class="nb">5</div>
				<div class="nb">6</div>
				<div class="nb">7</div>
				<div class="nb">8</div>
				<div class="nb">9</div>
			</div>
		</div>
		<canvas id="canvas" width="400" height="800"></canvas>
		<div class="num-bottom">
			<div class="num-wrap-b">
				<div class="nb">0</div>
				<div class="nb">1</div>
				<div class="nb">2</div>
				<div class="nb">3</div>
				<div class="nb">4</div>
				<div class="nb">5</div>
				<div class="nb">6</div>
				<div class="nb">7</div>
				<div class="nb">8</div>
				<div class="nb">9</div>
				<div class="nb">10</div>
				<div class="nb">11</div>
				<div class="nb">12</div>
				<div class="nb">13</div>
				<div class="nb">14</div>
				<div class="nb">15</div>
				<div class="nb">16</div>
				<div class="nb">17</div>
				<div class="nb">18</div>
				<div class="nb">19</div>
			</div>
		</div>
	</div>
	<script src="tetrominos.js"></script>		
	<script src="tetris.js"></script>
</body>
</html>

【问题讨论】:

  • 如果 delta &lt;= 800 则不会再调用它,因此 delta 永远不会变为 > 800,因为代码永远不会再次调用... requestAnimationFrame 只调用一次给定函数...要再次调用它,您必须再次 requestAnimationFrame ...因为您不这样做,所以什么也没有发生

标签: javascript html css


【解决方案1】:

简单地回答这个问题:在 requestAnimationFrame(drop) 嵌套在 if 语句中的示例中,永远不会满足 if 条件。

该函数依赖于发生动画循环,否则整个drop() 函数将只运行一次,看到 delta 不是 800,忽略其块内的代码,并且不再运行。

当 requestAnimationFrame() 在 if 语句之外时,它总是会运行,并且会创建 drop() 发生的永无止境的循环,并且每次运行时,nowdelta 都会增加多少毫秒要运行的函数,最终会比dropStart大800毫秒,最终满足语句,然后首先将时间变量重置为基本相同,然后动画俄罗斯方块移动一个空间。

【讨论】:

  • 其实是nvm,我还是有点迷糊哈哈。您说答案仅仅是因为 if 条件永远不会满足。但是当我看到它不断地进入 if 语句时。我可以看到 Delta 总是越来越高,所以 if 语句总是会得到满足,因为 delta 总是大于 > 800。如果我错过了更大的图景,我很抱歉。我想如果你像程序一样在程序步骤中写下你的答案,我会学得更好,这样我就可以看到开始发生的事情以及到达结束的所有步骤
  • 或者当你说 if 条件永远不满足时,你的意思是它永远不会完全完成,因为我有 requestAnimationFrame(drop) 导致一个永无止境的循环?
  • 对不起,如果我混淆了,我说的是 requestAnimationFrame 何时位于嵌套的 if 语句中。您想要永无止境的循环(当requestAnimationFrame() 在 if 语句之外时),因为这是增加delta 以最终通过条件的原因。我编辑了我的答案,使其更加简洁明了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-02-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-06
相关资源
最近更新 更多