Posted on

Starling簡報分享

Starling簡介

  1. 基於Stage3D技術來實作
  2. 在Flash Player 11之後的版本才能支援此技術
  3. 使用GPU做圖形的運算,讓Flash的效能能夠到之前的1000倍(官方說法)!
  4. 易學,使用跟Flash native API類似的類別,方法,架構等,讓原本熟悉Flash的開發者可以很快的上手可發布到多種平台(包括 iOS andAndroid及各種瀏覽器)
    image-712

 

3D畫面運作原理

  1. Flash原有的坐標系統:Global Point和Local Point
  2. 3D世界的坐標系統:世界坐標到相機坐標的轉換
    201212141827446597-349

3D透視變換方法

  1. 正交投影
    201212141827541985-383
  2. 透視投影
    201212141827559901-404
  3. 比較圖
    201212141827571132-411

Stage3D的渲染過程

VertexShader 主要作用就是3D流程中的前半段操作(對頂點進行一系列的矩陣變換)
FragmentShader:對這些變換後的頂點(及流程中的光柵化部分)進行渲染
螢幕快照-2014-01-30-下午1.03.21-494

過去主要的3D技術

  1. 使用GPU的3D引擎:硬件加速(hardware acceleration)
    1. DirectX
    2. OpenGL
  2. 其他Flash3D引擎:軟件模式(software mode)
    1. Papervision3D
    2. Away3D
    3. Alternativa3D

Starling的渲染方式

螢幕快照-2014-02-01-下午11.37.51-731

 

剩的請自行看投影片….

Posted on 1 Comment

產生TextureAtlas素材的方式

方法一、使用TexturePacker

軟體官網:http://www.codeandweb.com/texturepacker
範例圖檔下載:woman
螢幕快照 2014-02-12 下午2.39.46
首先,要先把圖檔整理成多個png圖檔,若是連續的圖檔,則需要在後面加0001~~XXXX之類的數字,固定是四個數字。若是單一圖檔則可以不用加。到時在取圖檔時,例如本範例是woman0001~woman0028,則只需要用woman當前置詞就可以取出全部的動態圖檔了

var woman:MovieClip = new MovieClip(atlas.getTextures("woman"),30);

而在操作TexturePacker時,最重要的是Data Format要選擇Sparrow/Starling。

索取TexturePacker免費序號

免費序號申請單:http://www.codeandweb.com/request-free-license

首先要說一下這套軟體的開發者真的很用心,當時看到有Blog說如果是有部落格的開發者,可以寫信去申請免費序號。我寫了申請表後,他回信了這封信給我:

Hi Claire,

Here’s your license key for TexturePacker:
TP-xxxxxxxxxxxxxxxx
I’ve added a license for PhysicsEditor (see file attached) in case you might want to try it too 😉
Nice blog! I would be happy to get a (short) blog post in return.
In case you do a tutorial post about my tools I can link back to your blog from the tutorials section on my page. That might give you some more visitors on your page!

Kind regards
Kerstin on behalf of Andreas

因為還有我的名字,我就回信問他中文的部落格可以嗎?結果居然真的是人工回信的耶(本以為都是自動發信),而且回信速度很快,真的很用心在經營他的產品。

最酷的是,後來因為我在寫Starling前面的教程,所以遲遲未寫關於TexturePacker的介紹文,他居然隔了一段時間又寄了封信給我:

Dear Claire,

I sent you a blogger license for TexturePacker some time ago,
and I am curious how you like the program.
Did you get it running successfully? Or do you need some assistance?
I would be happy to get a (short) blog post in return.

Kind regards
Kerstin on behalf of Andreas

還會關心我們的使用狀況耶!真的是超用心的開發者~

方法二、使用Flash CC

Flash CC和之前的版本比起來,就是它終於支援可以把元件庫的東西匯出了。

只需要在元件庫按右鍵,就可以選擇是要將其匯出成連續png或者是直接匯出成Sprite Sheet,並可同時選擇多個圖檔然後一起匯在同一個Spite Sheet裡。相關操作教學請見此:Sprite Sheets in Flash Professional CS6
螢幕快照 2014-02-12 下午2.47.52
螢幕快照 2014-02-12 下午2.49.40

Posted on

Starling的Display Objects介紹(五)

上一篇:Starling的Display Objects介紹(四) 下一篇:產生TextureAtlas素材的方式 這篇會介紹starling.display.MovieClip以及starling.animation.Juggler

MovieClip物件介紹

官方手冊在此:http://doc.starling-framework.org/core/starling/display/MovieClip.html 在Starling裡面的MovieClip和原生的MovieClip差異蠻大的,列舉說明如下:

  1. 每一個MovieClip都可設定不同的fps(需在new MovieClip時指定):這是因為一般來說在Starling裡的frameRate都會設定的很高,但動畫可能不會有這麼多圖片可跑,因此每一個MovieClip
  2. 由一連串的連續圖檔組成:MovieClip是由一連串的動畫圖片(TextureAtlas)輪流播放。
  3. MovieClip裡面無法有任何物件:在Starling裡的MovieClip並不是繼承DisplayObjectContainer,而是繼承於Image,因此無法addChild()。我們可以想像MovieClip在Starling裡是一個Image下面放著一張很大的png,然後有一個方型遮罩,不停的變換顯示的區塊。
  4. 動畫效果必需由Juggler驅動:在Starling裡所有的動畫物件都必需實作IAnimatable這個介面。而所有的動畫效果則統一由Juggler驅動(另外還包括Tween、DelayedCall)。
  5. 沒有frameLabel的概念(這部份有些Starling extension有加上去此功能)
  6. 當isComplete等於true時會停止動畫的播放

順便介紹兩個好用的method。第一個為setFrameDuration(),可以另外再設定某個影格的停留時間,影格數從0開始。而setFrameSound()可以設定播放到某影格時播放一個聲音檔。 連續圖檔的產生方式請見此文章:產生TextureAtlas的方式

Juggler物件介紹

官方手冊在此:http://doc.starling-framework.org/core/starling/animation/Juggler.html 介紹在此:http://grayliao.blogspot.tw/2011/11/starling-framework6jugglertweendelaycal.html

Juggle是個簡單的Class,用來控制動畫的進行。他負責管理經由add()加進來的實現IAnimatable介面的物件,然後當Juggler的advanceTime()被呼叫時,它會負責去呼叫這些IAnimatable的advanceTime(),讓動畫進行下去;而當某個IAnimatable到達complete狀態時,則會被Juggler踢出去。我們就只要負責每個frame去呼叫Juggler的advanceTime()就好。而Starling class裡有個預設的juggler,當Starling.current正在運行時,Starling.juggler在每個frame時會自動被呼叫advanceTime()。通常我們把遊戲裡的動畫加到Starling.juggler裡,而一些特殊的動畫,例如遊戲暫停時要撥放的動畫,再加到另一個我們新增的Juggler,然後每個frame去呼叫它的advanceTime()。這裡講的每個frame,我們是使用EnterFrameEvent.ENTER_FRAME,而不是Event.ENTER_FRAME,因為EnterFrameEvent可以取得passedTime,這個passTime是指跟上一次事件發生經過的時間,可以傳給Juggle的advanceTime()的第一個參數。用經過時間來播放動畫,這樣就不會受frame數不穩定而影響動畫撥放的時間。 而要實現IAnimatable介面,只要實作advanceTime()這個方法,並且要設定一個complete條件,當達到這個條件時將自己的isComplete設為true,這樣就可以自動被Juggle移除。

簡單的MovieClip範例

因為在Starling裡面,不論是MovieClip或是Button,都是正方形的。若要去判別透明,將透明的Touch事件設為無效,都需要去覆寫原有的類別裡的hitTest函數,以最原始的BitmapData的hitTest去判別是否為透明圖層。 這邊有一個已寫好的類別:AlphaMovieClip,已經寫好將透明圖層的所有hitTest事件設為無效。若有這個需求的人可以使用此類別來應用。下面是一個我寫的簡單應用範例,可點此下載原始檔:StarlingTest StarlingTest.as

package
{
	import flash.display.Sprite;

	import starling.core.Starling;

	[SWF(frameRate="60",Width="800",Height="600")]
	public class StarlingTest extends Sprite
	{
		public function StarlingTest()
		{
			var star:Starling = new Starling(Main, stage);
			star.start();
		}
	}
}

Main.as

package {
	import flash.display.Bitmap;

	import starling.core.Starling;
	import starling.display.MovieClip;
	import starling.display.Sprite;
	import starling.events.Touch;
	import starling.events.TouchEvent;
	import starling.events.TouchPhase;
	import starling.textures.Texture;
	import starling.textures.TextureAtlas;

	public class Main extends Sprite {
		[Embed(source = 'test.xml', mimeType = 'application/octet-stream')]
		private var AtlasXML:Class;

		[Embed(source = 'test.png')]
		private var AtlasTexture:Class;

		private var mc:AlphaMovieClip ;
		public function Main() {
			var bitmap:Bitmap = new AtlasTexture();
			var texture:Texture = Texture.fromBitmap(bitmap);
			var xml:XML = XML(new AtlasXML());
			var atlas:TextureAtlas = new TextureAtlas(texture, xml);

			mc = new AlphaMovieClip("run",atlas, bitmap.bitmapData,30);
			var m2:MovieClip = new MovieClip(atlas.getTextures("run"),30);
			m2.loop = false;
			m2.x = 200;
			mc.addEventListener(TouchEvent.TOUCH, touchEventHandler);
			addChild(mc);
			addChild(m2);

			Starling.juggler.add(mc);
			Starling.juggler.add(m2);
		}

		private function touchEventHandler(event:TouchEvent):void {
			var touch:Touch = event.getTouch(this);
			if(!touch ) return;
			if (touch.phase == TouchPhase.BEGAN){
				mc.pause();
			}else if(touch.phase == TouchPhase.ENDED){
				mc.play();
			}
		}
	}
}

AlphaMovieClip.as

package {
	import flash.display.BitmapData;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.utils.Dictionary;
	import starling.display.DisplayObject;
	import starling.display.MovieClip;
	import starling.textures.SubTexture;
	import starling.textures.Texture;
	import starling.textures.TextureAtlas;

	public class AlphaMovieClip extends MovieClip
	{
		private var m_TexturePrefix	:String				= "";
		private var m_TextureAtlas	:TextureAtlas		= null;
		private var m_Textures		:Vector.	= null;
		private var m_TextureInfo	:Dictionary			= null;
		private var m_BitmapData	:BitmapData			= null;

		public function AlphaMovieClip(texturePrefix:String, textureAtlas:TextureAtlas, bitmapData:BitmapData, fps:Number = 12)
		{
			m_TextureInfo = new Dictionary();

			var names:Vector. = textureAtlas.getNames(texturePrefix);
			for each (var name:String in names)
			{
				var textureInfo:Object = { };
				textureInfo.name = name;
				textureInfo.texture = textureAtlas.getTexture(name);
				m_TextureInfo[name] = textureInfo;
			}

			m_TexturePrefix = texturePrefix;
			m_TextureAtlas = textureAtlas;
			m_Textures = textureAtlas.getTextures(texturePrefix);
			m_BitmapData = bitmapData;

			super(m_Textures, fps);
		}

		override public function hitTest(localPoint:Point, forTouch:Boolean = false):DisplayObject
		{
			if (forTouch && visible && touchable)
			{
				if (getBounds(this).containsPoint(localPoint))
				{
					var texture:Texture = getFrameTexture(currentFrame);
					var subtexture:SubTexture = texture as SubTexture;
					var textureFrame:Rectangle = subtexture.frame;
					var clipping:Rectangle = subtexture.clipping;
					var frameBound:Rectangle = new Rectangle(
						Math.abs(textureFrame.x),
						Math.abs(textureFrame.y),
						clipping.width * m_TextureAtlas.texture.width,
						clipping.height * m_TextureAtlas.texture.height
					);
					clipping.x *= m_TextureAtlas.texture.width;
					clipping.y *= m_TextureAtlas.texture.height;

					var final_x:uint = (frameBound.containsPoint(localPoint) ? localPoint.x - frameBound.x : uint.MAX_VALUE);
					var final_y:uint = (frameBound.containsPoint(localPoint) ? localPoint.y - frameBound.y : uint.MAX_VALUE);

					if (final_x != uint.MAX_VALUE && final_y != uint.MAX_VALUE)
					{
						var pixel:uint = m_BitmapData.getPixel32(clipping.x + final_x, clipping.y + final_y);
						if (uint((pixel >> 24) & 0xFF) == 0)
						{
							return null;
						}
					}
					else
					{
						return null;
					}
				}
			}
			return super.hitTest(localPoint, forTouch);
		}
	}
}

test.png
test
test.xml

