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

2014年4月10日木曜日

html5のcanvasにレーダーチャートを描画する

レーダーチャートの話が仕事中に出て自前で作るかどこかのコンポーネントを購入するかという話になり結局購入することになったのだけれども、デモ用にちゃちゃっとレーダーチャートを実装したのがあるので公開しておく。

デモはこちら

実装周り
// Knockoutjs周りは省略

var canvas = document.getElementById("canvas")
 , c = canvas.getContext("2d");
function drawRader(){
 var points = viewModel.points()
    , eachRad = (Math.PI*2) / points.length
 , i
 , accumRad = Math.PI/2
 , radius = 150
 , center = 200
 , sin
 , cos
    , endOfAxisPt
 , firstPt
 , prevPt
 , currentPt;
 c.clearRect(0,0,400,400);
 for(i = 0; i < points.length; i ++){
  c.strokeStyle = "#ffa500";
  c.beginPath();
  sin = Math.sin(accumRad);
  cos = Math.cos(accumRad);
        endOfAxisPt = {
            x: center + (cos * radius),  
            y: center - (sin * radius)
        };
  accumRad += eachRad;
  c.moveTo(center, center);
  c.lineTo(endOfAxisPt.x, endOfAxisPt.y);
  c.stroke();
        
        c.fillStyle = "#00A0E9";
        c.fillText(points[i].text(),
                   endOfAxisPt.x - 10, 
                   endOfAxisPt.y - (sin * 20));
  
  c.strokeStyle = "#00A0E9";
  c.beginPath();
  currentPt = { 
    x: center + (cos * (radius * points[i].ratio())), 
    y: center - (sin * (radius * points[i].ratio())) 
   };
  if(prevPt){   
   c.moveTo(prevPt.x, prevPt.y);
   c.lineTo(currentPt.x, currentPt.y);
  }
  else
   firstPt = currentPt;
  prevPt = currentPt;  
  c.stroke();
 } 
  
 c.beginPath();
 c.moveTo(prevPt.x, prevPt.y);
 c.lineTo(firstPt.x, firstPt.y);
 c.stroke();
}
drawRader();
drawRader()の冒頭でviewModel.points()と取得しているのはKnockoutjs用のViewModelが内部的に保持しているObservableArrayだ(Knockoutjsを知らない人は配列のようなものと考えてもらって構わない)。描画の処理は単純で配列のアイテム数で360度を割ってその角度ごとに軸線を描画し、前後の軸線上の点と点を結んでいくだけ。

2014年1月4日土曜日

html5のcanvasに描画した曲線をヒットテストする

昨年はWPFを使ってGUIをグリグリ動かすアプリ開発にどっぷりはまっていたので今回は久しぶりにJavaScriptをいじりたくなり表題のものをガリガリ作った。

デモはこちら
githubはこちら(デモと差は皆無)

赤い四角が始点と終点だ。オレンジの四角が制御点になる。すべてdraggableなので任意に動かしてもらいたい。線上の点は曲線を直線に分割している点だ。曲線をクリックすると緑色になる。

曲線描画 on canvas
html5のcanvas上で曲線を描画するのは至極簡単だ。context.bezierCurveToまたはcontext.quadraticCurveToを呼び出せば良い。前者は制御点が2つのcubic bezierで後者は名称そのままの制御点1つのquadratic bezierだ。今回のデモではcubic bezierのほうを使用している。

曲線ヒットテスト on canvas
しかしあたり判定になると手段が提供されていないので自前でやる必要がある。以下任意のクリックした点が曲線上に位置しているかを計算する方法である。

1、曲線上の任意の点の接線の傾きを計算し曲線上の近傍点の接線の傾きと比較する
2、1の差が許容範囲内ならば2点は直線に近いと判断する
3、1の差が許容範囲外ならば2点間は曲がっているので2点間の中央で分割し再度1の判定を再帰的に行う
4、1~3までを繰り返し曲線を点で分割する
5、4で得られた点群とクリックされた点が直線上に位置するかを計算する
6、5で直線上に存在すれば曲線がクリックされたとする
7、5で直線上に存在しないならば曲線はクリックされていないとする

上記の計算に必要なものを解説していく。

曲線上の任意の点の計算方法
Cubic bezier curveの式を使うと簡単に任意の点を取得できる。Cubic bezier curveの式は以下。
b(t) = p0*(1-t)^3 + p1*3t(1-t)^2 + p2*3(1-t)t^2 + p3*t^3
p0は始点、p3が終点、p1、p2はそれぞれ制御点の1と2だ。これに時間であるtを0~1の間で指定すると曲線上の任意の点が取得できる。

