9leapの埋め込みプレイヤーで、キー操作できるようにする

9leapの各ゲームの詳細ページにはゲームを埋め込むためのコードが発行されていて
ブログなどに貼付けて、気軽に遊んでもらえるようになるのですが
Safariでは、そのまま貼り付けるとキーボード操作ができません。
[はてなダイアリー + Mac Safari 5.x で確認 2011/5/23]

9leapの埋め込みプレイヤーはiframeを使っているようなのですが
どうもフレームにフォーカスが来てないことが原因っぽいです。
なのでゲーム開始時にwindow.focus()でフォーカスを持ってくれば解決します。

ライブラリ側でいずれ修正されるかもしれませんが
ひとまずアプリ側で対策するなら、次の1行を加えます。

window.focus(); //フォーカスをもってくる
enchant(); //enchant.jsの初期化

これでキーボード操作のあるゲームも遊んでもらえますね!

ついでに、はてなダイアリーに貼付ける方法も紹介します。

はてなダイアリーに9leapのゲームを埋め込む

はてなダイアリーは一部のHTMLをのぞいて、そのまま埋め込む事ができません。

そこで、Googleガジェットを使います。
Googleガジェットの定義用XMLに、9leapの埋め込みコードを仕込んでしますのです。

このXMLは、どこかURLのある場所に公開する必要があるので
レンタルサーバや、Dropboxなどの公開できるオンラインストレージを持っているのなら
次のエントリーが参考になります。

はてなダイアリーにいいねボタンを置く方法

自由に公開できるサーバがない場合は
Googleの用意しているガジェットエディタを使う方法もあります。
ガジェットの保存と公開にはGoogleのアカウントが必要です。

Google Gadget Editor

http://www.google.com/ig/ifr?url=gge.xml&nocache=1&synd=open&output=html

Googleアカウントでログインしたら、Editorタブの編集エリアに下記を貼付けて
必要箇所(ガジェット名、作者名、埋め込みコード)を編集してください。

<?xml version="1.0" encoding="UTF-8" ?>
<Module>
<ModulePrefs title="ガジェット名" author="作者名" width="320" height="365" />
<Content type="html"><![CDATA[

9leap埋め込みコード

]]></Content>
</Module>

編集できたら、File > Save で保存します。

はじめて保存する場合は、プライバシーポリシーの確認がでます。
内容を確認して問題なければ保存します。
保存が完了したら、貼付け用コードを取得します。

File > Publish... > Add to a webpage

途中で警告(Description attribute is missing or undefined など)がでるかもしれませんが、
iGoogleのガジェットディレクトリに登録する予定がないのであれば無視して大丈夫です。

確認画面に移ったら、ページ下部にある「コードを取得」をクリックして
出力されたコードをはてなダイアリーの編集エリアにペーストします。

はてなダイアリーのプレビュー画面では、たぶん表示されませんが
記事を公開したらちゃんと動作している思います。

Processing.js製 弾幕シューティングを、enchant.jsに移植してみた

wise9で連載されていた弾幕シューティング作成講座がかなり面白かったですね。
第四回目の記事で、ついに弾幕が出た時は興奮ものでした!

ちょうど、enchant.jsの習作としてなにか作りたいなーと考えていたので
これの移植に挑戦してみたいと思います。

元記事一覧
http://wise9.jp/category/連載-processing-js-で初めてのゲームプログラミング

障害になるような違いはありません

Processing.jsや、ゲームのロジックは元記事を参照していただくとして
移植するには、文法的な違いを理解する必要がありそうですが
Processing.jsは、そもそもJSライブラリなので大きな違いはありません。

JSにはあまりなじみのない、型宣言とクラス定義さえおさえてしまえば簡単です。

Processing.jsのクラス定義の例
class Example {
  int x;
  Example(int dx) {
    x = dx;
  }
  void method(int dy) {
    x = x + dy;
  }
}

それぞれの意味はこんな感じ

class クラス名 {
  型 プロパティ;
  コンストラクタ(型 引数) {
    //初期化時によばれる関数
  }
  型 メソッド() {
    //戻り値がないならば、型はvoid
  }
}

つまり例示の変数 x はint(整数)型であることを宣言し
method()は戻り値をもたない関数ということになります。

これをenchant.jsで書くならば
var Example = Class.create({
	initialize: function(dx) {
		this.x = dx;
	},
	method: function(dy) {
		this.x = this.x + dy;
	}
});

Class.createにクラスの定義内容をオブジェクトで渡します。
initialize()は、継承または生成時に自動的に呼び出されるので
これをコンストラクタとして使います。
それから、型宣言はないので消してしまいます。

実際に書き直す

試しに次のソースコードを移植してみました。
サンプルプログラム03-2

enchant.jsに移植

//enchant.jsを初期化
enchant();
var mousePressed, mouseX, mouseY;
var game, tama, stage, canvas;

