LTextureList,是一個與前例介紹的LTexturePack形似而神異的不同存在。
兩者的差異在於:
LTexturePack專注於“分散紋理的統一管理,會將注入當中的所有小圖合併爲一”。
LTextureList專注於“分散紋理的分散管理,會保留所有小圖的引用而分別調用”。
事實上,由於Android中提供個單獨程序的圖像空間非常有限,無論怎麼有效釋放,Bitmap都不能同時存在太多。而LTextureList就是專爲處理海量圖片所準備的,在配置了相關xml文檔後,LTextureList將僅在執行對應名稱紋理的loadTexture時,纔會加載LTexture(也就是所謂的“惰性加載”)。而不會一次性加載完畢,且加載一次後會立即產生緩存,只要不註銷資源,即使再次loadTexture也不會重複加載。因此,即使您在xml中填入幾萬張圖片地址也無所謂,完全不必擔心實時加載所帶來的程序癱瘓。
LTextureList最簡單的用法莫過於此:
images.xml配置:
<?xml version="1.0" standalone="yes"?>
<images>
<ref name="hero">
<image src="assets/hero_a.png">
</image>
</ref>
<ref name="enemy">
<image src="assets/enemy_a.png">
</image>
</ref>
</images>
對應的java配置如下:
package org.loon.test;
import org.loon.framework.javase.game.GameScene;
import org.loon.framework.javase.game.core.graphics.Screen;
import org.loon.framework.javase.game.core.graphics.opengl.GLColor;
import org.loon.framework.javase.game.core.graphics.opengl.GLEx;
import org.loon.framework.javase.game.core.graphics.opengl.LTextureList;
import org.loon.framework.javase.game.core.input.LTouch;
import org.loon.framework.javase.game.core.input.LTransition;
import org.loon.framework.javase.game.core.timer.LTimerContext;
public class LTextureListTest extends Screen {
LTextureList list;
public LTransition onTransition() {
return LTransition.newEmpty();
}
public void onLoad() {
// 把Screen背景色定爲紅色
setBackground(GLColor.red);
// 從指定xml文檔獲取LTextureList實例
list = new LTextureList("assets/images.xml");
}
public void alter(LTimerContext timer) {
}
public void draw(GLEx g) {
if (isOnLoadComplete()) {
g.drawTexture(list.loadTexture("hero"), 32, 32);
g.drawTexture(list.loadTexture("enemy"), 32, 64);
}
}
public void touchDown(LTouch e) {
}
public void touchDrag(LTouch e) {
}
public void touchMove(LTouch e) {
}
public void touchUp(LTouch e) {
}
public void dispose() {
if (list != null) {
list.dispose();
list = null;
}
}
public static void main(String[] args) {
GameScene game = new GameScene("LTextureListTest", 480, 320);
game.setShowFPS(true);
game.setShowLogo(false);
game.setScreen(new LTextureListTest());
game.showScreen();
}
}
運行上述程序後,我們會得到如下顯示畫面:
此時,如果有一些基本的圖像變動,也不需再修改任何程序代碼,僅微調xml參數即可,比如,當我們需要hero去掉黑底時,只要進行如下設置:
<?xml version="1.0" standalone="yes"?>
<images>
<ref name="hero">
<image src="assets/hero_a.png">
<mask r="0" g="0" b="0" />
</image>
</ref>
<ref name="enemy">
<image src="assets/enemy_a.png">
</image>
</ref>
</images>
這時,我們在image元素中,加入了<mask r="0" g="0" b="0" />一行,即過濾掉0,0,0像素,這時我們再次執行程序,畫面將變爲如下所示。
<?xml version="1.0" standalone="yes"?>
<images>
<ref name="hero">
<image src="assets/hero_a.png" x="0" y="0" w="24" h="24" scale="2">
<mask r="0" g="0" b="0" />
</image>
</ref>
<ref name="enemy">
<image src="assets/enemy_a.png">
</image>
</ref>
</images>
這次,增加了x="0" y="0" w="24" h="24"這樣一行文字,並且添加有scale="2"。這是幹什麼用的呢?其實在上例講到LTexturePack時,小弟已經做過了類似的事情,不過是告知系統從一整張圖片的x=0,y=0處開始取圖,一直取到w=24,h=24處停止罷了(也就是第一個“士兵”的圖片位置)。不過這裏有處與LTexturePack明顯的差別,既LTexturePack中所取得的小圖是系統從一整張大紋理中“虛擬”出來的,不會消耗任何額外的內存或顯存空間,而LTextureList所取出的小圖,對系統而言可是真實紋理,顯存中實際存在的一張圖像。
當然,LTextureList也可以單純作爲圖像List使用,設定統一的setBlendMode改變圖像的混圖模式,透明度等等,比如:
package org.loon.test;
import org.loon.framework.javase.game.GameScene;
import org.loon.framework.javase.game.core.graphics.Screen;
import org.loon.framework.javase.game.core.graphics.opengl.GL;
import org.loon.framework.javase.game.core.graphics.opengl.GLColor;
import org.loon.framework.javase.game.core.graphics.opengl.GLEx;
import org.loon.framework.javase.game.core.graphics.opengl.LTextureList;
import org.loon.framework.javase.game.core.input.LTouch;
import org.loon.framework.javase.game.core.input.LTransition;
import org.loon.framework.javase.game.core.timer.LTimerContext;
public class LTextureListTest extends Screen {
LTextureList list;
public LTransition onTransition() {
return LTransition.newEmpty();
}
public void onLoad() {
// 把Screen背景色定爲紅色
setBackground(GLColor.red);
list = new LTextureList();
list.add("assets/hero_a.png", 32, 32);
list.add("assets/enemy_a.png", 32, 64);
list.setBlendMode(GL.MODE_COLOR_MULTIPLY);
}
public void alter(LTimerContext timer) {
}
public void draw(GLEx g) {
if (isOnLoadComplete()) {
list.draw(g);
}
}
public void touchDown(LTouch e) {
}
public void touchDrag(LTouch e) {
}
public void touchMove(LTouch e) {
}
public void touchUp(LTouch e) {
}
public void dispose() {
if (list != null) {
list.dispose();
list = null;
}
}
public static void main(String[] args) {
GameScene game = new GameScene("LTextureListTest", 480, 320);
game.setShowFPS(true);
game.setShowLogo(false);
game.setScreen(new LTextureListTest());
game.showScreen();
}
}
不過,這樣就失去預設定與惰性加載的能力了。
說完了LTextureList,但這種程度的篇幅作爲博文來說依舊太短了,所以小弟下面再來談談0.3.2中新增的幾個輔助類。
關於Session類
LGame中的Session類,是爲了在多Screen中傳值與保存多值而設計的,RecordStore類(高仿JavaME)的再簡化版本,它每次set的可以是唯一的鍵值對,也可以在同一鍵下掛多值,在執行dispose函數前,session每次save的數值都將永久保存(JavaSE版保存爲本地文件,Android版保存到手機數據庫)。
下面是一個非常簡單的用例。
package org.loon.test;
import java.util.Calendar;
import org.loon.framework.javase.game.GameScene;
import org.loon.framework.javase.game.core.LSystem;
import org.loon.framework.javase.game.core.graphics.Screen;
import org.loon.framework.javase.game.core.graphics.opengl.GLEx;
import org.loon.framework.javase.game.core.input.LTouch;
import org.loon.framework.javase.game.core.input.LTransition;
import org.loon.framework.javase.game.core.store.Session;
import org.loon.framework.javase.game.core.timer.LTimerContext;
public class SessionTest extends Screen {
Session session = new Session(SessionTest.class.getName());
public LTransition onTransition() {
return LTransition.newEmpty();
}
public void onLoad() {
}
public void alter(LTimerContext timer) {
}
public void draw(GLEx g) {
g.drawString("save 0 :" + session.get("save", 0), 32, 64);
g.drawString("save 1 :" + session.get("save", 1), 32, 96);
}
public void touchDown(LTouch e) {
}
public void touchDrag(LTouch e) {
}
public void touchMove(LTouch e) {
}
public void touchUp(LTouch e) {
}
public void dispose() {
if (session != null) {
session.set("save", 0, session.getInt("save", 0) + 1);
session.set("save", 1, System.currentTimeMillis());
session.save();
}
/**
* delete session
*
* if (session != null)
* {
* session.dispose();
* session = null;
* }
*/
}
public static void main(String[] args) {
GameScene game = new GameScene("SessionTest", 480, 320);
game.setShowFPS(true);
game.setShowLogo(false);
game.setScreen(new SessionTest());
game.showScreen();
}
}
關於HttpClient類
HttpClient類是爲了保證LGame應用在跨平臺時接口一致而構建的,處理簡單網頁資源瀏覽的工具類,基本用法如下所示。
HttpClient webClient = new HttpClient("www.baidu.com");
webClient.start();
System.out.println(webClient.doHTML("gb2312"));
webClient.stop();
除了常規的網頁加載外,HttpClient還可以作爲下載器使用,基本用例如下所示:
package org.loon.test;
import org.loon.framework.javase.game.GameScene;
import org.loon.framework.javase.game.action.sprite.Label;
import org.loon.framework.javase.game.core.graphics.Screen;
import org.loon.framework.javase.game.core.graphics.component.LButton;
import org.loon.framework.javase.game.core.graphics.component.LProgress;
import org.loon.framework.javase.game.core.graphics.opengl.GLColor;
import org.loon.framework.javase.game.core.graphics.opengl.GLEx;
import org.loon.framework.javase.game.core.input.LTouch;
import org.loon.framework.javase.game.core.input.LTransition;
import org.loon.framework.javase.game.core.timer.LTimerContext;
import org.loon.framework.javase.game.net.HttpClient;
import org.loon.framework.javase.game.net.HttpDownload;
import org.loon.framework.javase.game.net.HttpDownload.HttpDownloadListener;
public class DownloadTest extends Screen {
public LTransition onTransition() {
return LTransition.newEmpty();
}
public void onLoad() {
//背景紅色
setBackground(GLColor.red);
//構建一個字符標籤
final Label label = new Label("State : None", 200, 128);
label.setColor(GLColor.white);
add(label);
//構建HttpClient
final HttpClient webClient = new HttpClient(
"http://libgdx.googlecode.com/files/libgdx-0.9.1.zip");
//構建一個進度條
final LProgress progress = new LProgress(32, 52, 420, 50);
progress.setProgressTitle(true);
add(progress);
//構建一個下載按鈕
LButton button = new LButton("download", 32, 64, 100, 100) {
HttpDownload download;
//設定一個下載標記,避免重複點擊
boolean downloadFlag = false;
public void downClick() {
if (!downloadFlag) {
downloadFlag = true;
//進度監聽
final HttpDownloadListener listener = new HttpDownloadListener() {
public void cancel() {
label.setLabel("State : Cancel");
}
public void completed() {
label.setLabel("State : Completed");
downloadFlag = false;
if (download != null) {
download.save("c:\\test.zip");
webClient.stop();
}
}
public void downloading(float c) {
label.setLabel("State : Downloading");
progress.percent((int) c);
}
public void error(Exception ex) {
label.setLabel("State : Error");
}
public void paused() {
label.setLabel("State : Paused");
}
};
Runnable runnable = new Runnable() {
public void run() {
webClient.start();
download = webClient.getHttpDownload();
download.setListener(listener);
download.start();
}
};
callEvent(runnable);
}
}
};
add(button);
}
public void alter(LTimerContext timer) {
}
public void draw(GLEx g) {
}
public void touchDown(LTouch e) {
}
public void touchDrag(LTouch e) {
}
public void touchMove(LTouch e) {
}
public void touchUp(LTouch e) {
}
public void dispose() {
}
public static void main(String[] args) {
GameScene game = new GameScene("DownloadTest", 480, 320);
game.setShowFPS(true);
game.setShowLogo(false);
game.setScreen(new DownloadTest());
game.showScreen();
}
}
效果如下所示:
另,在LGame的SVN中,有一個小弟開發中的0.3.3測試版(內含jar及源碼,loon-simple.googlecode.com/svn/trunk/),此版本與小弟目前手中的最新版本僅有個別細節處的差異(差的僅爲效率問題修正),因爲小弟正在集中精力搞C#版的完善與C/C++版的開發,0.3.3正式版暫時不會面世(我會將C/C++、C#、Java版都統一到0.3.3結構下,所以會多用點時間),但小弟會將一些最近的修改發往此處存底,如果大家在使用0.3.2時遇到一些問題,也可以換用0.3.3測試版實驗運行,也許相關問題在此版就已經解決了(此LGame-0.3.3-test文件大約每週更新一次,上次更新是三天前)。