31-精确滚动的完整代码示例
9.4.9 精确滚动的完整代码示例
例 9-3 展示了精确滚动示例的完整代码。注意,代码中加入了 colBuffer 和 rowBuffer变量并使用了矩阵变换,这两者共同组成了平滑精确滚动的秘密。
例9-3 精确滚动
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>CH9 EX4 Scrolling Test 2 fine scrolling</title>
<script src="modernizr.js"></script>
<script type="text/javascript">
window.addEventListener('load', eventWindowLoaded, false);
function eventWindowLoaded() {
canvasApp();
}
</script>
<script language="Javascript">
function canvasSupport () {
return Modernizr.canvas;
}
function canvasApp(){
if (!canvasSupport()) {
return;
}else{
var theCanvas = document.getElementById('canvas');
var context = theCanvas.getContext('2d');
}
document.onkeydown=function(e){
e=e?e:window.event;
keyPressList[e.keyCode]=true;
}
document.onkeyup=function(e){
//document.body.onkeyup=function(e){
e=e?e:window.event;
keyPressList[e.keyCode]=false;
};
//用户按键列表
var keyPressList=[];
//图像
var tileSheet = new Image();
tileSheet.src = "scrolling_tiles.png";
//地图数据
var world={};
//镜头
var camera={};
//用户按键列表
var keyPressList={};
var rowBuffer=1;
var colBuffer=1;
var scrollRate=4;
function init() {
world.cols=15;
world.rows=15;
world.tileWidth=32;
world.tileHeight=32;
world.height=world.rows*world.tileHeight;
world.width=world.cols*world.tileWidth;
camera.height=theCanvas.height;
camera.width=theCanvas.width;
camera.rows=camera.height / world.tileHeight;
camera.cols=camera.width / world.tileWidth;
camera.dx=0;
camera.dy=0;
camera.x=0;
camera.y=0;
keyPressList=[];
//console.log("camera.rows=", camera.rows, "camera.cols=", camera.cols);
gameLoop()
}
function runGame() {
camera.dx=0;
camera.dy=0;
//检查用户输入
if (keyPressList[38]){
console.log("up");
camera.dy=-scrollRate;
}
if (keyPressList[40]){
console.log("down");
camera.dy=scrollRate;
}
if (keyPressList[37]){
console.log("left");
camera.dx=-scrollRate;
}
if (keyPressList[39]){
console.log("right");
camera.dx=scrollRate;
}
camera.x+=camera.dx;
camera.y+=camera.dy;
if (camera.x<=0) {
camera.x=0;
colBuffer=0;
}else if (camera.x > (world.width - camera.width)-scrollRate) {
camera.x=world.width - camera.width;
colBuffer=0;
}else{
colBuffer=1;
}
if (camera.y<=0) {
camera.y=0;
rowBuffer=0;
}else if (camera.y > (world.height - camera.height)-scrollRate) {
camera.y=world.height - camera.height;
rowBuffer=0;
}else{
rowBuffer=1;
}
console.log("scrollRate=", scrollRate);
var xDistance=(world.width - camera.width)-scrollRate;
console.log("camera.x=", camera.x);
console.log("(world.width - camera.width)-scrollRate =", xDistance);
var yDistance=(world.height - camera.height)-scrollRate;
console.log("camera.y=", camera.y);
console.log("(world.height - camera.height)-scrollRate =", yDistance);
console.log("colBuffer=", colBuffer);
console.log("rowBuffer", rowBuffer);
context.fillStyle = '#000000';
context.fillRect(0, 0, theCanvas.width, theCanvas.height);
//绘制镜头
//计算起始区块的位置
var tilex=Math.floor(camera.x/world.tileWidth);
var tiley=Math.floor(camera.y/world.tileHeight);
var rowCtr;
var colCtr;
var tileNum;
context.setTransform(1,0,0,1,0,0);
context.translate(-camera.x%world.tileWidth, -camera.y%world.tileHeight);
for (rowCtr=0;rowCtr<camera.rows+rowBuffer;rowCtr++) {
for (colCtr=0;colCtr<camera.cols+colBuffer;colCtr++) {
tileNum=(world.map[rowCtr+tiley][colCtr+tilex]);
var tilePoint={};
tilePoint.x=colCtr*world.tileWidth;
tilePoint.y=rowCtr*world.tileHeight;
var source={};
source.x=Math.floor(tileNum % 5) * world.tileWidth;
source.y=Math.floor(tileNum /5) *world.tileHeight;
context.drawImage(tileSheet, source.x, source.y, world.tileWidth,
world.tileHeight,tilePoint.x,tilePoint.y,
world.tileWidth,world.tileHeight);
}
}
}
world.map=[
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
,[0,1,2,1,1,1,1,1,1,1,1,1,1,1,0]
,[0,1,0,1,0,0,1,0,1,0,0,1,0,1,0]
,[0,1,0,1,0,0,1,0,1,0,0,1,0,1,0]
,[0,1,0,1,0,0,1,1,1,0,0,1,0,1,0]
,[0,2,1,1,1,1,0,0,0,1,1,1,1,1,0]
,[0,1,0,0,0,1,0,0,0,1,0,0,0,1,0]
,[0,1,1,1,2,1,0,0,0,1,1,1,1,1,0]
,[0,0,0,0,0,1,1,1,1,1,0,0,0,0,0]
,[0,1,1,1,1,1,0,0,0,1,1,1,1,1,0]
,[0,1,0,1,0,0,1,1,1,0,0,1,0,1,0]
,[0,1,0,1,0,0,2,0,0,0,0,1,0,1,0]
,[0,1,0,1,0,0,1,0,1,0,0,1,0,1,0]
,[0,1,1,1,1,1,1,2,1,1,1,1,1,1,0]
,[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
];
init();
var FRAME_RATE=10;
var intervalTime=1000/FRAME_RATE;
function gameLoop() {
runGame();
window.setTimeout(gameLoop, intervalTime);
}
}
</script>
</head>
<body>
<div style="position: absolute; top: 50px; left: 50px;">
<canvas id="canvas" width="160" height="160">
Your browser does not support the HTML5 Canvas.
</canvas>
</div>
</body>
</html>
代码中保留了console.log语句,用于展示算法中rowBuffer和colBuffer的值。这里的值与之前在例9-3中的值一样。
在浏览器中运行示例时,每次按上、下、左、右方向键可以将镜头移动4个像素。读者可以通过scrollRate调整这个值。
这就是关于如何在基于区块的屏幕上使用精确滚动和粗糙滚动的全部内容。通过使用前面章节的示例,读者可以利用路径查找、物理引擎甚至基于像素的碰撞检测对此进行扩展,从而创建出任意类型的支持滚屏的游戏。