//setup()にあたる処理
window.onload = function() {
	
	game = new Game(320, 320);
	game.fps = 30;
	noCursor();
	tama = new Tama(160, 0, 10);
	
	//描画用canvasを追加
	stage = new Sprite(320, 320);
	stage.image = new Surface(320, 320);
	game.rootScene.addChild(stage);
	game.addEventListener(enchant.Event.ENTER_FRAME, draw);
	canvas = stage.image;
	
	//開始
	game.start();
};

function ship(x, y) {
	stroke(255, 255, 255);
	triangle(x, y - 7, x - 10, y + 7, x + 10, y + 7);
	if (mousePressed) {
		line(x, y- 7 , x, 0);
	}
};

var Tama = Class.create({
	initialize: function(x, y, r) {
		this.tx = x;
		this.ty = y;
		this.tr = r;
	},
	update: function() {
		this.ty += 10;
		stroke(255, 0, 0);
		ellipse(this.tx, this.ty, this.tr, this.tr);
		if (this.ty > game.height) {
			this.ty = 0;
			this.tx = Math.random() * game.width;
		}
	}
});

function draw() {
	clear();
	ship(mouseX, mouseY);
	tama.update();
};

//------------------------------------------------------------------------------
// Processing.jsのメソッドを簡易的に再現
// @see http://processingjs.org/
//------------------------------------------------------------------------------
/**
 * Base64形式の透明GIFを表示させて、デフォルトカーソルを消す
 */
function noCursor() {
	game.rootScene._element.style.cursor =
	 "url('data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw=='), auto";
};

/**
 * クリア
 */
function clear() {
	canvas.context.fillStyle = "rgb(0, 0, 0)";
	canvas.context.fillRect(0, 0, 320, 320);
};

/**
 * 線の色
 */
function stroke(r, g, b) {
	canvas.context.strokeStyle = "rgb("+ r +", "+ g +", "+ b +")";
};

/**
 * 三角形を描く
 */
function triangle(x1, y1, x2, y2, x3, y3) {
	canvas.context.beginPath();
	canvas.context.moveTo(x1, y1);
	canvas.context.lineTo(x2, y2);
	canvas.context.lineTo(x3, y3);
	canvas.context.closePath();
	canvas.context.stroke();
};

/**
 * 線を描く
 */
function line(x1, y1, x2, y2) {
	canvas.context.beginPath();
	canvas.context.moveTo(x1, y1);
	canvas.context.lineTo(x2, y2);
	canvas.context.closePath();
	canvas.context.stroke();
};

/**
 * 円を描く
 */
function ellipse(x, y, r) {
	canvas.context.beginPath();
	canvas.context.arc(x, y, r, 0, 2 * Math.PI, false);
	canvas.context.closePath();
	canvas.context.stroke();
};

/**
 * マウス座標
 */
document.addEventListener("mousemove", function(e) {
	mouseX = e.pageX;
	mouseY = e.pageY;
}, false);

/**
 * マウスダウン
 */
document.addEventListener("mousedown", function(e) {
	mousePressed = true;
}, false);

/**
 * マウスアップ
 */
document.addEventListener("mouseup", function(e) {
	mousePressed = false;
}, false);

コードの流れと関数名や変数をそのままになるように置き換えました。
前半部分のコードは、見た目的にサンプルと大きな違いはないと思いますが
構造的には、図形を描画するためのcanvas要素を生成して追加しています。

Processing.jsには、canvasを直感的に操作できる
triangleやellipseといった描画メソッドがあります。

後半部分は、このProcessing.jsの描画メソッドを必要な分だけ簡易的に追加してます。
これをenchant.jsとともに読み込ませると、サンプルと同じように動いてると思います。

最終的にできあがったのがこれ


safari/chrome
5/22追記 埋め込みプレイヤーだと safariでキーイベントが拾えないようです。。。 chromeは問題なし
5/24 アプリ側で対処するエントリ書きました→ http://d.hatena.ne.jp/nenjiru/20110523/1306164602

enchant.jsらしさということで、キャラクターはenchant.Spriteで表現し、
マウス操作からカーソルキー入力(バーチャルパッド)に変更してみました。

バランスを調整してるうちに、完全移植とは言い難くなりましたが
ロジック部分は無理なく移植できました。

まとめ

パソコンのキーボードで操作するぶんには問題ないですが
iPhoneのバーチャルパッドでの機体操作がちょっと厳しくなってしまいました。
これでは弾幕シューティングの売りである、よける快感がいまいちです。

元記事のタッチ操作なら、このへんのストレスがなく遊べますね。
ゲームなのでUIの選択も超重要ですね。

それから、やはりバランス調整が大変(大切)ですね。

enchant.jsが、表示やイベント管理をうまくやってくれるので
制作者がバランス調整に集中できる、すばらしいライブラリだと思います。

MacでClosure Compilerを簡単にするAntの導入

GoogleのClosure CompilerはJavaScriptの圧縮ツールですが
コメントや改行の除去以外にも、複数のJSファイルを結合することもできます。

