Posted on Leave a comment

[新手教程-2] 創立Angular的元件

使用CLI來為專案建立一個元件

ng generate component heroes

用這個指令,CLI會為我們初始化一個新的元件樣版
這時我們開啟app/heroes/heroes.component.ts

import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-heroes',
  templateUrl: './heroes.component.html',
  styleUrls: ['./heroes.component.css']
})
export class HeroesComponent implements OnInit {

  constructor() { }

  ngOnInit() {
  }

}

只要創建元件,都必需從Angular去import Component。
而@Component則是用來定義這一個元件的相關資訊,有三個metadata

  1. selector: the components CSS element selector以及在HTML裡要宣告的TAG名稱
  2. templateUrl: 要使用的HTML樣版位置
  3. styleUrls: 專為這個元件設定的CSS

要注意的是,我們通常會使用export class,以方便在其他的模組裡可以import來使用

修改元件內容

打開heroes.component.ts

import { Component, OnInit, ViewEncapsulation } from '@angular/core';

@Component({
  selector: 'app-heroes',
  templateUrl: './heroes.component.html',
  styleUrls: ['./heroes.component.css'],
  encapsulation: ViewEncapsulation.None
})
export class HeroesComponent implements OnInit {
  hero = 'heroes works!';//增加一個變數
  constructor() { }

  ngOnInit() {
  }

}

修改heroes.component.html,使用{{hero}}來顯示剛剛在TS檔裡定義的變數

<h1>{{hero}}</h1>

將元件放進頁面裡

打開src/app/app.component.html

<app-heroes></app-heroes>

這時候就可以在頁面中看到剛剛我們所增加的內容

使用物件

創建一個Hero物件
src/app/hero.ts

export class Hero {
   id: number;
   name: string;
}

打開src/app/heroes/heroes.component.ts,給予物件正確的值

import { Component, OnInit } from '@angular/core';
import { Hero } from '../hero';

@Component({
selector: 'app-heroes',
templateUrl: './heroes.component.html',
styleUrls: ['./heroes.component.css']
})
export class HeroesComponent implements OnInit
{
//在這邊設定物件內容
hero: Hero = {
id: 1,
name: 'Windstorm'
};

constructor() { }

ngOnInit() {
}

}

顯示在heroes.component.ts所設定的值



<h2>{{ hero.name }} Details</h2>




<div><span>id: </span>{{hero.id}}</div>




<div><span>name: </span>{{hero.name}}</div>


如果希望將變數格式化
則可以使用


<h2>{{ hero.name | uppercase }} Details</h2>


這個格式化的功能叫做Pipes,更多的說明請見Pipes說明

雙向繫結

Angular一個很方便的功能就是可以支持雙向繫結,使用[(ngModel)]能做到當欄位的值改變時,TS裡變數的值也同時被更改。
這個功能在做表單驗證時非常方便
詳細使用說明請見:NgModules
使用方法: 在src/app/heroes/heroes.component.html加上下面這段

<div>
    <label>name:
      <input &#91;(ngModel)&#93;="hero.name" placeholder="name">
    </label>
</div>

接著要去app.module.ts去加上import資訊讓專案能夠使用ngModel標籤
要注意是在app.module.ts裡喔!
先import並且將FormsModule加進@ngModule的imports列表內,讓下面所有的元件都可以使用FormsModule的功能
import { FormsModule } from ‘@angular/forms’; // <-- NgModel lives here[/code] [code lang="js"]imports: [ BrowserModule, FormsModule ],[/code] 接著,要把剛剛我們所建立的元件HeroesComponent放進@NgModule.declarations裡 [code lang="js"]import { HeroesComponent } from './heroes/heroes.component';[/code] 在app.module.ts的@NgModule增加 [code lang="js"] declarations: [ AppComponent, HeroesComponent ], [/code] 這時,我們會發現我們更動input裡的文字時,model的值也會被更改 今日練習成果下載:live example / download example.

Posted on Leave a comment

[新手教程-1] 建立一個Angular5的專案

這系列的文章為我在官網學習Angular 5時所紀錄下來的學習筆記。
原文的原始教程都可在Angular的Docs看到。

