5、使用Libgdx設計一個簡單的遊戲------雨滴

weixin_33941350發表於2017-05-03

(原文:http://www.libgdx.cn/topic/49/5-%E4%BD%BF%E7%94%A8libgdx%E8%AE%BE%E8%AE%A1%E4%B8%80%E4%B8%AA%E7%AE%80%E5%8D%95%E7%9A%84%E6%B8%B8%E6%88%8F-%E9%9B%A8%E6%BB%B4

在深入研究Libgdx提供的API之前,我們先來建立一個簡單的遊戲來感受一下libgdx各個功能。這裡將簡單的對一些功能做介紹。

使用的技術:

  • 檔案訪問

  • 清除螢幕

  • 渲染圖片

  • 使用相機

  • 主要的輸入

  • 播放音效

專案設定
首先建立一個libgdx專案,移步到這裡

  • 應用名稱(Application name):drop

  • 包名(Package name):cn.libgdx.drop

  • 遊戲類(Game class):Drop

生成專案之後,將其匯入到eclipse中(須要記住,是Gradle專案)。

遊戲設計思路
遊戲思路非常easy:

  • 使用一個桶雨滴

  • 桶在螢幕底部

  • 雨滴隨機從螢幕頂部下載。加速下落

  • 玩家能夠水平拖動桶

  • 遊戲沒有結束

Assets檔案

點選下載資原始檔

我們須要一些圖片和音效來讓遊戲變得更好。對於影象來說我們須要設定解析度為800*480畫素(在Android中要設定為橫向(landscape ))。假設裝置沒有這個解析度,我們須要設定適用螢幕。
為了讓資原始檔在遊戲中可用。我們必須將資原始檔放到Android專案的assets目錄下。

一共四個檔案:drop.wav。rain.mp3。droplet.png和bucket.png。

把他們放到drop-android/assets/目錄下。

配置啟動類
準備完之前的配置後。我們須要改動desktop專案的啟動類。開啟drop-desktop專案下的DesktopLauncher.java檔案。我們須要設定窗體為800*480,設定窗體標題為“雨滴”。程式碼例如以下:

package cn.libgdx.drop.desktop;

import com.badlogic.gdx.backends.lwjgl.LwjglApplication;
import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration;
import cn.libgdx.drop.Drop;

public class DesktopLauncher {
public static void main (String[] arg) {
LwjglApplicationConfiguration config = new LwjglApplicationConfiguration();
config.title="雨滴";
config.width=800;
config.height=480;
new LwjglApplication(new Drop(), config);
}
}

找到Android專案(即drop-android)。須要設定應用的螢幕方向。所以須要改動專案根資料夾AndroidManifest.xml檔案,設定android:screenOrientation="landscape"。程式碼例如以下:

<?

xml version="1.0" encoding="utf-8"?

>
<manifest xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
package="cn.libgdx.drop.android"
android:versionCode="1"
android:versionName=&quot;1.0&quot; >

<uses-sdk android:minSdkVersion="8" android:targetSdkVersion="21" />

<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/GdxTheme" >
<activity
android:name=&quot;cn.libgdx.drop.android.AndroidLauncher&quot;
android:label="@string/app_name"
android:screenOrientation="landscape"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize">
<intent-filter>
<action android:name=&quot;android.intent.action.MAIN&quot; />
<category android:name=&quot;android.intent.category.LAUNCHER&quot; />
</intent-filter>
</activity>
</application>

</manifest>

事實上是用GDX-setup生成的專案android:screenOrientation預設值為landscape。所以無需修改。


接下來須要禁用加速度計和羅盤。這須要修改Android專案AndroidLauncher.java檔案,程式碼例如以下:
package cn.libgdx.drop.android;

import android.os.Bundle;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.backends.android.AndroidApplication;
import com.badlogic.gdx.backends.android.AndroidApplicationConfiguration;

import cn.libgdx.drop.Drop;

public class AndroidLauncher extends AndroidApplication {
@Override
protected void onCreate (Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
AndroidApplicationConfiguration config = new AndroidApplicationConfiguration();
config.useAccelerometer=false;
config.useCompass=false;
initialize(new Drop(), config);
}
}

我們不能定義Activity的解析度,這個是由Android作業系統來定。

就像我們之前定義的,設定全部平臺解析度為800*480。

開始編寫程式碼

如今將程式碼分成幾個部分來分析。為了保持專案的可移植性,我們須要將程式碼寫到core專案下。

載入Assets
我們第一個任務就是載入assets檔案和儲存引數。Assets通常在ApplicationListener.create()方法中載入,程式碼例如以下:

package cn.libgdx.drop;

import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.audio.Music;
import com.badlogic.gdx.audio.Sound;
import com.badlogic.gdx.graphics.GL20http://com.badlogic.gdx.graphics.GL200;
import com.badlogic.gdx.graphics.Texturehttp://com.badlogic.gdx.graphics.Texturee;
import com.badlogic.gdx.graphics.g2d.SpriteBatchhttp://com.badlogic.gdx.graphics.g2d.SpriteBatchh;

public class Drop extends ApplicationAdapter {
private Texture dropImage;
private Texture bucketImage;
private Sound dropSound;
private Music rainMusic;

@Override
public void create () {
//將資源載入到GPU中。
dropImage=new Texture(Gdx.files.internal("droplet.png"));
bucketImage=new Texture(Gdx.files.internal("bucket.png"));
//載入雨滴音效和下雨背景音樂
dropSound=Gdx.audio.newSound(Gdx.files.internal("drop.wav"));
rainMusic=Gdx.audio.newMusic(Gdx.files.internal("rain.mp3"));
//開始播放背景音樂
rainMusic.setLooping(true);
rainMusic.play();
}

@Override
public void render () {

}
}

在create()方法中前兩行載入雨滴和桶。Texture是指將影象載入並儲存到快取。Texture通過一個檔案控制程式碼(FileHandle)。FileHandle通過Gdx.files獲取。這裡有不同的檔案。假設是呼叫Android下assets目錄下的資源。使用internal。


接下來是載入音效和背景音樂。libgdx分音效和音樂。音效是儲存到記憶體中。音樂是從儲存的地方直接載入的音樂。音樂檔案一般比較大不能所有載入記憶體。

假設聲音低於10秒,最好使用音效;假設超過10秒。就使用音樂。


載入音效通過Gdx.audio.newSound()方法。載入音樂使用Gdx.audio.newMusic()方法。兩種方法都須要傳遞一個檔案控制程式碼(FileHandle),即可上面的Texture。
接下來就是播放音樂而且設定迴圈。

假設你這是執行程式,會聽到下雨聲。

Camera和SpriteBatch
接下來須要建立相機(camera)和SpriteBatch。我們使用相機的目的是在全部的平臺都使用800*480解析度。不管它的真實螢幕的大小。SpriteBatch是繪製2D影象的特殊類,跟texture幾乎相同。


我們加入兩個變數到類中。例如以下:

private OrthographicCamera camera;
private SpriteBatch batch;
在create()方法中加入例如以下語句,建立camera:

camera = new OrthographicCamera();
camera.setToOrtho(false, 800, 480);

這將確保camera總是顯示800*480的範圍。能夠視作一個虛擬窗體。

這樣能夠讓應用可移植性增強。
接下來,在create()方法中建立SpriteBatch:
batch=new SpriteBatch();

加入桶
最後加入桶和雨滴,它們須要下面的條件:

  • 桶和雨滴在800*480中須要一個位置資訊。

  • 桶和雨滴須要寬和高。

  • Texture

為了展現桶和雨滴,我們須要儲存它們的位置和大小。在Libgdx中能夠通過Rectangle實現。程式碼例如以下:
private Rectangle bucket;

在create()方法中我們須要例項化而且設定他的僅僅。這裡設定在螢幕底部。而且水平居中。程式碼例如以下:

bucket = new Rectangle();
bucket.x = 800 / 2 - 64 / 2;
bucket.y = 20;
bucket.width = 64;
bucket.height = 64;

須要注意的是。在libgdx中,座標系原點在左下角。

渲染桶

接下來須要渲染我們的桶,首先須要設定螢幕的背景色,在render()方法中加入例如以下程式碼:

@Override
public void render () {
Gdx.gl.glClearColor(0, 0, 0.2f, 1)http://Gdx.gl.glClearColor(0.2f, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT)http://Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT)

}
為了使用頂層的類,像Texture和SpriteBatch。首先須要呼叫清除螢幕並設定為藍色。第一句的意思是設定清屏顏色,第二句才執行清屏操作。
接下來我們須要告訴camera確保它更新。接下來我們設定camera在每一幀中都更新。

接下來我們須要渲染桶。
batch.setProjectionMatrix(camera.combined);
batch.begin();
batch.draw(bucketImage, bucket.x, bucket.y);
batch.end();

第一句設定batch的座標系統為相機,batch.end();會馬上提交我們的繪製請求。

讓桶能夠移動

接下來我們控制桶。

在設計遊戲時。我們的設想是桶能夠拖動。假設觸控螢幕或者滑鼠button。

我們想讓桶進行水平移動。

if(Gdx.input.isTouched()) {
touchPos = new Vector3();
touchPos.set(Gdx.input.getX(), Gdx.input.getY(), 0);
camera.unproject(touchPos);
bucket.x = touchPos.x - 64 / 2;
}
首先我們詢問input模組通過Gdx.input.isTouched()來推斷是否被觸控。接下來我們將觸控或者滑鼠點選的衛士傳遞到camera的座標系統。Gdx.input.getX()和Gdx.input.getY()方法用於返回當前觸控和滑鼠的位置。

為了轉換當前座標系統為camera的座標系統我們須要使用camera.uproject()方法,呼叫這種方法須要一個Vector3,一個三維向量。

我們建立這個向量。設定當前觸控或者滑鼠的當前座標,呼叫方法。


須要注意的是touchPos須要在類中宣告,假設在if語句中,每次執行這個語句就會建立一個變數,這就會導致Android的垃圾處理產生異常。


touchPos是一個三維向量,你可能想知道為什麼我們用2D介面須要一個三維向量。其實,OrthographicCamera是一個三維相機(camera)。

讓桶移動(鍵盤)

在桌面和瀏覽器環境我們相同須要獲取鍵盤輸入。讓我們通過設定能夠通過鍵盤來操作桶。
if(Gdx.input.isKeyPressed(Keys.LEFT)) bucket.x -= 200 * Gdx.graphics.getDeltaTime()http://Gdx.graphics.getDeltaTime()FT)) bucket.x -= 200 * Gdx.graphics.getDeltaTime();
if(Gdx.input.isKeyPressed(Keys.RIGHT)) bucket.x += 200 * Gdx.graphics.getDeltaTime()http://Gdx.graphics.getDeltaTime()GHT)) bucket.x += 200 * Gdx.graphics.getDeltaTime();

當鍵盤按下時,Gdx.input.isKeyPressed()方法用來推斷是否為指定按鍵。Gdx.graphics.getDeltaTime()返回一幀的時間http://Gdx.graphics.getDeltaTime()用來推斷是否為指定按鍵。

Gdx.graphics.getDeltaTime()返回一幀的時間。
我們相同須要設定桶不要越界:
if(bucket.x < 0) bucket.x = 0;
if(bucket.x > 800 - 64) bucket.x = 800 - 64;

加入雨滴

對於雨滴來說我們須要使用一個Rectangle陣列。每一個儲存雨滴的位置和大小。

讓我們加入一個變數:
private Array<Rectangle> raindrops;
這個Array類是一個libgdx的工具類。用來取代java的ArrayList。後者將在非常多情況下產生垃圾。Array儘量降低垃圾的產生。
我們相同須要記錄上一次掉落的雨滴的時間。所以我們加入:
private long lastDropTime;
我們將儲存納秒。這就是我們為什麼使用long。

以下方法用來隨機產生雨點:

private void spawnRaindrop() {
Rectangle raindrop = new Rectangle();
raindrop.x = MathUtils.random(0, 800-64);
raindrop.y = 480;
raindrop.width = 64;
raindrop.height = 64;
raindrops.add(raindrop);
lastDropTime = TimeUtils.nanoTime();
}

我們須要在create()方法中進行例項化:
raindrops = new Array<Rectangle>();
spawnRaindrop();
接下來我們須要在render()方法中檢測雨點的時間間隔,並生成新雨點:
if(TimeUtils.nanoTime() - lastDropTime > 1000000000) spawnRaindrop();
我們相同須要雨點移動,一下是程式碼:

Iterator<Rectangle> iter = raindrops.iterator();
while(iter.hasNext()) {
Rectangle raindrop = iter.next();
raindrop.y -= 200 * Gdx.graphics.getDeltaTime()http://Gdx.graphics.getDeltaTime()getDeltaTime();
if(raindrop.y + 64 < 0) iter.remove();
}
雨點須要被渲染,所以須要SpriteBatch來進行渲染:
batch.begin();
batch.draw(bucketImage, bucket.x, bucket.y);
for(Rectangle raindrop: raindrops) {
batch.draw(dropImage, raindrop.x, raindrop.y);
}
batch.end();

最後須要推斷雨滴和桶是否重疊。假設重疊。就刪除雨滴:

if(raindrop.overlaps(bucket)) {
dropSound.play();
iter.remove();
}

退出清理
最後須要清理。程式碼例如以下:
@Override
public void dispose() {
dropImage.dispose();
bucketImage.dispose();
dropSound.dispose();
rainMusic.dispose();
batch.dispose();
}

點選下載原始碼
www.libgdx.cn版權全部,如需轉載。註明出處)

相關文章