Javascript - 带有 requestAnimationFrame 的面向对象 Canvas 游戏

标签 javascript html canvas drop-down-menu

我正在尝试整合 the code in this answer (运行问题答案中的片段以查看示例)与下面脚本的其余部分一起使用,以允许用户通过将鼠标悬停在选择菜单的底部或顶部区域来向下滚动 sideButtons 选择菜单。但是,我不确定如何编写 requestAnimationFrame 函数以使其与对象结构的其余部分一起使用或将其放置在何处。

附加到 sideButtons' mouseMove eventListener 函数的是两个 hitTest: 'lowerHoverBoxHitTest (x, y)' 和 'upperHoverBoxHitTest(x, y)'。这些检测是否悬停在选择菜单的上半部分或下半部分。如果是这样,hoverAmount 应相应增加,以便根据选择的 hoverBox 向上或向下推 sideButtons。但是,这部分(我认为)必须出现在 requestAnimationFrame 函数中 - 在上面的代码中不起作用。

如果仍然不清楚动画应该如何工作,请参阅上面的附加链接。应该清楚的是,它目前无法正常工作...任何帮助将不胜感激。

var buttonTypeSelection = document.getElementById('languageSelection');

var initialButtonType;
var buttonRanges = {'1-10': [1,2,3,4,5,6,7,8,9,10],
                    'One to Ten': ['One','Two','Three','Four','Five',
                                   'Six','Seven','Eight','Nine','Ten'],
                    '0000-1010': ['0001','0010','0011','0100','0101',
                                  '0110','0111','1000','1001','1010']};
var buttonTypeIndex = {'1-10': 1, 'One to Ten': 2, '0000-1010': 3};
Object.keys(buttonRanges).forEach(function(buttonType) {
  buttonTypeSelection.options[buttonTypeSelection.options.length] = new Option(buttonType, buttonTypeIndex[buttonType]);
}, buttonRanges);

buttonTypeSelection.options.selectedIndex = 1; // set to page source language's code
initialButtonType=buttonRanges[Object.keys(buttonRanges)[buttonTypeSelection.options.selectedIndex]];

function Game (elementID,width,height){
	this.elementID = elementID;
	this.element   = document.getElementById(elementID);
	this.width = width;
	this.height = height;

	this.palette = {
		color1:'#fff',
		color2:'#000',
		color3:'#9F3A9B',
		color4:'#a84ea5',
		color5:'#b56ab2',
		color6:'#bf7dbd',
		color7:'#d5a8d2'
	};

	this.element.style.width = width + 'px';
	this.element.style.height= height + 'px';
	this.element.style.border='solid thin ' + this.palette.color2;
	this.element.style.display= 'block';
	//this.element.style.margin='1em auto';
	this.element.style.background=this.palette.color3;

  this.buttonType=buttonRanges[buttonTypeSelection.options[buttonTypeSelection.selectedIndex].text];

  this.hoverAmount = 0;
  this.overTypes = {none:0, lower:1, raise:2}
  this.overBox = 0;
  this.overDist = 0;

	this.initialGame();
}

Game.prototype.initialGame = function(){
	this.canvas  = document.createElement("canvas");
	this.canvas.width  =  this.width;
	this.canvas.height =  this.height;
	this.element.appendChild(this.canvas);

    this.initialSideButtons();
	this.initialTitle();
	this.initialBoard();
	this.initialFooter();

  // initial selection
  this.sideButtons.select(this.sideButtons.buttons[0]);

	this.resize(this.width,this.height);
	this.render();
	this.attachEvents();
}

Game.prototype.attachEvents = function(){
	var element = this.element;

	var getX = function(evt){return evt.offsetX || evt.layerX || (evt.clientX - element.offsetLeft);};
	var getY = function(evt){return evt.offsetY || evt.layerY || (evt.clientY - element.offsetTop);};

	var game = this;
	this.element.addEventListener('mousemove',function(evt){
		game.hover(getX(evt),getY(evt));
    if (game.sideButtons.lowerHoverBoxHitTest(game.hoverX, game.hoverY)) {
			game.overBox=game.overTypes.raise;
		} else if (game.sideButtons.upperHoverBoxHitTest(game.hoverX, game.hoverY)) {
			game.overBox=game.overTypes.lower;
		} else {
			game.overBox=game.overTypes.none;
		}
		game.render();
	});

	this.element.addEventListener('click',function(evt){
		game.sideButtons.click();
		game.render();
	});
}

Game.prototype.onSelect = function(button){
	this.selected = button;
};

