Photoshop CC 以降の拡張パネルは html で作成するため、拡張パネルの制御も JavaScript で行います。拡張パネルと jsx(or jsfl) の関係は、例えば Web サイトの、クライアントとサーバの関係と同じようなイメージとなります。2つのプラットフォームをまたがって処理が実行されます。
ミニゲームは、試しに作ってみたゲームに最低限のグラフィクスや演出を加えた内容となっています。Google Play Game Services により ゲーム結果ランキング登録が可能なため、多少遊べるものにはなっているかと思います。
脱出系ゲームはストーリー仕立てで そこそこ凝った内容となっています。専用の BGM もいくつか作成しており、後にミュージックボックス的にどこかページを設けたいところです。
現在までのちょんまげゲームでの Google アカウントログイン ユニークユーザ数は、だいたい 1000人ほどです。
初めての脱出ゲーム制作後、何万人とアクセスされたものの、Google Play Game Services にログインしてまでプレイしてくれる人はほとんど無い状況でした。ログインする事によりゲームヒントがもらえるようにしてみたところ、少しずつログインしてくれる人が増えた形となります。
Google アカウントは多くの人が所持しているであろう事から、アカウントをゼロから作成してもらう手間は省けますが、それでもログインしてもらうには多くの工夫が必要となりそうです。
package sample;
import flash.display.MovieClip;
import flash.text.TextField;
import openfl.Assets;
abstract CircleView(MovieClip){
public function new()
this = Assets.getMovieClip('assets:sample.CircleView');
@:to public function getInstance():MovieClip
return this;
}
package game;
import flash.display.MovieClip;
import openfl.Assets;
abstract View(MovieClip){
public function new()
this = Assets.getMovieClip('test:game.View');
@:to public function getInstance():MovieClip
return this;
public var circleMC(get, never):View_circleMC;
function get_circleMC(){
return new View_circleMC(cast this.getChildByName('circleMC'));
}
}
abstract View_circleMC(MovieClip){
public function new(mc:MovieClip)
this = mc;
@:to public function getInstance():MovieClip
return this;
public var memoText(get, never):flash.text.TextField;
function get_memoText(){
return cast(this.getChildByName('memoText'), flash.text.TextField);
}
public var cardSetMC(get, never):View_circleMC_cardSetMC;
function get_cardSetMC(){
return new View_circleMC_cardSetMC(cast this.getChildByName('cardSetMC'));
}
}
abstract View_circleMC_cardSetMC(MovieClip){
public function new(mc:MovieClip)
this = mc;
@:to public function getInstance():MovieClip
return this;
public var cardA(get, never):flash.display.MovieClip;
function get_cardA(){
return cast(this.getChildByName('cardA'), flash.display.MovieClip);
}
public var cardB(get, never):flash.display.MovieClip;
function get_cardB(){
return cast(this.getChildByName('cardB'), flash.display.MovieClip);
}
}
試作品ができたので中途報告を。
Toolkit for CreateJS から出力される js, html ファイルの内容を解析し、Haxe クラスに変換するアプリを Adobe AIR にて作成しています。
例えば Toolkit for CreateJS から出力された js ファイル内に以下のクラスがあったとします。
(lib.view = function() {
this.initialize();
// scene
this.instance = new lib.shootingsceneGameOverView();
// guide
this.instance_1 = new lib.shootingeffectExplosionView();
this.instance_1.setTransform(67,106);
this.playerPosition = new lib.shootingplayerView();
this.playerPosition.setTransform(52,195);
// game area
this.gameAreaView = new lib.shootingareaGameAreaView();
this.gameAreaView.setTransform(0,20);
// click area
this.instance_2 = new lib.shootingareaClickAreaView();
this.instance_2.setTransform(275,200,1,1,0,0,0,275,200);
this.addChild(this.instance_2,this.gameAreaView,this.playerPosition,this.instance_1,this.instance);
}).prototype = p = new cjs.Container();
p.nominalBounds = new cjs.Rectangle(0,0,550,400);
作成中のアプリケーションで変換を行うと、以下の様な Haxe 用クラスに変換されます。
class View extends Container {
public var instance:ShootingsceneGameOverView;
public var instance_1:ShootingeffectExplosionView;
public var playerPosition:ShootingplayerView;
public var gameAreaView:ShootingareaGameAreaView;
public var instance_2:ShootingareaClickAreaView;
public var nominalBounds:Rectangle;
public function new(){
super();
nominalBounds = new Rectangle(0,0,550,400);
js.Lib.eval('this.instance = new lib.ShootingsceneGameOverView();');
js.Lib.eval('this.instance_1 = new lib.ShootingeffectExplosionView();');
js.Lib.eval('this.instance_1.setTransform(67,106);');
js.Lib.eval('this.playerPosition = new lib.ShootingplayerView();');
js.Lib.eval('this.playerPosition.setTransform(52,195);');
js.Lib.eval('this.gameAreaView = new lib.ShootingareaGameAreaView();');
js.Lib.eval('this.gameAreaView.setTransform(0,20);');
js.Lib.eval('this.instance_2 = new lib.ShootingareaClickAreaView();');
js.Lib.eval('this.instance_2.setTransform(275,200,1,1,0,0,0,275,200);');
js.Lib.eval('this.addChild(this.instance_2,this.gameAreaView,this.playerPosition,this.instance_1,this.instance);');
}
}
Toolkit for CreateJS パブリッシュデータの html ファイル内にある、素材ファイル読み込み用パス manifest もクラス化されます。
また、上記サンプルコードでは確認できませんが、プロパティ名に連番が付与されてしまう問題への対処も行なっています。
変換仕様
あまり見た目が良くない箇所の理由です。
クラス名の先頭は大文字に
Haxe の言語仕様よりクラス名の先頭は大文字にする必要があります。
Flash 内で「shooting.scene.GameOverView」とリンケージ設定後、Toolkit for CreateJS にて出力を行うと「shootingsceneGameOverView」というピリオドが取れたクラス名に変換されます。そこから更に当アプリケーションで「ShootingsceneGameOverView」という先頭大文字変換を行うため、とてもカオスなクラス名になってしまっています。
理想は、アプリケーションで変換する際 「shooting.scene.GameOverView」と Flash で設定したパッケージ構造のクラス名に復元できればよいのですが、Toolkit for CreateJS 1.1 の出力情報のみでは難しい所です。
見た目の動作的にはほとんど変化はありません。サウンド周りは Web Audio API が利用されるようになっているはずなので、iOS6 でも音が聞こえるようになっているのではないかと思います。鳴らなかったらごめんなさい。
Web Audio API に対応している PC版 Google Chrome で検証してみたところ、BGM のループは音が途切れることはなくなったような感じはあります。しかし音のにじみ方がややひどくなってしまいました。
今回の修正に沿った Toolkit for CreateJS 用 Haxe ライブラリは後日 github にて公開予定です。現在の Toolkit for CreateJS にある問題点をなるべく緩和するためのライブラリとなります。Haxe を変換して js ファイル用ライブラリとしても公開できたらと思います。
SCORE 欄 に最大 5桁の数値を入力し登録ボタンを押すと処理が開始します。使用しているブラウザで Google アカウントにログイン中の場合、GAE サーバ上に入力した数値が記録され、ログインしていない場合 ログインを促す画面が表示されます。
数値を登録した Google アカウントには アプリケーション上で ユニークID が割り振られ、http://dango-itimi.appspot.com/crypto_test/home/ユニークID/ という URL で、記録された数値を誰からも閲覧することができるようになります。
Google アカウント情報から取得可能な情報(ユーザID)はハッシュ化(暗号化)して利用しており、どの Google アカウントがこのサンプルアプリケーションを利用したのか等の情報は 管理人の私でもわからないようにしています。数値を登録するだけの大した内容ではありませんが、お気軽にご利用ください。
GAE と Google アカウント
GAE には Google アカウントと紐付けたアプリケーションの作成を比較的簡単に行うことができる仕組みがあります。何かユーザサービスを作成したい場合、GAE と Google アカウントを利用する事で、アプリケーション作成者はユーザのアカウント管理システムを作成する必要はなくなります。私のようなサーバ側の知識はほとんどない Flash 開発者にとっては、この仕組は非常に大きいです。アカウント管理は Google にまかせ、コンテンツ制作に力をそそぐことができます。
現在 Google アカウントを取得するには電話番号確認が必須となっています。(IP によっては電話番号は必須にならないケースもあるとの情報も見かけます)
Web サービスに Google アカウントを利用するメリットとして、ユーザの唯一性が保ちやすいという点が挙げられます。例えば何かの投票サービスを作成する場合、一人が多数のアカウントを利用してたくさんの投票を行う、という事態を避ける事ができます。
デメリットとしては、電話番号が必須のため アカウント作成にやや手間がかかるという点が挙げられます。サービスにログインしようとしたら、Google アカウントが必須な事がわかり、アカウントを取得するには電話番号が必須、となると「これはめんどうだ」という事で、ユーザを逃してしまう可能性がでてきます。簡単なゲーム等では、ログインはしなくても遊ぶことは可能で、スコア登録を行う場合のみログインが必要である、といった工夫が必要となりそうです。
PC 向け Flash(swf) が Flash Player 7 である理由は、Flash Player 7 が Flash Lite 1.1 用スクリプトを判別可能な最大のバージョンであるからです。Flash Player 8 からは Flash Lite 1.1 のスクリプトはパブリッシュできません。
動作検証の手間
Google App Engine SDK でのローカル(Windows上)環境上では動作したものが、サーバにアップロードすると動作しない、といった箇所がいくつかありました(後述)。バグを完全に取り除いてから本サーバにアップロード、という手順は無理かもしれません。
また、Google App Engine Launcher からの「Deploy」コマンドによるファイルアップロードは 毎回 ID と パスワード入力を行わなくてはならないため、本サーバ上での動作確認はやや手間がかかります。
Windows 上では、プロジェクトルートからの相対パスで静的ファイルが取得できるのに対し、本サーバ上では相対パスでの urlopen による静的ファイルの取得は不可。「http://~」というアドレス経由で Web 上から取得できる形にしておけば本サーバで取得可能。しかし、ローカル環境上では「http://localhost~」というアドレス経由では urlopen が機能せず?ファイル取得できず。
---
3D 表示において色々ネット上で調査をしておりましたら、今月に「Flash が 3D 対応する」といった旨の発表が「Adobe Max 2010」とやらで行われるようですね。これは Flash Player で Zバッファ を用いることができるようになるのですかなあ。なんとも期待したいところです。
private var main:Function;
private var pngEncoder:PNGEncoder;
...
public function Sample() {
...
pngEncoder = new PNGEncoder(
new TypeBitmapData32(bitmapData), //32bit PNG エンコード指定
bitmapData.width, bitmapData.height,
5000 //1フレーム内に実行するループ数を任意に設定
);
main = encode;
addEventListener(Event.ENTER_FRAME, run);
}
private function run(event:Event):void{
main();
}
private function encode():void{
var pngBytes:ByteArray = pngEncoder.run();
trace(pngEncoder.getProgress());
if(pngBytes) main = stop;
}
private function stop():void {}
mx.graphics.codec.PNGEncoder では、処理行数が多くなる for 文内で if 文があり、これはなくしたほうがよいのではと考え、コンストラクタの引数には あらかじめ一定の処理を行うためのインスタンスを渡すようにしました。しかし逆にこれでは処理が遅くなってしまうという場合はごめんなさい。
この index.xml ファイルはデータ量が多くなるので直接 Flash からは読み込みません。コンテンツごとの複数の xml ファイルに分割し、各コンテンツ表示時に読み込むようにします。
ファイル分割を行なうには AIR を用います。index.xml を AIR で作成したアプリケーションで読み込み、index.xml の内容を解析し、定めたフォーマットに整形した後、コンテンツごとの xml ファイルを出力させます。
Flash Player 10 から FileReference クラスによる ファイル入出力機能がサポートされたとのことで、簡易的な xml ファイル操作と xml 入出力アプリケーション製作をしてみようかと調査してみました。しかし FileReference クラスでは一括で複数のファイル出力を行なうといった事は無理なのですね。一度のユーザのボタン押下等のタイミングに対し、ひとつのファイル操作処理が可能、という仕様でした。
Flash でファイル入出力ができるようになったので、個人的な AIR の用途はますますなくなった、と思っていましたが見当違いでした。AS3 を用いて複数のファイル操作を行なうアプリケーションを作成するには AIR で、ということで。
Adobe Device Central CS3のエミュレータからメモリについて調べてみたところ、現状の au の FlashLite のヒープメモリ量では トレジャーボインゴを動作させることは困難かもしれません。後もう少しで動作する…! というところでメモリが足りなくなってしまいます。vodafone は au よりもヒープメモリが高く設定されている(500KB程多い)ようで、動作するみたいです。
ローグライクマップ自動生成処理を AIR か何かで作成し、マップ情報をあらかじめたくさんの静的ファイルに書き出しておき、ゲーム実行時にそのファイルをランダムで読みに行く… といった対策が考えられますが、ローグライクマップ自動生成処理をAS3で作り直す気力は現在なし。
「処理フレーム分割」等、携帯用の対策を行っているだけで時間がかかり 先になかなか進めることができないため、しばらくは携帯で動作させる事はあきらめようと思います。当面は PC と Wii 用向けということで、今後 携帯端末の性能がもう少し上がってくれることを願います。
private var sID:Number;
//1000ミリ秒(一秒)後にメソッドfuncを実行
public function main():Void{
this.sID = setInterval(
function(sc){ clearInterval(sc.sID); sc.func(); }, 1000, this );
}
private function func():Void{
trace( "実行" );
}