Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/435.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 如何在俄罗斯方块游戏中正确使用requestAnimationFrame函数?_Javascript_Canvas - Fatal编程技术网

Javascript 如何在俄罗斯方块游戏中正确使用requestAnimationFrame函数?

Javascript 如何在俄罗斯方块游戏中正确使用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

我正在尝试使用javascript编写俄罗斯方块游戏,但几天前我一直在尝试为创建的块制作动画。我的代码如下所示:

Draw.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));
    }
}

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会将动画帧与监视器的刷新率对齐。