Game.prototype.hover=function(x,y){
	this.hoverX = x;
	this.hoverY = y;
};

Game.prototype.initialBoard = function(){
	var game = this;
	var Board = function(){
		this.left   = 0;
		this.top    = 0;
		this.width  = 0;
		this.height = 0;
	};

	Board.prototype.render = function(ctx){
		if(game.selected){

			var shapeWidth = this.width/3;

			ctx.fillStyle = game.palette.color1;
			ctx.strokeStyle = game.palette.color1;
			var fontSize =  14;
			ctx.font = 'bold '+ fontSize +'px Noto Sans';
			ctx.textAlign='center';
			ctx.lineWidth=8;
			ctx.lineJoin = 'round';
			ctx.strokeRect(this.left + this.width/2 - (shapeWidth/2),this.height/2-(shapeWidth/2) + this.top,shapeWidth,shapeWidth);
			ctx.fillText(game.selected.text,this.left + this.width/2,this.height/2 + this.top );
		}
	};

	this.board =  new Board();
};

Game.prototype.initialSideButtons = function(){
	var game = this;
	var ButtonBar =function(text){
		this.text = text;
		this.left = 0;
		this.top  = 0;
		this.width = 1;
		this.height= 1;
		this.selected=false;
	};

	ButtonBar.prototype.hitTest=function(x,y){
		return 	(this.left < x) && (x < (this.left + this.width)) &&
				(this.top <y) && (y < (this.top + this.height));
	};

	ButtonBar.prototype.getColor=function(){
		var hovered = this.hitTest(game.hoverX,game.hoverY);

		if(this.selected){
			if(hovered)
			{
				return game.palette.color7;
			}
			return game.palette.color6;
		}

		if(hovered){
			return game.palette.color5;
		}
		return game.palette.color4;
	};

	ButtonBar.prototype.render = function(ctx){
		var fontSize = 14;
		ctx.fillStyle = this.getColor();
		ctx.fillRect(this.left, this.top, this.width, this.height);
		ctx.fillStyle = game.palette.color1;
		ctx.textAlign = 'left';
		ctx.font ='bold '+ fontSize +'px Noto Sans';
		ctx.fillText(this.text,this.left + 10,this.top+ this.height/2);
	};

	var SideButtons = function(){
		this.buttons = [];
		this.width = 1;
		this.height= 1;
		this.left=1;
		this.top=1;
	};

  SideButtons.prototype.lowerHoverBoxHitTest = function(x, y) {
    game.overDist = y - (game.title.height + game.footer.top) - game.hoverScrollSize;
    return (x >= this.width) && (x <= game.width) &&
    (y >= ((game.title.height + game.footer.top) - game.hoverScrollSize)) && (y <= (game.title.height + game.footer.top));
  }

  SideButtons.prototype.upperHoverBoxHitTest = function(x, y) {
    game.overDist = game.hoverScrollSize - y;
    return (x>=this.width) && (x <= game.width) &&
    (y >= game.title.height) && (y <= (game.title.height+game.hoverScrollSize));
  }

	SideButtons.prototype.render = function(ctx){
		if(!this.buttons.length){
			return;
		}

		var height = (this.height / this.buttons.length)/0.45;
		for(var i=0;i<this.buttons.length;i++){
			var btn = this.buttons[i];
			btn.left = this.left;
			btn.top = i * height + this.top;
			btn.width = this.width;
			btn.height = height;
			this.buttons[i].render(ctx);
		}
	};

	SideButtons.prototype.click = function() {
    var current = null;
		for(var i=0;i<this.buttons.length;i++){
			var btn = this.buttons[i];
      if(btn.hitTest(game.hoverX,game.hoverY)) {
				this.select(btn);
        break;
			}
		}
	};

  SideButtons.prototype.select = function(btn) {
    for(var i=0; i<this.buttons.length; i++) {
      this.buttons[i].selected = false;
    }
    btn.selected=true;
    game.onSelect(btn);
  };

  SideButtons.prototype.refreshShapes = function() {
    this.buttons = [];
    for (var buttonIndex=1; buttonIndex<=10; buttonIndex++) {
      this.buttons.push(new ButtonBar('Button ' + game.buttonType[buttonIndex]));
    }
  }

	this.sideButtons = new SideButtons();

  for (var buttonIndex=1; buttonIndex<=10; buttonIndex++) {
    this.sideButtons.buttons.push(new ButtonBar('Button ' + game.buttonType[buttonIndex]));
  }
};

