什麼是Routing?
Routing意指路由器,也就是由一個路由器來決定現在要顯示的頁面是什麼
在套用Routing時,會有下列的實踐流程
1. 套用轉址設定(讓伺服器不去真正網址所在的位置去讀取資料,而改由Routing來決定現在要顯示什麼畫面)
2. 由url分析要顯示的狀態是什麼
3. 由狀態去獲得真正要取得那些資訊
4. 從這些資訊組成實體
5. 套用導覽動作,由這個畫面切換至另一個畫面
在Angular裡,最佳做法是將載入和設定Routing放在一個top-level的模組內,並於AppModule內來import所有的路由資訊。
按照慣例,模組AppRoutingModule
和app-routing.module.ts
會放在src/app
裡
Angular的Routing 產生的虛擬 URL,並不是真的存在於檔案系統裡,因此需要伺服器能夠支援,否則重新整理時會出現404 not found。
新增AppRoutingModule
透過下列CLI的指令來新增一個Routing
ng generate module app-routing --flat --module=app
--flat
的意思是將產出文件放在src/app裡,而非自己一個資料夾
--module=app
則是告知CLI註冊這個Routing在AppModule的imports裡
新產生的src/app/app-routing.module.ts檔案內容如下:
import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; @NgModule({ imports: [ CommonModule ], declarations: [] }) export class AppRoutingModule { }
一般我們不會在Routing裡宣告元件,因此可以將@NgModule.declarations及CommonModule的宣告刪除
通常我們會使用Routes與RouterModule來實做Routing,修改後的檔案如下:
import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; @NgModule({ exports: [ RouterModule ] }) export class AppRoutingModule {}
增加Routes
此時我們來設定不同路徑要導向的位置,如下面的程式碼
import { HeroesComponent } from './heroes/heroes.component'; const routes: Routes = [ { path: '', redirectTo: '/dashboard', pathMatch: 'full' }, { path: 'heroes', component: HeroesComponent }, { path: 'detail/:id', component: HeroDetailComponent } ];
上述程式碼代表在網址為http://localhost/heroes時,會在標籤內顯示HeroesComponent這元件的內容。
另外,也要設定當伺服器剛運行時(http://localhost/),要顯示的模組。
設定完Router的map後,將之設定進RouterModule.forRoot()裡
然後再將這整個Router功能設定為可以被export,之後便可以在app.module裡import這個Router
import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; import { DashboardComponent } from './dashboard/dashboard.component'; import { HeroesComponent } from './heroes/heroes.component'; import { HeroDetailComponent } from './hero-detail/hero-detail.component'; const routes: Routes = [ { path: '', redirectTo: '/dashboard', pathMatch: 'full' }, { path: 'dashboard', component: DashboardComponent }, { path: 'detail/:id', component: HeroDetailComponent }, { path: 'heroes', component: HeroesComponent } ]; @NgModule({ imports: [ RouterModule.forRoot(routes) ], exports: [ RouterModule ] }) export class AppRoutingModule {}
而detail/:id裡的:id可於HeroDetailComponent裡去取得,來做進一步更詳細的資料顯示
取得方法如下:
ngOnInit(): void { this.getHero(); } getHero(): void { const id = +this.route.snapshot.paramMap.get('id');//用route.snapshot.paramMap.get取得Routing時傳入的變數 this.heroService.getHero(id) .subscribe(hero => this.hero = hero); }
我們可以發現,例子中不同的path為所傳入的參數不同,它們代表不同的意義,可以更多元化的設定Routing的功能。Routes可傳入的參數有下面這些
interface Route { path?: string //瀏覽器上方的網址列的字串 pathMatch?: string //當導航至此網址時要顯示的元件 matcher?: UrlMatcher //網址列過濾器 component?: Type<any> redirectTo?: string //要轉址到那邊 outlet?: string canActivate?: any[] canActivateChild?: any[] canDeactivate?: any[] canLoad?: any[] data?: Data //要傳入元件裡的資料 resolve?: ResolveData children?: Routes loadChildren?: LoadChildren runGuardsAndResolvers?: RunGuardsAndResolvers }
在這邊可看一下APP_BASE_HREF的設定方式
如果沒有設定,會跑出錯誤訊息如下:
另一個簡單的方式則是在index.html增加下面這行,也可以解決這個錯誤
<base href="/">
在src/app/app.component.html中增加這個導航功能
<h1>{{title}}</h1> <router-outlet></router-outlet>
利用routerLink來增加導航用超連結
修改src/app/app.component.html如下:
<h1>{{title}}</h1> <nav> <a routerLink="/heroes">Heroes</a> </nav> <router-outlet></router-outlet>
如果要回上一頁則使用
goBack(): void { this.location.back(); }
這篇文章的範例檔案可由此觀看: live example / download example。
參考資料
[新手教程-5] 建立Service
這邊是上一篇Angular的主從元件開發的範例檔案:按此下載
創建 HeroService
使用Angular CLI創建一個名為hero的服務
ng generate service hero
我們會看到在src/app下多出了兩個檔案:hero.service.spec.ts和hero.service.ts
打開src/app/hero.service.ts可以看到下面內容
import { Injectable } from '@angular/core'; @Injectable() export class HeroService { constructor() { } }
注意到我們用@Injectable() 來宣告HeroService這個類別,代表這個類別可能本身有依賴注入,對Service來說是強烈建議要加上這個宣告
將HeroService提供給app使用
Service可以供appModule、或任何Component使用,如果要給appModule使用,
則需在src/app/app.module.ts的@NgModule裡加入
providers: [ HeroService ],
這邊有更多NgModule的說明:NgModule
另外,若要使用CLI來自動完成providers的設定,則可以用下面的指令
ng generate service hero --module=app
修改HeroesComponent去使用HeroService裡的資料
打開src/app/heroes/heroes.component.ts,修改成以下的內容
import { Component, OnInit } from ‘@angular/core’;
import { HeroService } from ‘../hero.service’;//1. 增加HeroService並移除HEROES
import { Hero } from ‘../hero’;
@Component({
selector: ‘app-heroes’,
templateUrl: ‘./heroes.component.html’,
styleUrls: [‘./heroes.component.css’]
})
export class HeroesComponent implements OnInit {
heroes: Hero[];//2. 在這邊先不設定內容
selectedHero: Hero;
constructor(private heroService: HeroService) { }//3. 宣告注入的service
getHeroes(): void {
this.heroes = this.heroService.getHeroes();//4. 取service內的資料放進變數內
}
ngOnInit() {
this.getHeroes();//5. ngOnInit會在初始化元件時被呼叫,在此時去取得heroes的值
}
onSelect(hero: Hero): void {
this.selectedHero = hero;
}
}
讓getHeroes被更動時能夠被通知
Observable是RxJS library中很重要的一個功能。
當我們在src/app/hero.service.ts的getHeroes方法回傳值前面加上Observable宣告,當service內的資料變動時,其他注入的內容也會同步被異動
首先要先import下面兩個檔案
import { Observable } from 'rxjs/Rx'; import { of } from 'rxjs/observable/of';
然後在getHeroes的回傳直類型前加上Observable宣告
getHeroes(): Observable<hero[]> { return of(HEROES); }
注:若使用HttpClient.get<Hero[]>()亦會傳回Observable<Hero[]>,只是內容是由http傳來
在接收Observable物件時的方法也與非Observable物件的方式不同,過去若非Observable物件時,在hero.component.ts裡的getHeroes函數如下
getHeroes(): void { this.heroes = this.heroService.getHeroes(); }
若要使用Observable宣告則須改為:
getHeroes(): void { this.heroService.getHeroes() .subscribe(heroes => this.heroes = heroes); }
Observable.subscribe()是最關鍵的相異之處
最大的差異在於我們送出修改到伺服器傳回回應之間,未使用Observable.subscribe()方法時,它不會先凍結UI不讓使用者修改,而有可能會造成資料的不一致。而使用Observable.subscribe()可以避免這個問題。
本日範例下載: live example / download example
[新手教程-4] Angular的主從元件開發
創立hero-detail元件
在前一篇新手教程3-使用angular的迴圈及判斷式等功能裡,我們在顯示selectedHero的資訊時是與列表寫在同一個頁面
但如果顯示詳細資訊的地方有需要額外拆分出來,可以在創立一個元件,並將selectedHero傳入元件
ng generate component hero-detail
寫入hero-detail的內容
開啟檔案src/app/hero-detail/hero-detail.component.html,這邊會將selectedHero的名稱改為hero
<div *ngIf="hero"> <h2>{{ hero.name | uppercase }} Details</h2> <div><span>id: </span>{{hero.id}}</div> <div> <label>name: <input [(ngModel)]="hero.name" placeholder="name"/> </label> </div> </div>
讓元件能接受外部傳送物件進來
開啟src/app/hero-detail/hero-detail.component.ts
import { Hero } from '../hero';
在hero-detail.component.ts裡面,hero一定要以@Input來宣告這個物件
@Input() hero: Hero;
而在HeroesComponent裡,則會以下面的宣告來將hero的值傳入
<app-hero-detail [hero]="selectedHero"></app-hero-detail>
現在我們打開heroes.component.html,修改後的網頁內容會如下
<h2>My Heroes</h2> <ul class="heroes"> <li *ngFor="let hero of heroes" [class.selected]="hero === selectedHero" (click)="onSelect(hero)"> <span class="badge">{{hero.id}}</span> {{hero.name}} </li> </ul> <app-hero-detail [hero]="selectedHero"></app-hero-detail>
今日練習的範例連結:live example / download example
[新手教程-3] 使用Angular的迴圈及判斷式等功能
延續上一篇的範例: 請按此下載.
利用*ngFor來做迴圈顯示完整列表
首先開啟src/app/heroes/heroes.component.ts
設定一個變數heroes
heroes: Hero[] = [ { id: 11, name: 'Mr. Nice' }, { id: 12, name: 'Narco' }, { id: 13, name: 'Bombasto' }, { id: 14, name: 'Celeritas' }, { id: 15, name: 'Magneta' }, { id: 16, name: 'RubberMan' }, { id: 17, name: 'Dynama' }, { id: 18, name: 'Dr IQ' }, { id: 19, name: 'Magma' }, { id: 20, name: 'Tornado' } ];
接著開啟app.component.html,利用*ngFor來迴圈式的顯示列表內容
<ul class="heroes"> <li *ngFor="let hero of heroes"> <span class="badge">{{hero.id}}</span> {{hero.name}} </li> </ul>
這時網頁上就可以看到成果如下圖:
更多資訊有關於ngFor
使用(click)來設定觸發事件
開啟src/app/heroes/heroes.component.ts,在li裡面增加click的事件
<li *ngFor="let hero of heroes" (click)="onSelect(hero)">
在src/app/heroes/heroes.component.ts增加處理的函數
selectedHero: Hero; onSelect(hero: Hero): void { this.selectedHero = hero; }
以條件式去增加元件的類別
打開heroes.component.html,在li內增加 [class.要增加的類別名稱]=”條件式為true時增加”
<li *ngFor="let hero of heroes" [class.selected]="hero === selectedHero" (click)="onSelect(hero)"> <span class="badge">{{hero.id}}</span> {{hero.name}} </li>
這樣當hero === selectedHero為真時,這個li就會被加上selected這個類別
接下來再到src/app/heroes/heroes.component.css設定該類別的CSS,就能突顯現在所選擇的是那一個了
.selected{
color:red;
}
[新手教程-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
- selector: the components CSS element selector以及在HTML裡要宣告的TAG名稱
- templateUrl: 要使用的HTML樣版位置
- 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 [(ngModel)]="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.
[新手教程-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的設定檔。 |
Starling簡報分享
Starling簡介
- 基於Stage3D技術來實作
- 在Flash Player 11之後的版本才能支援此技術
- 使用GPU做圖形的運算,讓Flash的效能能夠到之前的1000倍(官方說法)!
- 易學,使用跟Flash native API類似的類別,方法,架構等,讓原本熟悉Flash的開發者可以很快的上手可發布到多種平台(包括 iOS andAndroid及各種瀏覽器)
3D畫面運作原理
3D透視變換方法
Stage3D的渲染過程
VertexShader 主要作用就是3D流程中的前半段操作(對頂點進行一系列的矩陣變換)
FragmentShader:對這些變換後的頂點(及流程中的光柵化部分)進行渲染
過去主要的3D技術
- 使用GPU的3D引擎:硬件加速(hardware acceleration)
- DirectX
- OpenGL
- 其他Flash3D引擎:軟件模式(software mode)
- Papervision3D
- Away3D
- Alternativa3D
Starling的渲染方式
剩的請自行看投影片….
UI進化論-行動裝置使用者介面設計
此文為閱讀此書的讀後心得:http://www.books.com.tw/products/0010471021
閱讀想法
這本書算是為專業的產品設計師所寫的,會講到許多有關於如何管理一個專業的設計團隊、制定開發流程、設計師頭銜討論,以及設計師如何訓練自己的藝術感等。並且也有說到一些相關電腦知識,例如掌上型行動設備的基礎知識之類。主要是以設計師的角度,去探討該如何去成為一個產品經理,然後開發一個產品。
也因為此書完全是以設計師角度去撰寫的,我是程式師,以想了解怎麼設計行動裝置的角度去看此書,很多地方會因身份角度不同而較無意義,不過或許對於設計師而言是一本很有意義的書。
重點筆記
使用者如何看待產品:這邊告訴我們使用者會怎樣看待我們的產品
如何將設計商品化
- 做市場需求的觀察:包括人口特徵、使用行為、利潤潛力、價值觀、需求、動機、購買因素、態度、產品使用場合、地理位置
- 使用者研究:目標族群的身份、使用場合、怎樣會讓使用者感覺這是個好商品、為使用者和產品間建立感情的聯繫(例如遊戲打寶,因為有感情因素,使用者會願意花時間去練功)、觀察使用者想買這個APP的目的,要能符合他們想像中的目的。
- 研究目標市場的文化內涵
使用者分析與研究
分析方法
當我們想要做一個行動介面的產品設計圖,除了美術的畫面及色彩設計外,對使用者的分析及研究也非常重要,這一篇是這本書裡我覺得最喜歡的,它提供我們怎麼去設計一個行動介面的動線的方式。在此介紹如下:
- 任務分析法:把特定的任務分成好幾個階段,先想好自己的APP想要提供給使用者那些功能,然後把特定的功能分解成多個步驟。例如像穿襯衫,可以分解為:雙手抓住襯衫領子>把襯衫披在肩上>右手穿進袖子裡,從袖口伸出>左手穿進袖子裡,從袖口伸出>把後襟拉平>把左右門襟對齊
這邊也列出一些心智模型工具:物理符號系統、諾爾曼模型、流程認知模型、SOAR模型、心智的社會模型、動力振盪理論模型、大腦協調學。 - 情境設定法:要包含角色和劇情。如在那邊、發生什麼事、怎樣的狀況下會想操作系統,不同情境下會需要不同的設計。例如會議中,靜音模式就很重要,或是在家裡,那就要有輕鬆、方便的感覺。
- 社會性研究法:研究一些社會的事件影響產品的事件。例如使用者的使用心得影響銷售的狀況、或是被影響等等。理解不同地域、文化背景、社會環境中的介面風格。
範例:MP3播放器
如何讓圖型介面更有創意
- 更人性化
- 情感化因素不可忽視:應該要從美學本能和功能主義的瓶頸中跳脫,營造一種感覺,這種感覺能讓使用者把產品和品牌連繫在一起
- 互動特效的引入
- 產品=體驗=品牌
- 臨場的體驗決定購買意願
視覺設計的原則
- 介面清楚明瞭
- 讓機器幫助記憶,減少短期記憶的負擔
- 依賴認知而非記憶。例如列印圖示的記憶等
- 提供視覺線索
- 完善的視覺清晰度
- 介面的協調一致:如手機介面的按鈕排放、左鍵肯定右鍵否定或內容擺放位置
- 色彩與內容:整體設計不要超過五的色系,相近的色系表示相似的意思
制定設計流程
在本書的最後幾章一直在強調設計流程的重要性,其實這有點像程式開發的流程圖的設計師版本…XD
大概就是在強調一致的設計產出流程對設計師而言很重要,可以確保多個產品間的一致性,也可以提高產出效能。總而言之和程式的開發流程方法有點像。流程大概會劃分為十個步驟:
- 制定流程
- 確定工作內容
- 圖示風格:這本書前面有提到在設計圖示的風格上,可以分為兩個部份的會議去討論(也就是3與4)。
第一次的會議採用Brainstorming的方式,Brainstorming的討論方式其實和這篇的原則類似,總之就是不要特別限定某種想法,讓點子越多越好,讓所有人發表所有他們所想的到的可能風格和idea,不去評斷idea的優劣,所有的討論內容越自由越好,隨意的讓點子發想。在會議之後,讓各個設計師去分別設計自己想要的圖示風格及理念想法 - 首次檢查:展開討論設計方向、設計師闡述設計概念、第一次設計評審會議。
然後第二此的會議則和第一次完全相反,由某個人去引導會議,並且由每個人提出前一個會議中提出各個點子的優劣,並由主導者來決定以那個圖示為主。 - 介面風格:定義色彩、解析度、關鍵介面數量、介面元素、通用性等
- 互動特效:定義合適的互動效果、思考如何更好的表現互動模型、視覺化介面風格、並要考慮最終實現的難度
- 介面設計:設計師分別獨立完成
- 準備演練展示
- 互動模型:例如用flash去做一個demo檔案
- 最終提案:最後決定要用那一個介面
Intro to Artificial Intelligence
課程網址:https://www.udacity.com/course/viewer#!/c-cs271
什麼是Intelligent Agent
人工智能代理(Agent)根據環境的感知器(下圖的Sensors)傳入的資料,經過一連串的映設函數(紅箭頭部份),藉由效應器對環境做影響(下圖Actuators)。在裡面紅色箭頭部份是最重要的課題,這稱為代理控制策略。
如上圖這樣的一個決策過程會重覆進行很多次,從環境將資訊透過Sensors傳給Agent,經過代理做出決定,然後用Actuators影響環境,這樣的一個周期稱為perception action cycle。
AI應用範疇
- 財務金融:應用環境可以在股票市場、債卷市場或期貨市場,感知到一些東西的資訊和相關新聞,決策則是買入和賣出。
- 機器人學:這個是研究時間最長的一門ai領域,他的Sensors及Actuators都是與物理環境交互,而更為特殊。
- 遊戲:分兩種,一種是與人類對戰,像是象棋對戰,對Agent來說玩家是環境,它必需觀察玩家的動作,目的是戰勝玩家。另一種是遊戲情境模擬,為了要讓遊戲更自然,讓玩家感覺遊戲世界像真實世界般。
- 醫藥學:可以用在終身醫療上,輸入過去病史,讓它可以幫助判斷未來可能出現的疾病。
- WEB應用:像智能搜索,對語意進行判定,然後幫助找出可能更符合使用者想要的搜尋結果。
術語介紹
- 完全可觀察的環境 vs 部份可觀察的環境(partially)
完全可觀察:例如一些牌類遊戲,當所有牌都已被掀開在桌子上,我們可以看到所有的資訊,可以算出最佳解答。
部份可觀察:像另一些紙牌遊戲,有些牌是掀開的,有些則是未被掀開的。這時就要去觀察並記憶過去曾有的牌型紀錄,和桌上現有的牌,來推算可能是最有利的出牌方式。越多的歷史紀錄可以幫助Agent去做出更正確的推斷。這個循環稱為馬爾可夫模型(Markov Model),我們會廣泛的討論要如何具有下面的這種結構:
- 確定性環境 vs 隨機性環境(stochastic)
確定性環境:Agent所做的結果會產生的影響是否確定。例如像在象棋遊戲中,移動一個棋子的效果是完全可預見的。
隨機性環境:像是大富翁的擲骰子遊戲,雖然所做的決定會影響結果,但是我們無法預期骰子會擲出多少,因此無法完全預見所做決策會影響到的效果。 - 離散環境 vs 連續環境(continuous)
離散環境:有有限多個選擇和可能性,例如象棋遊戲。
連續環境:可做的行動或可能性是無限的,例如丟飛鏢會有無限種角度的可能性與加速方式 - 良性環境 vs 敵對環境(adversarial):環境因素的存在與影響是否剛好與我們所要達成的目標相反?
AI的不確定性
包括感知器的有限、很多時候會忽略掉某些不重要或無法判別的因素、敵對因素的影響、隨機性環境的不可預測因素、可計算的步數有限性等…。而AI的存在就是在處理並控制不確定性以供做出決策的規則。
定義問題
- 初始狀態:一開始的狀態
- 動作狀態:若當Agent處於該狀態時會有那幾種可能性(返回一組該狀態可做行動的序列)
- 結果狀態:一個狀態和一個動作為輸入,一個新的狀態為輸出
- 目標測試函數:是否這個狀態是可達成目標的。
- 路徑成本函數:計算從a狀態到b狀態要花的成本
幾個路徑計算方式
求從上圖的路徑中的A點到B點的最佳路徑的方式有下面這些工具:
- Graph Search vs Tree Search
- Graph
- Tree
- BFS
- DFS
- Best-first Search:在大部份的時後,找到最佳解是最困難的,因此這部份很難實作,有許多文章有在探討相關實作方式。
像上述的這些搜尋方式,是完全不考慮有什麼意外發生的狀態下才有效的。
要使用上面這種路徑搜尋方式,環境必須符合下面幾項條件:
- 搜索域必須是完全可觀察的,換句話說,我們必須具備觀察我們開始的初始狀態的能力
- 域必須是可知的,我們必需知道我們可採取的行動的集合
- 必須為離散域,可選擇的行動的數量必需是有限的
- 域必須是具有確定性的,必須知道採取某一行動所產生的結果
- 域必須是靜態的,除了我們自己的行動以外,域中不可以存在任何可以改變它的東西
在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
貝葉斯網絡可以簡潔地表示一個聯合概率分佈狀況,如下圖可表示一個汽車壞掉可能原因的貝葉斯網路圖,我們觀察一些面板數值,然後去推斷可能的原因的發生機率,再去做交叉比對,這樣就可以列出一個概率分布圖。
機率學相關概念:互補事件、獨立性事件(任意兩個變量的聯合概率是兩個機率的乘積)、貝葉斯法則
貝葉斯公式
P(A,B) = P(A|B) P(B)
P(A|B) = P(B|A) P(A) / P(B)
經過如下的推導
可得知P(A,B|C) = P(A|B,C) P(B|C)
這邊有相關的理論說明:條件機率與貝氏定理
是在探討今天若心情很好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.
產生TextureAtlas素材的方式
方法一、使用TexturePacker
軟體官網:http://www.codeandweb.com/texturepacker
範例圖檔下載:woman
首先,要先把圖檔整理成多個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