跳到主要內容

發表文章

Good Game Editor 1.4.2

* 支援Good.GenObj可以生成任意關卡資源內的子物件。 * 修正搜尋路徑(Search Path Dependency)的錯誤。 這個功能作好後一直沒真正被使用,所以也一直沒有發現到有問題。所以說, 沒用到的功能還是儘可能不要去作 ! * 播放器(In Editor Player)新增顯示目前使用貼圖資訊(Ctrl+Alt+T)。 * 編輯器新增輸出ZIP格式資源包(Create ZIP Package)。 * 擴充Good.GetTexId可以回傳地圖物件(MAPBG)的貼圖ID。 下載Good Game Editor 1.4.2 下載Good Game Player 1.4.2 for Android

逆轉大老2的AI

逆轉大老2 是大老2遊戲的改良玩法,靈感是來自小時候在掌機上玩過的某個遊戲。  逆轉大老2遊戲規則- * 遊戲使用整副牌52張+2張鬼牌。 * 牌型包含(單張,對子,三條,四條,同花順),同花順最少3張沒有張數上限。 * 只比數字大小,不比花色。 * 數字3最小,依次為3<4<5<6<7<8<9<10<J<Q<K<A<2<鬼牌最大。 * 每次打出四條時大小逆轉2變最小,依次為2<A<K<Q<J<10<9<8<7<6<5<4<3<鬼牌還是最大。 * 鬼牌可以當作任意牌和其它牌配對。例如:鬼牌+2=2一對,方塊2+鬼牌+方塊4=234順子。 * 遊戲開始,手上有梅花3的玩家先出手,可以打包含梅花3的任意牌型的牌。 * 下家要跟上家打出同樣的牌型的牌,無法出牌則PASS。 * 若三家都PASS,則有得到先手權可以再打出新的任意牌型的牌。 * 三家把手上的牌都打完只剩一家未完時,牌局結束。 << Free Android Download >> ; 目前遊戲內容定義了4個不同分級的AI,不過目前第4級AI還沒實作,等未來視情況再看看... AI1:簡單的規則讓AI動起來 手上有梅花作為開局者,出單張梅花3。 順位的情況,出最小的單張牌。 下手跟著上手出同類牌組,數字>上手即可。 無牌可出PASS。 重覆2-4,直到打完手上牌為止。 AI2:計算牌組分數決定出什麼牌 根據已經打出的桌面上的牌和自己手上的牌來計算每張牌的分數來估計自己手上所有牌的分數(被蓋牌的機率),若自己手上有二張3和一張5,且還有一張4和二張6未出(共三張牌未出),則: 3的分數 = (可蓋過3的牌數)/(總牌數) = (1(1張5) + 2(2張6)) / 3 5的分數 = (可蓋過5的牌數)/(總牌數) = 2(2張6) / 3 分數的調整:每張牌計算出分數後再作調整 若這張牌可以是對子(/2) 若這張牌可以是三條(/3) 若這張牌可以是順子(/3.5) 若這張牌可以是四條(/4) 自己手上這把牌的總分 = 3的分數/2(對子) + 3的分數/2(對子) + 5的分數 = (3/3)/2 + (3/3)/2 + 2/3 計算所有可能牌型各別打出後的牌組分數,得分最低分者為...

使用source control system的壞習慣

很多人都有使用 source control system(SCM) 的好習慣,不過我也發現到有些人在使用SCM時的壞習慣,以致於把使用SCM的好處給抵消掉不少,有時候甚至還得到反效果。其實我自己在初期剛使用SCM時,也是犯了同樣的壞習慣,一直到後來才意識到。因為這個壞習慣是那麼的不明顯,以致於大多數人都很自然而然的犯而不自知。 這個壞習慣是什麼呢? 那就是把SCM當作是純粹的source code database來使用。為什麼我會說這是一個壞習慣(或錯誤)?雖然說source code database原本也是SCM的功能之一,但我認為並不是最重要的功能,最重要的功能應該是在control這個字的功能上面才對。SCM讓我們對source所作的修改、內容增減作記錄,每一筆記錄就是一個版本,每一個版本的所有變動都匯入到database裡。我們可以透過SCM client介面對這些版本作檢視,隨時可以更新到任意版本,隨時復原所作的變動回到指定版本。 在軟體開發過程中,有一大半都是在對原有的程式作修改,尤其是在大型的系統來說,有更多的小修改、錯誤修正等等。想想看,假如某一個版本的修改(bugfix或功能增減)僅在一個版本裡面就包含了十項、數十項或甚至數百項或更多的修改會是什麼樣的情況? 當開發的軟體一切都正常的時候,把SCM當作source備份的database沒什麼問題,事實上也很合適。但是軟體的開發並不那麼簡單順利,尤其是大型系統的開發過程中,絕對會產生大大小小的bug。這些bug有時候很容易就可以解決修正,在一些複雜系統裡面,有些bug需要利用復原回朔(revert)的功能,將修改的內容還原到舊版本,一個一個版本往上回朔檢查問題是從那一個版本開始發生的。利用這個雖然辛苦但有效的土方法來找到問題發生點的版本,再去比對所作的修改是那裡產生的問題再去修正。 想想看當你用回朔法找到你想要解決的問題發生的某個版本,而在這個版本裡面有一堆的修改,裡面混雜了多個bug修正、功能增減等等會是什麼樣的情況?這一定會增加debug的難度。如果在這個版本裡面只包含對一件事情的修改,無論是bugfix或是功能增減,要回朔到上一個版本一定是件相對容易多的事情。一個版本只作一件事情,同時對於review也會是一件單純的事情。 所以對於SCM的使用,我永遠都秉持底下幾個...

