::senseable.life::

星期一, 11月 08, 2010

Hoberman Associates - Transformable Design - Expanding Video Screen (U2 360?Tour)

Hoberman Associates - Transformable Design - Expanding Video Screen (U2 360?Tour)

星期二, 10月 06, 2009

線上玩家行為分析



一般使用行為


線上遊戲玩家大多還是偏好進行多人線上遊戲(MMOG),其次則為電腦單機遊戲,值得注意的是,電腦單機小遊戲與網頁型遊戲也分別受到近五成與超過三成的玩家青睞,說明不少玩家希望能玩到不用花太多時間進行,並且能夠輕鬆獲得樂趣、讓自己放鬆心情的遊戲。
交叉比對玩家常進行的電腦線上遊戲型態,有58.7%的玩家表示平時只會玩MMOG,另有35%玩家除了MMOG外,也習慣在不同時間、情境下,進行網頁型遊戲或是區域網路連線遊戲。
進一步分析玩家進行線上遊戲的習慣,可發現性別不同、喜好的遊戲型態也不同,女性玩家特別偏好網頁型遊戲,而超過五分之一男性玩家則為區域網路連線遊戲的支持者,此結果與遊戲的內容、類型(genre)有關,目前市面上所見的網頁型遊戲,由於程式設計時的限制,大多為內容、規則、操作上比較簡單的遊戲,較易吸引偏好輕鬆玩遊戲、不注重聲光效果的女性族群;著重於玩家間互相對戰、競爭,內容多為第一人稱射擊(FPS)、即時戰略(RTS)的區域網路連線遊戲,較受男性玩家的喜愛,尤其對於大專男學生而言,與同學、室友一起進行LAN Party,除了可打發時間外,更可謂是促進彼此間情誼的重要活動。
42%的線上遊戲玩家同時為電視遊樂器玩家,其中53.6%會使用支援連線遊戲功能的PS3Xbox 360或是Wii進行遊戲。然而,使用上述主機進行電視遊樂器連線遊戲的玩家仍屬少數,僅佔整體樣本的11%


玩家每次進行線上遊戲時花費時間平均約123分鐘,高於2007年的113分鐘、2006年的119分鐘,並等同於2005年的調查結果,推論與前兩年休閒遊戲風行,許多玩家轉而選擇花費時間較少的遊戲來遊玩,同時也吸引許多輕度玩家加入遊戲,但在2008年話題性風潮過後,玩家挑選、遊玩遊戲時,回歸遊戲本質,只選擇一至兩款自己最有興趣的遊戲,花費較長的時間來遊玩。
受訪玩家中有七成表示,他們每天都會撥出時間來玩線上遊戲,尤其是擁有較多自由時間的大學生,有近半數每天會多次登入遊戲、與其他玩家同樂,玩家維持進行同一款遊戲的期間平均約1.5年,並可依此推估市面上大部分線上遊戲的平均生命周期約1-2年,若遊戲沒有特出之處,玩家大多會在接觸後4-6個月之內放棄、改玩別款遊戲。


消費行為

線上遊戲每月支出近300元,便利商店仍為主要銷售通路

2008年台灣玩家每月支出於線上遊戲的平均金額為298元,較2007年的280元微幅成長,與不消費玩家的比例由40.3%降至33.2%有關,線上遊戲也是玩家線上娛樂消費(含線上音樂、部落格等)中的主要支出項目,平均來說,玩家每月消費於線上娛樂的金額中,有65.2%是支出於線上遊戲。

由於習慣消費於線上遊戲的族群以學生居多,學生習慣透過實體通路購買點數,除了可以免除沒有信用卡的困擾外,也不會像經由電信帳單、轉帳等其他虛擬交易方式,留下帳單、帳戶記錄,避免家長的追問。這樣的現象,說明了大多數玩家選擇便利商店作為購買遊戲點數場所的原因。
雖然玩家大多到便利商店購買點數,但遊戲產包不再是玩家取得遊戲的唯一選擇,2008年調查結果顯示,自行下載遊戲資料已經成為最多玩家偏好的遊戲取得方式,與免費遊戲成為市場主流後,玩家習慣先試玩、再決定要不要消費有關,玩家付出的成本愈低,愈能有效吸引玩家嘗試,因此除了低價產包的銷售外,遊戲下載的機制簡便、速度快、連線穩定,也是能激勵玩家進行試玩的方式。
「免月費、收道具費」之收費方式雖仍受到較多數的玩家喜好,但與2007(66.3%)相比,受到歡迎程度已下降,或許與部分玩家在訪談中表示,目前市面上些許熱門遊戲雖號稱免費遊戲,但若不進行消費、購買虛擬商品,會嚴重的影響到遊戲的進行,造成玩家反感相關。

27%玩家曾進行私下交易,C2C平台為私下交易管道首選

在所有玩家中,有27%玩家曾經進行過私下交易,並另有17%玩家表示若有機會,會嘗試進行私下交易,常進行私下交易的玩家佔4%,每個月平均的私下交易金額約為700元,此族群花費於一般交易的金額也高於其他族群。
當玩家有意進行私下交易時,「C2C交易平台」為大多數人的首選,與其他交易管道相比,交易平台提供較多樣化的選擇,玩家可較方便、快速的找到自己需要的虛擬商品,同時亦可在購買前先行比價,並透過評價機制,自行評估交易的安全性,因而受到較多玩家的青睞。
若遊戲營運業者開放販賣遊戲中的貨幣、虛擬寶物,則只有不到三成玩家表示歡迎,與私下交易的標的物特性有關,此類標的物大多無法由一般管道輕易獲得,若由業者公開販售,便直接去除了標的物的特殊性,在該標的物缺少「難以取得」等附加價值的情況下,玩家也就不需要尋求私下交易等其他管道進行購買。



玩家偏好

角色扮演、東方可愛風格遊戲廣受歡迎

在玩家偏好的遊戲類型方面,最受喜愛的類型與往年調查結果相同,為角色扮演類型的遊戲,但除了角色扮演與冒險遊戲普遍受到兩性玩家歡迎外,男性玩家與女性玩家喜好的遊戲類型大多不相同,舉例而言,男性玩家偏好動作、第一人稱射擊、即時戰略等較為刺激的遊戲,女性玩家喜愛益智、養成、戀愛、音樂等不需繃緊神經,可以輕鬆遊玩的遊戲。
本次調查結果與2007年最大的不同處,在於競速、音樂、運動等三類型的遊戲受歡迎程度的衰退,推測與2007年時此三類型遊戲曾成功的引起話題性,吸引到不少玩家的選擇遊玩,但在話題退燒後嚐鮮玩家先後退出有關。
兩性玩家對於遊戲風格的喜好,也有些許的差異,男性玩家喜好的遊戲美術風格受傳統ACG印象影響,偏愛東方可愛、西方寫實風,女性玩家則特別喜歡風格可愛的遊戲。玩家對於遊戲時空背景的設定,整體來說並沒有特別顯著的差異,最受歡迎的為「古代中國」,其次為「科幻未來」以及「中古歐洲」。

口碑影響遊戲挑選決策,能與他人互動為玩遊戲首要考量

遊戲的內容通常為玩家挑選遊戲的主要依歸,然而對於線上遊戲玩家來說,「口碑」方為玩家對一款遊戲產生興趣的最主要因素,由其是可信任度高的評價、討論,例如朋友或是網路社群的推薦等,相對而言,邀請遊戲代言人以及透過廣告宣傳遊戲效果就較為有限,唯因習慣瀏覽遊戲討論網站的網友,多為喜愛玩遊戲的玩家,刊登於遊戲討論網站的廣告影響力亦不低。
能夠與他人互動是玩家進行線上遊戲的重要考量,本次調查中多數玩家表示,促使他們持續玩同一款線上遊戲的主要原因,是「能夠與認識的朋友一起玩」,其次方為受到遊戲的風格、內容所吸引,另有許多玩家表示只想選擇沒有外掛的遊戲來長期的遊玩。
在玩家對遊戲的滿意度方面,全體受訪者中僅28.4%的玩家對目前的線上遊戲完全滿意,玩家最感困擾的仍為連線品質與外掛問題。

星期二, 9月 29, 2009

[教學]利用google code 存放swf檔案

有甚麼辦法可以使用免費空間,其實 Google 有一項服務叫 Google Code,Google Code 可以存放程式設計師想發表的程式專案。Google Code 提供 1 G 空間讓您使用,如何上傳並即時預覽 swf 檔案呢?這邊將做個介紹:











1. 先至 Google Code 申請服務
2. 下載並安裝 TortoiseSVN (重開機才能使用)
3. 開機後在您要上傳的 swf 檔上按右鍵 Tortoise SVN -> Repo-Browser
4. 先跳到您的專案首頁選擇 source 分欄頁面
5. 拷貝橘色部分 svn checkout http://yourproject.googlecode.com/svn/trunk/ yourproject--username (yourproject 請置換您的專案名稱)
6. 在Repo-Browser 的 URL 欄位貼上並確定
7. username 輸入您的帳號 password 輸入您的密碼( source 分欄頁面可以找到googlecode.com password連結)
8. 進到Repository頁面,接下來就看您想要上傳甚麼東西 (把Tortoise SVN 當作FTP軟體用就好),在 trunk 資料夾上按右鍵 -> addFile...
9. 上傳好後可以直接連到 http://yourproject.googlecode.com/svn/trunk/demo.swf





大功告成,各位可以試試,有問題可以留言給我 : )



星期二, 9月 22, 2009

[AS3實作範例]A*尋路徑演算法

文件類別 (Document Class)
TestAstar.as

package
{
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Point;

import net.eidiot.map.AStar;

import test.map.MapTileModel;
import test.map.Tile;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;

[SWF(width = 1024, height = 768, frameRate = 12)]

/**
* A* 尋路測試類別
*
* @author chugo
* @
* @date 09212009
*/
public class TestAstar extends Sprite
{
//====================================
// Member Variables
//====================================
private var m_player : Tile;
private var m_map : Array;

private var m_AStar : AStar;
private var m_mapTileModel : MapTileModel;

private var m_mapW : int = 20;
private var m_mapH : int = 10;

private var m_mapX : int = 10;
private var m_mapY : int = 40;

private var m_m_clogRate : Number = 0.3;

private var m_path : Array;
private var m_outTxt : TextField;
//====================================
// Constructor
//====================================
public function TestAstar()
{
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.doubleClickEnabled = true;
stage.addEventListener(MouseEvent.DOUBLE_CLICK, resetHandle);

this.m_outTxt = new TextField();
addChild(this.m_outTxt);
with (this.m_outTxt)
{
x = y = 20;
selectable = false;
autoSize = TextFieldAutoSize.LEFT;
}

this.m_mapTileModel = new MapTileModel();
this.m_AStar = new AStar(this.m_mapTileModel);
this.reset();
}
//====================================
// Private Methods
//====================================
private function reset() : void
{
var tile : Tile;
var isClog : Boolean;
this.m_map = new Array();

for (var i : int = 0; i < m_mapW; i++)
{
m_map[i] = new Array();
for (var j : int = 0; j < m_mapH; j++)
{
isClog = Math.random() < 0.3;
tile = new Tile(isClog ? 0x000000 : 0xCCCCCC);
tile.addEventListener(MouseEvent.CLICK, clickHandle);
addChild(tile);
tile.x = m_mapX + i * 30;
tile.y = m_mapY + j * 30;
m_map[i][j] = isClog ? 0 : 1;
}
}

m_player = new Tile(0xFF0000);
addChild(m_player);
m_player.x = m_mapX;
m_player.y = m_mapY;

this.m_mapTileModel.map = this.m_map;

output("單擊白色方塊區域測試尋路,雙擊空白區域重新排列地圖");
}

private function getPoint(p_x : Number, p_y : Number) : Point
{
p_x = Math.floor((p_x - this.m_mapX) / 30);
p_y = Math.floor((p_y - this.m_mapY) / 30);
return new Point(p_x, p_y);
}

private function output(p_info : String) : void
{
this.m_outTxt.htmlText = "A* 尋路徑演算法\t\t\t" + p_info;
}
//====================================
// Event Handles
//====================================
private function resetHandle(event : MouseEvent) : void
{
while (this.numChildren > 1)
{
var tile : Tile = this.getChildAt(1) as Tile;
if (tile.hasEventListener(MouseEvent.CLICK))
{
tile.removeEventListener(MouseEvent.CLICK, clickHandle);
}
this.removeChild(tile);
}
this.reset();
}

private function clickHandle(event : MouseEvent) : void
{
var findPiont : Point = getPoint(this.mouseX, this.mouseY);
var playerPoint : Point = getPoint(this.m_player.x, this.m_player.y);
this.m_path = this.m_AStar.find(playerPoint.x, playerPoint.y, findPiont.x, findPiont.y);
if (this.m_path != null && this.m_path.length > 0)
{
output("路徑已經找到,正在移動");
this.addEventListener(Event.ENTER_FRAME, enterframeHandle);
} else
{
output("無法到達");
}
}
private function enterframeHandle(event : Event) : void
{
if (this.m_path == null || this.m_path.length == 0)
{
output("單擊白色方塊區域測試尋路,雙擊空白區域重新排列地圖");
this.removeEventListener(Event.ENTER_FRAME, enterframeHandle);
return;
}

var note : Array = this.m_path.shift() as Array;
this.m_player.x = this.m_mapX + note[0] * 30;
this.m_player.y = this.m_mapY + note[1] * 30;
}
}
}