這三十天的筆記大綱預計分為新手教程、功能介紹、技術支援三個部份:

  • 新手教程:一個最簡單的專案,用step by step的方式引導大家去做
  • 功能介紹:一個個介紹Angular裡面各別的功能和特性
  • 技術支援:涵蓋如何佈署、設定以及angular所使用的npm、typescript等的設定

建立專案

確認電腦已有安裝NodeJS(6.9.x以上版本)以及NPM(3.x.x以上版本)

創建專案

ng new my-app

開啟專案

cd my-app
ng serve --open

編輯第一個自己的頁面

打開src/app/app.component.ts,改為

import { Component } from '@angular/core';

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css']
})
export class AppComponent {
    title = '我的第一個網頁';
}

打開src/app/app.component.html,將內容改為

這是 {{title}}!

src資料夾內的檔案架構

檔案 目的
app/app.component. {ts,html,css,spec.ts} 所有的 Componet、Service、Pipe、Unit test 等等..程式碼都是放在這個資料夾,而 app.component 則是 Angular CLI 預設建立的 root component
app/app.module.ts 預設的 root module , 告訴 Angular 有哪些 Components 、Modules、 Services,讓 Angular 知道如何 assemble the application
assets/* 放圖片或者是建立 application 需要用的到材料
environments/* 設定 Angular 程式碼會用到的參數,很像 Web.config 的東西。 預設為 environment.ts , 要產生不同的 environment 的話,參考命名規則為 environment.xxx.ts,在執行或者 build Angular application 的時候加入 xxx 的參數,則可以指定到該 environmnet ,例如 : ng build -xxx、 ng serve -xxx
favicon.ico 網頁頁籤的 icon
index.html 網頁進入點,當使用者拜訪網站的時候,是執行到這個頁面。 在大部分的情況,是不需用編輯的, Angular CLI 在 build application 的時候會自動加入 js 和 css
main.ts 若使用JIT,這個文件為JIT compiler和bootstraps的root module,也就是編譯的起始點。也可以用ng serve –aot,改為AOT編譯而不用修改任何的code
polyfills.ts 因為不同的瀏覽器會支援不同的 web standards, polyfills 就像補丁的概念,補足些沒有支援的部分。Browser Support guide for more information.
styles.css 放置 global styles 的 CSS
test.ts unit tests 的進入點,有些 unit tests 的設定也寫在這邊
tsconfig.{app|spec}.json TypeScript 編譯設定檔(tsconfig.app.json) and for the unit tests (tsconfig.spec.json).

 

根目錄資料夾檔案列表

檔案 目的
e2e/ 負責放 End-to-End 測試程式碼的資料夾
node_modules/ Node.js 建立的資料夾,負責放 third party modules 的資料夾,其 thrid party modules 清單則放在 package.json裡面
.angular-cli.json 放 Angular CLI 的設定檔 Angular CLI Config Schema
.editorconfig 幫助開發者使用不同的 IDEs 保持檔案格式一致性的設定檔。更多資訊請見此
.gitignore Git 的設定檔,讓指定檔案不會 commit 到 Source control
karma.conf.js Karma test 的 unit tests 設定
package.json npm 設定檔, third party 清單與版本資訊
protractor.conf.js Angular end-to-end test framework Protractor 設定檔
README.md 專案基本說明文件
tsconfig.json TypeScript 編譯器設定檔案
tslint.json Codelyzer(用以保持code style的一致性)和TSLint的設定檔。
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

UI進化論-行動裝置使用者介面設計

此文為閱讀此書的讀後心得:http://www.books.com.tw/products/0010471021

閱讀想法

這本書算是為專業的產品設計師所寫的,會講到許多有關於如何管理一個專業的設計團隊、制定開發流程、設計師頭銜討論,以及設計師如何訓練自己的藝術感等。並且也有說到一些相關電腦知識,例如掌上型行動設備的基礎知識之類。主要是以設計師的角度,去探討該如何去成為一個產品經理,然後開發一個產品。

也因為此書完全是以設計師角度去撰寫的,我是程式師,以想了解怎麼設計行動裝置的角度去看此書,很多地方會因身份角度不同而較無意義,不過或許對於設計師而言是一本很有意義的書。

重點筆記

使用者如何看待產品:這邊告訴我們使用者會怎樣看待我們的產品

  1. 合格的產品
    螢幕快照 2014-02-28 下午11.52.28
  2. 優秀的產品
    螢幕快照 2014-02-28 下午11.52.38
  3. 卓越的產品
    螢幕快照 2014-02-28 下午11.52.54

如何將設計商品化

  1. 做市場需求的觀察:包括人口特徵、使用行為、利潤潛力、價值觀、需求、動機、購買因素、態度、產品使用場合、地理位置
  2. 使用者研究:目標族群的身份、使用場合、怎樣會讓使用者感覺這是個好商品、為使用者和產品間建立感情的聯繫(例如遊戲打寶,因為有感情因素,使用者會願意花時間去練功)、觀察使用者想買這個APP的目的,要能符合他們想像中的目的。
  3. 研究目標市場的文化內涵

使用者分析與研究

分析方法

當我們想要做一個行動介面的產品設計圖,除了美術的畫面及色彩設計外,對使用者的分析及研究也非常重要,這一篇是這本書裡我覺得最喜歡的,它提供我們怎麼去設計一個行動介面的動線的方式。在此介紹如下:

  1. 任務分析法:把特定的任務分成好幾個階段,先想好自己的APP想要提供給使用者那些功能,然後把特定的功能分解成多個步驟。例如像穿襯衫,可以分解為:雙手抓住襯衫領子>把襯衫披在肩上>右手穿進袖子裡,從袖口伸出>左手穿進袖子裡,從袖口伸出>把後襟拉平>把左右門襟對齊
    這邊也列出一些心智模型工具:物理符號系統、諾爾曼模型、流程認知模型、SOAR模型、心智的社會模型、動力振盪理論模型、大腦協調學。
  2. 情境設定法:要包含角色和劇情。如在那邊、發生什麼事、怎樣的狀況下會想操作系統,不同情境下會需要不同的設計。例如會議中,靜音模式就很重要,或是在家裡,那就要有輕鬆、方便的感覺。
  3. 社會性研究法:研究一些社會的事件影響產品的事件。例如使用者的使用心得影響銷售的狀況、或是被影響等等。理解不同地域、文化背景、社會環境中的介面風格。

範例:MP3播放器

  1. 定義產品功能:明確定義出產品要有的功能有那些
    螢幕快照 2014-03-02 下午9.49.53
  2. 繪製互動設計流程圖:
    螢幕快照 2014-02-28 下午11.46.40
  3. 繪製介面原型:最簡單的版面元件位置配置
  4. 視覺設計:先設定APP主要要使用的色彩有那些(先配色),然後再繪製介面細節

如何讓圖型介面更有創意

  1. 更人性化
  2. 情感化因素不可忽視:應該要從美學本能和功能主義的瓶頸中跳脫,營造一種感覺,這種感覺能讓使用者把產品和品牌連繫在一起
  3. 互動特效的引入
  4. 產品=體驗=品牌
  5. 臨場的體驗決定購買意願

視覺設計的原則

  1. 介面清楚明瞭
  2. 讓機器幫助記憶,減少短期記憶的負擔
  3. 依賴認知而非記憶。例如列印圖示的記憶等
  4. 提供視覺線索
  5. 完善的視覺清晰度
  6. 介面的協調一致:如手機介面的按鈕排放、左鍵肯定右鍵否定或內容擺放位置
  7. 色彩與內容:整體設計不要超過五的色系,相近的色系表示相似的意思

制定設計流程

在本書的最後幾章一直在強調設計流程的重要性,其實這有點像程式開發的流程圖的設計師版本…XD

大概就是在強調一致的設計產出流程對設計師而言很重要,可以確保多個產品間的一致性,也可以提高產出效能。總而言之和程式的開發流程方法有點像。流程大概會劃分為十個步驟:

  1. 制定流程
  2. 確定工作內容
  3. 圖示風格:這本書前面有提到在設計圖示的風格上,可以分為兩個部份的會議去討論(也就是3與4)。
    第一次的會議採用Brainstorming的方式,Brainstorming的討論方式其實和這篇的原則類似,總之就是不要特別限定某種想法,讓點子越多越好,讓所有人發表所有他們所想的到的可能風格和idea,不去評斷idea的優劣,所有的討論內容越自由越好,隨意的讓點子發想。在會議之後,讓各個設計師去分別設計自己想要的圖示風格及理念想法
  4. 首次檢查:展開討論設計方向、設計師闡述設計概念、第一次設計評審會議。
    然後第二此的會議則和第一次完全相反,由某個人去引導會議,並且由每個人提出前一個會議中提出各個點子的優劣,並由主導者來決定以那個圖示為主。
  5. 介面風格:定義色彩、解析度、關鍵介面數量、介面元素、通用性等
  6. 互動特效:定義合適的互動效果、思考如何更好的表現互動模型、視覺化介面風格、並要考慮最終實現的難度
  7. 介面設計:設計師分別獨立完成
  8. 準備演練展示
  9. 互動模型:例如用flash去做一個demo檔案
  10. 最終提案:最後決定要用那一個介面
Posted on

Intro to Artificial Intelligence

課程網址:https://www.udacity.com/course/viewer#!/c-cs271

什麼是Intelligent Agent

人工智能代理(Agent)根據環境的感知器(下圖的Sensors)傳入的資料,經過一連串的映設函數(紅箭頭部份),藉由效應器對環境做影響(下圖Actuators)。在裡面紅色箭頭部份是最重要的課題,這稱為代理控制策略。
螢幕快照 2014-02-18 下午11.05.25
如上圖這樣的一個決策過程會重覆進行很多次,從環境將資訊透過Sensors傳給Agent,經過代理做出決定,然後用Actuators影響環境,這樣的一個周期稱為perception action cycle。

AI應用範疇

  1. 財務金融:應用環境可以在股票市場、債卷市場或期貨市場,感知到一些東西的資訊和相關新聞,決策則是買入和賣出。
  2. 機器人學:這個是研究時間最長的一門ai領域,他的Sensors及Actuators都是與物理環境交互,而更為特殊。
  3. 遊戲:分兩種,一種是與人類對戰,像是象棋對戰,對Agent來說玩家是環境,它必需觀察玩家的動作,目的是戰勝玩家。另一種是遊戲情境模擬,為了要讓遊戲更自然,讓玩家感覺遊戲世界像真實世界般。
  4. 醫藥學:可以用在終身醫療上,輸入過去病史,讓它可以幫助判斷未來可能出現的疾病。
  5. WEB應用:像智能搜索,對語意進行判定,然後幫助找出可能更符合使用者想要的搜尋結果。

術語介紹

  1. 完全可觀察的環境 vs 部份可觀察的環境(partially)
    完全可觀察:例如一些牌類遊戲,當所有牌都已被掀開在桌子上,我們可以看到所有的資訊,可以算出最佳解答。
    部份可觀察:像另一些紙牌遊戲,有些牌是掀開的,有些則是未被掀開的。這時就要去觀察並記憶過去曾有的牌型紀錄,和桌上現有的牌,來推算可能是最有利的出牌方式。越多的歷史紀錄可以幫助Agent去做出更正確的推斷。這個循環稱為馬爾可夫模型(Markov Model),我們會廣泛的討論要如何具有下面的這種結構:
    螢幕快照 2014-02-19 上午1.10.56拷貝
  2. 確定性環境 vs 隨機性環境(stochastic)
    確定性環境:Agent所做的結果會產生的影響是否確定。例如像在象棋遊戲中,移動一個棋子的效果是完全可預見的。
    隨機性環境:像是大富翁的擲骰子遊戲,雖然所做的決定會影響結果,但是我們無法預期骰子會擲出多少,因此無法完全預見所做決策會影響到的效果。
  3. 離散環境 vs 連續環境(continuous)
    離散環境:有有限多個選擇和可能性,例如象棋遊戲。
    環境:可做的行動或可能性是無限的,例如丟飛鏢會有無限種角度的可能性與加速方式
  4. 良性環境 vs 敵對環境(adversarial):環境因素的存在與影響是否剛好與我們所要達成的目標相反?

AI的不確定性

螢幕快照 2014-02-19 上午1.51.16

包括感知器的有限、很多時候會忽略掉某些不重要或無法判別的因素、敵對因素的影響、隨機性環境的不可預測因素、可計算的步數有限性等…。而AI的存在就是在處理並控制不確定性以供做出決策的規則。

定義問題

  1. 初始狀態:一開始的狀態
  2. 動作狀態:若當Agent處於該狀態時會有那幾種可能性(返回一組該狀態可做行動的序列)
  3. 結果狀態:一個狀態和一個動作為輸入,一個新的狀態為輸出
  4. 目標測試函數:是否這個狀態是可達成目標的。
  5. 路徑成本函數:計算從a狀態到b狀態要花的成本

幾個路徑計算方式

螢幕快照 2014-02-19 下午2.20.59
求從上圖的路徑中的A點到B點的最佳路徑的方式有下面這些工具:

  1. Graph Search vs Tree Search
  2. Graph
  3. Tree
  4. BFS
  5. DFS
  6. Best-first Search:在大部份的時後,找到最佳解是最困難的,因此這部份很難實作,有許多文章有在探討相關實作方式。

像上述的這些搜尋方式,是完全不考慮有什麼意外發生的狀態下才有效的。
要使用上面這種路徑搜尋方式,環境必須符合下面幾項條件:
螢幕快照 2014-02-19 下午2.12.33

  1. 搜索域必須是完全可觀察的,換句話說,我們必須具備觀察我們開始的初始狀態的能力
  2. 域必須是可知的,我們必需知道我們可採取的行動的集合
  3. 必須為離散域,可選擇的行動的數量必需是有限的
  4. 域必須是具有確定性的,必須知道採取某一行動所產生的結果
  5. 域必須是靜態的,除了我們自己的行動以外,域中不可以存在任何可以改變它的東西

在AI中以機率去找出最佳解

貝葉斯概率:http://wiki.mbalib.com/zh-tw/%E8%B4%9D%E5%8F%B6%E6%96%AF%E6%A6%82%E7%8E%87
聯合概率分布:http://zh.wikipedia.org/wiki/%E8%81%94%E5%90%88%E5%88%86%E5%B8%83
貝葉斯網絡可以簡潔地表示一個聯合概率分佈狀況,如下圖可表示一個汽車壞掉可能原因的貝葉斯網路圖,我們觀察一些面板數值,然後去推斷可能的原因的發生機率,再去做交叉比對,這樣就可以列出一個概率分布圖。
螢幕快照 2014-02-19 上午3.15.19

機率學相關概念:互補事件獨立性事件(任意兩個變量的聯合概率是兩個機率的乘積)、貝葉斯法則

貝葉斯公式

螢幕快照 2014-02-19 下午7.55.50
P(A|B) = P(B|A) P(A) / P(B)
P(A,B) = P(A|B) P(B)

經過如下的推導
未命名1
可得知P(A,B|C) = P(A|B,C) P(B|C)

這邊有相關的理論說明:條件機率與貝氏定理

範例題目
螢幕快照 2014-02-19 下午5.37.10

是在探討今天若心情很好P(H)可能原因有天氣好P(S)或是被加薪P(R)
假使天氣好P(S)的機率為0.7
被加薪P(R)的機率為0.01

P(H | S,R) = 1 >> 天氣好且被加薪,心情好機率為1
P(H | ^S,R) = 0.9 >> 天氣不好但被加薪,心情好的機率為0.9
P(H | S,^R) = 0.7 >> 天氣好但沒被加薪,心情好的機率為0.7
P(H | ^S,^R) = 0.1 >> 天氣不好又沒被加薪,心情好的機率為0.1

則求出P( R | H,S)  > 也就是求出在心情好且天氣好的狀況下,是被加薪的機率
下面是好心人在討論版所給的詳解方式

According to Bayes formula p(R|H,S) = p(H,S|R)p(R)/p(H,S) = p(H|S,R)p(S|R)p(R)/p(H,S) (1)
In the second equality we used the analog of formula p(H,S) = p(H|S)p(S) but under definite value of R: p(H,S|R) = p(H|S,R)p(S|R).
Further, p(S|R) = p(R|S)p(S)/p(R). Plugging it in the formula (1) and accounting that p(H,S) = p(H|S)p(S) we get the targeted expression:
p(R|H,S) = p(H|R,S)p(R|S)/p(H|S). It’s the strict formula and should be remembered. It’s easy if you note that this formula is the custom Bayes rule p(R|H) = p(H|R)p(R)/p(H) but under definite value of S of all probabilities in the formula.

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 &amp;&amp; visible &amp;&amp; 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 &amp;&amp; final_y != uint.MAX_VALUE)
					{
						var pixel:uint = m_BitmapData.getPixel32(clipping.x + final_x, clipping.y + final_y);
						if (uint((pixel &gt;&gt; 24) &amp; 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