曲線上の任意の点の接線の傾きの計算方法
これもCubic bezier curveの式の導関数を使えば簡単に計算できる。式は以下。
b'(t) = 3(1-t)^2(p1-p0) + 6(1-t)t(p2-p1) + 3t^2(p3-p2)
p0~p3とtの説明は前述したものと同じだ。

上2つの式はWikipediaを見てもらったほうが分かりやすいと思う。

任意の点が2点間の線上に存在するかの計算方法
任意の点Pが線AB上に存在するならば距離AB=距離AP+距離PBが成り立つ。

コード解説
ここから実際にいくつかコードを見ていこう。

まずは曲線上の任意の点を取得するコード。pointsは始点、制御点1、制御点2、終点の配列だ。
function b0(t) { return Math.pow(1 - t, 3); };
function b1(t) { return t * Math.pow(1 - t, 2) * 3; };
function b2(t) { return (1 - t) * Math.pow(t, 2) * 3; };
function b3(t) { return Math.pow(t, 3); };
function getPointOnBezier(points, t){
 var x = points[0].x * b0(t) + points[1].x * b1(t) + points[2].x * b2(t) + points[3].x * b3(t)
  , y = points[0].y * b0(t) + points[1].y * b1(t) + points[2].y * b2(t) + points[3].y * b3(t);
 return new Point(x, y);
};

ついで曲線上の任意の点の接線の傾きを取得するコード。ここもpointsは始点、制御点1、制御点2、終点の配列だ。
function bd0(t) { return 3 * Math.pow(1-t, 2); };
function bd1(t) { return 6 * (1-t) * t; };
function bd2(t) { return 3 * Math.pow(t, 2); };
function getSlopeOfTangentLine(points, t){
 var x = bd0(t) * (points[1].x-points[0].x) + bd1(t) * (points[2].x-points[1].x) + bd2(t) * (points[3].x-points[2].x)
  , y = bd0(t) * (points[1].y-points[0].y) + bd1(t) * (points[2].y-points[1].y) + bd2(t) * (points[3].y-points[2].y);
 return y/x;
};

曲線を直線に分割していくコード。mDiffやdDiffのしきい値をどこに設定するかで分割する大きさが変わってくるので上手いこと調整してもらいたい。
function calculateDividingPoints(){
 var points = []
  , bi = bezierInfo
  , i;
 for(i = 0.1; i <= 1.0; i += 0.1){
  divideCurveRecursively(bi, points, i-0.1, i); 
 }
 points.push(bi.points[bi.points.length-1]);
 bi.dividingPoints = points;
};
function divideCurveRecursively(bi, points, t1, t2){
 var prevD = getSlopeOfTangentLine(bi.points, t1)
  , currentD = getSlopeOfTangentLine(bi.points, t2)
  , dDiff = Math.abs(Math.abs(prevD)-Math.abs(currentD))
  , mDiff = t2-t1
  , middleT = t1 + mDiff / 2;
  
 if(mDiff > 0.05 && (sign(prevD) !== sign(currentD) || dDiff > 0.2)){
  divideCurveRecursively(bi, points, t1, middleT);
  divideCurveRecursively(bi, points, middleT, t2);
 }
 else
  points.push(getPointOnBezier(bi.points, t1));
};

任意の点が2点間の線上に存在するかをチェックするコード。これも許容値を変更することで当たり判定を厳しくしたりゆるくしたりできるので上手いこと調整してもらいたい。
function onStraightLine(pt){
 var bi = bezierInfo
  , i;
 for(i = 1; i < bi.dividingPoints.length; i ++){
  var p1 = bi.dividingPoints[i-1]
   , p2 = bi.dividingPoints[i]
   , trueDistance = calculateDistance(p1, p2)
   , testDistance1 = calculateDistance(p1, pt)
   , testDistance2 = calculateDistance(pt, p2);
  if(Math.abs(trueDistance - (testDistance1 + testDistance2)) < 0.2)
   return true;
 } 
 return false;
};

ざーっと解説してきたけれどCubic Bezierの公式さえ分かっていればさほど難しくないと思う。フレームワークから提供される曲線のあたり判定などは多量の曲線が存在する場合にボトルネックになったりもするので自前で計算できるよう公式を理解しておいても損はないだろう。処理実行の最適化などはまったく考慮していないので使用メモリだったり処理時間などを勘案して計算処理をキャッシュするなどは実際のコードベースでは行ったほうがよいと思われる。

2013年3月17日日曜日

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

前回まではHTML5での2dゲーム開発を解説したが今回からはAndroidでのゲーム開発を解説する。「次回はAndEngineを」と述べたけれど気が変わったのでAndroid編初回の今回は前回までに作ったHTML5ベースのゲームをWebViewでラッピングし、さもAndroidネイティブで作られたゲームかのように動作させる方法を解説する。前回までのシリーズは以下。

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


ゲーム概要

