Javascript 如何在俄罗斯方块游戏中正确使用requestAnimationFrame函数?
我正在尝试使用javascript编写俄罗斯方块游戏,但几天前我一直在尝试为创建的块制作动画。我的代码如下所示: Draw.jsJavascript 如何在俄罗斯方块游戏中正确使用requestAnimationFrame函数?,javascript,canvas,Javascript,Canvas,我正在尝试使用javascript编写俄罗斯方块游戏,但几天前我一直在尝试为创建的块制作动画。我的代码如下所示: Draw.js export default class Draw { constructor() { this._canvas = document.getElementById(`main_screen`); this._context = this._canvas.getContext(`2d`); } get canv
export default class Draw {
constructor() {
this._canvas = document.getElementById(`main_screen`);
this._context = this._canvas.getContext(`2d`);
}
get canvas() {
return this._canvas;
}
get context() {
return this._context;
}
get clearAll() {
return this._clearAll();
}
get save() {
return this._save();
}
_clearAll() {
this._context.clearRect(0, 0, this.canvas.width, this.canvas.height);
}
_save() {
this._context.save();
}
}
import Draw from './Draw.js';
import Generator from './Generator.js';
export default class BlockController extends Draw {
constructor(x, y, width, height) {
super();
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.blockStartPoint = 160;
}
get drawBlock() {
return this._drawBlock();
}
/**
* Function creates and draws block.
*/
async _drawBlock() {
this.x = this.blockStartPoint;
const block = await Generator.getBlock();
const blockColor = await Generator.getBlockColor();
block.forEach(row => {
row.forEach(column => {
if(column === 1) {
this.context.fillStyle = `#${blockColor}`;
this.context.fillRect(this.x, this.y, this.width, this.height);
this.context.strokeRect(this.x, this.y, this.width, this.height);
}
this.x += this.width;
});
this.x = this.blockStartPoint;
this.y += this.height;
});
}
moveBlock() {
this.y += this.height;
}
}
import Draw from './Draw.js';
export default class BoardController extends Draw {
constructor(x, y, width, height) {
super();
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.blocksAmountInRow = this.canvas.width / width;
this.blockAmountInColumn = this.canvas.height / height;
}
get drawBoard() {
return this._drawBoard();
}
/**
* Function creates and draws game board.
*/
_drawBoard() {
for (let i = 0; i < this.blocksAmountInRow; i++) {
for (let j = 0; j < this.blockAmountInColumn; j++) {
this.context.fillStyle = `#E6F1FF`;
this.context.strokeRect(this.x, this.y, this.width, this.height);
this.context.fillRect(this.x, this.y, this.width, this.height);
this.y += this.height;
}
this.x += this.width;
this.y = 0;
}
}
}
import BlockController from './BlockController.js';
import BoardController from './BoardController.js';
export default class GameController {
constructor() {
this.boardController = new BoardController(0, 0, 20, 20);
this.blockController = new BlockController(0, 0, 20, 20);
}
update() {
this.boardController.clearAll;
this.boardController.drawBoard;
this.blockController.drawBlock;
this.blockController.moveBlock();
}
init() {
window.requestAnimationFrame(this.update.bind(this));
}
}
BlockController.js
export default class Draw {
constructor() {
this._canvas = document.getElementById(`main_screen`);
this._context = this._canvas.getContext(`2d`);
}
get canvas() {
return this._canvas;
}
get context() {
return this._context;
}
get clearAll() {
return this._clearAll();
}
get save() {
return this._save();
}
_clearAll() {
this._context.clearRect(0, 0, this.canvas.width, this.canvas.height);
}
_save() {
this._context.save();
}
}
import Draw from './Draw.js';
import Generator from './Generator.js';
export default class BlockController extends Draw {
constructor(x, y, width, height) {
super();
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.blockStartPoint = 160;
}
get drawBlock() {
return this._drawBlock();
}
/**
* Function creates and draws block.
*/
async _drawBlock() {
this.x = this.blockStartPoint;
const block = await Generator.getBlock();
const blockColor = await Generator.getBlockColor();
block.forEach(row => {
row.forEach(column => {
if(column === 1) {
this.context.fillStyle = `#${blockColor}`;
this.context.fillRect(this.x, this.y, this.width, this.height);
this.context.strokeRect(this.x, this.y, this.width, this.height);
}
this.x += this.width;
});
this.x = this.blockStartPoint;
this.y += this.height;
});
}
moveBlock() {
this.y += this.height;
}
}
import Draw from './Draw.js';
export default class BoardController extends Draw {
constructor(x, y, width, height) {
super();
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.blocksAmountInRow = this.canvas.width / width;
this.blockAmountInColumn = this.canvas.height / height;
}
get drawBoard() {
return this._drawBoard();
}
/**
* Function creates and draws game board.
*/
_drawBoard() {
for (let i = 0; i < this.blocksAmountInRow; i++) {
for (let j = 0; j < this.blockAmountInColumn; j++) {
this.context.fillStyle = `#E6F1FF`;
this.context.strokeRect(this.x, this.y, this.width, this.height);
this.context.fillRect(this.x, this.y, this.width, this.height);
this.y += this.height;
}
this.x += this.width;
this.y = 0;
}
}
}
import BlockController from './BlockController.js';
import BoardController from './BoardController.js';
export default class GameController {
constructor() {
this.boardController = new BoardController(0, 0, 20, 20);
this.blockController = new BlockController(0, 0, 20, 20);
}
update() {
this.boardController.clearAll;
this.boardController.drawBoard;
this.blockController.drawBlock;
this.blockController.moveBlock();
}
init() {
window.requestAnimationFrame(this.update.bind(this));
}
}
BoardController.js
export default class Draw {
constructor() {
this._canvas = document.getElementById(`main_screen`);
this._context = this._canvas.getContext(`2d`);
}
get canvas() {
return this._canvas;
}
get context() {
return this._context;
}
get clearAll() {
return this._clearAll();
}
get save() {
return this._save();
}
_clearAll() {
this._context.clearRect(0, 0, this.canvas.width, this.canvas.height);
}
_save() {
this._context.save();
}
}
import Draw from './Draw.js';
import Generator from './Generator.js';
export default class BlockController extends Draw {
constructor(x, y, width, height) {
super();
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.blockStartPoint = 160;
}
get drawBlock() {
return this._drawBlock();
}
/**
* Function creates and draws block.
*/
async _drawBlock() {
this.x = this.blockStartPoint;
const block = await Generator.getBlock();
const blockColor = await Generator.getBlockColor();
block.forEach(row => {
row.forEach(column => {
if(column === 1) {
this.context.fillStyle = `#${blockColor}`;
this.context.fillRect(this.x, this.y, this.width, this.height);
this.context.strokeRect(this.x, this.y, this.width, this.height);
}
this.x += this.width;
});
this.x = this.blockStartPoint;
this.y += this.height;
});
}
moveBlock() {
this.y += this.height;
}
}
import Draw from './Draw.js';
export default class BoardController extends Draw {
constructor(x, y, width, height) {
super();
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.blocksAmountInRow = this.canvas.width / width;
this.blockAmountInColumn = this.canvas.height / height;
}
get drawBoard() {
return this._drawBoard();
}
/**
* Function creates and draws game board.
*/
_drawBoard() {
for (let i = 0; i < this.blocksAmountInRow; i++) {
for (let j = 0; j < this.blockAmountInColumn; j++) {
this.context.fillStyle = `#E6F1FF`;
this.context.strokeRect(this.x, this.y, this.width, this.height);
this.context.fillRect(this.x, this.y, this.width, this.height);
this.y += this.height;
}
this.x += this.width;
this.y = 0;
}
}
}
import BlockController from './BlockController.js';
import BoardController from './BoardController.js';
export default class GameController {
constructor() {
this.boardController = new BoardController(0, 0, 20, 20);
this.blockController = new BlockController(0, 0, 20, 20);
}
update() {
this.boardController.clearAll;
this.boardController.drawBoard;
this.blockController.drawBlock;
this.blockController.moveBlock();
}
init() {
window.requestAnimationFrame(this.update.bind(this));
}
}
有人知道如何强制块设置动画吗?我知道我的更新函数一次又一次地创建新的块和板,但我不知道如何处理它。谢谢你的帮助 我还没有研究过您的代码以了解是否存在其他问题,但您肯定遇到了问题:
update() {
this.boardController.clearAll;
this.boardController.drawBoard;
this.blockController.drawBlock;
this.blockController.moveBlock();
}
init() {
window.requestAnimationFrame(this.update.bind(this));
}
如前所述,您将获得一个且只有一个更新requestAnimationFrame
仅请求单个事件,而不是一系列事件
抛开代码中可能存在的其他问题不谈,向前迈出的一步是:
update() {
this.boardController.clearAll;
this.boardController.drawBoard;
this.blockController.drawBlock;
this.blockController.moveBlock();
// You might want to make the line below conditional, so that
// some flag that indicates the game is over prevents another
// request from being made here.
setTimeout(() => {
window.requestAnimationFrame(() => this.update());
}, 100); // <- Use whatever refresh rate, in milliseconds, works best here.
}
init() {
window.requestAnimationFrame(() => this.update());
}
init () {
const that = this;
let last = -Infinity;
(function loop () {
const
now = new Date().getTime(),
delta = now - last
;
if (delta > 500) { // delta is just some delay
that.update();
last = now;
}
that.frameID = window.requestAnimationFrame(loop);
})()
}
update(){
this.boardController.clearAll;
这个.boardController.drawBoard;
this.blockController.drawBlock;
这是.blockController.moveBlock();
//您可能希望将下面的行设为条件行,以便
//表示游戏结束的一些标志阻止了另一个
//从这里提出的请求。
设置超时(()=>{
window.requestAnimationFrame(()=>this.update());
},100);//this.update());
}
我还没有研究过您的代码以了解是否存在其他问题,但您肯定遇到了问题:
update() {
this.boardController.clearAll;
this.boardController.drawBoard;
this.blockController.drawBlock;
this.blockController.moveBlock();
}
init() {
window.requestAnimationFrame(this.update.bind(this));
}
如前所述,您将获得一个且只有一个更新requestAnimationFrame
仅请求单个事件,而不是一系列事件
抛开代码中可能存在的其他问题不谈,向前迈出的一步是:
update() {
this.boardController.clearAll;
this.boardController.drawBoard;
this.blockController.drawBlock;
this.blockController.moveBlock();
// You might want to make the line below conditional, so that
// some flag that indicates the game is over prevents another
// request from being made here.
setTimeout(() => {
window.requestAnimationFrame(() => this.update());
}, 100); // <- Use whatever refresh rate, in milliseconds, works best here.
}
init() {
window.requestAnimationFrame(() => this.update());
}
init () {
const that = this;
let last = -Infinity;
(function loop () {
const
now = new Date().getTime(),
delta = now - last
;
if (delta > 500) { // delta is just some delay
that.update();
last = now;
}
that.frameID = window.requestAnimationFrame(loop);
})()
}
update(){
this.boardController.clearAll;
这个.boardController.drawBoard;
this.blockController.drawBlock;
这是.blockController.moveBlock();
//您可能希望将下面的行设为条件行,以便
//表示游戏结束的一些标志阻止了另一个
//从这里提出的请求。
设置超时(()=>{
window.requestAnimationFrame(()=>this.update());
},100);//this.update());
}
如@kshetline所述:
window.requestAnimationFrame(() => this.update());
接缝可能是问题所在。修复程序可能如下所示:
update() {
this.boardController.clearAll;
this.boardController.drawBoard;
this.blockController.drawBlock;
this.blockController.moveBlock();
// You might want to make the line below conditional, so that
// some flag that indicates the game is over prevents another
// request from being made here.
setTimeout(() => {
window.requestAnimationFrame(() => this.update());
}, 100); // <- Use whatever refresh rate, in milliseconds, works best here.
}
init() {
window.requestAnimationFrame(() => this.update());
}
init () {
const that = this;
let last = -Infinity;
(function loop () {
const
now = new Date().getTime(),
delta = now - last
;
if (delta > 500) { // delta is just some delay
that.update();
last = now;
}
that.frameID = window.requestAnimationFrame(loop);
})()
}
如果您想使用窗口.cancelAnimationFrame
停止循环,那么使用窗口.requestAnimationFrame
的返回值会很方便
window.requestAnimationFrame
要求浏览器触发给定的回调一次,因此要得到一个真正的“循环”,需要反复执行。使用setTimeout
运行窗口。不需要requestAnimationFrame
。没有延迟window.requestAnimationFrame
每秒可以运行60次,但如果浏览器无法快速计算和渲染,则运行速度会变慢。因此,如果需要,最好捕获时间步长。如@kshetline所述:
window.requestAnimationFrame(() => this.update());
接缝可能是问题所在。修复程序可能如下所示:
update() {
this.boardController.clearAll;
this.boardController.drawBoard;
this.blockController.drawBlock;
this.blockController.moveBlock();
// You might want to make the line below conditional, so that
// some flag that indicates the game is over prevents another
// request from being made here.
setTimeout(() => {
window.requestAnimationFrame(() => this.update());
}, 100); // <- Use whatever refresh rate, in milliseconds, works best here.
}
init() {
window.requestAnimationFrame(() => this.update());
}
init () {
const that = this;
let last = -Infinity;
(function loop () {
const
now = new Date().getTime(),
delta = now - last
;
if (delta > 500) { // delta is just some delay
that.update();
last = now;
}
that.frameID = window.requestAnimationFrame(loop);
})()
}
如果您想使用窗口.cancelAnimationFrame
停止循环,那么使用窗口.requestAnimationFrame
的返回值会很方便
window.requestAnimationFrame
要求浏览器触发给定的回调一次,因此要得到一个真正的“循环”,需要反复执行。使用setTimeout
运行窗口。不需要requestAnimationFrame
。没有延迟window.requestAnimationFrame
每秒可以运行60次,但如果浏览器无法快速计算和渲染,则运行速度会变慢。因此,如果需要,捕获时间步长可能是一个好主意。它几乎可以工作,但还有另一个问题。开始时,电路板和块的绘制方式如下:
然后只绘制新的随机块(无板):
问题是如何在每次画板时都像开始时一样画这个方块
从另一方面来说,你能谈谈我的代码的质量吗?这是我第一个使用javascript的项目,我想知道我的方向是否正确。它几乎可以工作,但还有另一个问题。开始时,电路板和块的绘制方式如下: 然后只绘制新的随机块(无板): 问题是如何在每次画板时都像开始时一样画这个方块
从另一方面来说,你能谈谈我的代码的质量吗?这是我的第一个javascript项目,我想知道我的方向是否正确。当调用
GameController.init()
时,是否抛出错误?当调用GameController.init()
时,是否抛出错误?另一个重要方面是计时。OPs代码不依赖于时间,而是在每次更新时以固定的步长递增y
位置。因此,根据您的建议,动画速度将取决于屏幕刷新率。积木会落得很快,人们甚至无法做出反应是的,@zett42,我会增加一个延迟。另一个重要方面是时间。OPs代码不依赖于时间,而是在每次更新时以固定的步长递增y
位置。因此,根据您的建议,动画速度将取决于屏幕刷新率。积木会落得很快,人们甚至无法做出反应是的,@zett42,我将添加一个延迟。从这里演示如何使用delta
。此外,它不是每秒60次,而是取决于监视器的刷新率。至少Chrome会将动画帧与显示器的刷新率对齐。最好从这里演示如何使用delta
。此外,它不是每秒60次,而是取决于监视器的刷新率。至少Chrome会将动画帧与监视器的刷新率对齐。