<?xml version="1.0" encoding="UTF-8"?>
<textureAtlas imagePath="test.png">
    <subTexture name="run0001" x="2" y="2" width="94" height="156" frameX="0" frameY="-4" frameWidth="100" frameHeight="160"/>
    <subTexture name="run0002" x="98" y="2" width="94" height="150" frameX="0" frameY="-10" frameWidth="100" frameHeight="160"/>
    <subTexture name="run0003" x="194" y="2" width="98" height="148" frameX="-1" frameY="-12" frameWidth="100" frameHeight="160"/>
    <subTexture name="run0004" x="294" y="2" width="100" height="154" frameX="0" frameY="-6" frameWidth="100" frameHeight="160"/>
    <subTexture name="run0005" x="396" y="2" width="98" height="160" frameX="0" frameY="0" frameWidth="100" frameHeight="160"/>
    <subTexture name="run0006" x="2" y="164" width="96" height="160" frameX="0" frameY="0" frameWidth="100" frameHeight="160"/>
    <subTexture name="run0007" x="100" y="164" width="96" height="158" frameX="-1" frameY="-2" frameWidth="100" frameHeight="160"/>
    <subTexture name="run0008" x="198" y="164" width="96" height="152" frameX="-1" frameY="-8" frameWidth="100" frameHeight="160"/>
    <subTexture name="run0009" x="296" y="164" width="98" height="150" frameX="-1" frameY="-10" frameWidth="100" frameHeight="160"/>
    <subTexture name="run0010" x="396" y="164" width="100" height="156" frameX="0" frameY="-4" frameWidth="100" frameHeight="160"/>
    <subTexture name="run0011" x="2" y="326" width="98" height="160" frameX="0" frameY="0" frameWidth="100" frameHeight="160"/>
    <subTexture name="run0012" x="102" y="326" width="96" height="160" frameX="-1" frameY="0" frameWidth="100" frameHeight="160"/>
</textureAtlas>
Posted on 2 Comments

Starling的Display Objects介紹(四)

上一篇:Starling的Display Objects介紹(三)
下一篇:Starling的Display Objects介紹(五)

這篇會介紹下圖裡的starling.display.Quad以及starling.display.Image
class_hierarchy

Quad物件介紹

官方手冊在此:http://doc.starling-framework.org/core/starling/display/Quad.html

A Quad represents a rectangle with a uniform color or a color gradient.

每一個端點都可以設定一個顏色,會呈現線性漸層。要顯示一個線性的漸變色,需要把一個色值設置給頂點0和頂點1,然後另一個顏色給頂點2和頂點3。

頂點位置是這樣安排的::

      0 - 1
      | / |
      2 - 3

在這個物件裡面,可以看到一個叫做mVertexData的屬性。在Starling Framework簡介的地方曾經說過,Starling是基於Stage3D而建的,關於3D渲染基礎原理請見此:3D渲染基礎原理VertexData官方介紹。所謂3D其實是一組3維的坐標,經由矩陣轉換,將之投影到2D螢幕上,計算其在2D畫面上的2D坐標,如下圖所示:
201212141827425715201212141827546379
在Starling裡面,因為是2D遊戲,則是使用正交投影的方式,直接去掉z軸的值,來將頂點坐標從3維轉至2維。但操作原理不變,這邊的則是要輸入四邊型的頂點數據。正交投影示意如下圖:
201212141827541985

下面是產生寬高各為200,200的方塊的簡單範例:

package {
	import starling.display.Quad;
	import starling.display.Sprite;
	import starling.events.Event;
	public class Game extends Sprite {
		private var q:Quad;
		public function Game() {
			addEventListener(Event.ADDED_TO_STAGE, onAdded);
		}
		private function onAdded ( e:Event ):void {
			q = new Quad(200, 200);
			q.color = 0x00FF00;
			q.x = stage.stageWidth - q.width >> 1;
			q.y = stage.stageHeight - q.height >> 1;
			addChild ( q );
		}
	}
}

Image物件介紹

官方手冊在此:http://doc.starling-framework.org/core/starling/display/Image.html

一個圖片(Image)其實就是一個四邊形上面映射了一個紋理(Texture),以下圖來說,兩個三角形是Quad的範圍,而Texture就是藍色衣服的娃娃的PNG圖檔,代表貼圖的材質。

螢幕快照 2014-02-11 下午4.32.05
Image相當於Flash的Bitmap類的Starling版本。但是Starling是用Texture來代替BitmapData來為圖像提供像素數據。 要顯示一個Texture,需要把它映射到一個四邊形上,而這就是Image這個類所實現的功能。

一個”Image”是繼承自”Quad”的,我們可以在Quad上設置顏色,對於每個像素來說,最終的顏色是根據紋理的顏色和四邊形的顏色相乘而來的。 這樣您就可以很容易用Quad的顏色改變一個紋理的色調。您還可以在不改變任何四邊形的頂點坐標的情況下,在一個圖片的內部移動紋理。用此功能,可以以一個非常有效的方式,創建一個矩形遮罩。

