83
HTML5 Canvasシューティングゲーム ~ 作り方、パフォーマンス、ツール ~

Html canvas shooting_and_performanceup

Embed Size (px)

Citation preview

Page 1: Html canvas shooting_and_performanceup

HTML5 Canvasで

シューティングゲーム

~ 作り方、パフォーマンス、ツール ~

Page 2: Html canvas shooting_and_performanceup

自己紹介

名前: 宗定 洋平(@yoheiMune)

 YoheiM.NET(http://www.yoheim.net/)ブロガー

趣味: テニス、プログラミング(最近は、HTML5, Objective-Cが中心)

Page 3: Html canvas shooting_and_performanceup

今日お話するネタはこちらです

http://www.yoheim.net/labo/html5/canvasShooting.html

Page 4: Html canvas shooting_and_performanceup

"Canvas de Shooting"

このゲームの作り方の解説を通して、

HTML5でのゲーム制作する際の技術ポイントを

少しでもお伝え出来ればと思います!

今日お話するネタはこちらです

Page 5: Html canvas shooting_and_performanceup

Sencha Touch

Page 6: Html canvas shooting_and_performanceup

Sencha TouchNO

Page 7: Html canvas shooting_and_performanceup

enchant.js

Page 8: Html canvas shooting_and_performanceup

enchant.jsNO

Page 9: Html canvas shooting_and_performanceup

ライブラリ無しで   いきます!!

Page 10: Html canvas shooting_and_performanceup

スクラッチでゲームを作る上で、

どんな仕組みで、どんな技術を使って、どんな事を考えて、

作って行くのかをお伝えできればと思います。

Page 11: Html canvas shooting_and_performanceup

ライブラリを使えば、

仕組みや技術要素は隠蔽され、

簡単に出来ます。

でも今回は、仕組みを学ぶ機会を提供したいと

考えています。

Page 12: Html canvas shooting_and_performanceup

では目次へ

Page 13: Html canvas shooting_and_performanceup

Agenda

1. HTML5 Canvasで今回利用する技術紹介

2. 実装内容のご紹介

3. Canvasのパフォーマンス向上

4. ツール紹介

5. 最後に

Page 14: Html canvas shooting_and_performanceup

Agenda

1. HTML5 Canvasで今回利用する技術紹介

Canvasの技術を4つ紹介します

Page 15: Html canvas shooting_and_performanceup

1. Canvasの準備

// Canvasエレメントを取得

var canvas = document.getElementById("myCanvas");

// 描画命令を行う為のコンテキストを取得

var ctx = canvas.getContext("2d");

Page 16: Html canvas shooting_and_performanceup

2. 色の指定

// 塗りつぶしの色を指定

ctx.fillStyle = "rgb(0,255,0)"; // 緑

ctx.fillStyle = "rgb(255,255,0)"; // 黄

ctx.fillStyle = "rgb(255,0,0)"; // 青

利用用途:壁色の指定、ショットの色の指定

Page 17: Html canvas shooting_and_performanceup

3. 図形の描画と、画像の描画

// 四角形の描画ctx.fillRect(posX, posY, width, height);

// 画像の描画ctx.drawImage(imageObject, posX, posY);

利用用途:ショットの描画、自機や敵機の描画

Page 18: Html canvas shooting_and_performanceup

4. 描画内容のクリア

// Canvas上の描画内容をクリアctx.clearRect(posX, posY , width, height);

利用用途:MainLoopで再描画する時に使う

Page 19: Html canvas shooting_and_performanceup

えっ!?これだけ?

Page 20: Html canvas shooting_and_performanceup

はい!これだけです。

Page 21: Html canvas shooting_and_performanceup

続いて、実装内容の紹介です

Page 22: Html canvas shooting_and_performanceup

Agenda

1. HTML5 Canvasで今回利用する技術紹介

2. 実装内容のご紹介

3. Canvasのパフォーマンス向上

4. ツール紹介

5. 最後に

Page 23: Html canvas shooting_and_performanceup

まずは初期処理です

Page 24: Html canvas shooting_and_performanceup

1. 初期化処理

// Canvasを取得var canvas = document.getElementById("myCanvas");

// Canvasの大きさを画面に合わせる

canvas.width = window.innerWidth || 800;canvas.height = window.innerHeight * 0.95 || 400;

// contextを生成する

var ctx = canvas.getContext("2d");

Page 25: Html canvas shooting_and_performanceup

1. 初期化処理

// 使う画像を、事前に読み込みますimg_plane = new Image();img_plane.src = "img/plane.png";img_plane.onload = function () {

// 読み込み終了した状態を保存

imageLoadDone = true;}