============================================================================================
AStar.as



package net.eidiot.map
{
/**
* A* 尋路徑演算法
*
* @author chugo
* @version 1.0
* @date 09212009
*/
public class AStar
{
//====================================
// Constants
//====================================
//橫向或豎向移動一格路徑評分
private const COST_STRAIGHT : int = 10;
//斜向移動一格路徑評分
private const COST_DIAGONAL : int = 14;

//(單個)節點數組 節點ID 索引
private const NOTE_ID : int = 0;
//(單個)節點數組 是否在開啟列表中 索引
private const NOTE_OPEN : int = 1;
//(單個)節點數組 是否在關閉列表中 索引
private const NOTE_CLOSED : int = 2;
//====================================
// Member Variables
//====================================
//地圖模型
private var m_mapTileModel : IMapTileModel;
//最大尋路徑步數,限制超時返回
private var m_maxTry : int;

//開放列表,存放節點ID
private var m_openList : Array;
//開放列表長度
private var m_openCount : int;
//節點加入開放列表時分配的唯一ID(從0開始)
//根據此ID(從下面的列表中)存取節點數據
private var m_openId : int;

//節點x座標列表
private var m_xList : Array;
//節點y座標列表
private var m_yList : Array;
//節點路徑評分列表
private var m_pathScoreList : Array;
//(從起點移動到)節點的移動耗费列表
private var m_movementCostList : Array;
//節點的父節點(ID)列表
private var m_fatherList : Array;

//節點(數組)地圖,根據節點座標記錄節點開啟關閉狀態和ID
private var m_noteMap : Array;
//====================================
// Constructor
//====================================
/**
* Constructor
*
* @param p_mapTileModel 地圖模型,實現 IMapTileModel 接口
* @param p_maxTry 最大尋路徑步數,限制超時返回
*/
public function AStar(p_mapTileModel : IMapTileModel, p_maxTry : int = 500)
{
this.m_mapTileModel = p_mapTileModel;
this.m_maxTry = p_maxTry;
}
//====================================
// Properties
//====================================
/**
* 最大尋路徑步數,限制超時返回
*/
public function get maxTry() : int
{
return this.m_maxTry;
}
/**
* @private
*/
public function set maxTry(p_value : int) : void
{
this.m_maxTry = p_value;
}

//====================================
// Public Methods
//====================================
/**
* 開始尋找路徑
*
* @param p_startX 起點X座標
* @param p_startY 起點Y座標
* @param p_endX 終點X座標
* @param p_endY 終點Y座標
*
* @return 找到的路徑(二維數組 : [p_startX, p_startY], ... , [p_endX, p_endY])
*/
public function find(p_startX : int, p_startY : int, p_endX : int, p_endY : int) : Array
{
this.initLists();
this.m_openCount = 0;
this.m_openId = -1;

this.openNote(p_startX, p_startY, 0, 0, 0);

var currTry : int = 0;
var currId : int;
var currNoteX : int;
var currNoteY : int;
var aroundNotes : Array;

var checkingId : int;

var cost : int;
var score : int;
while (this.m_openCount > 0)
{
//超時返回
if (++currTry > this.m_maxTry)
{
this.destroyLists();
return null;
}
//每次取出開放列表最前面的ID
currId = this.m_openList[0];
//將編碼為此ID的元素列入關閉列表
this.closeNote(currId);
currNoteX = this.m_xList[currId];
currNoteY = this.m_yList[currId];

//如果終點被放入關閉列表尋路結束,返回路徑
if (currNoteX == p_endX && currNoteY == p_endY)
{
return this.getPath(p_startX, p_startY, currId);
}
//獲取周圍節點,排除不可通過和已在關閉列表中的
aroundNotes = this.getArounds(currNoteX, currNoteY);
//對於周圍的每一個節點
for each (var note : Array in aroundNotes)
{
//計算F和G值
cost = this.m_movementCostList[currId] + ((note[0] == currNoteX || note[1] == currNoteY) ? COST_STRAIGHT : COST_DIAGONAL);
score = cost + (Math.abs(p_endX - note[0]) + Math.abs(p_endY - note[1])) * COST_STRAIGHT;
if (this.isOpen(note[0], note[1])) //如果節點已在播放列表中
{
checkingId = this.m_noteMap[note[1]][note[0]][NOTE_ID];
//如果新的G值比節點原來的G值小,修改F,G值,換父節點
if(cost < this.m_movementCostList[checkingId])
{
this.m_movementCostList[checkingId] = cost;
this.m_pathScoreList[checkingId] = score;
this.m_fatherList[checkingId] = currId;
this.aheadNote(this.getIndex(checkingId));
}
} else //如果節點不在開放列表中
{
//將節點放入開放列表
this.openNote(note[0], note[1], score, cost, currId);
}
}
}
//開放列表已空,找不到路径
this.destroyLists();
return null;
}
//====================================
// Private Methods
//====================================
/**
* @private
* 將節點加入開放列表
*
* @param p_x 節點在地圖中的x座標
* @param p_y 節點在地圖中的y座標
* @param P_score 節點的路徑評分
* @param p_cost 起始點到節點的移動成本
* @param p_fatherId 父節點
*/
private function openNote(p_x : int, p_y : int, p_score : int, p_cost : int, p_fatherId : int) : void
{
this.m_openCount++;
this.m_openId++;

if (this.m_noteMap[p_y] == null)
{
this.m_noteMap[p_y] = [];
}
this.m_noteMap[p_y][p_x] = [];
this.m_noteMap[p_y][p_x][NOTE_OPEN] = true;
this.m_noteMap[p_y][p_x][NOTE_ID] = this.m_openId;

this.m_xList.push(p_x);
this.m_yList.push(p_y);
this.m_pathScoreList.push(p_score);
this.m_movementCostList.push(p_cost);
this.m_fatherList.push(p_fatherId);

this.m_openList.push(this.m_openId);
this.aheadNote(this.m_openCount);
}
/**
* @private
* 將節點加入關閉列表裡
*/
private function closeNote(p_id: int) : void
{
this.m_openCount--;
var noteX : int = this.m_xList[p_id];
var noteY : int = this.m_yList[p_id];
this.m_noteMap[noteY][noteX][NOTE_OPEN] = false;
this.m_noteMap[noteY][noteX][NOTE_CLOSED] = true;

if (this.m_openCount <= 0)
{
this.m_openCount = 0;
this.m_openList = [];
return;
}
this.m_openList[0] = this.m_openList.pop();
this.backNote();
}
/**
* @private
* 將(新加入開放列表或修改了路徑評分的)節點向前移動
*/
private function aheadNote(p_index : int) : void
{
var father : int;
var change : int;
while(p_index > 1)
{
//父節點的位置
father = Math.floor(p_index / 2);
//如果該節點的F值小於父節點的F值則和父節點交換
if (this.getScore(p_index) < this.getScore(father))
{
change = this.m_openList[p_index - 1];
this.m_openList[p_index - 1] = this.m_openList[father - 1];
this.m_openList[father - 1] = change;
p_index = father;
} else
{
break;
}
}
}
/**
* @private
* 将(取出开启列表中路径评分最低的节点后从队尾移到最前的)节点向后移动
*/
private function backNote() : void
{
//尾部的節點被移到最前面
var checkIndex : int = 1;
var tmp : int;
var change : int;

while(true)
{
tmp = checkIndex;
//如果有子節點
if (2 * tmp <= this.m_openCount)
{
//如果子節點的F值更小
if(this.getScore(checkIndex) > this.getScore(2 * tmp))
{
//記節點的新位置為子節點位置
checkIndex = 2 * tmp;
}
//如果有兩個子節點
if (2 * tmp + 1 <= this.m_openCount)
{
//如果第二個子節點F值更小
if(this.getScore(checkIndex) > this.getScore(2 * tmp + 1))
{
//更新節點新位置為第二個子節點位置
checkIndex = 2 * tmp + 1;
}
}
}
//如果節點位置没有更新結束排序
if (tmp == checkIndex)
{
break;
}
//反之和新位置交換,繼續和新位置的子節點比較F值
else
{
change = this.m_openList[tmp - 1];
this.m_openList[tmp - 1] = this.m_openList[checkIndex - 1];
this.m_openList[checkIndex - 1] = change;
}
}
}
/**
* @private
* 判斷某節點是否在開放列表
*/
private function isOpen(p_x : int, p_y : int) : Boolean
{
if (this.m_noteMap[p_y] == null) return false;
if (this.m_noteMap[p_y][p_x] == null) return false;
return this.m_noteMap[p_y][p_x][NOTE_OPEN];
}
/**
* @private
* 判斷某節點是否在關閉列表中
*/
private function isClosed(p_x : int, p_y : int) : Boolean
{
if (this.m_noteMap[p_y] == null) return false;
if (this.m_noteMap[p_y][p_x] == null) return false;
return this.m_noteMap[p_y][p_x][NOTE_CLOSED];
}
/**
* @private
* 獲取某節點的周圍節點,排除不能通過和已在關閉列表中的
*/
private function getArounds(p_x : int, p_y : int) : Array
{
var arr : Array = [];
var checkX : int;
var checkY : int;
var canDiagonal : Boolean;

//右
checkX = p_x + 1;
checkY = p_y;
var canRight : Boolean = this.m_mapTileModel.isBlock(p_x, p_y, checkX, checkY) == 1;
if (canRight && !this.isClosed(checkX, checkY))
{
arr.push([checkX, checkY]);
}
//下
checkX = p_x;
checkY = p_y + 1;
var canDown : Boolean = this.m_mapTileModel.isBlock(p_x, p_y, checkX, checkY) == 1;
if (canDown && !this.isClosed(checkX, checkY))
{
arr.push([checkX, checkY]);
}

//左
checkX = p_x - 1;
checkY = p_y;
var canLeft : Boolean = this.m_mapTileModel.isBlock(p_x, p_y, checkX, checkY) == 1;
if (canLeft && !this.isClosed(checkX, checkY))
{
arr.push([checkX, checkY]);
}
//上
checkX = p_x;
checkY = p_y - 1;
var canUp : Boolean = this.m_mapTileModel.isBlock(p_x, p_y, checkX, checkY) == 1;
if (canUp && !this.isClosed(checkX, checkY))
{
arr.push([checkX, checkY]);
}
//右下
checkX = p_x + 1;
checkY = p_y + 1;
canDiagonal = this.m_mapTileModel.isBlock(p_x, p_y, checkX, checkY) == 1;
if (canDiagonal && canRight && canDown && !this.isClosed(checkX, checkY))
{
arr.push([checkX, checkY]);
}
//左下
checkX = p_x - 1;
checkY = p_y + 1;
canDiagonal = this.m_mapTileModel.isBlock(p_x, p_y, checkX, checkY) == 1;
if (canDiagonal && canLeft && canDown && !this.isClosed(checkX, checkY))
{
arr.push([checkX, checkY]);
}
//左上
checkX = p_x - 1;
checkY = p_y - 1;
canDiagonal = this.m_mapTileModel.isBlock(p_x, p_y, checkX, checkY) == 1;
if (canDiagonal && canLeft && canUp && !this.isClosed(checkX, checkY))
{
arr.push([checkX, checkY]);
}
//右上
checkX = p_x + 1;
checkY = p_y - 1;
canDiagonal = this.m_mapTileModel.isBlock(p_x, p_y, checkX, checkY) == 1;
if (canDiagonal && canRight && canUp && !this.isClosed(checkX, checkY))
{
arr.push([checkX, checkY]);
}

return arr;
}
/**
* @private
* 獲取路徑
*
* @param p_startX 起始點X座標
* @param p_startY 起始點Y座標
* @param p_id 終點的ID
*
* @return 路徑座標(Point)數組
*/
private function getPath(p_startX : int, p_startY : int, p_id: int) : Array
{
var arr : Array = [];
var noteX : int = this.m_xList[p_id];
var noteY : int = this.m_yList[p_id];
while (noteX != p_startX || noteY != p_startY)
{
arr.unshift([noteX, noteY]);
p_id = this.m_fatherList[p_id];
noteX = this.m_xList[p_id];
noteY = this.m_yList[p_id];
}
arr.unshift([p_startX, p_startY]);
this.destroyLists();
return arr;
}
/**
* @private
* 獲取某ID節點在開放列表中的索引(從1开始)
*/
private function getIndex(p_id : int) : int
{
var i : int = 1;
for each (var id : int in this.m_openList)
{
if (id == p_id)
{
return i;
}
i++;
}
return -1;
}
/**
* @private
* 獲取某節點的路徑評分
*
* @param p_index 節點在開啟列表中的索引(從1開始)
*/
private function getScore(p_index : int) : int
{
return this.m_pathScoreList[this.m_openList[p_index - 1]];
}
/**
* @private
* 初始化數組
*/
private function initLists() : void
{
this.m_openList = [];
this.m_xList = [];
this.m_yList = [];
this.m_pathScoreList = [];
this.m_movementCostList = [];
this.m_fatherList = [];
this.m_noteMap = [];
}
/**
* @private
* 銷毀數組
*/
private function destroyLists() : void
{
this.m_openList = null;
this.m_xList = null;
this.m_yList = null;
this.m_pathScoreList = null;
this.m_movementCostList = null;
this.m_fatherList = null;
this.m_noteMap = null;
}
}
}
=============================================================================================

MapTileModel.as


package test.map
{
import net.eidiot.map.IMapTileModel;

/**
* 地圖模型類別
*
* @author chugo
* @version 1.0
* @date 09212009
*/
public class MapTileModel implements IMapTileModel
{
private var m_map : Array;

public function MapTileModel()
{

}

public function get map() : Array
{
return this.m_map;
}
public function set map(p_value : Array) : void
{
this.m_map = p_value;
}

/**
* 是否為障礙
* @param p_startX 起始點X座標
* @param p_startY 起始點Y座標
* @param p_endX 終點X座標
* @param p_endY 終點Y座標
* @return 0為障礙 1為通路
*/
public function isBlock(p_startX : int, p_startY : int, p_endX : int, p_endY : int) : int
{
var mapWidth : int = this.m_map.length;
var mapHeight : int = this.m_map[0].length;

if (p_endX < 0 || p_endX == mapWidth || p_endY < 0 || p_endY == mapHeight)
{
return 0;
}
return this.m_map[p_endX][p_endY];
}
}
}
==============================================================================================
Tile.as



package test.map
{
import flash.display.Sprite;
/**
* 瓷磚類別
*
* @author chugo
* @version 1.0
* @date 09212009
*/
public class Tile extends Sprite
{
public function Tile(p_color : uint = 0xCCCCCC, p_w : int = 30, p_h : int = 30)
{
with (this.graphics)
{
lineStyle(1, 0x666666);
beginFill(p_color);
drawRect(0, 0, p_w, p_h);
endFill();
}
}
}
}
=============================================================================================
IMapTileModel.as



package net.eidiot.map
{
/**
* 地圖模型接口
*
* @author      chugo
* @version 1.0
* @date 09212009
*/
public interface IMapTileModel
{
/**
* 判斷是否為障礙
* @param p_startX 起始點X座標
* @param p_startY 起始點Y座標
* @param p_endX 起始點X座標
* @param p_endY 起始點Y座標
* @return 0為障礙 1為通路
*/
function isBlock(p_startX : int, p_startY : int, p_endX : int, p_endY : int) : int;
}
}
==============================================================================================