編輯:Android游戲開發
第18天:外星人圖形與圓形沖突、完美的子彈軌跡
今天我受夠了“射擊月亮”bug。有時候外星人即使在屏幕中出現,也可能射不中。我做了大量測試,在屏幕上布滿外星人並且設置月亮半透明以定位這個bug的原因。我發現測試擊中區域的坐標偏移了一個bit位,但即使解決了這個問題原先的bug依然存在。外星人圖形不能簡單用圓形覆蓋,否則玩家要麼射不到外星人,要麼會射到隱蔽在月亮下的外星人。
所以我決定使用圓形檢查。由於月亮比外星人大很多,能夠很容易地檢查外星人圖形邊緣的四個點是否都在圓形月亮內。為了測試,我使用libGDX內置的ShapeRender類,具體的實現代碼如下:
Java代碼上面的代碼加在SpriteBatch完成以後,沿著月亮表面畫白色的圓圈。類似地,給外星人邊界畫上長方形。
測試一個點是否在圓內的高效方法不是計算平方根(速度較慢)而是比較距離的平方。libGDX的內置函數Circle.contains(x,y)恰好實現了這個功能,所以我使用了這個函數進行檢查。事實證明這個方法非常有效。我為半徑長度增加了一些像素值,因為所有外星人之間會有一些間隔。改動後的結果令我非常滿意。
完美的子彈軌跡
在這個游戲中,子彈是從距離屏幕下方50像素值的地方發射的。我使用了函數atan2讓子彈旋轉著擊中目標,但我的代碼中有一些錯誤,在沒有射中目標時錯誤會經常出現。為了理解這部分內容,請注意在這個游戲所有的射擊都采用了HitScan策略。
譯注:HitScan與射擊目標相對,指的是射擊出的子彈不針對任何目標而是摧毀子彈運行軌跡上的任何物體。
在沒有射中目標時,現在的代碼將子彈軌跡延伸到屏幕盡頭,而以前的代碼把盡頭設置得太遠。由於子彈的飛行使用了中間位置,結果看上去有很大的跳躍並且在子彈射出屏幕之前只能看到2、3個點。通過把結束點設置到屏幕的邊緣來解決了這個問題,現在你能清楚地看到子彈在飛行。
這時又暴露出另外一個問題:子彈有時候距離玩家接觸的屏幕點只有10到20個像素點。導致這個問題有三個原因。第一個問題,我使用了子彈的X坐標和Y坐標。由於這個坐標位於屏幕底部的角落。通過把子彈的中心坐標加上一半的寬和高解決了這個問題。但仍有一些子彈沒有射中。第二個問題,我忘記設置原點,所以子彈圍繞著左下角進行旋轉。這個問題也解決了,但仍有一些朝屏幕左邊射射出的子彈沒有射中。
第三個問題,我意識到當子彈旋轉時寬度和高度是在變化的,所以子彈的中心點需要在旋轉後需要重新計算。解決了這個問題,子彈就能正確地從玩家觸摸的地方射擊。修改後的代碼如下:
Java代碼第19天:每日挑戰和任務
每日挑戰是收集5個字母,操作方式和道具一樣。一旦收集了所有字母,就可以得到一些用於購買道具的游戲幣。這是一個通過玩游戲獲取硬幣的簡單方法,這個靈感是受到“地鐵跑酷”(Subway Surfers)的啟發。
任務由許多子任務組成,通過完成這些子任務可以賺取硬幣。硬幣可以用於購買升級道具和消費物質,如盔甲、炸彈等等。每天的任務由三部分組成,你必須完成所有三項子任務才能獲得獎勵。
我發現使用內置的文本換行來顯示任務比較簡單。然而行高會顯得過大,而且直接修改代碼沒有辦法減小行高。因此我選擇編輯由BMFont生成的.fnt文件,進行如下調整:
lineHeight=33
變成
lineHeight=23
在開始生成位圖時,我在字母的四周增加了5個像素的陰影,所以現在需要把高度減少了10像素(上面減少5像素,下面減少5像素)。
在為此查找文檔時,我發現了一些先前遺漏的問題:在為游戲選擇字體時,可能數字看起來效果不是很好。數字1看起來很修長,而數字11看起來很奇怪。要解決這個問題,可以為圖中的字體設置固定寬度。
font.setFixedWidthGlyphs("0123456789");
這樣效果看起來會非常好。但由於已經決定使用修長字體,因而沒有采用固定寬度。
第20天:周挑戰、用戶數據持久化、Java日期災難
周挑戰是在一周內收集特定數目的星星,從而獲得一些優異的獎勵,如8個原子彈、5個盔甲等等。我用Gimp做了一個很棒的金色星星並在嘗試了不同的閃爍和星光效果,但是這些看上去效果不是特別好。所以我想到了強化道具的粒子效果,對它進行改變直到滿足星星的要求。星星有了自己的閃爍節奏,而且可以在屏幕上同時顯示星星和強化道具。
我還添加了玩家數據的加載和保存。這個比我想象中要簡單。我以為必須學習一些Android的數據存儲API,但libGDX提供了簡單鍵值存儲類。只要調用以下代碼進行初始化:
Preferences prefs = Gdx.app.getPreferences("DroneInvaders");
然後使用get(“key”, defaultValute)和set(key,value)進行值的讀寫。
我唯一遇到的麻煩是時間問題。為了持續跟蹤天挑戰和周挑戰,必須存儲最後玩游戲的時間。當玩家開始游戲,系統比較這個時間並重新設置一些計數器。理論上我可以阻止玩家將系統日歷修改到過去的時間,但是我不想這麼做。當時間回滾時,我所做的是設置新的每日挑戰和周挑戰並且重置星星和搜集到的字母個數。
為了實現這個功能,必須獲取上一次玩游戲的時間並計算與當前的時間差。是否是同一天、一天前或幾天前都會影響計算結果。我在谷歌上搜索到很多討論這個問題的網站以及StackOverflow問題。大多數答案很好笑。許多程序員簡單地用相差的秒數來計算時間差,然後除以60*60*24得到天數,完全忽略了夏令時和閏秒。有人會爭辯說,對一個游戲來說這個差別影響不大。但是我不喜歡每年收到2次大量的bug報告。另一些家伙簡單地通過從開始到結束日期一天天累加天數。這些循環看起來是正確的,但是計算結果還是會丟失了部分時間。比如一個對象在1月1號上午5點存儲了,然後你在1月2好晚上23點計算時間差,在第一個時間點上加上1天仍然比第二個時間點少。但是按他們的計算方法,實際增加了2天。
在這種情況下,我使用的一個技巧是總是設置前一次游戲的日期為早上10點,而設置最後一次游戲的日期為下午5點。盡管夏令時總是在晚上改變,但是這個設置是安全的。因為即使如果有一天有人決定夏令時的變化發生在中午,在這之間同樣也有7個小時。
進行軟件開發時,通常我們都喜歡使用較新版本的工具,但這裡我為什麼使用低版本的SDK來開發A
上一節講了如何使用SharedPreference和File流存儲數據,同時建
很多Android手機都沒有實體的上下左右導航鍵,那麼怎麼控制游戲方向呢?An
第6天:第一批外星人和屏幕方向 好了,現在有了一些復古風格的外星人它們正在到處飛。抱歉,暫時還沒有demo。這款Andriod游戲目前只有.apk