ラベル preloadjs の投稿を表示しています。 すべての投稿を表示
ラベル preloadjs の投稿を表示しています。 すべての投稿を表示

2013年3月16日土曜日

磯野ー!2Dゲーム開発しようぜー! HTML5編 その3

磯野と中島のゲーム開発も今回で3回目。HTML5編は今回で終了だ。ちなみに今回もめがねと坊主頭の出番はない。前回までの分は以下。

磯野ー!2Dゲーム開発しようぜー! HTML5編 その1
磯野ー!2Dゲーム開発しようぜー! HTML5編 その2

coffeescripts/platform.coffee
class GamePlatform
 constructor: (@stage, width, height, contentManager)->
  # 背景の用意
  background = new createjs.Bitmap contentManager.background
  background.setTransform 0, 0, width/400.0, height/300.0   # 背景画像は400*300でCanvasサイズと合わないので拡大する
  @stage.addChild background

  # 文字列表示
  text = new createjs.Text "Click on the characters!", "bold 24px Meiryo", "#000"
  text.x = (width/2)-(text.getMeasuredWidth()/2)
  text.y = 10
  # text.align = 'right'  # align指定はこの方法で
  @stage.addChild text

  # スプライトシートの設定
  shipSpriteSheet = new createjs.SpriteSheet
   images: [contentManager.ship]
   frames:
    width:100   # 1フレームの幅を指定
    height:100  # 1フレームの高さを指定
    regX:50     # 中心点(拡大縮小、回転、移動用の)を指定
    regY:50     #
   animations:
    move:
     frames: [0, 1, 2, 3, 4, 5] # アニメーションフレームの指定
     frequency: 10   # フレームごとの速度
  # スプライトアニメーションの設定
  shipAnimation = new createjs.BitmapAnimation shipSpriteSheet
  shipAnimation.x = shipAnimation.y = 100
  # スプライトシートから指定のフレームの画像を抜き取ってBitmapオブジェクトを作成する
  ship = new createjs.Bitmap createjs.SpriteSheetUtils.extractFrame shipSpriteSheet, 0
  ship.regX = ship.regY = 50 # 中心点をスプライトアニメーションに合わせる
  ship.x = ship.y = 100
  ship.onClick = =>
   shipAnimation.rotation = 90
   @stage.addChild shipAnimation
   shipAnimation.gotoAndPlay "move"
   @stage.removeChild ship
   # オブジェクトアニメーションを設定する
   createjs.Tween.get(shipAnimation)
     .to({x:width+100, scaleX:2, scaleY:2}, 1000, createjs.Ease.cubicIn)
     .to({rotation:270})
     .to({x:100, scaleX:1, scaleY:1}, 1000, createjs.Ease.cubicOut)
     .to({rotation:0}, 500)
     .wait(500)
     .call =>
      @stage.addChild ship
      @stage.removeChild shipAnimation
      shipAnimation.stop()
  @stage.addChild ship

  sqSpriteSheet = new createjs.SpriteSheet
   images: [contentManager.square]
   frames:
    width:100
    height:130
    regX:50
    regY:65
   animations:
    walk:
     frames: [0, 1, 2, 3, 4]
     frequency: 20
  sqAnimation = new createjs.BitmapAnimation sqSpriteSheet
  sqAnimation.x = 100
  sqAnimation.y = 250
  sq = new createjs.Bitmap createjs.SpriteSheetUtils.extractFrame sqSpriteSheet, 0
  sq.regX = 50
  sq.regY = 65
  sq.x = 100
  sq.y = 250
  sq.onClick = =>
   @stage.addChild sqAnimation
   sqAnimation.gotoAndPlay "walk"
   @stage.removeChild sq
   createjs.Tween.get(sqAnimation)
     .to({x:width+100}, 1000, createjs.Ease.quadInOut)
     .to({scaleX:-1})    # Y軸を中心にフリップする
     .to({x:100}, 1000, createjs.Ease.bounceOut)
     .to({scaleX:1})
     .wait(500)
     .call =>
      @stage.addChild sq
      @stage.removeChild sqAnimation
      sqAnimation.stop()
  @stage.addChild sq

  # Containerを使用してオブジェクトをまとめて管理したりもできる
#  container = new createjs.Container()
#       player = new createjs.Bitmap somethingImage
#  container.addChild player
#       player2 = new createjs.Bitmap somethingImage2
#  container.addChild player2
#  @stage.addChild container

  @fps = new createjs.Text "0 fps", "bold 14px Arial", "#000"
  @fps.x = @fps.y = 10
  @stage.addChild @fps
 startGame: ->
  createjs.Ticker.userRAF = true
  createjs.Ticker.setFPS 60
  createjs.Ticker.addListener this
 tick: =>
  #
  # キー入力にあわせたキャラクタの動作やあたり判定などをここで行う
  #
  @fps.text = (Math.round createjs.Ticker.getMeasuredFPS())+" fps"

  @stage.update()
window.GamePlatform = GamePlatform
・4行目、画像からBitmapオブジェクトを生成する
・5行目、setTransformは移動、スケール、回転、傾き、中心点をまとめて指定できる便利メソッド。ここではスケールまでしか指定していない
・6行目、Zオーダーという概念はなく後からstageに追加されたものほど上にくる。Zオーダーの指定がしたい場合は自分で実装しよう
・9行目、テキスト生成はこのとおり
・12行目、alignの指定などもおこなえる
・16行目、スプライトシートの設定を行う。画像の指定は複数可能。そちらの詳細はSpriteSheet Classを参照してほしい
・21行目、アクションの中心点を設定する。意味が不明な場合はXY両方の値を0に変更して実行してみよう。宇宙船の回転のアニメーションの部分で意味が理解できるはずだ
・23行目、BitmapAnimationで使用するアニメーションの設定を行う。ここの設定方法は複数あるのでこちらもSpriteSheet Classを参照してほしい
・28行目、BitmapAnimationオブジェクトを生成する。16行目で行ったスプライトシートのアニメーション設定をこのBitmapAnimationオブジェクトを通して使用する
・31行目、スプライトシートから指定のフレームを抜き取ってBitmapオブジェクトを生成する
・34行目、クリックイベントをハンドルする。これもEaselJSの大きな功績のひとつだ
・37行目、指定のアニメーションを実行する
・40行目、TweenJSを使用してオブジェクトアニメーションを設定する。指定のオブジェクトのプロパティ値を指定の時間と動かし方で変更できる
・46行目、TweenJSのアニメーションの終わりにコールバックを設定する。そのコールバックで宇宙船のアニメーションをstageからはずしたり宇宙船のアニメーションを止めたりする
・77行目、画像をフリップさせる場合はscaleXまたはscaleYに-1を設定する
・87行目、Containerを活用するとオブジェクトのグルーピングも楽に行える
・98行目、Tickerの設定あれこれ。詳細はTicker Classを参照してほしい
・102行目、今回のサンプルではあたり判定やらキー操作でのプレイヤーキャラクターの動作などは実装しなかったけれどそういった実装はtick()で行うようになる
・106行目、FPS(Frame Per Second)を表示する


ざーっと説明したけれども大体EaselJSを使ってのゲーム開発がどういうものか理解できただろうか。前回にも述べたけれどTicker(に登録したオブジェクトのtick())とStageという概念が基礎にあるだけでその上で行うゲーム開発は通常のゲーム開発とさほど変わらない。というわけでこれまでの解説を通してEaselJS、TweenJS、PreloadJSの便利さとか開発のしやすさが伝わったら幸いだ。


次回からはAndEngineの解説を行っていく。

2013年3月15日金曜日

磯野ー!2Dゲーム開発しようぜー! HTML5編 その2

今回はHTML5でのゲーム開発を解説するシリーズの第二回である。前回は以下。

磯野ー!2Dゲーム開発しようぜー! HTML5編 その1

今回からコードを使って解説していく。内容はCoffeeScriptをもとに説明するけれど、javascriptsフォルダ内に対応するJavaScriptファイルがあるのでCoffeeScriptになじみがない方はそちらを参照してほしい。

index.html
<body>
<canvas id="c" width="480" height="320"></canvas>
</body>
なぜかCSSからのサイズ指定が行えないのでCanvasタグに直接widthとheightを指定している。


coffeescripts/contentManager.coffee
class ContentManager
 manifest:[
  {src:'images/Background02.png', id:'background'},
  {src:'images/BlueShip.png', id:'ship'},
  {src:'images/WalkingSquare.png', id:'square'}
 ]
 constructor: (@stage, width, height, @downloadCompleteCallback)->
  @preload = new createjs.PreloadJS false # useXHR=false ローカルからファイルを読み込むのでimageタグを強要する
            # xhrはCross Origin Resource Sharingを許可しない
  @preload.onError = @handleElementError
  @preload.onFileLoad = @handleElementLoad
  @downloadProgress = new createjs.Text "-- %", "bold 18px Arial", "#fff"
  @downloadProgress.x = (width / 2)
  @downloadProgress.y = (height / 2)
  @elementLoadedCount = 0
 startDownload: ->
  @preload.loadManifest @manifest
  @stage.addChild @downloadProgress
  createjs.Ticker.addListener this
  createjs.Ticker.setInterval 50
 handleElementError: (e)=>
  alert "画像読み込み失敗 : #{e.src}"
 handleElementLoad: (e)=>
  @[e.id] = e.result
  @elementLoadedCount += 1
  if @elementLoadedCount is @manifest.length
   @stage.removeChild @downloadProgress
   createjs.Ticker.removeListener this
   @downloadCompleteCallback()
 tick: =>
  @downloadProgress.text = Math.round((@elementLoadedCount/@manifest.length) * 100) + " %"
  @stage.update()
window.ContentManager = ContentManager
何はともあれ画像がないとはじまらないのでPreloadJSを使用して画像を読み込む。
・2行目、読み込む対象画像へのパスを指定する。ここで指定しているidが11行目のonFileLoadイベントの引数e.idとして渡ってくる
・8行目、PreloadJSのコンストラクタにuseXHR=falseを指定している。この引数はPreloadJSにXHRではなくimageタグでの画像取得を行わせるための設定。今回のサンプルはローカルファイルからの読み込みなのでXHRでの取得ができない
・10行目、画像取得時にエラーが発生した場合のコールバックを設定する
・11行目、各画像取得完了時のコールバックを設定する
・17行目、PreloadJSに画像の読み込みを指示する
・19行目、createjs.Tickerのイベントリスナーを登録する。ここで登録したオブジェクトのtickメソッドが定期的に呼び出される。このtickメソッドがいわゆるゲーム開発におけるメインループとなる
・24行目、取得の完了した画像のidをプロパティ名として画像内容を設定する。このidは2行目で設定していたものと同一
・28行目、すべての画像の取得が完了したのでTickerのイベントリスナーを忘れずにはずしておく
・32行目、stage.update()で画面のリフレッシュを行う。stageについては後述する

とざっくりとだがPreloadJSの機能説明をした。簡単に言うと画像の取得が楽、という一言に尽きる。ちなみにPreloadJSを使わずに画像取得をする場合は以下のようになる。
var image = new Image();
image.onload = function() {
 context.drawImage(image, 10, 10);
};
image.src = "http://hoge/test.jpg";
上記のコードを汎用的に使いやすい形にするとPreloadJSになるのが理解できるかと思う。


coffeescripts/index.coffee
$(document).ready ()->
 isCanvasSupported = ->
  elem = document.createElement('canvas')
  return !!(elem.getContext && elem.getContext('2d'))
 unless isCanvasSupported()
  return alert "あなたのブラウザはCanvasが使えないです"

 canvas = $('#c')[0]
 stage = new createjs.Stage canvas

 contentManager = new ContentManager stage, canvas.width, canvas.height, ->
  platform = new GamePlatform(stage, canvas.width, canvas.height, this)
  platform.startGame()
 contentManager.startDownload()
使用しているブラウザがCanvasをサポートしているかチェックしてから先ほどのContentManagerで画像の取得を行っている。全画像取得完了時のコールバックでGamePlatform(後述)をインスタンス化しゲーム本編へと移行する。
・9行目、Stageをインスタンス化している。BitmapオブジェクトやBitmapAnimationオブジェクトなどの描画したいオブジェクトをstage.addChild(Obj)で追加する。stage.update()で追加されたオブジェクトのリストをコンストラクタで指定されたCanvasへと描画する。

EaselJSではTickerとStageが開発の基礎となる。

長くなったので続きは次回

2013年3月14日木曜日

磯野ー!2Dゲーム開発しようぜー! HTML5編 その1

ちぬあたりMEGAAndroid版もリリースし、HTML5とAndroidの2Dゲーム開発が何となく分かったのでこれから数回に分けて解説していく。最初の数回はHTML5(というよりもeaseljs)で残りはAndroidの解説になる。AndroidはAndEngineの使い方がメインとなる。ちなみに中島も磯野も出てはこないのであしからず。

今回のシリーズで使用する画像は下記から拝借している。商用利用する場合は連絡が必要ということなのでその意向がある方はリンク先の指示に従っていただきたい。
XNA Sprites


ゲーム内容

いたってシンプルな2dゲームである。キャラクターをクリックすると右端に消えた後に戻ってくるという内容だ。ちなみにゲームの対象年齢は2~3歳児ぐらいとなっている。


サンプルコード
今回のHTML5のソースコードはhttps://github.com/yooontheearth/html5-game-sampleから取得できる。後述する設定を行うことによってindex.htmlから動作確認できるはずだ。javascriptsフォルダ内のJavaScriptファイルはすべてcoffeescriptsフォルダ内のCoffeeScriptファイルから生成されている。


設定
今回はサーバをたてずにローカルからindex.htmlを起動するのでChromeにいろいろと設定が必要になる(IEとFireFoxは使用していないので不明)。Chromeの初期設定ではローカルからファイルを読み込んだ場合にほかの読み込んだローカルファイルをいじくるとセキュリティエラーが発生するようになっている。なのでそれを回避するために下記のフラグを設定する必要がある。
--allow-file-access-from-files
※セキュリティ上たいへんよろしくないのでテスト中などの場合にのみ使用するように

上記のフラグとともにChromeを起動する方法は下記。これはUbuntuの場合。
$ chromium-browser --allow-file-access-from-files
ちなみに上記のコマンドでChromeを立ち上げる前にすでにChromeのProcessが起動していたりするとフラグの設定が有効にならないのでUbuntuを再起動することをおすすめする。そのほかのWindowsやOS X、Androidなんかの起動方法は下記を参照してほしい。
Run Chromium with flags

どうやってもうまくいかん、という人はApacheでもなんでもよいので適当にWebサーバを立ち上げてhttp://localhost/index.htmlとかしてもらっても今回のサンプルは動作するはずなのでそちらからアプローチしてもらってもかまわない。


ライブラリ
今回はHTML5編の第一回ということで今回のシリーズで使用するライブラリの紹介をする。
EaselJS
ゲームのメインループや画像オブジェクトクラス、スプライトシート・アニメーションクラス、テキストクラスなどなど便利な機能盛り沢山のライブラリでHTML5の2dゲーム開発の核となる。各クラスの詳細な情報はEaselJS Documentを参照してほしい。

TweenJS
オブジェクトのアニメーションや動作を直感的に記述できるライブラリ。メソッドチェイン形式で振る舞いを記述できるので大変便利。デモでどのようなビルトインの動きがあるか参照してほしい。

PreloadJS
画像などを読み込むのに使用する。

上記のライブラリ群にSoundJSというライブラリを追加するとCreateJSというライブラリスイートになる。が、今回はサウンド周りは実装しないのでCreateJSではなく個別に参照している。


次回は前述のサンプルコードを使って色々と解説していく。