Androidローカル(assetsフォルダ)に配置したindex.html、画像、JavaScriptファイルなどをWebViewに読み込んでいる。ゲームの内容は前回までとまったく同じ。
※index.html等々はローカルから読み込んでいるけれど、jQuery、EaselJSなどのライブラリは前回までのコードそのままにCDN(Content Delivery Network)を利用しているのでインターネット経由で取得している。オフラインでも動作可能にするにはこれらの外部ライブラリもローカルに配置しそちらを参照するようにすればよい。


サンプルコード
今回のWebViewのサンプルコードはhttps://github.com/yooontheearth/html5-game-webview-sampleから取得できる。ではさっくりと見ていこう。


src/com.matsuosoftware.game.webview_sample/MainActivity
public class MainActivity extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);

        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
        setContentView(R.layout.main);

        WebView webview = (WebView)findViewById(R.id.webview);
        webview.getSettings().setJavaScriptEnabled(true);
        webview.loadUrl("file:///android_asset/index.html");
    }
}
いたってシンプルである。が、順に見ていこう。
・6、7行目、フルスクリーンで表示するためのフラグを設定する
・11行目、JavaScriptを有効にする
・12行目、assetsフォルダからファイルを読み込む。file:///android_assetはassetsフォルダへの特別なファイルパス

ここまででゲームはさもAndroidネイティブアプリかのように起動するのだけれども、見てくれをよくするためにもindex.htmlのbodyタグに以下のスタイル設定が必要となる。

<body style="margin: 0; padding: 0">

とまぁ、これでブラウザで動作させたときと同様のHTML5のゲームがAndroidでラッピングできたわけだけれども、WebViewにはこれだけではなくAndroidからJavaScriptを操作したり値を渡したりその逆もまた可能になっているのでJavaScript上の値をAndroid上で永続化したり復元したりもできるようになっている。詳しくは以下を参照してもらいたい。

・AndroidとJavaScriptとのやりとりは以下のリンクからaddJavascriptInterface()周りを参照してもらいたい。
Building Web Apps in WebView

・JavaScriptのエラーハンドルなどは以下のリンクからsetWebChromeClient、setWebViewClient周りを参照してもらいたい。
WebView


結論
HTML5のコードに手を加えずともWebViewでラッピングしてそのままAndroidアプリとしてリリースすることもできるし、Android用の特別な処理を実装したい場合はAndroidと双方向でやりとりできることも理解できたかと思う。

ただ、HTML5をそのまま使えるというわけで各プラットフォームごとに開発を行わなくてもよいかも!?と明るい展望を一瞬みせてくれたWebViewではあったけれど、その実、実行速度はひっじょうに遅い!!!通常だと50または60FPS平均のものが10FPS以下ほどへと速度が落ちてしまうので大体のゲームはゲームとして成り立たなくなると思われる。通常のアプリ類であればPhoneGapやTitaniumがプラットフォームフリーへの一応の答えになると思うけれど、ゲームはどうなんだろう。以前調べたときはあまりよさげなのはなかった。


というわけでAndroidの能力を搾り出すためにも次回からはAndEngineの使い方を解説していく。

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ではなく個別に参照している。


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

2012年1月5日木曜日

Html5でサイトを作る理由

Html5で新しい機能が大量に導入されたためHtml5を使う利点を考えるときには切り口によって色んな見方ができると思う。ブラウザベースのゲームを作っていた人はオーディオがネイティブでサポートされたのとCanvasによってぐりぐりとビジュアルをアニメーションさせることが可能になったので今までのようにプラグインを導入する必要がなくなったのが嬉しいだろうし、Web socketによってサーバとの通信がよりライトウェイトになったおかげで色々とアイディアを思いつく人もいるだろうし、Data StorageとかOffline時の制御やDrag & Dropも導入されたのでブラウザベースだからできないと言って限定されていたものがより普通のアプリのように動作するようになるだろうし、Html5と一口で言ってもこれだけ多種多様な広がる未来がある。

では通常のサイトを作る上でのHtml5を使う利点はなんだろうか。それはセマンティックウェブを意識した新しい要素達にある。以前もIntroducing HTML5を読んでの感想で軽く触れたけれども、Html5ではコンピュータから見て意味のある記述を可能とする新しい要素達がたくさん導入されている。それらを正しく使用することによってより検索エンジンフレンドリーになるし、それによって結果的に効果的なSEOとなるのは明らかだろう。というわけでなんらかのサイトを運営されている方は早めにHtml5で記述し始めたほうがお得というわけだ。

で、タグの紹介とか、タグの使用方法とかを調べるのにざっと見た中で下記のサイトでの解説が大変分かりやすかったのでお勧めだ。IE8以前のブラウザでHtml5のタグを正常に認識させる方法も解説してくれているので参考にしてもらいたい。
HTML5の簡易メモ