Page 26: Html canvas shooting_and_performanceup

次にメインループです

Page 27: Html canvas shooting_and_performanceup

// 描画や当たり判定を行うMainLoopをつくるvar gameMainLoop = function () { // 今回は、mainLoop内で再描画します

ctx.clearRect(0, 0, w, h);}

// setIntervalでゲームを開始!

var timer = setInterval(gameMainLoop, 50);

2. MainLoopを開始する

Page 28: Html canvas shooting_and_performanceup

ここまでで、

以下のような画面が出来ます

真っ暗です。でも動いてます。

Page 29: Html canvas shooting_and_performanceup

自機を動かします

Page 30: Html canvas shooting_and_performanceup

// まずは自機を表すオブジェクトを作ります

var plane = { img : img_plane, posX : 10, posY : (h - img_plane.height) / 2, life : 3}

3. 自機を動かす ①

Page 31: Html canvas shooting_and_performanceup

// 自機を動かす為に、keypressイベントを監視しますdocument.onkeypress = function (e) {

// 例えば自機を上に動かす場合

if (e.keyCode == 101/*E*/) { plane.posY -= 5; }}

3. 自機を動かす ②

Page 32: Html canvas shooting_and_performanceup

// そしてメインループ内で、自機を描画します

var gameMainLoop = function () {

// 自機を描画する ctx.drawImage(plane.img, plane.posX, plane.posY);}

3. 自機を動かす ③

Page 33: Html canvas shooting_and_performanceup

自機で攻撃してみます

Page 34: Html canvas shooting_and_performanceup

// 自機ショットを保持する配列を定義します

var plane_balls = [];

// 自機ショットは、以下のオブジェクト型と

// します

var ball = { radius : 5, posX : 10, posY : 10, speed : 10}

4. 自機がショットを撃つ ①

Page 35: Html canvas shooting_and_performanceup

// "K"ボタンが押されたら、ショットを生成

document.onkeypress = function () {

if (e.keyCode == 107/*K*/) { var newBall = { radius : 5, posX : plane.posX, posY : plane.posY, speed : 10 };

plane_balls.push(newBall); }}

4. 自機がショットを撃つ ②

Page 36: Html canvas shooting_and_performanceup

// mainLoop内で、speed分だけ移動させて描画する

var gameMainLoop = function () { for (var i = 0; i < plane_balls.length; i++) {

var ball = plane_balls[i]; ball.posX += ball.speed; ctx.fillStyle = "rgba(200,0,0,1)"; ctx.fillRect(ball.posX, ball.posY, ball.radius, ball.radius); }}

4. 自機がショットを撃つ ③

Page 37: Html canvas shooting_and_performanceup

これで自機を動かして、

攻撃できるようになりました

Page 38: Html canvas shooting_and_performanceup

次に、敵機を出現させます

Page 39: Html canvas shooting_and_performanceup

あっでも、敵機の実装は、自機やショットの実装説明と同じなので、パスします!!

Page 40: Html canvas shooting_and_performanceup

// まずは敵機を保持する配列を定義します

var enemies = [];

// 敵機は、以下のオブジェクト定義とします

var enemy = { img : img, /* 今回は2種類の画像を使う */

posX : x, posY : y, speed : s};

5. 敵機を出現させる ①

Page 41: Html canvas shooting_and_performanceup

// 敵機はランダムに出現させますfunction createEnemy () { var num =(Math.floor((Math.random()*100)%100); if (num < 5) { var s = num; var i = (num%2==0 ? imgE01 : imgE02); var y = canvasHeght * Math.random(); var x = canvasWidth; var enemy = {img:i, posX:x, posY:y, speed:s}; enemies.push(enemy); }}

5. 敵機を出現させる ②

Page 42: Html canvas shooting_and_performanceup

// MainLoop内でspeed分、左に移動させて描画

var gameMainLoop = function () { for (var i = 0; i < enemies.length; i++) {

var enemy = enemies[i]; var enemy.posX -= enemy.speed;

ctx.drawImage(enemy.img, enemy.posX, enemy.posY); }}

5. 敵機を出現させる ③

Page 43: Html canvas shooting_and_performanceup

これで敵機が左に向かって、

動くようになりました

Page 44: Html canvas shooting_and_performanceup

当たり判定です

Page 45: Html canvas shooting_and_performanceup

当たり判定は、物体と物体が重なったか、否かを判断します。重なっている場合には、2つの物体同士が当たっていると考えます。

6.当たり判定を行う ①

Hit!!

Page 46: Html canvas shooting_and_performanceup

例えば自機ショットと敵機の当たり判定の場合を説明します。

6.当たり判定を行う ②

x座標 = PosXy座標 = PosY

radius

x座標 = PosX+radiusy座標 = PosY

x座標 = PosX+radiusy座標 = PosY+radius

x座標 = PosXy座標 = PosY

x座標 = PosXy座標 = PosY + img.height

Page 47: Html canvas shooting_and_performanceup

// ソースコードではこんな感じですvar b = plane_balls[i];var e = enemies[j];

if ((b.posX + b.radius) >= e.posX /* x 座標 */

&& b.posY <= e.posY+e.img.width /* y座標下 */

&& b.posY >= e.posY) { /* y座標上 */

delete plane_balls[i]; delete enemies[j];}

6.当たり判定を行う ③

Page 48: Html canvas shooting_and_performanceup

// 最後にdeleteした要素をお掃除する// 例えば自機ショットの場合

var new_plane_balls = [];

for (var i = 0; i < plane_balls.length; i++) { if (plane_balls[i]) new_plane_balls.push(plane_balls[i]);}

plane_balls = new_plane_balls;

6. 当たり判定を行う ④

Page 49: Html canvas shooting_and_performanceup

// ボスを倒すか、自機が倒されたら終わりif (deadBoss() || deadSelf()) {

// mainLoopを終了させる

clearTimeout(timer);

// メッセージを表示する

if (deadBoss()) alert("CONGURATURATION!!"); else alert("GAME OVER");}

