本系列博文翻譯自以下文章
http://blog.sklambert.com/html5-canvas-game-panning-a-background/
Languages: HTML5, JavaScript
Code: https://github.com/straker/galaxian-canvas-game/tree/master/part1
1.遊戲背景滾動
最終的遊戲示範界面如下:
控制:移動 – (←↑↓→)箭頭
射擊 – 空格
The HTML5 Page
<!DOCTYPE html>
<html>
<head>
<title>Space Shooter Demo</title>
<style>
canvas {
position: absolute;
top: 0px;
left: 0px;
background: transparent;
}
</style>
</head>
<body onload="init()">
<!-- The canvas for the panning background -->
<canvas id="background" width="600" height="360">
Your browser does not support canvas. Please try again with a different browser.
</canvas>
<script src="space_shooter_part_one.js"></script>
</body>
</html>
以上代碼建立了一個600寬,360高的畫布。
基礎
建立一個封裝全部圖像的js對象:
/**
* Define an object to hold all our images for the game so images
* are only ever created once. This type of object is known as a
* singleton.
*/
var imageRepository = new function() {
// Define images
this.background = new Image();
// Set images src
this.background.src = "imgs/bg.png";
}
接下來,我們建立
Drawable對象,所有以後的可以運動的物體對象都繼承于它,Drawable對象包含一個空的draw方法。
/**
* Creates the Drawable object which will be the base class for
* all drawable objects in the game. Sets up default variables
* that all child objects will inherit, as well as the default
* functions.
*/
function Drawable() {
this.init = function(x, y) {
// Default variables
this.x = x;
this.y = y;
}
this.speed = 0;
this.canvasWidth = 0;
this.canvasHeight = 0;
// Define abstract function to be implemented in child objects
this.draw = function() {
};
}
接下來我們建立背景 Background對象,注意紅色部分的代碼,紅色2句代碼是背景移動的核心。
第一句讓背景從縱坐标0開始向下移動,第二句 讓背景從縱坐标(0-畫布)高度開始向下移動,這樣就産生了背景在不斷向下移動的效果。
最後一句藍色代碼是将 Background對象的原形設定為 Drawable對象,繼承 Drawable中的變量和方法。
/**
* Creates the Background object which will become a child of
* the Drawable object. The background is drawn on the "background"
* canvas and creates the illusion of moving by panning the image.
*/
function Background() {
this.speed = 1; // Redefine speed of the background for panning
// Implement abstract function
this.draw = function() {
// Pan background
this.y += this.speed;
this.context.drawImage(imageRepository.background, this.x, this.y);
// Draw another image at the top edge of the first image
this.context.drawImage(imageRepository.background, this.x, this.y - this.canvasHeight);
// If the image scrolled off the screen, reset
if (this.y >= this.canvasHeight)
this.y = 0;
};
}
// Set Background to inherit properties from Drawable
Background.prototype = new Drawable();
最後一步
建立Game對象,Game對象獲得web頁面中定義的畫布,初始化背景對象
Background,設定背景對象的
context以及畫布寬,畫布高屬性。
/**
* Creates the Game object which will hold all objects and data for
* the game.
*/
function Game() {
/*
* Gets canvas information and context and sets up all game
* objects.
* Returns true if the canvas is supported and false if it
* is not. This is to stop the animation script from constantly
* running on older browsers.
*/
this.init = function() {
// Get the canvas element
this.bgCanvas = document.getElementById('background');
// Test to see if canvas is supported
if (this.bgCanvas.getContext) {
this.bgContext = this.bgCanvas.getContext('2d');
// Initialize objects to contain their context and canvas
// information
Background.prototype.context = this.bgContext;
Background.prototype.canvasWidth = this.bgCanvas.width;
Background.prototype.canvasHeight = this.bgCanvas.height;
// Initialize the background object
this.background = new Background();
this.background.init(0,0); // Set draw point to 0,0
return true;
} else {
return false;
}
};
// Start the animation loop
this.start = function() {
animate();
};
}
以下是動畫功能的實作,其中
requestAnimFrame類似一個timer,會不定期的回調 animate()函數; animate()函數中調用
game.background.draw();不斷的重繪背景圖檔的位置,以實作背景滾動的動畫效果。
/**
* The animation loop. Calls the requestAnimationFrame shim to
* optimize the game loop and draws all game objects. This
* function must be a gobal function and cannot be within an
* object.
*/
function animate() {
requestAnimFrame( animate );
game.background.draw();
}
/**
* requestAnim shim layer by Paul Irish
* Finds the first API that works to optimize the animation loop,
* otherwise defaults to setTimeout().
*/
window.requestAnimFrame = (function(){
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(/* function */ callback, /* DOMElement */ element){
window.setTimeout(callback, 1000 / 60);
};
})();
最後啟動程式:
/**
* Initialize the Game and starts it.
*/
var game = new Game();
function init() {
if(game.init())
game.start();
}
最後的運作效果如下:
部落客其他系列博文推薦:
1.網絡采集軟體核心技術剖析系列博文索引
2.手把手教你使用FineUI開發一個b/s結構的取送貨管理資訊系統系列博文索引