Game.prototype.initialTitle = function(){
	var Title = function(value,width,height){
		this.value=value;
		this.width = width;
		this.height= height;
	};

	var game = this;
	Title.prototype.render=function(ctx){
		var k = 2;
		var fontSize =  this.height / k;
		ctx.fillStyle=game.palette.color1;
		ctx.fillRect(0,0,this.width,this.height);
		ctx.font='bold '+ fontSize +'px Noto Sans'; // check
		ctx.fillStyle=game.palette.color3;
		ctx.textAlign='center';
		ctx.fillText(this.value,this.width/2,this.height - fontSize/2);

	};

	this.title = new Title('Test',this.width,this.height / 10);
}

Game.prototype.initialFooter = function(){
	var Footer = function(){
		this.width = 1;
		this.height= 1;
		this.left=0;
		this.top=0;
	}
	var game = this;
	Footer.prototype.render = function(ctx){
		ctx.fillStyle =  game.palette.color5;
		ctx.fillRect(this.left,this.top,this.width,this.height);
	};

	this.footer = new Footer();
};

Game.prototype.resetCanvas = function() {
	this.canvas.width  =  this.width;
	this.canvas.height =  this.height;
};

Game.prototype.render = function () {
   var that = this;
   that._render();
}

Game.prototype._render = function() {
	this.resetCanvas();

	var context = this.canvas.getContext('2d');

    this.sideButtons.render(context);
	this.title.render(context);
	this.board.render(context);
	this.footer.render(context);

};

Game.prototype.resize =  function (width,height){
	this.width = width;
	this.height= height;

	this.element.style.width = width + 'px';
	this.element.style.height= height+ 'px';

	this.title.height = this.height / 14;
	this.title.width   = this.width;

	this.footer.height = this.title.height;
	this.footer.width  = this.width;
	this.footer.top = this.height - this.footer.height;
	this.footer.left = 0;

	this.board.top   = this.title.height;
	this.board.left  = 0;
	this.board.width = this.width / 2;
	this.board.height= this.height - this.title.height - this.footer.height;

	this.sideButtons.left= this.board.width;
	this.sideButtons.top = this.board.top + this.hoverAmount;
	this.sideButtons.width = this.width - this.board.width;
	this.sideButtons.height = this.board.height;

	this.maxSpeed = this.height*(5/500);
	this.shapeSize = this.height*(30/500);
	this.hoverScrollSize = this.height*(100/500);

	this.render();
};


var game = new Game('game',window.innerWidth -50,window.innerWidth * 2/3);

window.addEventListener('resize', function(){
	game.resize(window.innerWidth -50,window.innerWidth * 2/3);
});

buttonTypeSelection.addEventListener('change', function() {
  game.buttonType=buttonRanges[buttonTypeSelection.options[buttonTypeSelection.selectedIndex].text];
  var selectedIndex = game.sideButtons.buttons.indexOf(game.selected);
  game.sideButtons.refreshShapes();
  game.selected = game.sideButtons.buttons[selectedIndex];
  game.render();
});

requestAnimationFrame(() => {
  game.resize(window.innerWidth - 50, window.innerWidth * 2/3);
  requestAnimationFrame(mainLoop); // start main loop
});

function mainLoop() {
  if (game.overBox !== game.overTypes.none) {
    game.hoverAmount += game.overDist/game.hoverScrollSize * (game.overBox === game.overTypes.lower ? game.maxSpeed : -game.maxSpeed);
    var bottom = (game.height - (game.title.height + game.footer.height) + (game.sideButtons.buttons.length * game.shapeSize));

    // game.hoverAmount = (game.hoverAmount > 0) ? 0 : (game.hoverAmount < bottom) ? bottom : game.hoverAmount;
    game.resize(window.innerWidth - 50, window.innerWidth * 2/3);
  }
  requestAnimationFrame(mainLoop);
}
<!doctype html>
<html lang="en">
<body>
	<div id='game'></div>
	<div class="styled-select">
		<select id="languageSelection"></select>
	</div>
  <script type='text/javascript' src='scaleStack.js'></script>
</body>
</html>

最佳答案

为什么它不起作用?

这不是关于requestionAnimationFrame,而是关于计算滚动的逻辑(滚动偏移量,命中区域的命中率)。

  • 您必须检查计算upperBoxHitTestlowerBoxHitTest 的逻辑。
  • 当然,您在 mainloop 中的计算充满了问题。
  • 并且您必须了解代码中的索引外迭代。

代码风格提示