7.GameOver or GameClear ①

Page 50: Html canvas shooting_and_performanceup

これでシューティングゲームが

できました(*゚▽゚)ノ

Page 51: Html canvas shooting_and_performanceup

作ったら速く動かしたい!!

Page 52: Html canvas shooting_and_performanceup

続いて、Canvas描画処理手法を紹介をします。

3. Canvasのパフォーマンス向上

Page 53: Html canvas shooting_and_performanceup

Cavasの高速化

1、requestAnimationFrameの利用2、プレレンダリング3、複数のCanvasを使う4、描画範囲は最小に5、ステート変更は最小限に6、浮動点小数より整数値

Page 54: Html canvas shooting_and_performanceup

1、requestAnimationFrameの利用

今までの説明では、setIntervalを用いていましたが、requestAnimationFrameを用いると、ブラウザが最適なFPSで描画してくれます。

function gameMainLoop() { clearCnavas(); drawEnemies(); drawSelf(); ・・・

handle = requestAnimationFrame(gameMainLoop);}

Page 55: Html canvas shooting_and_performanceup

1、requestAnimationFrameの利用

参考URL:

・http://www.w3.org/TR/animation-timing/

・http://caniuse.com/#search=requestanimation

requestAnimationFrameを利用する上で、

以下の注意点があります。・ベンダープレフィックスが必要な場合も・サポート対象外のブラウザ(スマホは全滅に近い)

