這是一個很有趣的遊戲!
有趣的BOX2D的遊戲!
以後再來專篇介紹他~
下面是一個類似功能的一些簡單範例
簡單的範例
基本的操作 就是上下左右 四個方向鍵
上是加速
下是減速
前後 是轉角度
每台車有自己的速度上限 轉角度的速度 加速的速度 等等 的個別屬性
都有自己的 AI 轉向 讓自己不倒地的部分 加速的邏輯
下方的曲面地圖會隨機的 產生
右上方會有一個簡單的 小地圖
還可以看到其他車 目前所在的位置~~
不過真正的遊戲要判斷 四腳朝天 就會結束
到終點也會結束
但這個範例沒弄...
話說 BLOG 是不是這樣寫比較簡單.
2012年7月3日 星期二
2012年6月28日 星期四
[AS3][Sound]Sound相關的一些測試
其實是之前遇到的一個問題~~
就是 sound 輪播得時候 會有小中斷的感覺!
這個問題有兩個層面!
第一個
就是 sound 檔本身的處理的問題
Ticore大大寫的這篇 解決 Mp3 循環音效停頓的問題
可以解決這個問題
第二個
就是使用 sound.play()
然後聽他的 complete 的事件
然後再一次的使用 sound.play() 去播放
通常這樣的都是為了準確的了解這個聲音是否 結束了沒有!
我自己的聲音播放的類別也是這樣做~
不過聽說使用 sound.play(0, 次數)
卻不會有 斷音的問題
所以我就寫了測試程式測試~
//
//
用上面的程式測試! 會發現有下面的 trace
//
soCompChannel lp : 0 rp: 0
soLoopChannel lp : 0 rp: 0
soCompChannel lp : 0 rp: 0
soCompChannel lp : 0 rp: 0
soCompChannel lp : 0 rp: 0
soCompChannel lp : 0 rp: 0
soCompChannel lp : 0 rp: 0
soCompChannel lp : 0 rp: 0
//
就是 sound 輪播得時候 會有小中斷的感覺!
這個問題有兩個層面!
第一個
就是 sound 檔本身的處理的問題
Ticore大大寫的這篇 解決 Mp3 循環音效停頓的問題
可以解決這個問題
第二個
就是使用 sound.play()
然後聽他的 complete 的事件
然後再一次的使用 sound.play() 去播放
通常這樣的都是為了準確的了解這個聲音是否 結束了沒有!
我自己的聲音播放的類別也是這樣做~
不過聽說使用 sound.play(0, 次數)
卻不會有 斷音的問題
所以我就寫了測試程式測試~
//
package demo
{
import flash.display.Sprite;
import flash.events.Event;
import flash.events.ProgressEvent;
import flash.media.Sound;
import flash.media.SoundChannel;
import flash.net.URLRequest;
import ui.sound;
public class soundDemo extends Sprite
{
private var soComp:Sound;
private var soCompChannel:SoundChannel;
//
private var soLoop:Sound;
private var soLoopChannel:SoundChannel;
public function soundDemo()
{
super();
soComp = new sound();
soCompChannel = soComp.play();
soCompChannel.addEventListener(Event.SOUND_COMPLETE, onSoundCompleteFun);
soLoop = new sound();
soLoopChannel = soLoop.play(0, int.MAX_VALUE);
soLoopChannel.addEventListener(Event.SOUND_COMPLETE, onSoundCompleteFun);
this.addEventListener(Event.ENTER_FRAME, onEnterFrameFun);
}
private function onSoundCompleteFun(e:Event):void
{
soCompChannel.removeEventListener(Event.SOUND_COMPLETE, onSoundCompleteFun);
soCompChannel = soComp.play();
soCompChannel.addEventListener(Event.SOUND_COMPLETE, onSoundCompleteFun);
}
//
private function onEnterFrameFun(e:Event):void
{
var flag:Boolean = false;
if(soCompChannel.leftPeak == 0) flag = true;
if(soCompChannel.rightPeak == 0) flag = true;
if(flag) trace('soCompChannel lp : ' + soCompChannel.leftPeak + ' rp: ' + soCompChannel.rightPeak);
//
flag = false;
if(soLoopChannel.leftPeak == 0) flag = true;
if(soLoopChannel.rightPeak == 0) flag = true;
if(flag) trace('soLoopChannel lp : ' + soLoopChannel.leftPeak + ' rp: ' + soLoopChannel.rightPeak);
}
}
}
//
用上面的程式測試! 會發現有下面的 trace
//
soCompChannel lp : 0 rp: 0
soLoopChannel lp : 0 rp: 0
soCompChannel lp : 0 rp: 0
soCompChannel lp : 0 rp: 0
soCompChannel lp : 0 rp: 0
soCompChannel lp : 0 rp: 0
soCompChannel lp : 0 rp: 0
soCompChannel lp : 0 rp: 0
//
就程式面的角度看!
是代表聽 事件 重播的機制會讓 channel 有一個影格左右的沒有聲音!
因為我自己試聽不出來一個影格的差異 !
所以我是這樣去看到底有沒有斷音!
總之結論是使用 原生 sound.play 去 LOOP
會比聽事件 去 loop 順
所以我是這樣去看到底有沒有斷音!
總之結論是使用 原生 sound.play 去 LOOP
會比聽事件 去 loop 順
上面的測試環境
聲音是使用 SWC 鑲進去的
如果是使用
soComp = new Sound(new URLRequest('../asset/sound.mp3'));
的方式 測試也是一樣 ! (以我手邊第一次處理的 MP3)
不過~我後來有處理另外一個WAV
用SWC 的方式 是只有開始會有 0
但是使用 new URLRequest 的方式~
卻是和聽事件的一樣! 會中斷!
所以還是要看 Sound 檔
用SWC 的方式 是只有開始會有 0
但是使用 new URLRequest 的方式~
卻是和聽事件的一樣! 會中斷!
所以還是要看 Sound 檔
2012年6月24日 星期日
[雜談] Indie Game 觀後感
恩~今天去看了
獨立製作遊戲
http://igdshare.org/
雖然不是現在才發現~
不過在一次的確定了~
其實大家的想法都一樣~~
開發中的不確定感~
自己的經歷~
自己的喜好~
自己的過往~
發表 展示的感覺~
展示時出現 BUG..的心情...
大家的反應~
能不能了解我設計的目的~
巴拉~巴拉~巴拉的~~
有時候一改在改~
一改在改~
其實真正做才是最難的地方~
可以~勇敢~認真的放手一搏~~
創意其實大家都有的~
但是能真正生出來的有多少?
我自己的個性應該是不敢走鋼索的那種人巴...
今天看到的這些人
對我來說才是真正的勇者
其實還有更多想講的~
但是怎麼說~
還是介紹一下影片巴~~
今天的影片基本上~
是介紹獨立開發遊戲的
最重要的是下面這三款~
雖然一開始我把 FEZ 搞錯了~
搞成日本的那款~
理論上以獨立開發來說不應該搞錯的 orz
FEZ
一個在 2D世界的小人
突然發現世界是 3D 的! 所以開始探索~很有趣 很好玩~
很多很有趣的地方~~
然後他的技術 也蠻簡單實現的~
但是創意卻很難!
這個作者蠻有趣的~其實每一個都蠻有趣的~
不過以某種程度來說~我覺得他是最慘的一位
Super Meat Boy
這兩位開發者~怎麼說~
對遊戲得執著真的很厲害~~
寫到要打胰島素才能在寫~
然而以某種程度來說~
他們的成就也是驚人的~
特別是 他和異塵餘生 同檔期
但是在評價上比他高~~
而且還是自己會想買的遊戲 XD
那來講講遊戲~~
一款很有趣的動作遊戲!
一款創意 搞笑~和風格都很獨特的遊戲!
Braid
一個有趣的世界!
有愛情 有故事!
很多的創意的遊戲
利用 時間倒流 來達成 或是進行 解謎等等的遊戲~
關於這個作者給我的感覺就是像CSI的葛瑞修~
他做出了一個超棒的遊戲~
但是他卻因為一些評論 讓他非常沮喪~~
話說以我自己來講~
我應該也是會讓他很沮喪的那種人巴 orz
因為我應該是以解決問題為目的~
而不深究為什麼這樣的人
上面這幾款都是 有賺大錢的遊戲~
也很特殊的遊戲!
基本上 可以看出一個模式!
主角 本身都不會 在強化
而且都是 各有特別得地方!
重點以動作為導向
(雖然個人為人 FEZ 是以探索為導向)
接下來講講我最近的一些 獨立開發的遊戲巴? (應該巴~對我來說不是大公司作的 都算)
雖然說都不是算是很高知名度的作品 (不過換個角度看 應該算 知名度也蠻高的 orz)
大雄無理系列!
基本上 看影片巴!
http://www.youtube.com/watch?v=F_22X_mRr1E&feature=channel&list=UL
這個應該分成兩個一個是原版的
ドラえもんのび太 的 生化危機
這個就改編得很大~類型很多~
RPG 探索 SLG 等等等
生化危機 是其中之一
作者基本上都是掛名 aaa
再來就是
對這個作品進行二次改造後的無理版! (據了解有許多版本 也是一堆人都有作的)
基本上是讓 aaa 的版本 對人物的個性 等等的作修正~
修正到比較符合正常的哆啦ㄟ夢的人物個性~
後面延續的版本
不過就是 按照生化危機的劇情趣改編 延續~
還對一代的系統進行改造~
多了很多很有趣的東西~
多主角~換武器~躲子彈~劇情分支~多結局~真結局. 巴拉巴拉~
簡單的講 生化危機有的~大部分的他都有做了~
超神的
むなしい努力
網址 下載網址
http://freegame.on.arena.ne.jp/simulation/game_1554.html
基本上是一款 自行開發的 RTS + SLG 的遊戲~
因為我先看到的是這個~所以~和他類似的另外一款~
我就不介紹了~~
基本上 想像成 全場景的
聖魔戰記 就對了!
或者說 是 龍之力量!
事實上我看到的時候 是想到 吳氏工房的 波斯戰記系列~
和他的一些後續 的作品~(不是波斯 或 黑暗天使系列的)
簡單 大膽 的戰鬥系統!
多樣的招換 招式 劇情的分歧 選擇~
該有的我覺得都有了 !
其實 也是可以當 緋王傳 看也是一樣~
以魔王軍來說 純用招換戰 也不是不能統一世界!
不過 緋王傳的一些策略 和 特別的設計 這款就沒了
想當年 一定要凹贏盜賊拿寶物的部分~
這遊戲真的就感受不到了
剩下一些在
http://www.kongregate.com/ 的我就以後再寫...
這邊的好玩的遊戲好多阿~~
很多款我都 忍不住的全破了 orz
================================================
FEZ:
http://www.youtube.com/watch?v=CWUU0vvWLRo
Super Meat Boy
http://www.youtube.com/watch?v=CQ_PtD3LwpE&feature=related
Braid
http://www.youtube.com/watch?feature=player_embedded&v=uqtSKkyJgFM#!
2012年6月12日 星期二
[AS3][迷宮] 簡易的迷宮建立
先看看效果
本來是 只有文字的版本~
不過那個版本應該只有我看得懂~
所以就把貼圖的部分也一併弄了~
來講一下 DEMO
輸入 數字後 會產生一個正方形的 迷宮!
雖然根據我的寫法可以是長方形!
但是DEMO的部分 還是使用 正方形~
兩個圓點的部分是 出口 和 入口
入口 我固定在 0,0
出口 我就讓他隨機跑了
理論上 是除了 0,0 外都可以的
白色的路 是入口到出口的路!
其他顏色的路 一種顏色是代表一種 支路
然後迷宮理論上 是從 3~? 都可以的~
但是為了 好看的部分 這個DEMO 是從
8~100來做測試~
對了裡面的時間 是包含 畫出右邊的畫面的部分
所以比文章內的還要多一點
只有主體的SWF
先來定義一下 我所謂的迷宮
就是有一個入口
一個出口
然後入口可以走到出口
路中間會有叉路的地圖~~
先來講解迷宮建立的一些方法~
下面是找幾個我看得懂的方法來講解
但是也不敢說沒有誤導別人!
我這邊說的部分都很簡單 但是是最重要的幾個大方向!
但其實其中還是有相當多的細節要處理!
1. 掘路法
一開始的地圖是沒有路的
但是一路挖~挖到出口後~
然後再慢慢的把其他的挖完. (這是最簡單 最直觀的方法)
2. 棒倒法
先建立 基本的柱子 然後 慢慢的將柱子補起來~(或是應該說柱子倒下)
但是就算是補了起來
內部都是可以移動的
不會不能到下一層的情況~
然後上一層的出口 要和下一層的連接~
直到 挖滿為止~
這樣講解可能不好明白~但是去看
http://www5d.biglobe.ne.jp/~stssk/maze/make.html
的圖片的話 應該就比較容易了解~
3. 延伸牆法
由邊邊慢慢的把牆拉出來~
重點不能讓兩個拉出的牆 相連
但是可以把拉出的牆上再拉出牆~
不可以讓路斷掉
而且要把全部個格子用光~
然後迷宮就完成了~
很神奇 很意外 很簡單 很特殊的解法!
映像中~這是最快的一種!
4. 深度遍歷 (就是下面 PS 1 和 2 還有最後一篇的方式! 基本上要有一些 數學理論的基礎!)
類似 A*的方式
一個一個把可以移動的格子記錄(或者說 拆牆 )
然後再倒回的方式
直到全部的格子用光 然後迷宮就完成了
以上的方式~
都會是要成立在 奇數格下 才能建立迷宮~
雖然有一些偶數也是可以的~
但是生成的迷宮中包含牆的方式~
最好是要奇數才能 比較方便的完成~
才不會有一層都是牆的情況
在介紹一個優化的方法!
5. 分區法
上面全部的都可以使用這種方法優化!
其實也是從棒倒法出來的~~
分成小區塊 小區塊作~
理論上 不管是 方的 長的 都是可以切成四個 兩個 等等的方式~
只是切開的入口 要接 另外一個的出口!
確保可以入口一定走的到到出口!
這樣就是迷宮了
但是 不用棒倒法的方式~(因為只有棒倒法 會讓邊邊產生多個出口!)
會變成區塊與區塊間的支路不相通!
但是這樣可以有效的減少時間!
以我自己的方法來說 (demo 的部分是包涵 貼圖的部分)
10*10 = 大概 1~2 毫秒
20*20 = 大約 15~30毫秒
100*100 = 大約 4xx~6xx毫秒
如果20*20切成 四塊
用 10*10的拼接
大概也只要 4~8毫秒!
用來拼接 100 * 100 的大約是
1xx ~ 2xx毫秒
都比直接 作一個大塊的來的快!
如果再換一個方式想!
甚至 如果出口入口走不到的就不用生產和拼接!
更省! 不過地圖會 比較貧乏!
這邊就先不談了!
來談談這段差距得原因
主要的差距是 遍歷的部分~
10*10 從頭到尾 的時間
比
20*20 從頭到尾的時間
短很多
不過這個對 遍歷的次數越多的越有效!
遍歷次數越少~
那分區法 用處就不大了
甚至還沒有節約的效果
話說我自己是怎樣想也不是1 ~ 4 的方式
所以我弄出了自己的方式!
雖然沒啥理論~
不過基本的定義可以達成~
而且直觀
但是跟上面的方法比較並沒有比較快~
但是因為生成方式中~
不包含牆 只有路
所以理論上適合各種大小尺寸的地圖~
好現在就開始講解我的做法~
其實就是 第一種方式~~
掘路法 在經過一些變型~(參考過各種方式後 自己腦補的結果)
首先 他會從 入口 出口開時同時亂挖~
亂挖結束後~
然後利用 A* 尋路將出口 和 入口
亂挖出來的路連接起來~(最佳狀況~)
如果連不起來~就使用最短路徑~
然後再尋一次路~
把亂挖的路 和 最短路徑的路 權重 設成 2
重複的路徑設成 1然後再尋一次路~
(這段沒設權重的話 會分不清主路 和 叉路的分別...如果這邊不需要的話 也是可以不作)
這條路就設成 通路~
剩下的都當成 叉路來處理~
重點是我會記下每一條路的順序~
這樣在生成地圖時 有用~
特別在沒牆的版本中這點很重要~
因為 有牆的版本中
不會有下面這樣的路! ( 0 是牆 1是路)
111
011
011
而且這樣的解釋方式 很多種!
不過我也可以不記!
因為就算不記 也不會讓路 不能從頭走到尾!
問題是看貼圖的時候 怎樣去貼!
連著的格子都貼一樣可以走 (中間不會有牆)
或
貼成房間(2*3 開口在 0,0 和 1,2)!
或者
貼成
0,0 -> 1,0->2,0->2,1->1,1->1,2->2,2(路是單格 有牆 有方向性)
這樣的路!
但是 用 1~4的做法 都是無法產出
有小房間的迷宮!
但是可以生成後再特別去挖!
還有另外一個重點~
以後尋路的時候~
不用及時運算~
利用這個記錄下來的路 就可以輕易的尋路~
其他的雖然也可以在生產得時候記錄
但是 另外的分支都還要特別的去查 和記錄
不過我的應該也算從一開始就有目的的記錄
上面都是講一些我的方式的一些優點!
或者是特點!
那在講講我的生成方式的一些缺點~
1.
路是不會相連的~
不會有一條分支 會兩個開口
當然 分支上 是會長分支的~
但是不會有 D 字型的通路~
不過要 D 字型的通路 也可以
是透過 貼圖的部分去達成 !
應該這樣講! 因為理論的哪種我搞不定牆
所以 我的路 都是
2.
因為支線一定要從某條路上長出來
所以只能用路去找
會比找空格的方式來的慢~
而且可能會有漏掉的點~
上面的 拉伸 棒倒 深度遍歷 都是以空格的方式去找~(順序 從 0,0->0,1->0,2...)
但是我的卻要從路上找! (某些特殊點 不多跑幾次遞迴 還不一定找的到)
所以我的方法比上面的都還來的慢(一般情況 但是最佳情況是不一定)
至少 迴圈跑的次數是比較多的
3.
如果不填滿~但是要生成固定數量的支路!
其實這個生成方式非常快~
理論上生成從入口到出口的路 速度是差不多的~
但是我支線是從路上去生~
而且我不管牆! 其他的都會去考慮牆的部分
所以生成固定的支線的速度
會比從空格的去生來的快
但是如果要填滿~
那這個方式就非常的慢~
以下面的例子來說明!
1113
0213
0011
要把 0,3 這個點補起來 要兩次遞迴!
如果是 1~4的那些方法~
這樣的 空格
只需要一次遞迴就能解決!
我這的遞迴都是只從第一格 跑到最後一格
不過我的方法
是跑我的方法是跑路的格子
其他的方法是
跑全迷宮的格子
關於 CODE 的部分
package maze
{
import flash.display.BitmapData;
import flash.geom.Point;
public class MazeUtils
{
static public const WallTypt:int = 0;
static public const MainWayType:int = 1;
// 建立一個都是牆 沒有路的世界
static public function ceateEmptyMap(w:int, h:int):Array
{
var world:Array = new Array();
var j:int = 0;
for(var i:int= 0;i<h;i++)
{
world.push(new Array);
for(j=0;j<w;j++)
world[i][j] = WallTypt;
}
return world;
}
// 給任意兩點 會使用路來連接
static public function twoPointOneWay(world:Array, starPoint:Point, endPoint:Point, wayType:int, wayList:Array, lockObj:Object):void
{
var sArr:Array;
if(world[starPoint.y][starPoint.x] != WallTypt)
{ // 如果起點是可以走的話
sArr = onePointFindWay(world, starPoint, lockObj);
if(sArr.length < 0 )
return;
starPoint = sArr[int(sArr.length*RAND)];
}
if(world[endPoint.y][endPoint.x] != WallTypt)
{ // 如果終點是可以走的話
sArr = onePointFindWay(world, endPoint, lockObj);
if(sArr.length < 0 )
return;
endPoint = sArr[int(sArr.length*RAND)];
}
world[starPoint.y][starPoint.x] = wayType;
world[endPoint.y][endPoint.x] = wayType;
var starList:Array = onePointRandomWay(world, starPoint, wayType, world.length, lockObj);
var endList:Array = onePointRandomWay(world, endPoint, wayType, world.length, lockObj);
var sP:Point = starList[starList.length-1];
var eP:Point = endList[endList.length-1];
clearWorld(world, sP, WallTypt);
clearWorld(world, eP, WallTypt);
var fArr:Array = AstarUtil.findWayAstar(world, sP, eP, [1]);
if(!fArr)
{ // 如果沒辦法連線 那再找一條從起點到終點的路
var world2:Array = ceateEmptyMap(world.length, world[0].length);
fArr = AstarUtil.findWayAstar(world2, starPoint, endPoint, [1]);
// 畫到列表上
for(var i:int =0; i<fArr.length;i++)
{
if(world[fArr[i].y][fArr[i].x] == MainWayType)
world[fArr[i].y][fArr[i].x] = 3;
else
world[fArr[i].y][fArr[i].x] = 2;
}
//
var fArr2:Array = AstarUtil.findWayAstar(world, starPoint, endPoint, [AstarUtil.WALLCOST,2,100,1]);
for(i = 0; i<fArr2.length;i++)
world[fArr2[i].y][fArr2[i].x] = 4;
wayList.push(fArr2);
var j:int = 0;
// 轉成基準
for(i = 0; i<world.length;i++)
{
for(j=0;j<world[0].length;j++)
{
switch(world[i][j])
{
case 0:
break;
default:
world[i][j] = -2;
break;
case 4:
world[i][j] = MainWayType;
break;
}
}
}
//
var flag:Boolean = false;
var pp:Point;
for(i = 0; i<fArr.length;i++)
{
pp = fArr[i];
if(world[pp.y][pp.x] == MainWayType)
flag = false;
else if(world[pp.y][pp.x] == -2){
if(!flag) wayList.push(new Array);
flag = true;
wayList[wayList.length-1].push(pp);
world[pp.y][pp.x] = wayList.length;
}
}
//
flag = false;
for(i = 0; i<starList.length;i++)
{
pp = starList[i];
if(world[pp.y][pp.x] == MainWayType)
flag = false;
else if(world[pp.y][pp.x] == -2){
if(!flag) wayList.push(new Array);
flag = true;
wayList[wayList.length-1].push(pp);
world[pp.y][pp.x] = wayList.length;
}
}
//
flag = false;
for(i = 0; i<endList.length;i++)
{
pp = endList[i];
if(world[pp.y][pp.x] == MainWayType)
flag = false;
else if(world[pp.y][pp.x] == -2){
if(!flag) wayList.push(new Array);
flag = true;
wayList[wayList.length-1].push(pp);
world[pp.y][pp.x] = wayList.length;
}
}
return;
}
for(i = 0; i<fArr.length;i++)
world[fArr[i].y][fArr[i].x] = 1;
starList = starList.concat(fArr.reverse());
wayList.push(starList.concat(endList.reverse()));
}
// 特別改變地圖的一點
static private function clearWorld(world:Array, p:Point, wayTye:int):void
{
world[p.y][p.x] = wayTye;
}
// 給一點任意移動
static public function onePointRandomWay(world:Array, point:Point, wayType:int, limit:int = 10, lockObj:Object=null):Array
{
if(limit<0) limit = 999;
var wayList:Array = new Array();
var sArr:Array = onePointFindWay(world, point, lockObj);
if(sArr.length<1) return wayList;
wayList.push(point);
if(world[point.y][point.x] == WallTypt) world[point.y][point.x] = wayType;
var newP:Point;
var count:int = 0;
var tempArr:Array;
while(sArr.length > 0)
{
newP = sArr[int(sArr.length*RAND)];
world[newP.y][newP.x] = wayType;
wayList.push(newP);
sArr = onePointFindWay( world, newP, lockObj);
count++;
if(count > limit) break;
}
return wayList;
}
// 給一點會傳回 可以走的路
static public function onePointFindWay(world:Array, p:Point, lockObj:Object):Array
{
var selectList:Array = new Array();
if(lockObj[p.x+'_'+p.y] == 1) return selectList;
if(!world[p.y]) return selectList;
if(world[p.y-1]){
if(world[p.y-1][p.x] == WallTypt)
selectList.push(new Point( p.x, p.y-1));
}
if(world[p.y+1]){
if(world[p.y+1][p.x] == WallTypt)
selectList.push(new Point( p.x, p.y+1));
}
if(world[p.y][p.x-1] == WallTypt) selectList.push(new Point( p.x-1, p.y));
if(world[p.y][p.x+1] == WallTypt) selectList.push(new Point( p.x+1, p.y));
if(selectList.length<1) lockObj[p.x+'_'+p.y] = 1;
return selectList;
}
// 傳回隨機變數
static private function get RAND():Number
{
return Math.random();
}
// 在路上找一個點 製造一條分叉路
static public function getPointInWayCanWalk(world:Array, WarArr:Array, lockObj:Object, saveLen:int=0):Array
{
var CanWalkPointList:Array = new Array();
var j:int;
var sArr:Array;
for(var i:int = saveLen;i<WarArr.length;i++)
{
for(j=0;j<WarArr[i].length;j++)
{
sArr = onePointFindWay(world,WarArr[i][j], lockObj);
if(sArr.length > 0) CanWalkPointList.push(WarArr[i][j]);
}
}
return CanWalkPointList;
}
static public function fillWay(world:Array, WarArr:Array, lockObj:Object, num:int = 0, saveLen:int = 0):void
{
var sArr:Array;
var objList:Array;
var j:int;
var fArr:Array;
objList = getPointInWayCanWalk(world, WarArr, lockObj, saveLen);
if(objList.length < 1) return;
saveLen = WarArr.length;
for(var i:int=0;i<objList.length;i++)
{
sArr = onePointFindWay(world, objList[i], lockObj);
for(j=0;j<sArr.length;j++)
{
fArr = onePointRandomWay(world, sArr[j], WarArr.length+1,100,lockObj);
if(fArr.length>0) WarArr.push(fArr);
}
}
num++;
if(num > 5) return;
fillWay(world, WarArr, lockObj, num, saveLen);
}
// 創建迷宮
static public function createMaze(mazeWidth:int,
mazeHeight:int,
startPoint:Point,
endPoint:Point,
branNum:int = 10,
branLen:int = 10):Object
{
var world:Array = ceateEmptyMap(mazeWidth, mazeHeight);
var WarArr:Array = new Array();
var lockObj:Object = {};
// 用起點 終點 先建立一條主要路線
twoPointOneWay(world, startPoint, endPoint, MainWayType, WarArr, lockObj);
// 產生分支路
var sArr:Array;
var objList:Array = getPointInWayCanWalk(world, WarArr, lockObj);
var fArr:Array;
for(var i:int=0;i<branNum;i++)
{
sArr = onePointFindWay(world, objList[int(objList.length*RAND)], lockObj);
if(sArr.length >0)
{
fArr = onePointRandomWay(world, sArr[int(sArr.length*RAND)], WarArr.length+1,branLen,lockObj);
if(fArr.length > 0)WarArr.push(fArr);
}
}
// 填滿所有
fillWay(world, WarArr, lockObj);
var num:int = 0;
for(i=0;i<WarArr.length;i++)
{
num+=WarArr[i].length;
trace(' WarArr[i] i= ' +i +' ' + WarArr[i]);
}
trace(' num ' + num + ' endPoint ' + endPoint );
return {world:world, way:WarArr};
}
}
}
PS:
a 迷宮生成理論 淺顯易懂
http://www.4ngel.net/article/17.htm
b 迷宮 這有一系列 想法 作法 理論 更好的作法 等等
http://hctu.blogspot.tw/2005/08/blog-post_13.html
http://hctu.blogspot.tw/2005/08/blog-post_15.html
http://hctu.blogspot.tw/2005/08/blog-post_25.html 這篇是重點
前面是想法 這篇實作 後面是尋求更好的方式
http://hctu.blogspot.tw/2005/09/blog-post_06.html
http://hctu.blogspot.tw/2005/09/blog-post_07.html
http://hctu.blogspot.tw/2005/09/blog-post_13.html
c 迷宮生成 日文版的 但是有CODE 有圖 有日文說明 orz
http://wonderfl.net/c/v7Vh
http://www5d.biglobe.ne.jp/~stssk/maze/make.html
迷宮 都是比較理論向的東西 用其他的語言的寫法
http://www.doc88.com/p-67439537442.html
http://www.doc88.com/p-65320908259.html
2012年3月28日 星期三
[AS3] 取得FUNCTION 的名稱
其實我只是在想一個可以偷懶得好方法~
這樣在 LOG檔可以不用寫太多東西~
來簡介一下~
目前我會的取得FUNCTION NAME的名稱的方法
trace(getFunctionName(arguments.callee, this));
這樣子來使用!
非常麻煩 而且還有限定 是公開 非靜態的方法
雖然很早就在 Ticore 大的BLOG 上拜見過這招
不過我都一直沒想到可以拿來應用!
直到我看到某個範例
不管是靜態 公開 私用 等等的FUNCTION
通通都可以抓的到
更扯的是可以抓到上一層 上上一層
雖然還是有使用限制!
在非 debug 或是 ADL的環境下無法使用!
因為 getStackTrace 會是 null
不過跟原來的那招比~
好用很多了
更扯的是!
getFunctionName函數執行1000次 消耗的時間為2057毫秒
getName函數執行1000次 消耗的時間為45毫秒
不過直接輸出字串 約 1毫秒....
這兩個執行時間的差距!
如果你是跟我一樣的偷懶開發者!
在LOG的部分 不要忘了這招! 而且在非 debug的播放器下自動失效!
下面是我測的是文件
[SWF] C:\FlexWorks\testLocalClassCall\bin-debug\testLocalClassCall.swf - 6,432 bytes after decompression
test02函數執行1000次 消耗的時間為1843毫秒
test03函數執行1000次 消耗的時間為43毫秒
test04函數執行1000次 消耗的時間為1毫秒
[Unload SWF] C:\FlexWorks\testLocalClassCall\bin-debug\testLocalClassCall.swf
這樣在 LOG檔可以不用寫太多東西~
來簡介一下~
目前我會的取得FUNCTION NAME的名稱的方法
public function getFunctionName(f:Function, root:*):String
{
var t:Object = root;
var methods:XMLList = describeType(t)..method.@name;
for each (var m:String in methods)
if (t.hasOwnProperty(m) && t[m] != null && t[m] === f) return m;
return null;
}而且還要配合trace(getFunctionName(arguments.callee, this));
這樣子來使用!
非常麻煩 而且還有限定 是公開 非靜態的方法
雖然很早就在 Ticore 大的BLOG 上拜見過這招
不過我都一直沒想到可以拿來應用!
直到我看到某個範例
public static function getName():String {
var error:Error = new Error();
var stackTrace:String = error.getStackTrace(); // entire stack trace
if(stackTrace == null) return 'null';
var startIndex:int = stackTrace.indexOf("at ", stackTrace.indexOf("at ") + 1); //start of second line
var endIndex:int = stackTrace.indexOf("()", startIndex); // end of function name
var lastLine:String = stackTrace.substring(startIndex + 3, endIndex);
var functionSeperatorIndex:int = lastLine.indexOf('/');
var functionName:String = lastLine.substring(functionSeperatorIndex + 1, lastLine.length);
return functionName;
}
這招 BUG 到逆天了不管是靜態 公開 私用 等等的FUNCTION
通通都可以抓的到
更扯的是可以抓到上一層 上上一層
雖然還是有使用限制!
在非 debug 或是 ADL的環境下無法使用!
因為 getStackTrace 會是 null
不過跟原來的那招比~
好用很多了
更扯的是!
getFunctionName函數執行1000次 消耗的時間為2057毫秒
getName函數執行1000次 消耗的時間為45毫秒
不過直接輸出字串 約 1毫秒....
這兩個執行時間的差距!
如果你是跟我一樣的偷懶開發者!
在LOG的部分 不要忘了這招! 而且在非 debug的播放器下自動失效!
下面是我測的是文件
public function testLocalClassCall()
{
unitTestTool.addFunction('test02', this);
unitTestTool.addFunction('test03', this);
unitTestTool.addFunction('test04', this);
unitTestTool.startFunTest(1000);
unitTestTool.start();
}
public function test02():void
{
var s:String = getFunctionName(arguments.callee, this);
}
public function test03():void
{
var s:String = getName();
}
public function test04():void
{
var s:String = 'test04';
}
下面是他的輸出!(每次輸出都有差!)[SWF] C:\FlexWorks\testLocalClassCall\bin-debug\testLocalClassCall.swf - 6,432 bytes after decompression
test02函數執行1000次 消耗的時間為1843毫秒
test03函數執行1000次 消耗的時間為43毫秒
test04函數執行1000次 消耗的時間為1毫秒
[Unload SWF] C:\FlexWorks\testLocalClassCall\bin-debug\testLocalClassCall.swf
2012年3月8日 星期四
[AS3] 調教效能問題:濾鏡 並不會比較耗資源!
一樣也是在公司遇到的一個小狀況
讓我 非常非常的訝異~
多層濾鏡所構成的元件在 the miner 監測下所耗用記憶體
和 一張 PNG 所構成的元件 是一樣的!
本來我推論 可能會在 CPU 的耗用上有差異
但是更嚇的人是~
沒有~兩個我自己在測的時候都是 10% 左右~
圖中所見的差異...
那應該抓圖時間的錯置的問題...
大家可以自己回去測看看~
這個是我自己弄得一個小測試~~
個人懷疑多層濾鏡的元件
自動的轉成類似 bitmapdata的方式(我沒勾點陣快取 也沒設定)
而不是和以前一樣試即時運算的結果~
所以比較不吃資源和記憶體!
所以期待靠把濾鏡去掉 去增進效能的部分
最好還想想就好~
就我目前
做的一些部分來分享一下心得
1.
把滑鼠事件關閉 能省的資源不多
特別是物件不多的情況下
層次不多 或是 根本沒監聽的情況下
關閉 是省不了太多資源的!甚至如果你是一層一層一個一個元件關 那消耗的資源還會比較多 !
以我自己的例子 一個mc 物件下面有 200~300個 sprite原件~
你沒關 所消耗的資源量 在沒監聽的情況下
基本上 和只關 最上面 mc 元件是一樣的
如果你跟我一樣傻傻的從最裡面的 SP 元件開始關起!
那恭喜 你還會消耗更多的資源
但是我用很多 我自己覺得蠻 BUG的寫法~
利用事件流的部分~所以關閉對我自己的案子來說
是有作用的
2.
把濾鏡 換成 圖片(就這篇文章專為這點寫的)
說真的用處真的不大~
不過換成圖 還是會有一點點的縮減的
特別是你用換的圖會比較小 而且重複利用的時候
個人懷疑 他是把每個元件都快取成 點陣圖
但是每個點陣圖 是獨立存在記憶體中的!
所以換成同一個元件! 會有一點點的幫助!
3.
減少使用 movieClip 真的會節省很多資源!
特別是內有複雜原件的 mc 拆成多個 簡單的 sprite 在某種程度上
是非常有用處的
個人在這個部分 節省了相當 相當多的記憶體
第一點提到的 mc 原來內部都是用 mc 去包!
但是我只是將 底層類別改成 sprite
整體來說 減少了 20~30 mb的記憶體的資源
比我換了 400~500張左右的圖
所節省的 20mb 左右還來的多.
4.
大圖換小圖 有用!
多張靜態合成一張 有用!
5.
剩下的就是一些
縮減無用的程式碼
物件變數清空
固定不用的變數改成常數
減少使用一些過度的變數
6.
還有 到MC 的最後一格
如果你用程式讓他回到第一格!
在某些情況下 不會構成 物件 消失在建造的情況
如果你沒下 那這個物件會在更新一次
雖然不知道這部分 會影響多少~
但介意的人 就多一個CODE巴
7.
其實 timer 或是 setTimeout 等的東西
吃記憶體也是蠻凶的~個人懷疑 某開場爆增的 20mb
就是因為這個部分
不過這部分我自己是還夾了 事件發送..
等等等的東西在~
所以也不太確定!
有再考慮把這部分換成 enterFrame 去監聽 !
看看會不會比較省一點~
雖然我覺得不會~不過至少就某種程度來說
好控制~
比寫在元件最後一個影格送出EVENT 或是 seTimeout 的部分都好控制多了
雖然這幾點 感覺用處不大!
但是還是有一點點的用處~
有類似問題的可以考慮試看看
以我手上的案子~
最一開始沒調整過
開場約是 144~150 mb左右的記憶體
經過我自己一堆調整後
開場約 118 ~124
不過 穩定後 大約都是 106~118 左右的記憶體!
如果以關閉全部動畫和元件中的事件流...
穩定的時候 大約可以壓到 89mb左右....(最佳情況)
不過遊戲中 有一個算是特殊遊戲的東西~
這部分很誇張~
載入就約 220左右~
效能最高可以吃到 699mb
經過我一些調整後 大約最高 650mb
不過開場始終壓不下來~慘的是還會飆的比沒調高....
讓我自己覺得非常的失敗~
而且還是將大圖換小圖後的結果!
不過穩定約 186 mb 都是差不多的! 調前調後都一樣
不過我已經將大量 可以換成 靜態圖 取代的 濾鏡效果都替換了
連 大量的 大圖我都 換成小圖了....
這邊我想除了我從 程式的部分去調外~
原件的部分 我真的不知道怎樣調了...
[AS3] 調用本地的CLASS
調用 外部SWF 的CLASS 已經是稀鬆平常的事了~
調用本地類別 的CLASS 通常都是直接打 比較快 還有提示~
萬一本地的類別太多 須要靠拼字來調用
會讓程式碼減短一點
可以利用這招
this.loaderInfo.applicationDomain.getDefinition('className')
來調用~
這招我用很久了~
不過到最近工作才發現~
原來他有一個限制
就是一定要新增到場景上后 才能調用該類別 !
下面是測試的程式碼
理論上 會有這樣的輸出
test !!!!
mc1 : null
原來以前某些案子的 null 是這樣來的
所以以後調用 本地端的函數
還是先寫好 switch 然後~
靠拼字去取得 class 比較妥當
調用本地類別 的CLASS 通常都是直接打 比較快 還有提示~
萬一本地的類別太多 須要靠拼字來調用
會讓程式碼減短一點
可以利用這招
this.loaderInfo.applicationDomain.getDefinition('className')
來調用~
這招我用很久了~
不過到最近工作才發現~
原來他有一個限制
就是一定要新增到場景上后 才能調用該類別 !
下面是測試的程式碼
package
{
import flash.display.Sprite;
public class testLocalClassCall extends Sprite
{
public function testLocalClassCall()
{
trace("test !!!!");
var cla:Class;
if(this.loaderInfo.applicationDomain.hasDefinition('mc1'))
cla = this.loaderInfo.applicationDomain.getDefinition('mc1') as Class;
trace('mc1 ' + cla)
}
}
}理論上 會有這樣的輸出
test !!!!
mc1 : null
原來以前某些案子的 null 是這樣來的
所以以後調用 本地端的函數
還是先寫好 switch 然後~
靠拼字去取得 class 比較妥當
訂閱:
文章
(
Atom
)

