本文使用的libgdx是0.92版本,和現在的最新版可能有一些不一樣的地方。全文內容僅供參考。
先說明一下上一篇文章我使用了多張hiero圖的字型繪製,因為我對原始碼進行了一些修改,本來想這次發出來的,但是我仔細除錯了一下,發現對於多圖的支援還是有問題,有些字會出現偏移。
這個只有繼續嘗試了…大家可以考慮使用ttf字型檔。
然後繼續說上一篇,雖然實現了一個簡單的效果,但是目前有很多不足。我把AVG遊戲需要的資源全部提取出來,放在一個個資料夾中,然後通過配置檔案載入這些資料。
libgdx的工具庫
com.badlogic.gdx.utils就是libgdx的工具庫,支援兩種格式xml和json。
我最先傾向於使用json格式,但是反覆想了想,雖然json的大小可能要小點,但是沒有xml直觀好讀。
所以還是選擇使用xml格式,讀取xml檔案使用XmlReader。
XmlReader reader=new XmlReader();
try {
Element config=reader.parse(Gdx.files.internal("data/config.xml"));
config.get("name"); //獲取屬性值,如果沒有屬性值則返回同名child的值
config.getAttribute("name"); //獲取屬性值
} catch (IOException e) {
e.printStackTrace();
}
配置檔案格式分析
配置檔案需要配置的內容其實就是上一篇我們硬編碼進去的東西,有背景、邊框、對話等。
我設計的比較隨意,不一定是最好的,大家可以參考參考。
<?xml version="1.0" encoding="UTF-8"?>
<scene>
<packfile>pack</packfile>
<background>bg1</background>
<border>
<border-name>border</border-name>
<border-left>26</border-left>
<border-right>26</border-right>
<border-top>31</border-top>
<border-bottom>31</border-bottom>
</border>
<dialogues>
<dialogue>
<name>人物1</name>
<data>這是對話1</data>
</dialogue>
<dialogue>
<name>人物1</name>
<data>這是對話2</data>
</dialogue>
</dialogues>
</scene>
如果對話比較長還可以繼續新增<dialogue>節點。border-*那4個值就是NinePatch的左邊距、右邊距、上邊距、下邊距。
這裡還有一個地方需要注意,如果我們需要切換場景怎麼辦?切換的場景可能是一個AVG場景,也可能是個一般的Screen。我本來想做個簡單的IOC容器的,但後來想想也沒有那麼複雜。
在配置檔案中加上一句
如果是一般Screen就是
<nextscreen type="standard">com.cnblogs.htynkn.screen.GameOver</nextscreen>
如果是AVG場景就是
<nextscreen type="avg">data/scene2/config.xml</nextscreen>
使用libgdx實現相關效果
其實整個原理和上一篇原理是一樣的,唯一多的一個就是解析配置檔案和場景跳轉。
XmlReader xmlReader = new XmlReader();
try {
Element config = xmlReader.parse(Gdx.files
.internal(this.configFileName)); //載入配置檔案
atlas = new TextureAtlas(Gdx.files.internal(configFileName)
.parent()
+ "/" + config.get("packfile")); //獲取pack配置檔案
background = atlas.findRegion(config.get("background")); //建立背景圖
Element borderConfig = config.getChildByName("border"); //獲取border配置
border = new NinePatch(atlas.findRegion(borderConfig.getChild(0)
.getText()), Integer.parseInt(borderConfig.getChild(1)
.getText()), Integer.parseInt(borderConfig.getChild(2)
.getText()), Integer.parseInt(borderConfig.getChild(3)
.getText()), Integer.parseInt(borderConfig.getChild(4)
.getText())); //例項化border
dialogues = new ArrayList<String[]>();
Element dialoguesConfig = config.getChildByName("dialogues"); //開始處理對話
for (int i = 0; i < dialoguesConfig.getChildCount(); i++) {
dialogues.add(new String[] {
dialoguesConfig.getChild(i).get("name"),
dialoguesConfig.getChild(i).get("data") });
}
Element screenConfig = config.getChildByName("nextscreen"); //處理場景
if (screenConfig.getAttribute("type").equals("avg")) {
nextScreen = new AVGScreen(this.game, screenConfig.getText());
} else {
try {
nextScreen = (Screen) Class.forName(screenConfig.getText())
.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
}
} catch (IOException e) {
e.printStackTrace();
}
讀取完成後構建舞臺,然後繪製。唯一需要修改的就是場景跳轉。
borderImage.setClickListener(new ClickListener() {
@Override
public void click(Actor actor, float x, float y) {
if (currentSize < dialogues.size() - 1) {
currentSize++;
} else {
if (nextScreen != null) {
game.setScreen(nextScreen);
}
}
}
});
完整程式碼:
package com.cnblogs.htynkn.ui;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import com.badlogic.gdx.Game;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL10;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.NinePatch;
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.scenes.scene2d.ui.ClickListener;
import com.badlogic.gdx.scenes.scene2d.ui.Image;
import com.badlogic.gdx.scenes.scene2d.ui.Label;
import com.badlogic.gdx.scenes.scene2d.ui.Label.LabelStyle;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.XmlReader;
import com.badlogic.gdx.utils.XmlReader.Element;
public class AVGScreen implements Screen {
private String configFileName;
private Stage stage; // 舞臺
private List<String[]> dialogues; // 對話
private BitmapFont bitmapFont; // 文字
private NinePatch border; // 邊框
private int currentSize; // 當前對話序號
private TextureAtlas atlas;
private TextureRegion background;
private Screen nextScreen;
private Game game;
public AVGScreen(Game game, String configFileName) {
this.game = game;
bitmapFont = new BitmapFont(Gdx.files.internal("font/chinese.fnt"),
false);
this.configFileName = configFileName;
XmlReader xmlReader = new XmlReader();
try {
Element config = xmlReader.parse(Gdx.files
.internal(this.configFileName));
atlas = new TextureAtlas(Gdx.files.internal(configFileName)
.parent()
+ "/" + config.get("packfile"));
background = atlas.findRegion(config.get("background"));
Element borderConfig = config.getChildByName("border");
border = new NinePatch(atlas.findRegion(borderConfig.getChild(0)
.getText()), Integer.parseInt(borderConfig.getChild(1)
.getText()), Integer.parseInt(borderConfig.getChild(2)
.getText()), Integer.parseInt(borderConfig.getChild(3)
.getText()), Integer.parseInt(borderConfig.getChild(4)
.getText()));
dialogues = new ArrayList<String[]>();
Element dialoguesConfig = config.getChildByName("dialogues");
for (int i = 0; i < dialoguesConfig.getChildCount(); i++) {
dialogues.add(new String[] {
dialoguesConfig.getChild(i).get("name"),
dialoguesConfig.getChild(i).get("data") });
}
Element screenConfig = config.getChildByName("nextscreen");
if (screenConfig.getAttribute("type").equals("avg")) {
nextScreen = new AVGScreen(this.game, screenConfig.getText());
} else {
try {
nextScreen = (Screen) Class.forName(screenConfig.getText())
.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void dispose() {
bitmapFont.dispose();
stage.dispose();
}
@Override
public void hide() {
// TODO Auto-generated method stub
}
@Override
public void pause() {
// TODO Auto-generated method stub
}
@Override
public void render(float delta) {
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
((Label) stage.findActor("label"))
.setText(dialogues.get(currentSize)[0] + " : "
+ dialogues.get(currentSize)[1]);
stage.act(Gdx.graphics.getDeltaTime());
stage.draw();
}
@Override
public void resize(int width, int height) {
// TODO Auto-generated method stub
}
@Override
public void resume() {
// TODO Auto-generated method stub
}
@Override
public void show() {
currentSize = 0;
stage = new Stage(Gdx.graphics.getWidth(), Gdx.graphics.getHeight(),
false);
Image backgroundImage = new Image(background);
backgroundImage.x = backgroundImage.y = 0;
backgroundImage.setFillParent(true);
Image borderImage = new Image(border);
borderImage.x = borderImage.y = 0;
borderImage.width = Gdx.graphics.getWidth();
borderImage.height = Gdx.graphics.getHeight() / 4;
borderImage.setClickListener(new ClickListener() {
@Override
public void click(Actor actor, float x, float y) {
if (currentSize < dialogues.size() - 1) {
currentSize++;
} else {
if (nextScreen != null) {
game.setScreen(nextScreen);
}
}
}
});
LabelStyle labelStyle = new LabelStyle(bitmapFont, Color.WHITE);
Label label = new Label("", labelStyle, "label");
label.x = border.getLeftWidth() + 10;
label.y = borderImage.height - border.getTopHeight() - 10;
stage.addActor(backgroundImage);
stage.addActor(borderImage);
stage.addActor(label);
Gdx.input.setInputProcessor(stage);
}
}
最後貼上效果圖,這是我正在做的一個東西: