Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android游戲 >> Android游戲開發 >> 23天從0開始完成一款Android游戲開發 – 第15~17天

23天從0開始完成一款Android游戲開發 – 第15~17天

編輯:Android游戲開發

  第15天: Android“後退”按鈕、主菜單、固定坐標bug

  還記得第11天屏幕坐標和鼠標點擊射擊不到外星人的問題嗎?是的,那都是我的錯。幸運的是這讓我及時發現了很多下載游戲的Android用戶屏幕分辨率並不是800×400。在那之前我是這樣直接轉換觸摸坐標到實際坐標:

Java代碼
  1. float x = Gdx.input.getX() - 240f;  
  2. float y = 400 - Gdx.input.getY();  

  這不是正確的做法。簡單恰當的辦法是通過GDX進行轉換 :

Java代碼
  1. Vector3 touchPos;  
  2. touchPos.set(Gdx.input.getX(), Gdx.input.getY(), 0);  
  3. camera.unproject(touchPos);  

  在Android上處理“返回”按鈕

  大多數網上的例子在處理“返回”按鈕時都談到重載KeyDown方法。不幸的是這種辦法要求使用Stage,我沒有這麼做。我知道現在的代碼裡復制了很多Actor和Stage,但那不重要。在下一個項目裡我才會使用Stage。

  幸運的是,我找到了解決辦法。只要在Game子類的create()函數裡添加下面函數:

Java代碼
  1. Gdx.input.setCatchBackKey(true);  

  然後在render()方法中檢查否已經按下“返回”按鈕:

Java代碼
  1. if (Gdx.input.isKeyPressed(Keys.BACK))  
  2. {  
  3.     Gdx.app.exit();  
  4. }  

  由於render()每秒鐘會被調用很多次,你可能需要一個boolean標記變量來檢測“返回”按鈕是否已釋放。

Java代碼
  1. if (backReleased && Gdx.input.isKeyPressed(Keys.BACK))  
  2. {  
  3.     backReleased = false;  
  4.     Gdx.app.exit();  
  5. }  
  6. else  
  7. {  
  8.     backReleased = true;  
  9. }  

  現在可以進入游戲,進入商店菜單,然後返回主菜單。當然,菜單只顯示選項,還沒有真正實現功能。

  使用9-patch處理動態大小的按鈕和容器

  注:9-patch一個對png圖片做處理的工具,能夠為生成一個“*.9.png”的圖片實現部分拉升。

  我還學會了如何使用9-patch創建漂亮的按鈕。有一次,我意識到不得不像繪制10個大小不同的選項按鈕,但樣子基本上一模一樣只有裡面的內容不同。我甚至參考了Gdx按鈕,但最終還是決定自己DIY一個。在我游戲裡,按鈕有一些特殊需求,在一個文本按鈕裡要結合了2張圖、4個文本以及2種不同字體。

  無論如何,我得畫一個包括所有按鈕尺寸和其他的東西的46×46 9-patch圖片,然後寫一些代碼定制其他覆蓋在圖片上面的東西。我在構造函數裡通過TextureRegion從大皮膚裡提取9-patch。減掉了一個皮膚開關。

  通過這種處理使我得以有各種不同的選擇來填充主菜單,同時我還加入了滾動字幕給出玩法提示。我真的很喜歡這個概念,但很少有游戲使用它。有的游戲只顯在一開始的時候有個提示。也許他們不想讓玩家看主菜單時分心吧。

  下面是購買強化道具的商店菜單:

23天從0開始完成一款Android游戲開發 – 第15~17天

  強化道具

  關於道具我又有了一些新點子。一種是可以暫時讓外星人減速,另一種是在短時間內積分x5。我正在考慮移除之前商店裡的“雙倍積分”道具。有些玩家真的很能得高分,所以這可能是一個壞主意。

  另一方面,在下次裝彈前能增加射速的道具可能會大受歡迎,所以我正在加入。

  我希望商店能保持只有7個道具,這樣就能剛好在一個屏幕內顯示。但現在我不肯定所有可能的升級……拭目以待吧。

  第16天:從GDX游戲中錄制影片

  視頻地址:www.youtube.com/embed/RUy177pvT8I?rel=0

  我曾想過在YouTube上傳游戲視頻,然後用recordmydesktop程序錄制,但結果一團糟。由於libGDX和RMD不同步,我在屏幕上看到的是一堆零件,諸如被切掉了一半的精靈等等。我搜索了一下發現了幾篇有用的文章。基本上都是將每幀做成一個PNG文件然後組成視頻。可以想見這麼做會耗費大量的磁盤空間,這對我不是大問題。我發現了一個很有用的帖子:

  http://www.wendytech.de/2012/07/opengl-screen-capture-in-real-time/

  然而,他們的代碼有一些問題。出於某種原因,當我用半透明精靈疊加在背景上時,由此產生的PNG文件在那塊區域會出現半透明像素。這樣生成的視頻會有很多亂七八糟的東西。我嘗試了不同的設置,甚至改變渲染代碼,但問題依舊。現在,只要一個簡單的處理步驟——使用ImageMagick(加入黑色背景)就可以解決這個問題。所以我想,如果無論如何都要做這步處理,我可能還要在ImageMagick中做垂直翻轉。所以我關掉了代碼中的Y軸翻轉,這使得它更有效率,從而沒有必要在每一幀中分配w *h*4個字節的內存。在800×480的屏幕上,每一幀大約需要1.5MB!

  同時,處理幀率(跳幀)的代碼沒有怎麼優化。處理過程跳過了幾個文件號,這沒什麼問題。但同時還給每幀還創建了對應的ScreenShot對象,這完全沒有必要。譬如你正在錄制30fps的視頻而游戲運行速率是60fps,你花了一半的時間在創建完全用不到的對象上。

  最後,FPS處理代碼似乎沒有釋放像素圖。所以如果你運行了很長的時間,RAM會被吃光。

  所以,我從ScreenShot類裡提取出了全部的FPS代碼,剩下的代碼只負責處理連續視頻。我還注意到一些變量有初始化但從未使用過。現在ScreenShot類變得更加直觀並且易於理解:

Java代碼
  1. public class ScreenShot implements Runnable  
  2. {  
  3.   private static int fileCounter = 0;  
  4.   private Pixmap pixmap;  
  5.   
  6.   @Override  
  7.   public void run()  
  8.   {  
  9.       saveScreenshot();  
  10.   }  
  11.   
  12.   public void prepare()  
  13.   {  
  14.       getScreenshot(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), false);  
  15.   }  
  16.   
  17.   public void saveScreenshot()  
  18.   {  
  19.       FileHandle file = new FileHandle("/tmp/shot_"+ String.format("%06d", fileCounter++) + ".png");  
  20.       PixmapIO.writePNG(file, pixmap);  
  21.       pixmap.dispose();  
  22.   }  
  23.   
  24.   public void getScreenshot(int x, int y, int w, int h, boolean flipY)  
  25.   {  
  26.       Gdx.gl.glPixelStorei(GL10.GL_PACK_ALIGNMENT, 1);  
  27.       pixmap = new Pixmap(w, h, Pixmap.Format.RGBA8888);  
  28.       Gdx.gl.glReadPixels(x, y, w, h, GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE, pixmap.getPixels());  
  29.   }  
  30. }  

  好了,全部就這麼多。我在渲染循環中的每個渲染結尾加上了:

Java代碼
  1. ScreenShot worker = new ScreenShot();  
  2. worker.prepare(); // grab screenshot  
  3. executor.execute(worker); // delayed save in other thread  

  考慮到完整性,在Screen的子類添加了executor:

Java代碼
  1. private ExecutorService executor;  
  2. ...  
  3. executor = Executors.newFixedThreadPool(25);  

  現在,在我的酷睿2已經趕不上幀率了。這是好消息,一方面因為游戲速度變慢我能夠錄下更好的視頻,另一方面能更好地記錄截圖以供稍後導出視頻。所以我添加了一個截圖熱鍵。在按住S鍵時開始錄制,當你只是記錄了一些有趣的片段,松開S鍵讓PNG writer趕上進度。當CPU的負荷恢復到正常,意味著PNG都生成好了,你可以再次開始錄制。

  這種方式創建的視頻很容易編輯。只要刪除不需要的PNG文件,用剩下的壓制視頻即可。而且這種方法也很容易與音樂同步,因為可以隨意添加或刪除幀。

  用截圖生成YouTube視頻

  由於Android屏幕默認分辨率是480×800,而最接近YouTube的分辨率是1280 x720。因此需要將圖像縮放到432×720 ,以保持寬高比。這樣兩邊會多出很多未使用的面積。你可以把你的logo、廣告貼上去,甚至可以並排顯示兩個視頻。我決定用另一段視頻填補空白,那是我用一台手持設備拍攝的,所以圖像更小只有372×620。

  現在,我創建了一個大小1280×720包含了logo的靜態圖像。現在我把它混合進游戲,並垂直翻轉。在Linux上,我使用這樣的命令:

  for i in shot*png; do echo $i; convert $i -flip -filter Lanczos -resize 372x620 temp1.png; composite temp1.png back.png -geometry +126+56 $i; done

  一旦所有的圖像都准備就緒,就可以運行MEncoder來導出視頻。YouTube建議720p的視頻采用H.264格式和5000以上的比特率 。他們還建議兩個B幀(RGB)。這裡是執行的命令:

  mencoder mf://shot*.png -mf w=1080:h=720:fps=25:type=png -ovc x264 -audiofile music.mp3 -oac copy -o movie.avi -x264encopts bitrate=5000:bframes=2:subq=6:frameref=3:pass=1:nr=2000

  這樣就生成了一個質量過硬的YouTube游戲視頻。在這篇文章的開始,你可以看到我的成果。至於音頻,我只是提取了一些游戲的音軌並沒有捕捉實際游戲中的音頻。

  第17天:Android圖標、完成道具

  我喜歡Android允許(甚至建議)圖標不是圓角矩形。這樣可以賦予游戲自己的個性風格。起初,我考慮過給這游戲做一個特殊的圖標,但我真的非常非常喜歡這個畫著外星人像素圖形的盾。我用Inkscape制作,這樣就可以輸出任意大小的圖片(而不像在GIMP下制作的其他一些圖形)。獻上Drone Invaders官方圖標:

23天從0開始完成一款Android游戲開發 – 第15~17天

  豐富的道具

  下面的視頻顯示所有收藏的強化道具:

  http://www.youtube.com/embed/SZ73G0n6cm4?rel=0

  我准備了原子彈,但名字還沒有最終確定。也許會叫核彈、钚炸彈、智能炸彈或完全不同的東西。它會摧毀屏幕上的一切。Boss能抵擋一兩個,但遇到三個炸彈一樣完蛋。在系統內部,每個Boss有20點血而炸彈有8點的傷害。普通攻擊就是1點傷害,除非你升級激光。

  其次,有3路散彈。射擊三次仍然要更換彈夾。這是一個非常強大的道具,有了它,真是人擋殺人佛當殺佛,清理掉一波波的怪物和boss。

  第三,自動重裝填。正如名字那樣,你的激光會自動加載。所以可以自由地射擊,射擊,再射擊。

  第四,減速。它只是減緩外星人的移動速度,其他一切速度正常。在前20關這玩意兒相當廢柴。但越到後來,你就越覺得它有用。

  第五,雙倍積分。在道具作用期間,獲得的點數翻一倍。我仍然在考慮是否要在達到某個分數的時候給予獎勵,但達到高分仍是一件很酷的事情。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved