はじめに
今回は、任天堂の人気ゲーム機「Wii」で動作するFlashについての講座だ。Wii版Flashの特徴、開発、その応用について順を追って説明しよう。
現在Wiiの「インターネットチャンネル」で動作するAdobe Flash Playerは、パソコン用Flash Player 7相当の性能となっている。そういった環境を踏まえ、既存のPC用コンテンツをWii用に移植したいと考える方が多いのも事実である。しかし、移行の際にWiiのブラウザ制限を受ける事も多々あり、注意が必要だ。
そこで、講座を開始する前に、開発の際に注意すべき点を簡単に挙げておこう。
注意点
多くの画像を読み込む処理はメモリへの負担となるため避ける。
ポイントの多いシェイプは動作負荷となるため多用しない (可能な場合、最適化したビットマップ画像に変換)。
ステージサイズは横800ピクセル、縦600ピクセルとするとWiiの画面サイズに合う (縦100%、横100%としても良い)。
配置テキストの文字サイズは20ポイント以上が読みやすい。
上記を踏まえた上で、軽快なWiiコンテンツの開発に臨もう。
Wiiリモコンを活かしたコンテンツの制作
今回制作するのは、Wiiリモコン特有の傾きの操作を活かしたミニゲーム「球入れ」だ。 画面クリックでWiiリモコンの横回転の角度に球が移動するもので、時間制限の中、籠にいくつ球を入れられるかを競うゲームだが、籠が固定されていると面白味にかけるので、籠に球を入れると籠がランダムで違う場所に移動するようにしたい。
ゲーム処理の簡単な流れは以下のようになる。
- ゲーム開始(ゲームの初期設定)
- ゲーム処理(タイマーによる監視/壁、籠、球の衝突判定/得点計算)
- ゲーム終了(結果表示、1に戻る)
では、順を追って説明していこう。
STEP1. JavaScriptによる環境変数の取得
Wiiのブラウザの情報は、JavaScriptの環境変数から取得可能だ。これらを利用すれば、WiiとPCでコンテンツを分岐させる事が可能になる。以下、「navigator.appVersion」を元に分岐させた例になるが、こちらのコードは後ほど利用する。
JavaScript分岐サンプル
<script type="text/javascript">
if (navigator.appVersion.indexOf("Nintendo Wii") != -1) {
//Wii用のコンテンツ出力
} else {
//PC用のコンテンツ出力
}
</script>
STEP2. Flashコンテンツの制作
Flashコンテンツの開発を始める前に、コンテンツの開発に必要な要素の整理をしてみよう。大きく分けて、4つの要素がある。
開発に必要な要素
籠、壁、球となるオブジェクトの制作、物理計算
Wiiリモコンの情報の取得
JavaScriptとFlashの接続
メインFlashの出力
必要な要素が整理できたので、各々以下を利用する事にしたい。 必要なライブラリは以下に挙げる各サイトよりダウンロードしてもらいたい。
実際に利用するもの
- Flade(物理計算ライブラリ、ボールの動きや衝突判定に利用)
- 環境変数からWiiコントローラの情報を取得するJavaScript (Wii専用)
- Flash/JavaScriptインテグレーションキット
- SWFObject
Fladeの開発は現在停止しているが、APEというAS3のプロジェクトに継続されている。 詳細に関しては、こちらの公式サイトを確認してほしい。
Flash/JavaScriptインテグレーションキットを利用する理由は、Flash Player 8のExternalInterfaceと同等のJavaScript⇔ActionScript間の通信が可能なためだ。詳細に関しては、こちらの公式サイトを確認してほしい。
SWFObjectは、JavaScriptによるFlash出力においてもっとも普及しているため利用する。詳細に関しては、こちらの公式サイト を確認してほしい。
それでは、開発に入ろう。
基本的には、ソースを元に解説を進めていくので、こちらのファイルをダウンロードしてもらいたい。Wiiミニゲーム球入れソース一式のファイル構成は以下となる。全ファイル、Flash CS3にてFlash 8形式で保存してある。Flashコンパイルの際、上記にて説明したライブラリのインポートが必要になる。サンプルソースのimport文に沿った形で、クラスパスの設定をしてほしい。
Wiiミニゲーム球入れソース一式のうちWiiリモコン未対応サンプルファイルは 「WiiSample1.fla」と「WiiSample1.as」。球の操作はPCの矢印キーで行う。Wiiリモコン対応済サンプルファイルは「WiiSample.fla」、「WiiSample.as」、「WiiSample.swf」、「wiitest.html」。球の操作はPCでは矢印キー、WiiではWiiリモコンで行う。
STEP3. Fladeによる衝突判定の作成
衝突判定の作成の前に、Fladeとは何か簡単に説明したい。 処理の流れと関数は以下のようになる。
物理計算エンジンの初期化
_engine = new DynamicsEngine();
_engine.setDamping(減衰力);
_engine.setGravity(X軸重力, Y軸重力);
_engine.setSurfaceBounce(弾力);
_engine.setSurfaceFriction(摩擦力);
オブジェクトの登録
_engine.addPrimitive(新規Object);
_engine.addSurface(新規Object);
登録オブジェクトの描画
_engine.paintSurfaces();
物理計算エンジンの更新
_engine.timeStep();
_engine.paintPrimitives();
_engine.paintConstraints();
始めに、壁、籠、球となる基本的なオブジェクトを作成する。
左が壁と籠、右が球。これらは、Fladeの線、矩形、球を描画するメソッドの組み合わせで作成しよう |
利用する描画メソッド
線. new LineSurface(始点X座標, 始点Y座標, 終点X座標, 終点Y座標);
矩形. new RectangleTile(中心点X座標, 中心点Y座標, 横幅, 縦幅);
球. new Wheel(中心点X座標, 中心点Y座標, 球半径);
以下、壁、籠、球を生成する関数となる。各関数の詳しい内容は、「WiiSample1.as」の各メソッドを確認してもらいたい。
Fladeオブジェクトの生成
壁の生成. createWall();
籠の生成. createCup();
球の生成. createBall();
籠を生成する際、球の当たり判定となる座標も取得しておく。 これは、球が籠に入ったという判定座標に利用する。
衝突判定用変数
_hitPoint = {x:baseX, y:baseY};
なお、生成したオブジェクトを動作させるには、Fladeオブジェクトのプロパティに値を設定する必要がある。球を移動させるため、以下のプロパティの値を適宜変化させよう。
球オブジェクト移動に利用するプロパティ値
X座標. _ball.prev.x
Y座標. _ball.prev.y
横回転. _ball.rp.vs(正値で左回り、負値で右回り)
STEP4. ゲーム内容の作成
次に、ゲーム部分の説明をしよう。処理の流れと関数は以下のようになる。
処理の流れと関数
1.タイマー開始
startTimer();
2.タイマー動作(壁、籠、球の衝突判定、籠に入ったら初期化)
runEngine();
3.タイマー停止
stopTimer();
球と籠の衝突判定の際、先ほど取得済みの「_hitPoint」を利用する。 この座標の指定範囲内に入ったら、球を入れた数が加算され、籠の位置が初期化される。
指定時間後にタイマーが停止して、ゲーム結果画面が表示される。
今回の仕様の一つとして、Wiiリモコンの角度を移動量に変換する、というものがあるが、複雑な数式ではなく、簡単なルールを用いている。以下のような、Y軸方向への力を基準として、角度をX軸の力に用いる事により、理想的な力関係を実現している。
移動力量のルール
var vm:Number = 10; //力量の最大値
if (rotation > 90 || rotation < -90) vm = -10; //角度の-値補正
var vx:Number = rotation/10; //角度を10で丸め、X軸力量を取得
var vy:Number = vm-vx; //X軸力量を減算し、Y軸力量を取得
以上の処理をもって、ミニゲームの処理の完成だ。 各処理の詳しい内容、流れは、「WiiSample1.as」を確認してもらいたい。
STEP5. JavaScriptとFlashの連携の作成
最後に、JavaScriptとFlashの連携部分を説明しよう。 通信部分の全体像を簡単に図に表すと以下のようになる。
現状JavaScriptから取得可能なWiiリモコンの情報は、任天堂の公式サイトに記載されているので、そちらを確認してもらいたい。
今回は、定期的にFlashからJavaScriptにアクセスし、Wiiリモコンの情報を取得する。 処理の流れと関数は以下のようになる。
処理の流れと関数
1. FlashからJavaScriptの関数を呼び出す
_proxy.call("JavaScript関数名", 引数1...);
呼び出し関数の返り値を取得する場合、Flash内の関数を呼んで値を返す。
flashProxy.call("Flash関数名", 返す値1...);
2. JavaScriptからFlashの関数を呼び出す
flashProxy.call("Flash関数名", 引数1...);
呼び出し関数の返り値を取得する場合、JavaScript内の関数を呼んで値を返す。
proxy.call("JavaScript関数名", 返す値1...);
まずこちらから最新のライブラリ、Flash / JavaScript Integration Kit(Beta)をダウンロードしよう。
このままだと以下の問題があるので、キットに少し修正を加える。
Flash/JavaScriptインテグレーションキットの不具合
コンパイル時に「"com.macromedia.javascript.JavaScriptProxy" がロードされませんでした」というエラーが出る。 「JavaScriptProxy.as」と「JavaScriptSerializer.as」をFlashで一度開いてから、保存しなおす。
日本語が使えない 「JavaScriptFlashGateway.js」の以下部分を修正し、保存し直す。
修正前
case 'string':
qs += 't'+(i)+'=str&d'+(i)+'='+escape(args[i]);
修正後
case 'string':
qs += 't'+(i)+'=str&d'+(i)+'='+encodeURI(args[i]);
以上で不具合は改善された。
次に、FlashとHTMLの設定について説明したい。
Flash側の設定
source/flash/actionscriptのcomフォルダをFlashのクラスパスに追加、もしくはFlashファイルと同じディレクトリにコピー
comフォルダ内のJavaScriptProxyクラスのインポート、インスタンスの生成
import com.macromedia.javascript.JavaScriptProxy;
proxy = new JavaScriptProxy(root.lcId, _this);
3. JavaScriptが呼ぶFlash関数の追加
public function setWiimote(isEnabled, isDataValid, isBrowsing, dpdX, dpd Y, hold, dpdRollX, dpdRollY, dpdDistance, dpdValidity):Void {
var wiimote:Object = {isEnabled:isEnabled,
isDataValid:isDataValid,
isBrowsing:isBrowsing,
dpdX:dpdX,
dpdY:dpdY,
hold:hold,
dpdRollX:dpdRollX,
dpdRollY:dpdRollY,
dpdDistance:dpdDistance,
dpdValidity:dpdValidity};
_wiimote = wiimote;
}
4. JavaScriptを呼ぶFlash関数の追加
public function getWiimote() { _proxy.call("getWiimote"); }
JavaScriptを呼ぶ関数は、物理処理を開始する「startEngine();」に追加する。 ゲームの監視を行う「runEngine();」内への定義ではなく、startEngine内に「setInterval();」を用いて定義する理由は、キットを介した通信をenterFrame上で行うと、毎フレームの処理となりアクセス過多となってしまうためだ。
HTML側の設定
1. installationフォルダの「JavaScriptFlashGateway.js」、「JavaScriptFlashGateway.swf」をコピー
2. FlashProxyインスタンスの生成
<script type="text/javascript" src="JavaScriptFlashGateway.jsへのパス"></script>
<script language="javascript">
var lcId = new Date().getTime();
var flashProxy = new FlashProxy(lcId, "JavaScriptFlashGateway.swfへのパス");
</script>
3. Flashが呼ぶJavaScript関数の追加
<script type="text/javascript">
var wiimote;
function getWiimote() {
if (window.opera && window.opera.wiiremote) {
wiimote = window.opera.wiiremote.update(0);
flashProxy.call("setWiimote",
wiimote.isEnabled,
wiimote.isDataValid,
wiimote.isBrowsing,
wiimote.dpdX,
wiimote.dpdY,
wiimote.hold,
wiimote.dpdRollX,
wiimote.dpdRollY,
wiimote.dpdDistance,
wiimote.dpdValidity);
}
}
</script>
4. メインFlash出力タグの追加
<div id="content"></div>
<script type="text/javascript">
if (navigator.appVersion.indexOf("Nintendo Wii") != -1) {
//Wii用のコンテンツ出力
var so = new SWFObject("WiiSample.swfへのパス", lcId, "100%", "100%", "7 ", "#ffffff");
so.addVariable("lcId", lcId);
so.write("content");
} else {
//PC用のコンテンツ出力
document.write("Wiiのインターネットチャンネルでアクセスしてください");
}
</script>
JavaScriptを介してWiiリモコンの情報を取得する際、わかりやすさを兼ね、取得可能な環境変数を全て譲渡する形にしています。実際にコンテンツを作成する際は、必要なパラメータだけ譲渡すれば良いだろう。
メインFlash出力の際、Objectタグのidに「lcId」を設定する。これはキットを介した通信IDとなる。 こちらでPCとWiiのコンテンツ分岐させるJavaScriptを利用するが、PC用のコンテンツは無いため、Wiiでの閲覧を促す注意文言を出力する形としてある。
以上を反映させたのが「WiiSample.as」、「wiitest.html」だ。 これで一通りのファイルが用意できた。
では最初にダウンロードして頂いたWiiミニゲーム球入れソース一式に、修正したFlash/JavaScriptインテグレーションキット、SWFObjectに含まれるファイルを加え、一纏まりとして下記のファイル名でアップしよう。
アップロードファイル一式
「Flash/JavaScriptインテグレーションキット」、 「FlashProxy.js」、「FlashSerializer.js」、「FlashTag.js」、「JavaScriptFlashGateway.js」、「JavaScriptFlashGateway.swf」
「SWFObject」、「swfobject.js」
Wiiミニゲーム球入れソース一式「wiitest.html」、「WiiSample.swf」
Wiiのインターネットチャンネルからアップ先のサイトを確認すると、Wiiリモコンの傾きを利用した球入れゲームで遊ぶことができる。
さいごに
Wiiリモコンには、3軸加速度センサが内蔵されている。JavaScriptを介せば、ゲームと同じくリモコンを振ったり、傾けたりといった動きを検知してコンテンツの操作に利用可能だ。各家庭への普及率が高まっているWiiで、ゲームなどインターネット上でのコンテンツの充実が望まれているのも事実である。これを機に、Wii向けのコンテンツ制作を始めてみるのは如何だろう?