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();
}
}
运行上述程序后,我们会得到如下显示画面:
![](http://hi.csdn.net/attachment/201112/3/0_1322890579ww49.gif)
此时,如果有一些基本的图像变动,也不需再修改任何程序代码,仅微调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所取出的小图,对系统而言可是真实纹理,显存中实际存在的一张图像。
![](http://hi.csdn.net/attachment/201112/3/0_1322890587aApm.gif)
当然,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();
}
}
不过,这样就失去预设定与惰性加载的能力了。
![](http://hi.csdn.net/attachment/201112/3/0_1322890590fDsf.gif)
说完了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();
}
}
![](http://hi.csdn.net/attachment/201112/3/0_13228905930pTs.gif)
![](http://hi.csdn.net/attachment/201112/3/0_1322890598Qhg2.gif)
关于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文件大约每周更新一次,上次更新是三天前)。