24-更新渲染的重复周期
8.9.2 更新/渲染的重复周期
在任何一个应用状态中,都需要应用动画并对屏幕进行更新。从代码中分离出update()和render()函数来处理这些更新操作。例如,玩家飞船可以在游戏屏幕上移动,当玩家按下向上键时,屏幕上的飞船将推进,而不是静止。在之前的示例中,将所有更新飞船属性的代码和实际绘制飞船的代码全都包含在drawScreen()一个函数中。从例8-10开始,将摒弃简易的drawScreen()函数,用独立的update()函数和render()函数取而代之。将检测游戏专用按键的代码剥离出来,放入checkKeys()函数。
重新查看一下例8-8中的代码,这次将代码分解为几个函数,每个函数实现一个任务,如例8-10所示。
例8-10 分解为更新与渲染周期
function gameStatePlayLevel(){
checkKeys();
update();
render();
}
function checkKeys(){
//检查按键
if (keyPressList[38]==true){
//推进
var angleInRadians = rotation * Math.PI / 180;
facingX = Math.cos(angleInRadians);
facingY = Math.sin(angleInRadians);
movingX = movingX+thrustAcceleration*facingX;
movingY = movingY+thrustAcceleration*facingY;
}
if (keyPressList[37]==true){
//逆时针旋转
rotation−=rotationalVelocity;
}
if (keyPressList[39]==true){
//顺时针旋转
rotation+=rotationalVelocity;;
}
}
function update(){
x = x+movingX;
y = y+movingY;
}
function render(){
//绘制背景和文字
context.fillStyle = '#000000';
context.fillRect(0, 0, 200, 200);
context.fillStyle = '#ffffff';
context.font = '20px sans-serif';
context.textBaseline = 'top';
context.fillText ("render/update", 0, 180);
//形状变换
var angleInRadians = rotation * Math.PI / 180;
context.save(); //将当前状态保存到栈中
context.setTransform(1,0,0,1,0,0); //重置变换矩阵
//将画布原点平移到玩家飞船中心
context.translate(x+.5*width,y+.5*height);
context.rotate(angleInRadians);
//绘制飞船
context.strokeStyle = '#ffffff';
context.beginPath();
//将位置硬编码
//面向右边
context.moveTo(−10,−10);
context.lineTo(10,0);
context.moveTo(10,1);
context.lineTo(−10,10);
context.lineTo(1,1);
context.moveTo(1,−1);
context.lineTo(−10,−10);
context.stroke();
context.closePath();
//恢复环境
context.restore(); //将原有状态恢复到屏幕
}
var FRAME_RATE = 40;
var intervalTime = 1000/FRAME_RATE;
gameLoop();
function gameLoop() {
runGame();
window.setTimeout(gameLoop, intervalTime);
}
为了节省篇幅,没有加入例8-9中的应用状态机的代码。在例8-10中仅简单展示了gameStatePlayLevel()函数的内容。
在8.10节中,当搭建完整程序时,将探讨更多的细节。