Android遊戲5連發的一些記錄

這二個月裡面很密集的連發了5款android小遊戲,雖然這些遊戲主要都是移植或改版的作品,但在作移植或改版的過程還是學到了一些東西,並且最重要的是又對good作了點改良,雖然都是小改進但也是小進步,只要持續的作,這些小改進累積起來也是很可觀的 !這篇文章主要目的是在作這幾個遊戲的過程中,把那些值得記錄的事寫出來。 1, 跳跳伯尼熊 UpUp! 某一天終於心血來潮,很想要把什麼遊戲放上google play。這個遊戲是很早之前就完成的,因為也都是用GL成像的,程式也不大所以就挑了它開工。 移植UpUp第一個版本到android手機上很快,大概只花了不到二個小時,因為在那之前我就已經 移植過good ,直接套用相關的經驗很快就可以在手機上執行UpUp。完成第一步的任務後,接下來就要改版了。原來的設計是單機的,有個單人排行榜,現在要改版成有個多人排行榜。為了作到這件事,有好幾件事需要完成。 首先需要有個排行榜的server,這個功能我用php+mysql作了一個很陽春的server,透過http 和json作溝通。 玩家在排行榜上的名字要怎麼來?原來的版本是在gameover,成績有上排行榜時,讓user輸入,不過因為我只用了英數符圖的字圖,所以最後改成抓google account,然後再一開始用toast顯示。 AccountManager accountManager = AccountManager.get(this); Account[] accounts = accountManager.getAccountsByType("com.google"); String name = accounts[0].name; myName = name.substring(0, name.indexOf("@")); Toast.makeText(getBaseContext(), "hello " + myName, Toast.LENGTH_SHORT).show(); 再來就是聲音的處理。將相關的資源檔放在res/raw目錄下,再透過MediaPlayer.create(this, idRes);作到播放聲音的功能。 2, 報數快手123   ( src ) ...

Good Game Editor 1.4 Release

* 粒子程式編輯器(STGE Script Editor)編譯程式前提示存檔。 * 動作編輯器(Sprite Editor)選取項目使用紅色框。 * 新增Resource.GetMapTileSize。 * 新增範例snake(貪食蛇)。 * 新增範例solar(物件階層)。 * 取消TGA圖形格式支援。 * 最佳化繪圖程序。 * 修正Good.Clone的錯誤。 * 動作編輯器(Sprite Editor)改版,整合Preview視窗至編輯區。 * 修正Good.CallPackage機制堆疊錯誤。 * 更名Resource.GetMapTileSize為Resource.GetTileSize。 * 更名Resource.GetTextureId為Resource.GetTexId。 * 更名Resource.GetTextureSize為Resource.GetTexSize。 * 更名Resource.GetTileMapSize為Resource.GetMapSize。 * 更名Sound.ReleaseSound為Sound.KillSound。 * 線上API參考手冊改連至 WIKI 。 * 關卡編輯器(Level Editor)新增自訂貼齊格線大小。 * 修正當Tile寬高不同時顯示地圖物件的錯誤。 * 修正Resource.GetNextLevelId錯誤。 * 新增範例link(連連看)。 * 自動儲存及載入視窗屬性。 * 編輯器內建的播放器支援即時顯示除錯訊息。 * 修正開啟另一個專案時程式崩塌的錯誤。 * 修正Good.PickObj無法Pick子物件的錯誤。 * 移除Good.PickColorBgObj/PickMapObj/PickSpriteObj/PickTexBgObj。 * 新增Good.PauseAnim。 * 新增Good.AddChild index參數,允許指定位置加入父物件。 * 所有類型的物件都可在關卡編輯器(Level Editor)中指定顏色。 * 新增Good.IsAnimPlaying。 * 新增開新專案對話盒(New Project Dialog)。 * 編輯器不支援縮放。 * 新增範例numbers。 * 新增關卡編輯器貼圖物...