您不能只复制一段代码,做一些简单的替换并希望它能正常工作。您应该弄清楚它是如何工作的,它的内部逻辑,并且您不会害怕通过更复杂的实现来插入它。

所以我建议你再次检查你的代码,并尝试找出你的代码有什么问题。在你取得一些进展或者你真的无法解决之前,你可以看看我的代码是如何工作的。如果是后一种情况,你可能需要阅读更多关于逻辑思维、问题分析和编程方法论的书籍。

祝你好运!

修改后的代码

代码片段 stackoverflow 的 iframe 区域真的很小,你应该在这里查看 https://jsbin.com/bucisupugu/edit?js,output .

const btnTypeSelectElem = document.getElementById('languageSelection');

const buttonRanges = {
    '1-10': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
    'One to Ten': ['One', 'Two', 'Three', 'Four', 'Five', 'Six', 'Seven', 'Eight', 'Nine', 'Ten'],
    '0000-1010': ['0001', '0010', '0011', '0100', '0101', '0110', '0111', '1000', '1001', '1010']
};
const buttonTypeIndex = {
    '1-10': 1,
    'One to Ten': 2,
    '0000-1010': 3
};

Object.keys(buttonRanges)
    .forEach(function (buttonType) {
        btnTypeSelectElem.add(new Option(buttonType, buttonTypeIndex[buttonType]));
    });

btnTypeSelectElem.options.selectedIndex = 1; // set to page source language's code
const initialButtonType = buttonRanges[Object.keys(buttonRanges)[btnTypeSelectElem.options.selectedIndex]];

class Game {
    constructor(elementID, width, height) {
        this.elementID = elementID;
        this.element = document.getElementById(elementID);
        this.width = width;
        this.height = height;

        this.palette = {
            color1: '#fff',
            color2: '#000',
            color3: '#9F3A9B',
            color4: '#a84ea5',
            color5: '#b56ab2',
            color6: '#bf7dbd',
            color7: '#d5a8d2'
        };

        this.element.style.width = `${width}px`;
        this.element.style.height = `${height}px`;
        this.element.style.border = `solid thin ${this.palette.color2}`;
        this.element.style.display = 'block';
        //this.element.style.margin='1em auto';
        this.element.style.background = this.palette.color3;

        this.buttonRange = buttonRanges[btnTypeSelectElem.options[btnTypeSelectElem.selectedIndex].text];

        this.scrollTop = 0;
        this.overTypes = {
            none: 0,
            lower: 1,
            raise: 2
        };
        this.overBox = 0;

        // overDist have different meanings for upper box and lower box
        // for upper: y offset to the top of hover scroll zone
        // for lower: y offset to the bottom of hover scroll zone
        // and in fact it's actually for sidebuttons container, coz the sidebuttons is
        // the simulated scroll container
        this.overDist = 0;

        this.initiateGame();
    }

    initiateGame() {
        this.canvas = document.createElement("canvas");
        this.canvas.width = this.width;
        this.canvas.height = this.height;
        this.element.appendChild(this.canvas);

        this.initiateSideButtons();
        this.initiateTitle();
        this.initiateBoard();
        this.initiateFooter();

        // initial selection
        this.sideButtons.select(this.sideButtons.buttons[0]);

        this.resize(this.width, this.height);
        this.render();
        this.attachEvents();
    }

    attachEvents() {
        const element = this.element;

        const getX = function (evt) {
            return evt.offsetX || evt.layerX || evt.clientX - element.offsetLeft;
        };
        const getY = function (evt) {
            return evt.offsetY || evt.layerY || evt.clientY - element.offsetTop;
        };

        this.element.addEventListener('mousemove', (evt) => {
            this.hover(getX(evt), getY(evt));
            if (this.sideButtons.upperHoverBoxHitTest(this.hoverX, this.hoverY)) {
                game.overDist = game.hoverScrollZoneSize - (this.hoverY - game.title.height);
                this.overBox = this.overTypes.lower;
            } else if (this.sideButtons.lowerHoverBoxHitTest(this.hoverX, this.hoverY)) {
                game.overDist = game.hoverScrollZoneSize - (game.footer.top - this.hoverY);
                this.overBox = this.overTypes.raise;
            } else {
                game.overDist = 0
                this.overBox = this.overTypes.none;
            }
            this.render();
        });

        this.element.addEventListener('click', (evt) => {
            this.sideButtons.click();
            this.render();
        });
    }

    onSelect(button) {
        this.selected = button;
    }

