HTMLのバージョン5からcanvasという要素が追加されました。
このcanvasはブラウザ上にグラフィックの描画エリアを作ることができます。
この描画エリアにはJavaScriptを使って様々なグラフィックを表示することができます。
なのでもちろんゲームも作ることができるわけです。
そしてこのcanvasを利用して作られたゲームのことをHTML5ゲームと呼んだりします。
JavaScriptを使った開発ではライブラリを使うのが一般的で、もちろんゲームに使えるライブラリも色々あります。
基本的にはライブラリを使ってゲームを作った方が間違いなく楽で良いものができます。
ただ、今回はライブラリを使わない素のJavaScriptだけでゲームを作ってみます。
今回のプログラムはCodePenに上げています。CodePen上で編集できるので好きに使ってください。
See the Pen
JavaScriptで超簡易ゲームエンジン作ったよ by いんわん (@inwan78)
on CodePen.
サンプルのプログラムは大きく2つのパートに分かれていて前半部分はゲームエンジン的な部分で後半のwindow.onloadあたりからゲーム部分(今回はゲームじゃないけど)になってます。
プログラム
プログラムはこんな感じになっています。
const CORE = { setup: function(w, h){ this.engine = new Engine(w, h); } } class Engine { constructor(w, h){ const canvas = document.getElementById("canvas"); canvas.width = w; canvas.height = h; canvas.style.backgroundColor = "#000000"; CORE.canvas = canvas; CORE.ctx = canvas.getContext("2d"); window.addEventListener('resize', () => {this.resizeCanvas();}); this.resizeCanvas(); } _requestFrame(){ this.update(); requestAnimationFrame(()=>{this._requestFrame();}); } resizeCanvas(){ const canvas = CORE.canvas; const canvasHeightRatio = canvas.height / canvas.width; const windowHeightRatio = window.innerHeight / window.innerWidth; let width; let height; if (windowHeightRatio > canvasHeightRatio) { width = window.innerWidth; height = window.innerWidth * (canvas.height / canvas.width); } else { width = window.innerHeight * (canvas.width / canvas.height); height = window.innerHeight; } canvas.style.width = `${width}px`; canvas.style.height = `${height}px`; CORE.resolutionRatio = height / canvas.height; } preload(data){ const length = Object.keys(data).length; let count = 0; const assets = []; for(let key in data) { assets[key] = new Image(); assets[key].src = data[key]; assets[key].onload = ()=>{ if(++count == length){ this.onload(); } } } CORE.assets = assets; } clearCanvas(){//画面をクリア(前の画面描画を削除) CORE.ctx.clearRect(0, 0, CORE.canvas.width, CORE.canvas.height); } start(){ this.init(); requestAnimationFrame(()=>{this._requestFrame();}); } onload(){} init(){} update(){} } /*********************** */ class Sprite { constructor(w, h){ this.x = 0; this.y = 0; this.width = w; this.height = h; this.image; } draw(){ CORE.ctx.drawImage(this.image, 0, 0, this.width, this.height, this.x, this.y, this.width, this.height); } update(){ } } /****************** */ const CANVAS_HEIGHT = 900; const CANVAS_WIDTH = 900; let logo; window.onload = function(){ const assets = { "logo": "https://dl.dropbox.com/s/5tietjxglugrbpu/logo.png", } CORE.setup(CANVAS_WIDTH, CANVAS_HEIGHT); CORE.engine.preload(assets); CORE.engine.onload = function(){ CORE.engine.start(); } CORE.engine.init = () => { logo = new Logo(150, 150); logo.x = 300; } CORE.engine.update = () => { CORE.engine.clearCanvas(); logo.update(); } } class Logo extends Sprite { constructor(w, h){ super(w, h); this.vy = 2; this.vx = 2; this.image = CORE.assets['logo']; } update(){ this.y += this.vy; if(this.y+this.height > CANVAS_HEIGHT || this.y < 0){ this.vy *= -1; } this.x += this.vx; if(this.x+this.width > CANVAS_WIDTH || this.x < 0){ this.vx *= -1; } this.draw(); } }
プログラムの説明
一番最初にあるCOREオブジェクトがゲームの全体のいろいろな要素を持つようにしてます。
で、CORE.setupでこの中にEngineクラスが作られます。またEngineクラス内でCOREオブジェクトに要素が追加されます。
Engineクラスが一応ゲームエンジン的なもので必要な処理を持つようにしています。
Engineクラスについて少しだけ解説します。
resizeCanvas()
これはゲーム画面のサイズを変更する処理です。
Engineクラスを作るときの引数で幅と高さを指定しますがこれはcanvasの解像度です。通常はこの解像度と画面に表示されているcanvasの大きさは同じです。
ただ、そうするとウィンドウの大きさと一致しません。極力ウィンドウの大きさにフィットするようにcanvasの大きさを変更します(※解像度は変わらずcanvasのcssの大きさを変えるってことです)。
ウィンドウの幅高さから一番フィットするサイズを計算して表示します。
で、これをウィンドウの大きさが変わったとき(イベントって言います)に実行するようにします。それがちょっと上にあるこの部分。
window.addEventListener('resize', () => {this.resizeCanvas();});
preload()
これは画像を読み込む処理です。
画像の情報を配列で渡してやると読みこむようになっています。
配列の数だけ読み込みが完了するとEngineクラスのonload()が実行されます。
clearCanvas()
canvasに描画したものを消す処理です。
これを行わないと書いたものがそのままで上書きだけされます。
更新処理を行うときは描いて消して描いて消してを繰り返します。
start()
これを実行するとゲームが開始して自動更新が始まります。
init()は初期化処理でEngineクラス内では空ですが、必要があれば上書きします(下のwindow.onload内で上書きしています)。
その下の
requestAnimationFrame(()=>{this._requestFrame();});
これが自動更新をしてくれる処理です。
このrequestAnimationFrameというメソッドはおよそ60FPSになるような一定の間隔で引数に渡した関数を実行します。
引数はthis._requestFrame()になっていてこのthis._requestFrame()内にupdate()があるのでupdate()が毎フレーム実行されます。
update()もCoreクラス内では空ですが後で上書きします。
まとめ
以上のような感じで素のJavaScriptでゲームエンジンらしきものを作っています。
大雑把な解説しかしていませんが一つ一つググれば詳しい解説はすぐ見つかります。
このゲームエンジンを使ったゲームの作り方を追加しました。