Reduce C++ code size

如果拿程式執行速度和code size二者來比的話,我個人會先偏好較小的code size,而不會特別先去關注較快的執行速度,除非效能問題是個問題。很多時候,較小的code size,也意謂著較快的速度。C++程式最讓人經常誤解的一點是,會產生較大的code size,較慢的執行速度是另一個常見的迷思。不過事實上,在使用STL之類的template library或template class時,的確使用不當的話是特別容易產生較大的code size。下面提供幾個簡單的要點,可以幫忙稍減code size。 使用compiler的最佳化選項。一般分為針對執行速度最佳化或code size最佳化。以Visual Studio為例,/O1是minimize size對code size最佳化,/O2是maximize speed對執行速度作最佳化。 避免重複。把common code抽出來,作成function,library或之類的東西。減少source size也減少code size,也減少bug發生的可能性。 砍掉沒用的code。整支程式裡面若是包含了大量的無用程式,除了增加code size外,也可能會隱藏潛在的bug。花點時間,整理一個你的程式把無用的程式碼,短期內或可見的未來內用不到的程式碼清一清。不要過早加入用不到的功能,減少code size也減少bug。 不要include <iostream> ,假如你沒有用使用cin/cout/cerr/clog之類的內建物件。用include < iosfwd> 來取代 ,避免包含使用不到的物件來減少code size。 避免類似型別參數的template類。例如:vector<int> ,vector <unsigned int> 等,這些類別的參數可以替換成同一種型別,例如vector<unsigned int> 。使用同一類別的template容器,也能減少code size。 減少使用exception及RTTI。沒必要的話,減少使用exception及RTTI也能減少code size。 以上是幾個大方向上,如何減少code size的要點。當然還有一些手法,但都是較細節的小技巧,不一定有什麼幫助。就好像在作最佳...

HTML5 互動式象棋譜

十多年前在舊書攤上挖到寶,發現一本曾經在某處讀到得到高度評價的棋譜”佈局津梁”,雖然只有下集,立刻把它買下來,印象中花了100塊左右,現在倒是漲了不少,可惜的是一直找不到上集...不過和許多買過的書的下場同樣,後來大多變成收藏用,只有有時候心血來潮會把它拿出來翻看。因為這本書的年紀比我大,怕把它給翻壞了,事實上封面皮都快掉了,好像隨時都要碎掉的感覺,所以後來花了不少時間將內容手工輸入電腦建檔。最近因為玩些HTML5的東西,所以順便就把它作成網頁版本,實作一個簡易版的互動式棋盤幫助看譜,順便當作練習題。程式很簡單,倒是花了非常大量的時間在校對棋譜內容改正原書的錯誤,不過因為個人能力有限還是有許多錯誤還沒更正... 這個程式主要在Chrome及Firefox測過,手機版viewport寬限定為320。 ( 玩玩看 ) 整個程式很簡單,因為棋譜格式是制式的,所以只需要利用幾個簡單的re的幫忙,很簡單的可以用來找出那一段是文字那一段是棋譜,然後再parse出棋譜內容走步。基本上棋譜還是以字串方式作處理,只要棋譜格式及內容沒有錯誤,都能正確演示。有任何顯示錯誤,則表示棋譜格式或內容有誤,因為我並沒有多作錯誤的檢查。 實際實作時在Chrome及Firefox有二個地方需要特別注意。 Firefox不支援innerText的用法,需改用textContent。實作上可以簡單以a = p.innerText || p.textContent解決。 Firefox不支援mouse event的offsetX/offsetY,我們可以另外包裝一個getOffset的函式解決: function getOffset(e) { if (e.offsetX) { return {x:e.offsetX, y:e.offsetY}; } var el = e.target; var offset = {x:0, y:0}; while (el.offsetParent) { offset.x += el.offsetLeft; offset.y += el.offsetTop; el = el.offsetParent; } offset.x = e.pageX - offset.x; offs...