Page 56: Html canvas shooting_and_performanceup

2、プレレンダリング

画像描画や複雑な図形の描画を、事前にフレーム外のCanvasに描画しておき、実際に描画する際にCanvasにプレ描画したCanvasに流し込む事で、高速化します。

// 通常の描画

function gameMainLoop() { drawEnemy(xxx); requestAnimationFrame(gameMainLoop);}

Page 57: Html canvas shooting_and_performanceup

2、プレレンダリング

// プレレンダリングvar m_canvas = document.createElement('canvas');m_canvas.width = 32;m_canvas.height = 32;var m_context = m_canvas.getContext(‘2d’);drawEnemy(xxx);

// メインループでの描画

function gameMainLoop() { context.drawImage(m_canvas, 0, 0); requestAnimationFrame(render);

}

Page 58: Html canvas shooting_and_performanceup

2、プレレンダリング

Page 59: Html canvas shooting_and_performanceup

3、複数のCanvasを使う

描画の変更タイミングが異なるオブジェクトは、異なるCanvasに描画することで、各Canvasの描画速度を向上させることが出来ます。

Main Contents Canvas

Backgound Canvas

Page 60: Html canvas shooting_and_performanceup

3、複数のCanvasを使う

パフォーマンスの違いは以下の感じです。

Page 61: Html canvas shooting_and_performanceup

4、描画範囲は最小に

Canvasでフレーム毎に全体を描画するより、変更個所のみ描画し直す方が、処理が速く終わります。

これは当たり前な感じなので、詳細説明はパス!!

Page 62: Html canvas shooting_and_performanceup

5、ステートの変更は最小に

Canvasの描画色や線の太さなどのCanvasのステートの変更回数を減らす事で、処理速度を向上させることが出来ます。

// Badfor (var i = 0; i < STRIPES; i++) { context.fillStyle = (i % 2 ? COLOR1 : COLOR2); context.fillRect(i * GAP, 0, GAP, 480);}

Page 63: Html canvas shooting_and_performanceup

5、ステートの変更は最小に

// Goodcontext.fillStyle = COLOR1;for (var i = 0; i < STRIPES/2; i++) { context.fillRect((i*2) * GAP, 0, GAP, 480);}

context.fillStyle = COLOR2;for (var i = 0; i < STRIPES/2; i++) { context.fillRect((i*2+1) * GAP, 0, GAP, 480);}

Page 64: Html canvas shooting_and_performanceup

5、ステートの変更は最小に

パフォーマンスの違いは以下のイメージです。

Page 65: Html canvas shooting_and_performanceup

6、浮動点小数より整数値を

HTML5 Canvasではサブピクセルレンダリングがサポートされています。

整数以外で座標で描画すると、線が滑らかになるように自動的にアンチエイリアスがかかります。

Page 66: Html canvas shooting_and_performanceup

6、浮動点小数より整数値を

Whole pixel bunny vs sub-pixel bunny参考URL:http://seb.ly/2011/02/html5-canvas-sprite-optimisation/

Page 67: Html canvas shooting_and_performanceup

6、浮動点小数より整数値を

滑らかな描画を意図しない場合には、整数に整形する処理を行うべきです。

// 例var x = Math.floor(baseX * 0.9);var y = Math.round(baseY * 1.02);

また似た例として、ShadowやBlurをCanvas上で多用すると、処理が非常に重たくなります。

Page 68: Html canvas shooting_and_performanceup

6、浮動点小数より整数値を

Page 69: Html canvas shooting_and_performanceup

パフォーマンスのお話は、以上です。

Page 70: Html canvas shooting_and_performanceup

と、ここまでライブラリなしで実装することを説明してきました。

