以前、Donnet の DEMO でオナニー ゲームを見て、その写真と音声を書き留めました。 。 。 。趣味で書き直しました。娯楽のためだけに。 。 。 。 。 。フレームワークは使用せず、すべての js を自分で書きます。 。 。 。 。 。これは、Canvas を初めてプレイする人にとっては役立つかもしれない簡単なチュートリアルです。ご容赦ください。
早速、デモ: 飛行機ゲームから始めましょう。元の投稿者はこれをただ楽しむために書いたもので、本格的なゲームに書き込むつもりはありませんでした。
本題に入りましょう: オナニー ゲーム ファイルには、index.html エントリ ファイル、allSprite.js スプライトのロジック処理ファイル、loading.js 読み込み処理ファイル、および data.js (一部の初期化データ) が含まれています。
まず、通常のゲームは基本的にロードが必要です。ロード ページは、スプライト シートの画像、オーディオなどを含むデータを事前にロードするために使用されます。これは小規模なゲームであるため、一部のオーディオと画像のみをロードする必要があります。内部の読み込みコードは主に次のとおりです。その他は読み込みアニメーションを作成するためのものです。興味がある場合は、デモのコンソールをご覧ください。 >
XML/HTML コード
コンテンツをクリップボードにコピー
- loadImg:function(datas){
-
var _this = this;
-
var dataIndex = 0;
- li();
- function li(){
-
if(datas[dataIndex].indexOf("mp3")>=0){
-
var audio = document.createElement("audio");
- document.body.appendChild(audio);
-
audio.preload = "auto";
-
audio.src = datas[dataIndex];
-
audio.oncanplaythrough = function(){
-
this.oncanplaythrough = null;
- dataIndex ;
-
if(dataIndex===datas.length){
-
_this.percent = 100;
- }else {
-
_this.percent = parseInt(dataIndex/datas.length*100);
- li.call(_this);
- }
- }
- }其他 {
- preLoadImg(datas[dataIndex] , function(){
dataIndex ; -
地
-
;
} 其他 { -
(dataIndex/datas.length*100);
- }
- })
}
}
- },
-
- //再貼出preLoadImg的方法
- 函數 preLoadImg(src, 回調){
- var img
- = new
- Image();
- img.src
- = src;
- if(img.complete){
callback.call(img);
}其他 {
- img.onload = 函數
callback.call(img);
- }
- }
-
}
まず、配列を使用してファイルへのリンクを data.js に保存し、次にこれらのリンクが画像であるかオーディオであるかを判断します。画像の場合は、preLoadImg を使用して画像をロードします。非常に簡単で、新しい画像を作成し、それにリンクを割り当て、ロード後にコールバックするだけです。オーディオは、HTML5 オーディオ dom オブジェクトを生成し、それにリンクを割り当てることによってロードされます。オーディオには「canplaythrough」イベントがあり、ブラウザーがバッファリングのために停止せずに指定されたオーディオ/ビデオの再生を継続できると予想される場合、canplaythrough イベントが発生します。これは、canplaythrough が呼び出された時点でオーディオがほぼロードされており、次のオーディオをロードできることを意味します。このように、すべてがロードされた後、コールバックが行われ、ゲームが開始されます。
ゲームが始まりました。ゲームには多くのオブジェクトが必要になるため、異なるオブジェクト間の各フレームの動きをビヘイビアーを使用して個別に記述することができます。
XML/HTML コードコンテンツをクリップボードにコピー
- W.Sprite = 関数(name , painter , behaviors , args){
-
if(名前 !== 未定義) this.name = 名前;
-
if(ペインター !== 未定義) this.painter = ペインター;
-
this.top = 0;
-
this.left = 0;
-
this.width = 0;
-
この高さ = 0;
-
this.velocityX = 3;
-
this.velocityY = 2;
-
this.visible = true;
-
this.animating = false;
-
this.behaviors = 動作;
-
this.rotateAngle = 0;
-
this.blood = 50;
-
this.fullBlood = 50;
-
if(名前==="計画"){
-
this.rotateSpeed = 0.05;
-
this.rotateLeft = false;
-
this.rotateRight = false;
-
this.fire = false;
-
this.firePerFrame = 10;
-
this.fireLevel = 1;
-
}else if(名稱==="星星"){
-
this.width = 數學
數學-
2;
this.speed =
1-
this1this
this.lightLength-
= 5;
- this.cacheCanvas = 文件
- 這this.cacheCtx = this.cachevasCtx = this.cachevas.getContext'2005);
-
這個this.cacheCanvas.width = this.width 2.Lengength*;
-
- 這個this.cacheCanvas.height =this.width this.width this.Length*width
- this.painter.cache(this);
}else if(名稱==="badPlan"){
- this.badKind = 1;
-
this.speed = 2;
-
this.rotateAngle =
數學- }else if(名稱==="missle"){
- this.width = missleWidth;
-
}else if(名稱==="boom"){
- this.width = boomWidth =
boomWidth- = boomWidth = boomWidth = boomWidth;
-
}else if(名稱==="食物"){
- this.width = 40 = 40
40- ;
this.speed = 3;
this.kind = 「升級」 = 「升級」 = 「升級」 }
-
this.toLeft = false;
-
this.toTop = false;
-
this.toRight = false;
-
this.toBottom = false;
-
-
this.outArcRadius = 數學.s
*- .s
*-
.s.s
-
-
if(args){
-
for(var arg in args){
-
這[arg] = args[arg];
-
}
-
}
}
-
- Sprite.prototype = {
-
建構子:Sprite,
paint:function(){
-
if(
- this.name==="badPlan"){this.update();}
-
- if(this.painter !== 未定義 && this.visible){
- if(this.name!=="badPlan") {
- this.update();
}
if(this.name==="計劃"||this.name
==="計劃"||-
this.name==="計劃"||
this.name==="badPlan"){ -
ctx.save(); -
ctx.translate(this.left, this.top); -
ctx.rotate(this.rotateAngle); -
this.painter.paint(this); -
ctx.restore(); -
}其他 { -
this.painter.paint(this); -
}
}
},
- update:function(time){
- if(this.behaviors){
-
for(var i=0;ithis.behaviors.length;i ){
- this.behaviors[i].execute(this,time);
- }
- }
- }
- }
寫出精靈類別後,就可以透過寫每個的painter以及behavior來產生不同的物件了。接下來就是寫painter了,painter分成兩種,一種是普通的painter,一種就是精靈表painter,因為像爆炸動畫,飛機開槍動畫,都不是一張圖片就能搞定的,所以就需要用到精靈表了:
而繪製這些就要為他們定制一個精靈表繪製器,下面這個是最簡單的精靈表繪製器,針對遊戲的複雜性可以相對的修改精靈表寫法,直到合適,不過原理都大同小異,就是小修小改而已:
XML/HTML Code複製內容到剪貼簿
-
var SpriteSheetPainter = 函數(單元函數
- (單元 >
this.cells
- = 細胞
this.cellIndex = }
-
SpriteSheetPainter.prototype-
= { =
提前:function(){
-
if(
- this.cellIndex === .
this.cellIndex
-
}
其他 this.cellIndex ;
},
-
繪畫:函數(精靈){
-
var
- cell 🎜>
- context.drawImage(spritesheet , cell.x , cell.y ,spcell.p . .h);
-
}
}
-
而普通的器就更簡單了,直接寫一個畫家,把要畫的東西都寫進去就行了。
有了精靈類和精靈表較差器後,我們就可以把星星,飛機,子彈,爆炸對像都寫出來了:下面是整個allSprite.js的代碼:-
- JavaScript 程式碼 將內容複製到剪切板
- (函數(W){
-
「使用嚴格」
-
var planWidth = 24,
- 計畫高度= 24,
- missleWidth = 70,
- missleHeight = 70,
- boomWidth = 60;
-
-
W.Sprite = 函數(姓名、畫家、行為、參數){
-
if(name !== 未定義) 這個這個
- if(畫家!==未定義) 畫家>
這
.top = 0; -
這
.left = 0; -
這
.width = 0; -
這
.height = 0; -
這個
.velocityX = 3; -
這
.velocityY = 2; -
這個
.visible = -
true;
這個.animating =
- 這個.behaviors = 行為;
這
- .rotateAngle = 0;
這
- .blood = 50;
這
- .fullBlood = 50;
if
- (name==="計畫"
- 這.rotateSpeed = 0.05; .rotateSpeed = 0.05;
這個
- .rotateLeft = .rotateLeft =
這個-
.rotateRight = .rotateRight = 這個.fire =
-
.fire =
-
這.firePerFrame = 10;
.firePerFrame = 10; -
這
- .fireLevel = 1; .fireLevel = 1;
}否則 if
-
if(nameif
(name-
if(name>if ){
- 這.width = Math.random
這
- .speed = 1*這.speed = 1*這.speed = 1*這這樣
-
這.lightLength = 5; .lightLength = 5;
這.cacheCanvas = .T.createElement(" >
- 這.cacheCtx = 這個>這個>這個>這個>這個>這個> );
這.cacheCanvas.width =
- 這樣🎜>.lightLength*2;
這.cacheCanvas.height = 這.lightLength*2;
-
這.painter.cache( }否則
if-
if(nameif(nameif(name
if-
(nameif(name
if-
(name(name ){
-
這.badKind = 1;
.badKind = 1; -
這.speed = 2; .speed = 2;
-
這.rotateAngle = Math
}否則 if if(name
if-
(nameif ){
- 這.width = missleWidth;
}否則 if if(nameif(name ){
這.width = boomWidth; 🎜
}其他 if(name==="食物"){ >
- 這.width = 40; .width = 40;
-
這
- .speed = 3; .speed = 3;
這個
- .kind = 「升級」
.kind = -
「升級」 }
這個
- .toLeft =
這個.toTop =
-
這個.toRight =
這個
.toBottom = -
這個.outArcRadius = Math.sqrt((
這- .width/2)*2);
-
if(args){
for- (
var-
(var(
var-
(var
這[arg]
- }
}
- }
- Sprite.prototype = {
- 建構子:Sprite,
- 繪製:函數
- (){
- 如果(這個
- (這個(這個(這個.> > ){這個.update();}
-
-
if( .可見){
if
- (if(if(if(這個計畫
- ) {
這- update();這個 update();
}
-
如果(如果(如果(如果這個計劃這個>||這個.name===“導彈”||
- 這個 .name===
- "壞計畫"){
ctx.save();
ctx.translate(
- 這.
ctx.rotate(
這個- 這
ctx.restore();
- }
其他-
{
這
}
}
}, -
更新:
- 函數(時間){
-
- 如果(
對於-
(對(對(
var- 這個(var這.behaviors.length;i ){
這個.beofo[
-
}
}
}
- }
-
-
-
W.SpriteSheetPainter = 関数(cells , isloop , endCallback , spritesheet){
-
この.cells = cells || [];
-
この.cellIndex = 0;
-
this.dateCount = null;
-
この.isloop = isloop;
-
これ.endCallback = endCallback;
-
この.spritesheet = スプライトシート;
- }
- SpriteSheetPainter.prototype = {
-
advance:関数(){
-
this.cellIndex = this.isloop?(this.cellIndex===この.cells.length-1?0:この.cellIndex 1):(この.cellIndex 1);
- }、
-
paint:関数(スプライト){
-
if(this.dateCount===null){
-
this.dateCount = new Date();
-
}else {
-
var newd = new Date();
-
var tc = newd-this.dateCount;
-
if(tc>40){
-
this.advance();
-
this.dateCount = newd;
- }
- }
-
if(this.cellIndex<this。セル.長さ || この.isloop){
- var cell = this.cells[this .cellIndex];
- ctx.drawImage(this.spritesheet , cell.x , cell.y , cell.w , cell.h , sprite.left-sprite.width/ 2、sprite.top-sprite.width/2、cell.w、cell.h);
- } else if(this.endCallback) {
- この.endCallback.call(sprite);
- この.cellIndex = 0;
- }
- }
- }
-
-
- W.controllSpriteSheetPainter = 関数(セル, スプライトシート){
- この.cells = cells || [];
- この.cellIndex = 0;
- this.dateCount = null;
- this.isActive = false;
- this.derection = true;
- この.spritesheet = スプライトシート;
- }
- controllSpriteSheetPainter.prototype = {
- advance:関数(){
- if(this.isActive){
- この.cellIndex ;
- if(this.cellIndex === this.cells.length){
- この.cellIndex = 0;
- this.isActive = false;
- }
- }
- }、
- paint:関数(スプライト){
- if(this.dateCount===null){
- this.dateCount = new Date();
- }else {
- var newd = new Date();
- var tc = newd-this.dateCount;
- if(tc>sprite.firePerFrame){
-
this.advance();
-
this.dateCount = newd;
- }
- }
-
var cell = this.cells[this .cellIndex];
-
ctx.drawImage(this.spritesheet , cell.x , cell.y , cell.w , cell.h , -planWidth/2 , -planHeight/ 2、セル.w、セル.h);
- }
- }
-
- W.planBehavior = [
-
{実行:関数(スプライト,時間){
-
if(sprite.toTop){
- sprite.top = sprite.top
- }
-
if(sprite.toLeft){
- sprite.left = sprite.left
- }
-
if(sprite.toRight){
- sprite.left = sprite.left>canvas.width-planWidth/2? sprite.left : sprite.left sprite.velocityX;
- }
-
if(sprite.toBottom){
- sprite.top = sprite.top>canvas.height-planHeight/2? sprite.top : sprite.top sprite.velocityY;
- }
-
if(sprite.rotateLeft){
- sprite.rotateAngle -= sprite.rotateSpeed;
- }
-
if(sprite.rotateRight){
- sprite.rotateAngle = sprite.rotateSpeed; スパン