WindowsとAndroidでゲーム作りたいぞ! ついでにWebブラウザでも体験できるようにしたい。
プログラミング言語は何を選ぶ?
以前、少し使ったことのあるActionScript3.0、つまりFlashにするぜ。
AdobeAIRというのを使えば、Windows向けのexe実行ファイルと、Android向けのインストールapkファイルを作れるらしい。もちろんFlashだからWebブラウザでもswfファイルを実行できる。
Flash作るソフトは持っているのか?
FlashDevelop 4.0.4 と Flex SDK 4.6の無料コンビを使うぜ。Flash Professional CS6も購入したが使い方は後で調べよう。
Flashで私が作りたいのはインタラクション interaction のある、つまり操作できるアプリだ。操作するには、ブラウザとWindowsアプリなら、マウスとキーボードを感知しなければ。というわけで、マウス操作を認識するアプリを作ってみる。
アドビのWebサイト http://livedocs.adobe.com/flash/9.0_jp/ActionScriptLangRefV3/flash/events/MouseEvent.html の最下部にあるサンプルを少し変えて、以下のようにしたぞ。
実際に動作するFlashはコレだ。
https://sites.google.com/site/itouhiro/2012/20121104mouseEvent.swf
動作は‥‥以下がある。
- マウスカーソルを動かして、オブジェクト上に乗せる MOUSE_OVER, ROLL_OVER
- マウスカーソルをオブジェクト上に乗せた後で、ホイールを動かす MOUSE_WHEEL
- マウスカーソルを動かして、オブジェクトの外に出す MOUSE_OUT, ROLL_OUT
- マウスカーソルをオブジェクト上に乗せた後で、左クリック(押したままに)する MOUSE_DOWN
- マウスカーソルをオブジェクト上で押したまま、ドラッグする MOUSE_MOVE
- マウスカーソルをオブジェクト上で押した状態のとき、離す MOUSE_UP, MOUSE_CLICK
アドビのWebサイトではtrace()でログ文を出力していたけど、こちらでは画面上に表示している。
ソースが3分割されているのか。こういうのって、どこから読めばいいかわからないなー。
実行される順に読むのが素直じゃないか? まずMainクラスの、Mainコンストラクタが実行されてその中でinit()メソッドが呼ばれる。まず、Mainクラス。単にLoggerクラスとChildSpriteクラスのインスタンスを生成して、それをaddChild()してるだけ。
Main.as
package
{
import flash.display.Sprite;
import flash.events.Event;
/**
* ...
* @author itouhiro
*/
[SWF(backgroundColor="0xf8f8f8", width="320",height="240", frameRate="15")]
public class Main extends Sprite
{
public function Main():void
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
// entry point
var logger:Logger = new Logger('START!!');
addChild(logger);
var myObj:ChildSprite = new ChildSprite(logger);
myObj.x = stage.stageWidth / 2;
myObj.y = stage.stageHeight / 2;
addChild(myObj);
}
}
}
addChild()するとDisplayListに追加されて、すなわち画面に表示されるようになる。loggerというのはSTART!!と表示されてる文字の部分で、myObjというのが四角形。
冒頭のpackageって何だっけ?
複数のクラスをまとめる。たとえばオープンソースで他人に使ってほしいライブラリを公開する場合、
package com.YourDomain/yourLibrary
と書いておけばいい、らしい。
[SWF(backgroundColor="0xf8f8f8", width="320",height="240", frameRate="15")]
って何だっけ?
メタデータ。Flash Proffessional使わなくても、mxmlcにコマンドライン渡さなくても、swfのサイズとか秒あたりのフレーム数を指定できる。ドキュメントクラスの直前に書く。
ドキュメントクラス?
最初に実行されるクラス。(swfを実行するとき、ドキュメントクラスのコンストラクタがまず呼び出される)
上のFlashDevelopの画像右側を見てほしい。Main.asと書かれた左下に小さなアイコンで↓とあるだろう。これがドキュメントクラスの印。右クリックして、別のファイルをドキュメントクラスに指定することもできるぞ。
LoggerクラスとかChildSpriteクラスは、明示的に読み込んでないんだけど、自動的に読み込まれる?
ドキュメントクラスと同じ階層のフォルダにあるasファイルは自動的に読み込まれる。ドキュメントクラスと違う階層にある場合、たとえば Logger.asファイルが
com/YourDomain/yourLibrary/Logger.as
という階層にあるなら
import com.YourDomain.yourLibrary.Logger
と書けば、その階層の Logger.as
ファイルを読み込む。
次にLoggerクラス。log()メソッドでログ文字列を追加されたら、画面に表示されている内容を書き換える。
Logger.as
package
{
import flash.display.Sprite;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.text.TextFormat;
/**
* ...
* @author itouhiro
*/
public class Logger extends Sprite
{
private var tf:TextField;
private var lines:Array;
public function Logger(str:String = ''):void
{
var format:TextFormat = new TextFormat();
format.font = "Courier New";
format.size = 12;
format.color = 0x999999;
tf = new TextField();
tf.x = 10;
tf.y = 0;
tf.defaultTextFormat = format;
tf.text = str;
tf.autoSize = TextFieldAutoSize.LEFT;
addChild(tf);
lines = new Array();
}
public function log(str:String):void
{
lines.push(new Date().time.toString().substr(-5) + ' ' + str);
if (lines.length >= 15)
{
lines.shift();
}
tf.text = lines.join('\n');
}
}
}
import flash.text.TextFieldAutoSize;
とかは全部 手で書いてるわけ?
いや、FlashDevelop使っていれば、import文は手で書く必要が無い。
テキストカーソルを適切な位置(このソースだとTextFieldAutoSize.LEFT
のどこか)に置いて、[Refactor - Code Generator] (Ctrl+Shift+1) 押せば、勝手にimport文を追加してくれる。Ctrl+Shift+1 は押しにくいので Ctrl+Jにしているがな。
private var tf:TextField;
は手で入力した?
いや、
tf = new TextField()
のtfにカーソルを置いて[Refactor - Code Generator]。
そもそも、このファイル冒頭の
package {
は手で入力した?
いや、Main.asの
var logger:Logger = new Logger('START!!')
のLoggerにカーソルを置いて[Refactor - Code Generator]。そのとき extends (Base Class)
をマウスで指定する必要はあったけどな。
substr(-5)
ってなんだ?
「as3 substr」でGoogle検索すると http://livedocs.adobe.com/flash/9.0_jp/ActionScriptLangRefV3/String.html#substr() が見つかるぞ。文字列の最後5文字だけ取り出すという意味だ。
Date().time.toString()
で現在時刻を1970/1/1からのミリ秒の文字列にする。最後の3ケタがミリ秒で、上位2ケタは秒ということになる。
var format:TextFormat = new TextFormat()
のTextFormatは2回書く必要があるのか? 一度で済ましたいのだが
var format = new TextFormat()
と書くこともできるようだ。しかしその場合 17 Warning: variable 'format' has no type declaration. という警告がでるのだ。
var sizeS:uint = 50;
は
var sizeS:uint;
sizeS = 50;
の2行をひとつにまとめたものであることからも、2回書いたほうがよい。
最後にChildSpriteクラス。マウス操作を検知する、四角形なオブジェクトだ。
ChildSprite.as
package
{
import flash.display.Sprite;
import flash.events.MouseEvent;
/**
* ...
* @author itouhiro
*/
public class ChildSprite extends Sprite
{
private var logger:Logger;
private var sizeS:uint = 50; //stop
private var colorS:uint = 0xffcc00;
private var sizeO:uint = 60; //over
private var colorO:uint = 0xccff00;
private var colorD:uint = 0x00ccff; //down
public function ChildSprite(arg_logger:Logger)
{
draw(sizeS, sizeS, colorS);
addEventListener(MouseEvent.CLICK, clickHandler);
addEventListener(MouseEvent.DOUBLE_CLICK, doubleClickHandler);
addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
//addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
addEventListener(MouseEvent.MOUSE_OUT, mouseOutHandler);
addEventListener(MouseEvent.MOUSE_OVER, mouseOverHandler);
addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
addEventListener(MouseEvent.MOUSE_WHEEL, mouseWheelHandler);
addEventListener(MouseEvent.ROLL_OUT, rollOutHandler);
addEventListener(MouseEvent.ROLL_OVER, rollOverHandler);
//addEventListener(MouseEvent.CONTEXT_MENU, contextMenuHandler);
//addEventListener(MouseEvent.MIDDLE_CLICK, middleClickHandler);
//addEventListener(MouseEvent.MIDDLE_MOUSE_DOWN, middleMouseDownHandler);
//addEventListener(MouseEvent.MIDDLE_MOUSE_Up, middleMouseUpHandler);
//addEventListener(MouseEvent.RIGHT_CLICK, rightClickHandler);
//addEventListener(MouseEvent.RIGHT_MOUSE_DOWN, rightMouseDownHandler);
//addEventListener(MouseEvent.RIGHT_MOUSE_UP, rightMouseUpHandler);
logger = arg_logger;
}
private function draw(w:uint, h:uint, bgColor:uint):void
{
graphics.clear();
graphics.beginFill(bgColor);
graphics.drawRect(0, 0, w, h);
graphics.endFill();
}
private function rightMouseUpHandler(e:MouseEvent):void
{
logger.log('RIGHT_MOUSE_UP');
}
private function rightMouseDownHandler(e:MouseEvent):void
{
logger.log('RIGHT_MOUSE_DOWN');
}
private function rightClickHandler(e:MouseEvent):void
{
logger.log('RIGHT_CLICK');
}
private function middleMouseUpHandler(e:MouseEvent):void
{
logger.log('MIDDLE_MOUSE_UP');
}
private function middleMouseDownHandler(e:MouseEvent):void
{
logger.log('MIDDLE_MOUSE_DOWN');
}
private function middleClickHandler(e:MouseEvent):void
{
logger.log('MIDDLE_CLICK');
}
private function contextMenuHandler(e:MouseEvent):void
{
logger.log('CONTEXT_MENU');
}
private function rollOverHandler(e:MouseEvent):void
{
logger.log('ROLL_OVER');
}
private function rollOutHandler(e:MouseEvent):void
{
logger.log('ROLL_OUT');
}
private function mouseWheelHandler(e:MouseEvent):void
{
logger.log('MOUSE_WHEEL delta:' + e.delta);
}
private function mouseUpHandler(e:MouseEvent):void
{
logger.log('MOUSE_UP');
var spr:Sprite = Sprite(e.target);
spr.removeEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
spr.stopDrag();
draw(sizeO, sizeO, colorO);
}
private function mouseOverHandler(e:MouseEvent):void
{
logger.log('MOUSE_OVER');
draw(sizeO, sizeO, colorO);
}
private function mouseOutHandler(e:MouseEvent):void
{
logger.log('MOUSE_OUT');
draw(sizeS, sizeS, colorS);
}
private function mouseMoveHandler(e:MouseEvent):void
{
logger.log('MOUSE_MOVE');
e.updateAfterEvent();
}
private function mouseDownHandler(e:MouseEvent):void
{
logger.log('MOUSE_DOWN');
draw(sizeO, sizeO, colorD);
var spr:Sprite = Sprite(e.target);
spr.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
spr.startDrag();
}
private function doubleClickHandler(e:MouseEvent):void
{
logger.log('DOUBLE_CLICK');
}
private function clickHandler(e:MouseEvent):void
{
logger.log('CLICK');
}
}
}
private function clickHandler(e:MouseEvent):void
とかを手で入力した?
いや、
addEventListener(MouseEvent.CLICK, clickHandler)
のclickHandlerにカーソルを置いて[Refactor - Code Generator]。
MouseEvent.RIGHT_MOUSE_DOWN
とか書かれたaddEventListenerをコメント化してあるけど、これはなぜ?
Flex SDK 4.6 (FlashPlayer 11.3)では非対応で、コンパイルエラー(Error: Access of possibly undefined property RIGHT_MOUSE_DOWN )に なるからコメント化してある。 http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/events/MouseEvent.html を読む限り、FlashPlayer 11.2 以降は RIGHT_MOUSE_DOWN に対応してるはずなんだけどね‥‥なぜだろう
メソッド
mouseDownHandler()
の中で var spr:Sprite = Sprite(e.target)
とあるけど new がないね。
これはSpriteオブジェクトを新規生成してるわけじゃなくて、すでに存在する e.targetのオブジェクトを再選択してるようだな。そして addEventListener() と startDrag() のメソッドを実行してる。
ドラッグしたままマウスをFlashステージ外に出した場合、オブジェクトが消えて、マウスをFlashステージ内に戻すとオブジェクトが復活するね。でマウスをドラッグしてないのに、ドラッグになってる。これって、どう実現してるのかな?
‥‥このソースコードのようにすれば動作するんだろうな。
別のソース書いてstartDrag()試してみたぞ。
実際のFlashはコレだ。
https://sites.google.com/site/itouhiro/2012/20121104mouseEvent2.swf
Main.as
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
/**
* ...
* @author itouhiro
*/
[SWF(backgroundColor="0xf8f8f8", width="320",height="240", frameRate="15")]
public class Main extends Sprite
{
private var circle:Sprite;
public function Main():void
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
// entry point
circle = new Sprite();
circle.graphics.beginFill(0xFFCC00);
circle.graphics.drawCircle(0, 0, 40);
addChild(circle);
circle.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
circle.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
}
private function mouseUpHandler(e:MouseEvent):void
{
circle.stopDrag();
}
private function mouseDownHandler(e:MouseEvent):void
{
circle.startDrag();
}
}
}
これも、ドラッグしたままマウスをFlashステージ外に出してもオブジェクトが正しくついてくるね。ふーん。
0 件のコメント:
コメントを投稿