    hover(x, y) {
        this.hoverX = x;
        this.hoverY = y;
    }

    initiateBoard() {
        const game = this;

        class Board {
            constructor() {
                this.left = 0;
                this.top = 0;
                this.width = 0;
                this.height = 0;
            }

            render(ctx) {
                if (game.selected) {

                    const shapeWidth = this.width / 3;

                    ctx.fillStyle = game.palette.color1;
                    ctx.strokeStyle = game.palette.color1;
                    const fontSize = 14;
                    ctx.font = `bold ${fontSize}px Noto Sans`;
                    ctx.textAlign = 'center';
                    ctx.lineWidth = 8;
                    ctx.lineJoin = 'round';
                    ctx.strokeRect(this.left + this.width / 2 - shapeWidth / 2, this.height / 2 - shapeWidth / 2 + this.top, shapeWidth, shapeWidth);
                    ctx.fillText(game.selected.text, this.left + this.width / 2, this.height / 2 + this.top);
                }
            }
        }

        this.board = new Board();
    }

    initiateSideButtons() {
        const game = this;

        class ButtonBar {
            constructor(text) {
                this.text = text;
                this.left = 0;
                this.top = 0;
                this.width = 1;
                this.height = 1;
                this.selected = false;
            }

            hitTest(x, y) {
                return this.left < x &&
                    x < this.left + this.width &&
                    this.top < y &&
                    y < this.top + this.height;
            }

            getColor() {
                const hovered = this.hitTest(game.hoverX, game.hoverY);

                if (this.selected) {
                    if (hovered) {
                        return game.palette.color7;
                    }
                    return game.palette.color6;
                }

                if (hovered) {
                    return game.palette.color5;
                }
                return game.palette.color4;
            }

            render(ctx) {
                const fontSize = 14;
                ctx.fillStyle = this.getColor();
                ctx.fillRect(this.left, this.top, this.width, this.height);
                ctx.fillStyle = game.palette.color1;
                ctx.textAlign = 'left';
                ctx.font = `bold ${fontSize}px Noto Sans`;
                ctx.fillText(this.text, this.left + 10, this.top + this.height / 2);
            }
        }

        class SideButtons {
            constructor() {
                this.buttons = [];
                this.width = 1;
                this.height = 1;
                this.left = 1;
                this.top = 1;
            }

            upperHoverBoxHitTest(x, y) {
                return x >= this.left &&
                    x <= this.left + this.width &&
                    y >= game.title.height &&
                    y <= game.title.height + game.hoverScrollZoneSize;
            }

            lowerHoverBoxHitTest(x, y) {
                return x >= this.left &&
                    x <= this.left + this.width &&
                    y >= game.footer.top - game.hoverScrollZoneSize &&
                    y <= game.footer.top;
            }

            render(ctx) {
                if (!this.buttons.length) {
                    return;
                }

                const height = this.height / this.buttons.length / 0.45;
                for (let i = 0; i < this.buttons.length; i++) {
                    const btn = this.buttons[i];
                    btn.left = this.left;
                    btn.top = i * height + this.top;
                    btn.width = this.width;
                    btn.height = height;
                    this.buttons[i].render(ctx);
                }
            }

            click() {
                const current = null;
                for (let i = 0; i < this.buttons.length; i++) {
                    const btn = this.buttons[i];
                    if (btn.hitTest(game.hoverX, game.hoverY)) {
                        this.select(btn);
                        break;
                    }
                }
            }

            select(btn) {
                for (let i = 0; i < this.buttons.length; i++) {
                    this.buttons[i].selected = false;
                }
                btn.selected = true;
                game.onSelect(btn);
            }

            refreshShapes() {
                this.buttons = [];
                // note: fix an out-of-index bug here
                for (let buttonIndex = 0; buttonIndex < 10; buttonIndex++) {
                    this.buttons.push(new ButtonBar(`Button ${game.buttonRange[buttonIndex]}`));
                }
            }
        }

        this.sideButtons = new SideButtons();

        // note: fix an out-of-index bug here
        for (let buttonIndex = 0; buttonIndex < 10; buttonIndex++) {
            this.sideButtons.buttons.push(new ButtonBar(`Button ${game.buttonRange[buttonIndex]}`));
        }
    }

