[Flash] Starlingの学習 Texture
EventのBubblingについても学ぶ。
環境:
- Starling 2.1
- Adobe AIR SDK 22
- FlashDevelop 5.2
- Windows 7 64bit
StarlingのTextureについて、書籍『Introducing Starling』で学ぶぞ。
まずはテクスチャー画像を画像編集ソフトで作成する。 32x64 pixelの8bit PNGファイル。
ソースコードは書籍とほぼ同じ。
Main.as
package
{
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
import starling.core.Starling;
/**
* ...
* @author foo
*/
[SWF(width="480",height="480",frameRate="60",backgroundColor="#002143")]
public class Main extends Sprite
{
private var stln:Starling;
public static var frameRate:uint = 0;
public function Main()
{
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
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;
stage.stage3Ds[0].addEventListener(Event.CONTEXT3D_CREATE, onContext3dCreated);
stln = new Starling(Game, stage);
stln.showStats = true;
stln.antiAliasing = 0;
stln.start();
}
private function onContext3dCreated(e:Event):void
{
stage.stage3Ds[0].removeEventListener(Event.CONTEXT3D_CREATE, onContext3dCreated);
if (Starling.context.driverInfo.toLowerCase().indexOf("software") != -1) {
// GPU disable
Starling.current.nativeStage.frameRate = 30;
} else {
// GPU enable
}
frameRate = Starling.current.nativeStage.frameRate;
}
}
}
Game.as
package
{
import flash.display.Bitmap;
import starling.display.Image;
import starling.display.Sprite;
import starling.events.Event;
import starling.textures.Texture;
import starling.utils.deg2rad;
/**
* ...
* @author foo
*/
public class Game extends Sprite
{
private const NUM_BRICK:uint = 80;
private var bricks:Vector.<Image> = new Vector.<Image>(NUM_BRICK, true);
// current dir 'Proj/src/'
[Embed(source = "../bin/201705brick1.png")]
private static const Brick:Class;
public function Game()
{
if (stage) init()
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
addEventListener(Event.ENTER_FRAME, onGetGpuStyle);
}
private function onGetGpuStyle(e:Event):void
{
if (Main.frameRate <= 0) return;
removeEventListener(Event.ENTER_FRAME, onGetGpuStyle);
addItem();
}
private function addItem():void
{
var brickBitmap:Bitmap = new Brick();
var texture:Texture = Texture.fromBitmap(brickBitmap);
for (var i:int = 0; i < NUM_BRICK; i++) {
var img:Image = new Image(texture);
img.alpha = Math.random();
img.x = Math.random() * stage.stageWidth;
img.y = Math.random() * stage.stageHeight;
img.rotation = deg2rad(Math.random() * 360);
img.color = (Math.random() * 0xEE) << 16 | (Math.random() * 0xEE) << 8 | (Math.random() * 0xEE);
addChild(img);
bricks[i] = img;
}
}
}
}
こんな表示になる。
ポイントは Texture.fromBitmap(brickBitmap);
の行をloopの外で実行したこと。もしloopの中で実行すると、loop毎に画像をGPUに転送するのでメモリを無駄に使うし、毎回mipmap生成で遅くもなる。
画像ファイルをswfに埋め込んだのが先ほどだ。 次はPNG画像ファイルを外部から読み込んで表示することにする。
Main.asは同じ。
Game.asの変更点は
--- /r/201705texture1/src/Game.as 2017-05-30 10:06:39.781823200 +0900
+++ /r/201705texture2/src/Game.as 2017-05-30 11:34:10.479145900 +0900
@@ -3,2 +3,4 @@
import flash.display.Bitmap;
+ import flash.display.Loader;
+ import flash.net.URLRequest;
import starling.display.Image;
@@ -17,5 +19,3 @@
private var bricks:Vector.<Image> = new Vector.<Image>(NUM_BRICK, true);
- // current dir 'Proj/src/'
- [Embed(source = "../bin/201705brick1.png")]
- private static const Brick:Class;
+ private var loader:Loader;
@@ -37,9 +37,13 @@
removeEventListener(Event.ENTER_FRAME, onGetGpuStyle);
- addItem();
+ // current dir 'Proj/bin/'
+ loader = new Loader();
+ loader.load(new URLRequest("201705brick1.png"));
+ loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoadComplete);
}
- private function addItem():void
+ private function onLoadComplete(e:Object):void
{
- var brickBitmap:Bitmap = new Brick();
- var texture:Texture = Texture.fromBitmap(brickBitmap);
+ loader.contentLoaderInfo.removeEventListener(Event.COMPLETE, onLoadComplete);
+ var loadedBitmap:Bitmap = loader.content as Bitmap;
+ var texture:Texture = Texture.fromBitmap(loadedBitmap);
for (var i:int = 0; i < NUM_BRICK; i++) {
ポイントは private function onLoadComplete(e:Object):void
の行。
本に書かれてるとおり (e:Event)
にすると
Error #1034: Type Coercion failed: cannot convert flash.events::Event to starling.events.Event (強制型変換に失敗しました)
というエラーになる。これはflash.display.Loaderクラスが、starling.events.Eventじゃなくてflash.events.Eventを送出するから。
これを使い分けるには、ソースコードでimport flash.events.Event
を追加して、ソースコードのEventの文字列すべてをflash.events.Event
またはstarling.events.Event
と書き分ければいいはず。 でも面倒なので、flash.events.Eventはe:Object
で受けることにする。
実行結果としては先ほどと同じ。
これは表示するだけ?
そうだよ。 次に、クリック(タップ)の検知方法はEventのBubblingを使うとラク、と書籍にある。確認してみる。
変更点は以下。
--- /r/201705texture2/src/Game.as 2017-05-30 11:34:10.479145900 +0900
+++ /r/201705texture3/src/Game.as 2017-06-01 20:54:38.918072900 +0900
@@ -5,2 +5,3 @@
import flash.net.URLRequest;
+ import starling.display.DisplayObject;
import starling.display.Image;
@@ -8,3 +9,7 @@
import starling.events.Event;
+ import starling.events.Touch;
+ import starling.events.TouchEvent;
+ import starling.events.TouchPhase;
import starling.textures.Texture;
+ import starling.textures.TextureSmoothing;
import starling.utils.deg2rad;
@@ -55,2 +60,3 @@
img.color = (Math.random() * 0xEE) << 16 | (Math.random() * 0xEE) << 8 | (Math.random() * 0xEE);
+ img.textureSmoothing = TextureSmoothing.NONE;
@@ -59,2 +65,16 @@
}
+ stage.addEventListener(TouchEvent.TOUCH, onTouch);
+ }
+
+ private function onTouch(e:TouchEvent):void
+ {
+ var touchPoints:Vector.<Touch> = e.getTouches(this);
+ var touchedItem:DisplayObject = e.currentTarget as DisplayObject;
+
+ if (touchPoints.length != 1) return;
+
+ var theTouchPoint:Touch = touchPoints[0];
+ if (theTouchPoint.phase == TouchPhase.ENDED) {
+ trace(e.currentTarget, e.target, e.bubbles);
+ }
}
テトリスのブロックみたいのをクリックすると、traceでなにやら表示するね。
EventのBubblingについては
http://www.adobe.com/devnet/actionscript/articles/event_handling_as3.html の以下の箇所がわかりやすいな。
StarlingのEventはBubblingはあるが、Captureはない。 で、今回の場合、テトリスのようなブロックをクリックすると
e.currentTarget
はstage。これはaddEventListenerしていてEventを受け取ったやつだ。e.target
はテトリスのようなブロック。 これはクリックされたやつだ。e.bubbles
は後で説明する。
最初はe.targetがクリックEventを受け取り、それがBubblingで浮き上がっていって、stageもクリックEventを受け取ったんだ。
なるほど。クリックを監視したのはstageだけなのに、どのオブジェクトをクリックしたのか判明するのか。
個々のオブジェクトひとつひとつを監視(個々のObjectにaddEventListenerを付ける)しなくてもいい、ということだね。
そう。
ちなみにActionScript3.0のflash.events.Eventは、capture段階では受け取らないのがデフォルト。受け取るには addEventListenerの第3引数を指定する必要がある。
また、先ほどのtraceにあった e.bubbles
なんだけど、 「e.currentTargetが受け取ったEventはBubblingで受け取ったものですか? Yes」という意味‥‥と書籍には書いてあったが http://www.adobe.com/devnet/actionscript/articles/event_handling_as3.html や http://doc.starling-framework.org/current/starling/events/Event.html を見ると違って、BubblingするタイプのEventなら実際にBubblingしようがしまいがtrueになるらしい。TouchEvent.TOUCH はBubblingするタイプらしい。
0 件のコメント:
コメントを投稿