開発時は機能ごとにファイルを分けて管理して
リリース時には1ファイルに結合、という感じに使ってます。

ただ、ターミナルからいちいちコマンドを打つのが面倒だったのですが
Antというビルドツールを導入すると、コマンド一発で圧縮と結合を行えます。

Macには、JavaとAntがすでにインストールされてるので
Ant用の設定ファイルをつくってしまえば即利用できます。
サンプルも用意したのでぜひ試してみてください。

Closure Compilerのインストール

Closure Compilerをまだ持っていなければ
下記URLからダウンロードして、解凍後に任意の場所へ移してください。

http://closure-compiler.googlecode.com/files/compiler-latest.zip

使用にはJava 1.6が必要です。
優先するバージョンを変更するには
アプリケーション>ユーティリティ>Java Preferences.appから行います。


Java SE 6を一番上にします。
リスト内になければ、ソフトウェアアップデートをかけて最新にしてください。

コマンドラインからバージョンを確認するには
アプリケーション>ユーティリティ>ターミナル.appを起動して次を入力します。

java -version

いちおうAntもチェック。

ant -version

エラーがでなければ、準備が整いました。

コンパイルサンプル

http://dl.dropbox.com/u/498311/closure-compiler-sample.zip

index-dev.htmlをブラウザで開くと、カーソルキーでキャラクターを動かせるサンプルがでます。
JSはこんな感じで、5ファイルに分けてます。

<script src="./src/ui/Keyboard.js"></script> 
<script src="./src/display/Element.js"></script> 
<script src="./src/display/Sprite.js"></script> 
<script src="./src/display/Player.js"></script> 
<script src="./src/init.js"></script> 

いっぽうのindex.htmlは、5ファイルを結合した "./bin/app.js" を読み込ませようとしてますが
まだ作成していないためエラーになります。

ちなみに、この5ファイルをClosure Compilerで
結合・圧縮するならこんなコマンドになります。

java -jar compiler.jar --js ./src/ui/Keyboard.js --js ./src/display/Element.js --js ./src/display/Sprite.js --js ./src/display/Player.js --js ./src/init.js --js_output_file ./bin/app.js
ファイル数によってはさすがに面倒です。
これを設定用のXMLに記述して、Antにやってもらおうというわけです。

Antを使ったコンパイル(圧縮)の手順

フォルダ内の build.xmlテキストエディタで開きます。
AntはこのXMLファイルの設定に従ってビルドを行います。

圧縮対象のJSはすでに記述してあるので、Closure Compilerの場所を追記します。

<taskdef name="jscomp" classname="com.google.javascript.jscomp.ant.CompileTask" classpath="コンパイラまでのパス"/>

要素の classpath属性を適宜修正してください。
サンプルでは、/Developer/SDKs/compiler-latest/compiler.jar にあると仮定してます。

XMLの修正が完了したら、ターミナルでサンプルファイルまで移動します。
移動にはcdコマンドで "移動先のパス" を入力します。

サンプルファイルをダウンロードフォルダで解凍したのならば、こんな感じです。

cd Downloads/closure-compiler-sample

無事に移動できたら、ant と入力して実行します。

処理が進んで BUILD SUCCESSFUL と表示されたら成功です。
サンプルファイル内に bin/app.js が出力されているでしょうか?
これでindex.htmlのJSも正常に動くようになってると思います。

まとめ

build.xmlのファイル名を変えた場合は、ant -f ファイル名.xml とします。

コンパイル対象のJSが増えたりしたら、build.xmlを修正します。
指定はファイル毎に追記し、ディレクトリ単位での指定はできません。

また結合順もこれに従うので注意が必要です。
(HTMLのscript要素の並びと同等と考えれば大丈夫です)

オプションとして、コンパイルレベルの指定や型チェックなどもありますが
Antでの設定項目はいまのところ限られてるようです。

ですので、この使い方は開発支援というよりは
リリースファイルの作成用に的を絞った使い方です。

Mac OSXにAntを手動でインストール

MacにはAntが標準で入ってると知らず
手動でセットアップした時の手順をメモってたので、エントリー。

Ant最新版
http://ant.apache.org/bindownload.cgi

"Current Release of Ant" から zip archiveをDL
解凍したファイルを任意の場所に移動。
ターミナルを起動して、Antのパスを設定します。

vi .profile

.profile はファインダーからは見えない不可視ファイルですが
これに環境変数として登録。

ターミナルは、ファイルやディレクトリ名をTabキーで補完してくれるので
.pからはじまるファイルが他になければ "vi .p"+Tabキーでいけます。

ファイルを開いたら、iキー押下で、入力モードにします。
入力モードの終了はescです。

例えば、/Developer/SDKs/apache-ant-1.8.2/ に格納したのであれば

export ANT_HOME="/Developer/SDKs/apache-ant-1.8.2"
export PATH="$PATH:$ANT_HOME/bin"

終わったら、インサートモードをぬけて保存して終了します。

:wq

念のため、ant -version でバージョンが表示されれば成功です。