下面是一個簡單的Image使用範例:
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;
public class Game2 extends Sprite {
private var sausagesVector:Vector. = new Vector.(NUM_SAUSAGES, true);
private const NUM_SAUSAGES:uint = 400;

[Embed(source = “boy.png”)]
private static const Sausage:Class;

public function Game2() {
addEventListener(Event.ADDED_TO_STAGE, onAdded);
}

private function onAdded (e:Event):void {
// create a Bitmap object out of the embedded image
var sausageBitmap:Bitmap = new Sausage();
// create a Texture object to feed the Image object
var texture:Texture = Texture.fromBitmap(sausageBitmap);
for (var i:int = 0; i < NUM_SAUSAGES; i++) { // create a Image object with our one texture var image:Image = new Image(texture); // set a random alpha, position, rotation image.alpha = Math.random(); // define a random initial position image.x = Math.random()*stage.stageWidth image.y = Math.random()*stage.stageHeight image.rotation = deg2rad(Math.random()*360); // show it addChild(image); // store references for later sausagesVector[i] = image; } } } }[/code]

Posted on 1 Comment

Starling的Display Objects介紹(三)

上一篇:Starling的Display Objects介紹(二)
下一篇:Starling的Display Objects介紹(四)

這篇會介紹下圖裡的starling.display.Button以及starling.display.Sprite
class_hierarchy

Button物件介紹

官方手冊在此:http://doc.starling-framework.org/core/starling/display/Button.html

和Flash的SimpleButton的不同點,是它只有兩個狀態的圖檔,也就是upState與downState,而沒有over的狀態。它的disabled樣式可以經由alphaWhenDisabled的屬性去設定Disabled時的圖檔透明度。

另外,按下Button會觸發的事件是Event.TRIGGERED,因此若我們要監聽一個Button按下的事件,可用下面的方式去監聽:

menuContainer.addEventListener(Event.TRIGGERED, onTriggered);
private function onTriggered(e:Event):void {
    // outputs : [object Sprite] [object Button]
    trace ( e.currentTarget, e.target );
    // outputs : triggered!
    trace ("triggered!");
}

這是starling.display.Button一個簡單的使用範例:

package {
	import flash.display.Bitmap;
	import starling.display.Button;
	import starling.display.Sprite;
	import starling.events.Event;
	import starling.textures.Texture;

	public class Game extends Sprite {
		[Embed(source = "../media/textures/button_up.png")]
		private static const Button_UP:Class;

		[Embed(source = "../media/textures/button_down.png")]
		private static const Button_DOWN:Class;

		public function Game() {
			addEventListener(Event.ADDED_TO_STAGE, onAdded);
		}

		private function onAdded (e:Event):void {
			// create a Bitmap object out of the embedded image
			var buttonSkinUp:Bitmap = new Button_UP();
			var buttonSkinDown:Bitmap = new Button_DOWN();

			// 創建按鈕
			var myButton:Button = new Button(Texture.fromBitmap(buttonSkinUp), "這是按鈕", Texture.fromBitmap(buttonSkinDown));

			// 創建Menu容器並把按鈕加上去
			var menuContainer:Sprite = new Sprite();
			menuContainer.addChild(myButton);

			// centers the menu
			menuContainer.x = stage.stageWidth - menuContainer.width &gt;&gt; 1;
			menuContainer.y = stage.stageHeight - menuContainer.height &gt;&gt; 1;

			// show the button
			addChild(menuContainer);
		}
}
}

要注意的是,在starling裡面沒有hit area的設計,因為圖片有Bounds和Frame兩個屬性,所以要確定是否是碰到bounds的話,可以覆寫原有的hitTest函數,範例如下:

public override function hitTest( localPoint:Point, forTouch:Boolean=false ) :DisplayObject
{
	// on a touch test, invisible or untouchable objects cause the test to fail
	if( forTouch &amp;&amp; (!visible || !touchable) )
	{
		return null;
	}

	// otherwise, check bounding box of hitArea (which is a Rectangle here)
	var result:DisplayObject = null;
	if( _hitArea.containsPoint( localPoint ) )
	{
		result = this;
	}

	return result;
}

若是要偵測是否碰到透明區塊,則要使用原生的BitmapData.hitTest去測試,使用方法如下:

public hitTest(firstPoint:Point, firstAlphaThreshold:Number, secondObject:Object, [secondBitmapPoint:Point], [secondAlphaThreshold:Number]) : Boolean

Sprite物件

Sprite官方手冊在此:http://doc.starling-framework.org/core/starling/display/Sprite.html

DisplayObjectContainer官方手冊在此:http://doc.starling-framework.org/core/starling/display/DisplayObjectContainer.html

除了DisplayObjectContainer的功能以外,還多了一個flatten的屬性,這個屬性可以利用一些讓這個Sprite在播放動畫時更加的順暢,但若是開啟了flatten機制,所有之後對畫面的alpha、rotation和位置的改變都無法在畫面上被呈現。所以在使用此一屬性時要更加的小心。

Sprite一個專門用來放許多其他元件的標準容器,它可被偵聽下面這些事件:

  • Event.ADDED: the object was added to a parent.
  • Event.ADDED_TO_STAGE: the object was added to a parent that is connected to the stage, thus becoming visible now.
  • Event.REMOVED: the object was removed from a parent.
  • Event.REMOVED_FROM_STAGE: the object was removed from a parent that is connected to the stage, thus becoming invisible now.
  • KeyboardEvent.KEY_DOWN: 當按下按鍵時觸發
  • KeyboardEvent.KEY_UP: 當離開按鍵時觸發
  • EnterFrameEvent.ENTER_FRAME: 影格前進時觸發事件,根據frameRate的設定來決定一秒觸發幾次
    [SWF(frameRate="60", width="1024", height="768", backgroundColor="0x000000")]
  • Event.FLATTEN: 當開啟或關閉flatten功能時會觸發事件/li>
Posted on 2 Comments

Starling的Display Objects介紹(二)

上一篇:Starling的Display Objects介紹(一)
下一篇:Starling的Display Objects介紹(三)

這篇會介紹下圖裡的starling.text.TextField
class_hierarchy

TextField物件介紹

官方手冊請見此:http://doc.starling-framework.org/core/starling/text/TextField.html

下面是一個最簡單的使用範例:

package {

	import starling.display.Sprite;
	import starling.events.Event;
	import starling.text.TextField;

	public class Game extends Sprite {

		public function Game() {
			addEventListener(Event.ADDED_TO_STAGE, onAdded);
		}

		private function onAdded (e:Event):void {
			// create the TextField object
			var legend:TextField = new TextField(300, 300, "簡單的文字範例", "Verdana", 38, 0xFFFFFF);
			// centers the text on stage
			legend.x = stage.stageWidth - legend.width &gt;&gt; 1;
			legend.y = stage.stageHeight - legend.height &gt;&gt; 1;
			// show it
			addChild(legend);
		}
	}
}

內嵌字型方式比較

在Starling裡的TextField可以用兩種方式去嵌入特殊字型,如下圖所示:
2014-01-17_153055
從上圖我們可以發現,原始的字體嵌入方式,在1到2的部份,將字型從ttf裡抽取出來壓成Bitmap Snapshot,這部份會需要使用到CPU來做運算。因為會多一個程序,在效能上,會比右邊的方式慢一些。Bitmap Font則是使用一份字型列表的圖檔(如下圖),去比對xml的字型資訊檔,它完全只會用到GPU的運算,在效能上優於傳統字體嵌入的方式。
fontRegular字型範例下載:fontRegular

但是若我們要求字體在各種解析度都要能夠有很高的解析,由於原始的字型嵌入方式是即時將字型轉換成Bitmap圖檔,在各種大小都可以有良好的表現。而若我們想要使用不同大小的Bitmap字型,則需要在產生文字圖檔時就決定要使用那些大小的字型,而不能在執行時才決定要顯示的文字大小為何。

在下面的Bitmap Font產生工具裡都可以有設定的選項,包括要使用那些文字、字體、等等…,以及字型要叫什麼都可以在產生時設定好。

Bitmap Font產生工具

這邊有幾個可以產生Bitmap文字圖檔及.fnt檔案的工具:

  1. Glyph Designer(適用於Mac)
    螢幕快照 2014-02-07 下午9.58.42
  2. BMFont(適用於Windows)
    螢幕快照 2014-02-07 下午9.59.34

內嵌字型實作範例

下面我們簡介一下這兩種方式的實作方式:

  1. Standard TrueType fonts:也就是一般內嵌字型的方式,將.ttf的文字檔案直接用embed的方式嵌入swf裡。
    下面是一個簡單的範例:

    package {
    	import flash.text.Font;
    	import starling.display.Sprite;
    	import starling.events.Event;
    	import starling.text.TextField;
    
    	public class Game extends Sprite {
    		[Embed(source='/../media/fonts/Abduction.ttf', embedAsCFF='false', fontName='Abduction')]
    		public static var Abduction:Class;
    
    		public function Game() {
    			addEventListener(Event.ADDED_TO_STAGE, onAdded);
    		}
    
    		private function onAdded (e:Event):void {
    			// create the font
    			var font:Font = new Abduction();
    			// create the TextField object
    			var legend:TextField = new TextField(300, 300, "使用內嵌字型的簡單範例!", font.fontName, 38, 0xFFFFFF);
    			// centers the text on stage
    			legend.x = stage.stageWidth - legend.width &gt;&gt; 1; legend.y = stage.stageHeight - legend.height &gt;&gt; 1;
    			// show it
    			addChild(legend);
    		}
    	}
    }
    
  2. Bitmap fonts:If you need speed or fancy font effects, use a bitmap font instead. That is a font that has its glyphs rendered to a texture atlas. To use it, first register the font with the method registerBitmapFont, and then pass the font name to the corresponding property of the text field.
    一個使用Bitmap來當作字型檔案的簡單範例如下:
    字型檔案下載:fontRegular

    package
    {
    	import flash.display.Bitmap;
    	import starling.display.Sprite;
    	import starling.events.Event;
    	import starling.text.BitmapFont;
    	import starling.text.TextField;
    	import starling.textures.Texture;
    	import starling.utils.Color;
    
    	public class Game extends Sprite {
    
    		[Embed(source = "../media/fonts/fontRegular.png")]
    		private static const BitmapChars:Class;
    		[Embed(source="../media/fonts/fontRegular.fnt", mimeType="application/octet-stream")]
    		private static const BritannicXML:Class;
    
    		public function Game() {
    			addEventListener(Event.ADDED_TO_STAGE, onAdded);
    		}
    
    		private function onAdded (e:Event):void {
    			// creates the embedded bitmap (spritesheet file)
    			var bitmap:Bitmap = new BitmapChars();
    			// creates a texture out of it
    			var texture:Texture = Texture.fromBitmap(bitmap);
    
    			// create the XML file describing the glyphes position on the spritesheet
    			var xml:XML = XML(new BritannicXML());
    			// register the bitmap font to make it available to TextField
    			TextField.registerBitmapFont(new BitmapFont(texture, xml));
    			// create the TextField object
    			var bmpFontTF:TextField = new TextField(400, 400, "使用內嵌字型的簡單範例!", "BritannicBold", 10);
    			// the native bitmap font size, no scaling
    			bmpFontTF.fontSize = BitmapFont.NATIVE_SIZE;
    			// use white to use the texture as it is (no tinting)
    			bmpFontTF.color = Color.WHITE;
    			// centers the text on stage
    			bmpFontTF.x = stage.stageWidth - bmpFontTF.width &gt;&gt; 1;
    			bmpFontTF.y = stage.stageHeight - bmpFontTF.height &gt;&gt; 1;
    			// show it
    			addChild(bmpFontTF);
    		}
    	}
    }

參考資料

  1. The Starling Manual » Displaying Text
  2. TextField API
  3. Starting with Starling – Ep 10: Text and Fonts
Posted on 2 Comments

Starling的Display Objects介紹(一)

上一篇:Starling Framework簡介
下一篇:Starling的Display Objects介紹(二)

Starling framework啟動方式

所有使用Starling framework的應用程式的起始點,都是由一個Starling物件,來創建整個Starling世界(Starling物件說明可見此:Starling),下面是一個最簡單的範例:

package{
    import starling.core.Starling;
    import starling.display.Sprite;

    [SWF(width="1280", height="752", frameRate="60", backgroundColor="#000000")]
    public class Startup extends Sprite
    {
        private var mStarling:Starling;
        public function Startup() {
            // 建立Starling物件
            mStarling = new Starling(Game, stage);
            // start it!
            mStarling.start();
        }
    }
}

Starling世界的物件樹

官方的說明文件裡可以看到在Starling裡,畫面物件的繼承樹是長這樣的:
class_hierarchy
從上圖可看出在Starling裡面,DisplayObject是一切畫面物件的祖先,繼承於EventDispatcher。

DisplayObject物件介紹

官方手冊請見此:http://doc.starling-framework.org/core/starling/display/DisplayObject.html

這是所有物件樹的根物件,他的子孫包含像Quad、Image、MovieClip,這一邊是在做動畫影片的。另一邊像是DisplayObjectContainer則是放物件的容器,顧名思義,它可以再加入其他的DisplayObject在裡面。反向來說,在Starling世界裡面的MovieClip,是沒有辦法使用addChild的,它只能像是一個動畫影片一樣的單純被播放、控制位置、旋轉、或偵測碰撞,而無法在MovieClip裡面加入其他的MovieClip

在Starling的DisplayObject其實只是一個abstract class,他沒有辦法被直接new出來,一定要被繼承並實作這兩個方法:

//要實作要如何利用Stage3D來產生畫面的方式
function render(support:RenderSupport, parentAlpha:Number):void;
//實作物件碰撞偵測的方式
function getBounds(targetSpace:DisplayObject, resultRect:Rectangle=null):Rectangle

從上面的繼承樹我們可以發現MovieClip與DisplayObjectContainer是採用不一樣的碰撞偵測方法以及圖形render方式的。

在Starling裡的DisplayObject則有偵測多點觸控,以及設定物件坐標、及與不同層DisplayObjectContent的坐標轉換功能。

Stage物件介紹

官方手冊請見此:http://doc.starling-framework.org/core/starling/display/Stage.html

Starling物件有它主場景物件Stage,也就是上圖的Starling.display.Stage,它和flash裡的Stage一樣,是放所有物件的母容器(The Starling stage object, which is the root of the display tree that is rendered)。

這個物件裡面只能夠有繼承於starling.display.DisplayObject的物件,而無法包含任何flash.display.DisplayObject相關的物件,這兩種類別是完全不能兼容的。雖然在Starling裡面,可以用

Starling.current.nativeOverlay.addChild(textInput);

來加入原生flash物件,但就如我前一篇簡介所說,其實他也只是會取得flash.display.Stage的物件把元件放到裡面而已,它永遠都會被放在畫面的最上層。
螢幕快照 2014-02-01 下午11.45.51

Stage會在創建Starling物件時被自動創建,所以不用自己去建立它。

參考資料

  1. The Starling Manual > Display Objects
  2. Display Object API
  3. Juggler API
  4. Starling API
Posted on 2 Comments

Starling Framework簡介

下一篇:Starling的Display Objects介紹(一)

Starling的技術基礎

Starling是基於Stage3D來實作的,因此在學習Starling之前,我建議應該要對Stage3D的特性有基礎的了解。有關於Stage3D的介紹可以看這篇文章:Stage3D運作原理。在這篇文章裡,我們可以知道Stage3D比起OpenGL及DirectX等傳統3D的APIs的優勢與劣勢。

Stage3D會依發佈平台的不同而使用不一樣的GPU運算引擎,例如在mac電腦上所使用的是OpenGL,而在Windows則會視電腦所使用的硬體設備去選擇所使用的基礎技術。值得一提的是,即使遇到不支援的硬體,Stage3D仍然可以使用軟件模式去做3D運算,只是會變得十分的緩慢。這邊有一個簡單的性能比較:Stage3D vs WebGL 性能較量

下圖是Starling的技術基礎示意圖:

image

Starling運作模式

過去我們很容易因為Stage3D這個名字而誤會這是專門為3D而做的引擎,而不能使用在2D的技術上。3D引擎的運算與2D運算最大的差異點,在於3D畫面是由一個個三角型為基礎,去建構整個畫面。而2D的向量圖形,則是由多個頂點組合而成的複雜多邊型。

要將3D的技術使用在2D上,便是將圖片整理成png或jpg等圖片,然後將圖片視為兩個三角型去繪製物件,再加上貼材質的方式,將人物的圖片貼至範圍裡。這樣便可以利用GPU去執行它最擅長的三角型繪製以及材質貼圖的動作。

 

螢幕快照 2014-02-01 下午11.37.51

Starling簡單範例

這是一個最簡單的Starling Sample:StarlingTest
StarlingTest.as

package
{
	import flash.display.Sprite;

	import starling.core.Starling;

	[SWF(frameRate="60",Width="800",Height="600")]
	public class StarlingTest extends Sprite
	{
		public function StarlingTest()
		{
			var star:Starling = new Starling(Main, stage);
			star.start();
		}
	}
}

Main.as

package
{
	import starling.core.Starling;
	import starling.display.MovieClip;
	import starling.display.Sprite;
	import starling.textures.Texture;
	import starling.textures.TextureAtlas;

	public class Main extends Sprite
	{
		[Embed(source = 'test.xml', mimeType = 'application/octet-stream')]
		private var AtlasXML:Class;

		[Embed(source = 'test.png')]
		private var AtlasTexture:Class;

		public function Main()
		{
			var texture:Texture = Texture.fromBitmap(new AtlasTexture());
			var xml:XML = XML(new AtlasXML());
			var atlas:TextureAtlas = new TextureAtlas(texture, xml);

			var mc:MovieClip = new MovieClip(atlas.getTextures("run"),30);
			addChild(mc);

			Starling.juggler.add(mc);
		}
	}
}

全新的影格運作方式

從上面的Code來看,Flash programmer似乎會覺得好像和原本的程式幾乎一模一樣,其實這是Staring刻意希望讓程式師可以無痛學習Starling,刻意去這樣設計的。在很像的外表下,若我們使用Starling去建置我們的flash程式,不論在影格、圖形渲染方式、碰撞偵測方式、事件傳遞方式等。其實與原生程式,在根本上是完全不一樣的東西。也因為在基本概念上就有很大的不同(starling是以3D去模擬2D的環境,而原有的Flash則是完全使用CPU去做畫面的運算)。我建議所有Flash的開發者還是要以全新的角度去學習這套framework,並且要了解其根本的運作原理,這樣在操作上才不會被它與原生語言的不同之處搞混淆。

因此我們要知道,上面範例裡面的starling.display.MovieClip與原生的flash.display.MovieClip在本質上便已經是完全不同的東西了。在表現的圖層上也並不相同,下圖是圖層的示意圖:
螢幕快照 2014-02-01 下午11.45.51
從上圖可以看到,所有原來我們用flash.display.*去產生的畫面,一律會被放在最上面那層的『Display List』,而所有stage3D(在這裡也就是Starling)的物件則會放在它下面。另外StageVideo則是可以使用GPU去播放的影片,則會放在最下面一層。

這也可以看出,若是想要採用starling去開發你的應用程式,不太可能混合starling和原生的flash DisplayObject一起使用,因為原生的flash所產生的畫面會永遠的被放在starling之上(請見註一)。另外,若是使用starling,在嵌入swf至網頁時,一定要將wmode設成direct,starling不支援透明的嵌入方式,否則會跳出如下圖的錯誤訊息。

螢幕快照 2014-02-07 下午2.42.20

另外,雖然Starling很多類別的名稱或屬性都很相似,或者一樣,但用法其實也是有很大的不同。這邊是Starling的API手冊:Starling Framework Reference

註一:
我們可以利用nativeOverlay將原生的flash的displayObject放到starling的場景上。
請見下面的範例,下面範例是如何在starling裡加入可打字的文字框的方式。

var textInput:flash.text.TextField = new flash.text.TextField();
textInput.type = TextFieldType.INPUT;
Starling.current.nativeOverlay.addChild(textInput);

因為starling的textField本身是不能直接設定為可打字的,因此如果想要在場景上加一個可輸入文字的文字欄位,這邊有很詳細的方法介紹:Text Input with Starling framework
不過要注意,使用nativeOverlay所加進場景裡的物件,也是永遠會在最上層。下面是官網對於Native overlay的說明:

Sometimes you will want to display native Flash content on top of Starling. That’s what the nativeOverlay property is for. It returns a Flash Sprite lying directly on top of the Starling content. You can add conventional Flash objects to that overlay.

Beware, though, that conventional Flash content on top of 3D content can lead to performance penalties on some (mobile) platforms. For that reason, always remove all child objects from the overlay when you don’t need them any longer. Starling will remove the overlay from the display list when it’s empty.

參考資料

Posted on 1 Comment

Stage3D運作原理

本文為此文章的中文重點翻譯:How Stage3D works

3D技術的突破

在過去幾年中,開發人員已經用FLASH創造了許多3D工具,如Papervision3D,Away3D和Alternativa3D,以及所有類似的3D引擎,顯示Flash對即時3D渲染的強烈需求。

過去Flash 3D的渲染是在不使用3D硬件加速的情況下進行的。 事實上,所有在Flash Player 11之前版本的3D渲染是依靠CPU的完成,我稱之為軟件模式(software mode)。 軟件模式是緩慢的,不能用來呈現細緻的3D場景。 到目前為止,軟件模式不能渲染出我們今天3D遊戲中常見的高級的圖形效果。

隨著Flash Player 11的發布,新的可能性已被實現。 開發人員可以利用3D硬件(顯卡)加速,而不是僅僅依靠計算機的CPU渲染。在新的渲染模式中Flash可以使用一個被稱為圖形處理單元(GPU)的副處理器。 GPU是設計完全用來圖形渲染的物理硬件。Stage3D API的公佈對Flash開發者是一個重大的事件。 在Flash中使用3D加速,使許多以前不能實現的Flash遊戲和Flash應用成為可能。

回顧過往,硬件加速的來到,永遠改變了世界上3D編碼方式。 遊戲質量和複雜性成倍增加。 硬件加速使得3D遊戲畫面渲染能力大大提高,迅速的渲染複雜的模型,逼真的效果,低延遲的遊戲體驗都成為可能。

使用3D硬件加速(hardware acceleration)

3D硬件加速利用現代普通PC就包含的GPU進行渲染。 GPU完全致力於圖形渲染和呈現3D內容的任務。通過這種方法,各類軟件以及你的Flash應用程序,只需要定義一個3D場景。 通過將3D場景定義數據送到GPU,GPU就能渲染出指定場景。 這個過程比使用軟件模式(software mode)通過CPU渲染3D內容快得多。

下面我們將花點時間比較軟件模式(software mode)和硬件模式(hardware mode)渲染的差異。

一般來說3D場景定義為一組3D幾何形狀或稱網格(meshes)。 每個幾何形狀又是一組三角形,對於每個三角形,又是一個由3個頂點組成的集合。 因此,一個3D場景只需要定義一個頂點集和一些相關的渲染信息,例如紋理或頂點著色。當您使用以前的軟件模式(software mode)時,3D引擎(如Away3D)就會收到這個頂點流。 它會計算三角形的屏幕位置,然後逐個通過一些填充操作(drawTriangles(),fill()) 驅動Flash Player在舞台上顯示這些三角形。即使3D引擎編碼優秀,這個過程仍然是極其緩慢的。 在某些情況下渲染的結果還不是特別準確。 3D內容顯現是按每個三角形為最小單位,而不是每個像素。 這將引起深度排序錯誤。 渲染後的三角形有時會出現在錯誤的地方或在錯誤的深度上。

在可接受的腳本運行幀數下,Flash Player 10軟件模式(software mode)通常呈現最多4000三角形的場景。

使用最新的Stage3D API後。 在3D硬件加速下開發者只需定義幾何形狀,然後將數據傳遞到GPU。 幾何形狀將到上載到GPU顯存(這片數據記憶空間充當GPU數據存儲空間)。 GPU將處理接收到的數據,完成渲染3D內容的整個工作。

由於只需要將渲染參數上載到GPU,基於此的應用將變得更有效。 例如:程序只需要在三維場景中指定觀測點(3D場景中攝像機位置),設置場景中的燈光位置以及其他影響3D呈現對象的細節。接收上載數據後, 它通過從分析頂點流開始,開始一個接一個渲染(由頂點流描述)三角形。 GPU將渲染最終在用戶屏幕上顯示的圖像,這一切步驟都是封閉在顯卡物理硬件內部完成的。

GPU的渲染速度遠遠高於CPU的軟件模式(software mode)。 這是因為GPU設計的重點著眼於一個非常具體的任務:計算頂點集和渲染由頂點集合所表述的三角形。由於這是一個非常具體的任務,3D硬件渲染過程是非常高效迅速的。相比之下CPU是通用處理器。 它不對呈現三角形的具體任務進行優化。因此軟件模式要低效的多。

通過統計對比,使用硬件加速渲染包含幾百萬個三角形的情況並不在少數。 相比在軟件模式(software mode)下提供的4000個三角形可是一個顯著的改善

3D rendering pipeline

3D rendering pipeline的作用是將渲染操作轉化為一組基本數據操作。GPU邏輯上由許多功能明確的功能區塊組成,每一塊對應著某種基本數據操作。在一條流水線中,這些區塊設置為一連續的操作,也就是說上一個區塊的輸出結果作為下一個區塊的輸入。最簡單的3D圖形渲染管線被叫做固定功能管線。稱之為固定是有原因的,因為該管線是不可不可編碼的,固定管線所以顯得有些僵化,因為它只是把輸入的形狀數據經過管線(一系列級聯的區塊)處理後成為用來顯示的最終圖像。

螢幕快照 2014-01-30 下午1.03.12

固定功能管線以以下參數作為輸入:幾何描述(頂點集合和三角形)、幾何形狀所應用的紋理數據、3D場景的幾何結構位置和方向,攝像機的位置和方向,光線數據(每組光線的顏色、位置、強度等等數據),和一些設置管線如何渲染呈現的額外參數。換句話說,你只要提供頂點集合、三角形、紋理數據,硬件就可以完成渲染。固定功能管線通過一個坐標變換和光照區塊(transform and lighting),把頂點集合從模型(model)本地坐標轉換為屏幕舞台坐標。這個區塊也負責處理頂點照明,緊接著的區塊是視角剪裁區塊(viewport clipping),主要負責對上一個區塊處理後場景數據進行剪裁(關係到是否參與此區塊以後的渲染和是否在可見等)以符合實際顯示視角的需要。

這部份的3D運算原理的詳細說明,可看這篇文章:初探Stage3D(一) 3D渲染基礎原理

經過處理和剪裁場景數據將送入下一個被稱為光柵器(rasterizer)的區塊,這個區塊除了執行紋理映射(texture mapping),也對模型進行霧化,透明通道混合效果和以深度排序的順序呈現三角形像素所需的深度緩衝測試。固定功能管線已經應用多年,但隨著時間的推移渲染過程僵化的缺點就暴露出來。 特別是關於光照的處理,渲染被限制使用標準著色器模型,如基本Goraud和Phong著色模型。 固定功能管線不夠靈活以至於開發人員不能添加更多創造性和有趣的效果, 在管線的渲染下大多數產品效果看上去是相似的。

隨著技術發展,可編碼圖形渲染管線被開發出來,下面是可編碼圖形渲染管線的邏輯流程圖:

螢幕快照 2014-01-30 下午1.03.21
頂點著色器(Vertex Shader)和片段著色器(Fragment Shader)的引入帶來了巨大的變革。當你使用可編碼渲染管線時,開發者可以寫一些被稱之為著色器(Shaders)的代碼片段,這些代碼片段將會影響管線中的渲染過程。

著色器的應用這一看似小小的改變,使得3D渲染髮生了天翻地覆的變化,通過編寫影響頂點轉換和修改的頂點著色器(Vertex Shaders)和填充三角形每個像素呈現的片段著色器(Fragment Shaders),我們將有能力創造之前無法體驗的美妙效果。例如:使用著色器你運用各種光照手段甚至自定義有特性的應用,而不是使用預設的管線照明模型。 著色器使模型陰影成為可能,並加速了骨骼系統,很酷的效果也變得司空見慣了。

使用Stage3D的優勢

開始創建一個基於DirectX和OpenGL的3D應用程序不是一件容易的事。 的確渲染一個簡單的三角形是十分容易的,但使用C++編寫一個成熟的3D應用程序則需要相當的技巧。 對於經驗尚淺的程序員來說無疑是很艱巨的任務。創建一個本地3D應用程序的困難之一是使用標準的DirectX和OpenGL API。為了保證利用圖形硬件的全部能力,項目必須支持全部硬件特性的選項。

原生API是專門針對硬件的。項目的開發工作不得不包括對特定GPU性能的優化(如同現在的遊戲開發商要同時支持nVIDIA和ATI顯卡一樣).通過大量的調整代碼,使項目能夠充分發揮硬件的強大能力。這對開發者是很有誘惑的,因為你將憑藉最強大的硬件創造最絢麗的特效.但同時這也意味著,應用程序必須進行調整和測試以適應不同的硬件。

在使用Stage3D工作時情況並非如此。開發者只需面向Stage3D對象如Context3D和Program3D編程,你創建的應用程序將運行在每一個支持Flash Player或AIR的平台上。

在某種程度上,Stage3D比原生API更抽象也離特定硬件更遙遠一點。 因此Stage3D更容易使用,這一點當然也是能算是一種缺點,為了多平台性,Stage3D不得不放棄針對特定硬件編碼。這樣做的一大好處是:使用Stage3D可以用同一個應用程序把3D硬件加速和功能強大且易用的普通2D FLASH創作結合起來.

一個基於原生API的3D應用,2D UI往往需要定製的解決方案,很少有像FLASH這般靈活的創作工具。在新API下,原先的2D顯示對象和Stage3D對象可以共存。 所以你會保留所有Flash的優點同時你也可以使用經過3D渲染的內容。 開發者可以選擇創建一個由3D場景作為背景的應用,也可以將3D對象嵌入往常的2D內容中

Stage3D應用可以運行在多種平台。 Stage3D也被應用於AIR應用程序中就像由Flash Player運行一樣。此功能意味著開發者可以使用Stage3D創建桌面3D應用程序(AIR)就像開發標準3D的PC遊戲一樣。 在iOS和Android移動平台上亦可使用相同的代碼。

認識Stage3D的限制

主要缺點是針對多平台開發應用程序的能力。 由於使用一個統一的基於多平台API,Stage3D無法應用當下最先進的3D圖形渲染特性。為了確保應用程序可跨多平台,Stage3D必須針對一個抽象的3D硬件設備操作,而為了面面俱到這個抽象層硬件僅僅包含所有硬件圖形特性的公共部分。例如:現代GPU支持Shader Model(頂點和片段著色器使用的標準)4.0版。 然而Stage3D僅僅支持Shader Model 2.0版本。

這代表當我們使用Stage3D編碼時將會遇到一些限制,各個不同的GPU可能有其擅長的優勢,這些將不會被使用到。 例如: AGAL可以使用的著色寄存器將相當有限。 您可以使用最多8個臨時寄存器,而基於Shader Model 4.0的GLSL最多可使用的寄存器為4096個。

Stage3D著色器代碼長度只能包含最多200操作碼,而Shader Model 4.0支持4096個。又如 Shader Model3.0和4.0支持循環和條件語義,而Stage3D不支持。換句話說,Stage3D著色器代碼設計的將是比較簡單的程序,而不是面向更先進的硬件和Shader Model的編碼。 因此在今天的AAA遊戲中使用的著色器代碼和一些高級效果可能無法應用於Stage3D。

另外Stage3D的技術在下面這些平台上可能無法正常運作:Stage3D unsupported chipsets, drivers | Flash Player 11, AIR 3

Stage3D:舞台背後的「舞台」

螢幕快照 2014-01-30 下午10.41.32

一組Stage3D舞台位於主Flash舞台後面。 這意味著每個Stage3D創建3D內容分別呈現在各自的Stage3D的矩形視野中,而普通2D 顯示對象都呈現在3D內容上面。 你可以試想如何兩全其美:你應用3D場景渲染使用硬件加速,而2D的顯示對象在最上面(如遊戲UI)。 UI可以使用強大的FLASH直接創建,而不是一些特殊定製的UI創建工具。

開發者可以使用多個Stage3D. 每個Stage3D擁有自己的矩形視界(簡單說就是width,height和x,y)。這意味著你可以在屏幕一部分區域添加一個Stage3D,然後在另一個地方添加另一個,最後傳統的2D顯示對象顯示在最上層。 每一個Stage3D和StageVideo層可以部分(甚至完全)重疊。 然而現在我們的Stage3D版本不支持層與層之間的混合模式。 因此上層的Stage3D覆蓋下層的Stage3D,你只能夠看到頂層和下面一層的未被遮擋部分內容。

參考文章

  1. Stage3D vs WebGL 性能較量
  2. 初探Stage3D(一) 3D渲染基礎原理
  3. Stage3D unsupported chipsets, drivers | Flash Player 11, AIR 3
  4. How Stage3D works
Posted on

hasEventListener()與willTrigger()區別

承上一篇介紹Event事件流的基本概念
AS3的事件傳遞機制(Event、dispatchEvent及addEventListener)
再來介紹相關的檢查函數。

hasEventListener()方法:
檢查 EventDispatcher 對象是否為有註冊這個事件的監聽器。
willTrigger()方法:
檢查是否用此 EventDispatcher 對象或其父容器是否有註冊這個事件的監聽器

hasEventListener() 與 willTrigger()的區別是:hasEventListener() 只檢查它所屬的對象
而 willTrigger() 檢查對象以及對象的父容器是否有註冊這個事件(不管capture的值)。

假如像下面這樣的物件階層來說

efAzj

今天我們對stage註冊事件

stage.addEventListener(MouseEvent.CLICK, stageClick);

則檢查box的willTrigger及hasEventListener

trace(box.willTrigger(MouseEvent.CLICK));
trace(box.hasEventListener(MouseEvent.CLICK));

的結果為
true
false

而若我們對box註冊事件

box.addEventListener(MouseEvent.CLICK, stageClick);

則檢查box的willTrigger及hasEventListener

trace(box.willTrigger(MouseEvent.CLICK));
trace(box.hasEventListener(MouseEvent.CLICK));

的結果為
true
true

而若我們對box註冊事件

box.addEventListener(MouseEvent.CLICK, stageClick);

則檢查stage的willTrigger及hasEventListener

trace(stage.willTrigger(MouseEvent.CLICK));
trace(stage.hasEventListener(MouseEvent.CLICK));

的結果為
false
false
代表box不在stage完整可能有的事件流的動線裡。