使用JavaScript和Canvas開發遊戲(二)
原文作者:Matthew Casperson • 編輯:Michele McDonough
原文連結: Game Development with JavaScript and the Canvas element
1、認識一下Canvas
2、在Canvas上繪圖
3、通過Canvas元素實現高階影像操作
4、通過Canvas實現視差滾動
5、寫一個遊戲框架(一)
6、寫一個遊戲框架(二)
7、動畫
8、JavaScript鍵盤輸入
9、綜合運用
10、定義級別
11、跳躍與墜落
12、新增道具
13、載入資源
14、新增主選單
3、通過Canvas元素實現高階影像操作
http://www.brighthub.com/internet/web-development/articles/39509.aspx
這篇文章將帶領大家學習使用JavaScript和Canvas元素操作影像了幾種不同的方式,這些方式在Canvas元素出現之前是不可能的事兒。
上一篇文章演示瞭如何利用Canvas實現一個基本的影像動畫。那個例子很簡單,同樣的效果通過修改IMG或DIV等標準HTML元素的一些屬性,照樣也可以輕易實現。下面我們就來演示一下畫布元素的高階應用,展示一下它的真正威力。
首先,還是準備一個HTML頁面。
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html lang="en">
<head>
<title>JavaScript Platformer 2</title>
<script type="text/javascript" src="jsplatformer2.js"></script>
<style type="text/css">
body { font-family: Arial,Helvetica,sans-serif;}
</style>
</head>
<body>
<p>
<a href="http://www.brighthub.com/internet/web-development/articles/38364.aspx">
Game Development with Javascript and the canvas element
</a>
</p>
<canvas id="canvas" width="600" height="400">
<p>Your browser does not support the canvas element.</p>
</canvas>
<br />
<button onclick="currentFunction=alpha;">Change Alpha</button>
<button onclick="currentFunction=shear;">Shear</button>
<button onclick="currentFunction=scale;">Scale</button>
<button onclick="currentFunction=rotate;">Rotate</button>
</body>
</html>
與上個一例子的HTML頁面相比,唯一的區別就是新增了一些按鈕。單擊這些按鈕,就會設定currentFunction變數(稍後介紹)的值,用以改變在渲染迴圈中執行的函式。
以下是 jsplatformer2.js 的程式碼。
// 每秒多少幀
const FPS = 30;
const SECONDSBETWEENFRAMES = 1 / FPS;
const HALFIMAGEDIMENSION = 75;
const HALFCANVASWIDTH = 300;
const HALFCANVASHEIGHT = 200;
var image = new Image();
image.src = "jsplatformer2-smiley.jpg"; //還是第一個例子中的影像
var canvas = null;
var context2D = null;
var currentFunction = null;
var currentTime = 0;
var sineWave = 0;
window.onload = init;
function init()
{
canvas = document.getElementById('canvas');
context2D = canvas.getContext('2d');
setInterval(draw, SECONDSBETWEENFRAMES * 1000);
currentFunction = scale;
}
function draw()
{
currentTime += SECONDSBETWEENFRAMES;
sineWave = (Math.sin(currentTime) + 1) / 2;
context2D.clearRect(0, 0, canvas.width, canvas.height);
context2D.save();
context2D.translate(HALFCANVASWIDTH - HALFIMAGEDIMENSION, HALFCANVASHEIGHT - HALFIMAGEDIMENSION);
currentFunction();
context2D.drawImage(image, 0, 0);
context2D.restore();
}
function alpha()
{
context2D.globalAlpha = sineWave;
}
function shear()
{
context2D.transform(1, 0, (sineWave - 0.5), 1, 0, 0);
}
function scale()
{
context2D.translate(HALFIMAGEDIMENSION * (1 - sineWave), HALFIMAGEDIMENSION * (1 - sineWave));
context2D.scale(sineWave, sineWave);
}
function rotate()
{
context2D.translate(HALFIMAGEDIMENSION, HALFIMAGEDIMENSION);
context2D.rotate(sineWave * Math.PI * 2);
context2D.translate(-HALFIMAGEDIMENSION, -HALFIMAGEDIMENSION);
}
跟前面一樣,這個JavaScript檔案先定義了一些全域性變數。
- FPS:每秒多少幀
- SECONDSBETWEENFRAMES:兩幀之間間隔的秒數(FPS的倒數)
- HALFIMAGEDIMENSION:要繪製影像的寬度/高度的一半,用於把影像定位到畫布的中心點
- HALFCANVASWIDTH:畫布寬度的一半,用於配合HALFIMAGEDIMENSION使用,以便在畫布上居中影像
- HALFCANVASHEIGHT:畫布高度的一半,用於配合HALFIMAGEDIMENSION使用,以便在畫布上居中影像
- currentFunction:渲染迴圈(參見上一篇文章)中執行的函式
- currentTime:應用已經執行了多少秒
- sineWave:0到1之間的一個值,用於控制影像的運動
- image:要在畫布上繪製的影像
- canvas:畫布元素的引用
- context2D:畫布元素的2D上下文的引用
然後,跟前面一樣,要設定在window的onload事件發生時立即呼叫init函式(關於init函式的介紹,請參見上一篇文章)。
draw函式
下面來看一看draw函式:
function draw()
{
currentTime += SECONDSBETWEENFRAMES;
sineWave = (Math.sin(currentTime) + 1) / 2;
context2D.clearRect(0, 0, canvas.width, canvas.height);
context2D.save();
context2D.translate(HALFCANVASWIDTH - HALFIMAGEDIMENSION, HALFCANVASHEIGHT - HALFIMAGEDIMENSION);
currentFunction();
context2D.drawImage(image, 0, 0);
context2D.restore();
}
這個例子要演示4種效果:修改alpha值(透明度),以及縮放、旋轉和切變影像。為了展示這些效果,需要基於某一範圍內的值來應用變化。變數sineWave就用來定義這個範圍值的基準。
標準的正弦函式能夠在-1到1之間產生非常完美的波形圖。首先,我們通過遞增currentTime變數來反映動畫已經執行了多長時間,然後再利用這個值在正弦曲線上找到一個點。給正弦函式返回的值(從-1到1)先加1再除以2,就可以把它們轉換成0到1這個範圍內的值。
currentTime += SECONDSBETWEENFRAMES;
sineWave = (Math.sin(currentTime) + 1) / 2;
然後,呼叫clearRect方法清空畫布,以便為後面的繪圖準備一個乾淨的版面。
context2D.clearRect(0, 0, canvas.width, canvas.height);
應用到畫布上面的效果是可以累積的,因而就可以利用幾個簡單的函式來“組合”出效果來。例如,在向螢幕上繪製之前,可能會有一艘飛船需要旋轉、變換和縮放。因為所有效果都對畫布起作用,所以這些效果會應用到將被繪製在螢幕上的所有物件,而不僅僅是某一幅影像或某一個形狀(比如一艘飛船)。
其中,save和restore函式為應用這些累積的效果提供了一種簡單的機制,可以將應用了這些效果的影像或圖形繪製到畫布上,然後“撤銷”這些改變。後臺的操作是什麼呢?save函式把當前的繪製狀態推進棧裡,而restore函式則把最後一個狀態彈出棧。還拿前面提到的飛船為例,需要執行下列操作:
- 呼叫save函式(儲存當前的繪製狀態)
- 旋轉、變換和縮放上下文
- 繪製飛船
- 呼叫restore函式,移除自上一次呼叫save方法以來所新增的任何效果,也就是撤銷之前的變化
在這裡,我們就是要組合起來使用這兩個方法。首先,在把任何效果應用到畫布之前,先儲存繪製狀態。
context2D.save();
儲存了繪製狀態之後,就該應用目標效果了。為此,首先呼叫translate函式,從而將隨後要繪製的影像在畫布上居中。
context2D.translate(HALFCANVASWIDTH - HALFIMAGEDIMENSION, HALFCANVASHEIGHT - HALFIMAGEDIMENSION);
接下來,呼叫由變數currentFunction引用的函式。正是這些被引用的函式,是讓影像發生alpha(透明度)變化以及縮放、旋轉和切變的關鍵。這些函式我們稍後再介紹。
currentFunction();
為影像應用完效果之後,就可以把它繪製到畫布上面了。所以,接下來就是呼叫drawImage來繪圖。
context2D.drawImage(image, 0, 0);
最後,再呼叫restore函式,把自呼叫save函式以來應用的所有效果從畫布上移除。
context2D.restore();
alpha函式
function alpha()
{
context2D.globalAlpha = sineWave;
}
通過修改上下文物件的globalAlpha屬性,所有後續繪製操作的透明度都會被修改。將globalAlpha設定為0,意味著被繪製的任何物件都將完全透明,而將這個屬性設定為1,則意味著任何繪製操作都會保持原有的透明度級別。在此,我們通過修改這個globalAlpha屬性,可以實現笑臉的淡入和淡出效果。
shear函式
function shear()
{
context2D.transform(1, 0, (sineWave - 0.5), 1, 0, 0);
}
[/code] 切變操作是通過transform函式向畫布應用一個矩陣來實現的。變換矩陣本身就是一個值得研究的主題,但對我們來說,如果不想理解背後的數學原理,可以在網上找到很多標準的2D變換矩陣(http://en.wikipedia.org/wiki/Transformation_matrix#Examples_in_2D_graphics),直接使用transform函式來應用它們即可。所謂切變,其實就是把影像的頂部或底部推到一邊。
scale函式
function scale()
{
context2D.translate(HALFIMAGEDIMENSION * (1 - sineWave), HALFIMAGEDIMENSION * (1 - sineWave));
context2D.scale(sineWave, sineWave);
}
顧名思義,scale(縮放)函式修改的是影像的大小。但在此之前,我們還呼叫了一次transalte函式。這是為了讓縮放後的影像在畫布上居中。如果你把這行程式碼註釋掉,就會發現影像會從左上角向右下角膨脹。呼叫translate函式就是為抵消其圓心的位移,讓影像始終居中。
rotate函式
function rotate()
{
context2D.translate(HALFIMAGEDIMENSION, HALFIMAGEDIMENSION);
context2D.rotate(sineWave * Math.PI * 2);
context2D.translate(-HALFIMAGEDIMENSION, -HALFIMAGEDIMENSION);
}
與scale函式類似,rotate(旋轉)函式的作用也正如其名:旋轉影像。與scale函式同樣類似的是,這裡也額外呼叫了translate函式以確保影像圍繞中心點而不是左上角旋轉。建議大家把對translate函式的呼叫註釋掉,自己看一看結果有什麼不同。
剛剛我們看到了使用畫布元素實現的4種也還算簡單的效果,這些效果使用標準的HTML元素幾乎是不可能做到的。其中,有的效果可以使用scale和rotate等內建函式來實現,而使用transform函式則可以完成大量的影像操作(切變只是其中之一)。
看看Demo吧。http://webdemos.sourceforge.net/jsplatformer2/jsplatformer2.html
為之漫筆 最後編輯於: 2011/08/12 @ 06:29
相關文章
- 使用JavaScript和Canvas開發遊戲(一)JavaScriptCanvas開發遊戲
- 從零開始手把手教你使用javascript+canvas開發一個塔防遊戲01地圖建立JavaScriptCanvas遊戲地圖
- Javascript特效開發(二)JavaScript特效
- [Canvas前端遊戲開發]——FlappyBird詳解Canvas前端遊戲開發APP
- 用canvas開發H5遊戲小記CanvasH5遊戲
- 《HTML5Canvas遊戲開發實戰》——第3章 Canvas高階功能HTMLCanvas遊戲開發
- 第8章 高效開發和使用外掛 (二)
- 使用Xamarin開發移動應用示例——數獨遊戲(二)建立遊戲介面遊戲
- 【翻譯】使用React、 Redux 和 SVG 開發遊戲(三)ReactReduxSVG開發遊戲
- 【翻譯】使用React、 Redux 和 SVG 開發遊戲(一)ReactReduxSVG開發遊戲
- [譯] 使用 React、Redux 和 SVG 開發遊戲 - Part 2ReactReduxSVG開發遊戲
- 《HTML5Canvas遊戲開發實戰》——3.4 小結HTMLCanvas遊戲開發
- HTML5遊戲開發(二):使用TypeScript編寫程式碼HTML遊戲開發TypeScript
- HTML5 canvas遊戲開發實戰 5 : 石頭剪刀布HTMLCanvas遊戲開發
- 使用C#和MonoGame開發俄羅斯方塊遊戲C#MonoGAM遊戲
- 《HTML5canvas開發詳解(第2版)》——1.4 文件物件模型(DOM)和CanvasHTMLCanvas物件模型
- javascript設計模式與開發實踐(二)- 封裝和原型模式JavaScript設計模式封裝原型
- HTML5 canvas遊戲開發實戰 7 : "是男人就下一百層“遊戲HTMLCanvas遊戲開發
- 【譯】用一天入門 canvas 和 JavaScriptCanvasJavaScript
- 微信程式開發系列教程(二)使用JavaScript給微信使用者傳送訊息JavaScript
- Golang之go module開發系列二--使用偽版本和GoCenterGolang
- 使用重構件(Codemod)加速JavaScript開發和重構JavaScript
- Web 前端開發日誌(二):JavaScript 的二進位制操作Web前端JavaScript
- Android 2D Graphics學習(二)、Canvas篇1、Canvas基本使用AndroidCanvas
- HTML5 canvas遊戲開發實戰 6 : 俄羅斯方塊HTMLCanvas遊戲開發
- 物件導向的程式設計在遊戲開發中使用(二):方法物件程式設計遊戲開發
- canvas實現二維碼和圖片合成Canvas
- iOS開發中使用CIFilter生成二維碼和條形碼iOSFilter
- 深入 Git 和開發規範(二)Git
- iOS開發之使用Git的基本使用(二)iOSGit
- 使用Javascript 開發個JSON解析庫JavaScriptJSON
- JavaScript HTML DOM Canvas 物件JavaScriptHTMLCanvas物件
- 《HTML5Canvas遊戲開發實戰》——第1章 準備工作HTMLCanvas遊戲開發
- 用Swift和SpriteKit開發iOS遊戲SwiftiOS遊戲
- 使用 .NET 進行遊戲開發遊戲開發
- Android 2D Graphics學習(二)、Canvas篇2、Canvas裁剪和Region、RegionIteratorAndroidCanvas
- DBA和開發同事的代溝(二)
- 使用 Docker 開發 PHP 專案(二):配置DockerPHP