    initiateTitle() {
        class Title {
            constructor(value, width, height) {
                this.value = value;
                this.width = width;
                this.height = height;
            }

            render(ctx) {
                const k = 2;
                const fontSize = this.height / k;
                ctx.fillStyle = game.palette.color1;
                ctx.fillRect(0, 0, this.width, this.height);
                ctx.font = `bold ${fontSize}px Noto Sans`; // check
                ctx.fillStyle = game.palette.color3;
                ctx.textAlign = 'center';
                ctx.fillText(this.value, this.width / 2, this.height - fontSize / 2);
            }
        }

        const game = this;

        this.title = new Title('Test', this.width, this.height / 10);
    }

    initiateFooter() {
        class Footer {
            constructor() {
                this.width = 1;
                this.height = 1;
                this.left = 0;
                this.top = 0;
            }

            render(ctx) {
                ctx.fillStyle = game.palette.color5;
                ctx.fillRect(this.left, this.top, this.width, this.height);
            }
        }

        const game = this;

        this.footer = new Footer();
    }

    resetCanvas() {
        this.canvas.width = this.width;
        this.canvas.height = this.height;
    }

    render() {
        const that = this;
        that._render();
    }

    _render() {
        this.resetCanvas();

        const context = this.canvas.getContext('2d');

        this.sideButtons.render(context);
        this.title.render(context);
        this.board.render(context);
        this.footer.render(context);
    }

    resize(width, height) {
        this.width = width;
        this.height = height;

        this.element.style.width = `${width}px`;
        this.element.style.height = `${height}px`;

        this.title.height = this.height / 14;
        this.title.width = this.width;

        this.footer.height = this.title.height;
        this.footer.width = this.width;
        this.footer.top = this.height - this.footer.height;
        this.footer.left = 0;

        this.board.top = this.title.height;
        this.board.left = 0;
        this.board.width = this.width / 2;
        this.board.height = this.height - this.title.height - this.footer.height;

        this.sideButtons.left = this.board.width;
        this.sideButtons.top = this.board.top + this.scrollTop;
        this.sideButtons.width = this.width - this.board.width;
        this.sideButtons.height = this.board.height;

        this.maxSpeed = this.height * (5 / 500);
        this.shapeSize = this.height * (30 / 500);
        // hover scroll zone is that area when mouse hovers on it will trigger scrolling behavior
        this.hoverScrollZoneSize = this.height * (100 / 500);

        this.render();
    }
}

const game = new Game('game', window.innerWidth - 50, window.innerWidth * 2 / 3);

window.addEventListener('resize', function () {
    game.resize(window.innerWidth - 50, window.innerWidth * 2 / 3);
});

btnTypeSelectElem.addEventListener('change', function () {
    game.buttonRange = buttonRanges[btnTypeSelectElem.options[btnTypeSelectElem.selectedIndex].text];
    const selectedIndex = game.sideButtons.buttons.indexOf(game.selected);
    game.sideButtons.refreshShapes();
    game.selected = game.sideButtons.buttons[selectedIndex];
    game.render();
});

requestAnimationFrame(() => {
    game.resize(window.innerWidth - 50, window.innerWidth * 2 / 3);
    requestAnimationFrame(mainLoop); // start main loop
});

function mainLoop() {
    if (game.overBox !== game.overTypes.none) {
        game.scrollTop += game.overDist / game.hoverScrollZoneSize * (game.overBox === game.overTypes.lower ? game.maxSpeed : -game.maxSpeed);
        const bottom = -game.sideButtons.height;

        game.scrollTop = (game.scrollTop > 0) ? 0 : (game.scrollTop < bottom) ? bottom : game.scrollTop;
        game.resize(window.innerWidth - 50, window.innerWidth * 2 / 3);
    }
    requestAnimationFrame(mainLoop);
}
<!doctype html>
<html lang="en">

<body>
    <div id='game'></div>
    <div class="styled-select">
        <select id="languageSelection"></select>
    </div>
    <script type='text/javascript' src='game.js'></script>
</body>

</html>

关于Javascript - 带有 requestAnimationFrame 的面向对象 Canvas 游戏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45065743/

相关文章:

javascript - 带有圆 Angular 的html5 Canvas 三 Angular 形

javascript - 如果我们在 .js 中拥有所有详细信息,.vue .js 文件之间有什么区别?

javascript - jQuery - $(this) 不接受元素

html - 我的图像没有占据页面的整个宽度

javascript - 获取输入范围位置的背景颜色

javascript - IE8 上的 html2canvas 和 flashcanvas 无法正常工作

javascript - javascript中的for循环延迟

javascript - uglify-js 支持 es6 及以上版本吗?

java - 发送 GET 方法而不是 DELETE

html - Vuetify 等高 v-tab-items