Page 71: Html canvas shooting_and_performanceup

大変だなって感じましたか?

または、色々と考えることがあって面白いなって感じましたか?

(私は後者ですw。)

Page 72: Html canvas shooting_and_performanceup

ライブラリ(例えばenchant.js)をつかうと、こんなに楽!!という点をお伝えします。

Page 73: Html canvas shooting_and_performanceup

enchant.jsを用いた場合

Page 74: Html canvas shooting_and_performanceup

ゲームの前処理

window.onload = function() { enchant(); // サイズを決めるのはこれだけ。HTML要素も要らない。

var game = new Game(320,320); // 画像読み込み完了か否かはライブラリが判断してくれる。

game.preload('fig1.png','fig2.png'); game.onload = function(){/*ゲーム開始時の処理*/} game.start();}// ゲームループの実装は必要ない

// ループ毎のCanvasのお掃除もない(Canvasではない為)

Page 75: Html canvas shooting_and_performanceup

ゲーム中 part1

要素の追加、フレーム毎の処理

// 登場キャラクターの追加(オブジェクト指向で便利)

// アーキテクチャ設計は既にされていて、考える必要なしvar enemy = new Sprite(32,32);enemy.image = game.assets['enemy01.png'];enemy.x = enemy.y = 50;game.rootScene.addChild(enemy);

// フレーム毎の処理は、追加した要素毎に記載

enemy.addEventListener('enterframe',function(){ this.x -= 2;});

Page 76: Html canvas shooting_and_performanceup

ゲーム中 part2

// Sprite毎のタップイベントも簡単に扱える。

// 位置特定を自動でしてくれるなんていい感じ。plane.addEventListener("touchend", function(param){ plane.x = param.x; plane.y = param.y;});

// 衝突判定はたったこれだけ。

// 面倒な条件判定はライブラリがやってくれる。if(ball1.intersect(enemy1)){ game.rootScene.removeChild(enemy1);}

Page 77: Html canvas shooting_and_performanceup

さて続いては、開発効率を上げるために使っているツールを紹介させて頂きます。

4. ツール紹介

Page 78: Html canvas shooting_and_performanceup

開発効率を上げるツールたち

・Scss、Sass・qUnit・grunt.js・jsLint, jsHint・HTML5 Boiler Plate・Chrome Developer Tool・jsperf・Where can I use.

Page 79: Html canvas shooting_and_performanceup

最後に。

Page 80: Html canvas shooting_and_performanceup

最後までご清聴頂きありがとうございました。

最後に、何故ライブラリなしで実装する事をここで話そうと思ったのか話できれば思います。

私はライブラリなしのスクラッチで開発する事が好きです。(仕事では開発スピード、サポートブラウザを考慮してライブラリを使いますけど)

Page 81: Html canvas shooting_and_performanceup

スクラッチで開発する理由は以下です。

・仕組みを知りたい・仕組みを作れる人になりたい・ないところから何かを作る(0から1を生み出す)ことを生き甲斐にしたい

何か新しいことが世の中にでた場合に、その最前線で戦うのに、ライブラリは無いかもしれない。

Page 82: Html canvas shooting_and_performanceup

人の力を借りずとも、自分が今まで経験/学習したことで新しいことに挑戦していく。

そのためには、一見無駄かと思えるスクラッチでの開発でたくさんの困難に出会い、それに立ち向かう。

その経験をたくさん積む事ができるのがスクラッチ開発であり、将来に繋がる活動だと思っています。

Page 83: Html canvas shooting_and_performanceup

まだまだやりたい事は一杯あるけど、力がないと感じる今日この頃。

明日の自分は今日よりも1歩進んでいて、1週間後の自分はだいぶ先に進んでいて、1ヶ月後の自分は全くの別人となる。

そんな目標をもとに、活動しています。

これからもたくさんの方々に接したいと思います。あとの懇親会でもヨロシクおねがいしますw。

今日はお時間頂きありがとうございました。