第六章:AssetManager概述
资产(assets)指的是各种多媒体文件,诸如3D模型、材质、纹理、场景、着色器、音乐、字体等。JME3集成了一个资产管理器(AssetManager),用来帮你组织、管理游戏资产。你可以把它理解为一个独立于实际发布平台的文件系统。
AssetManager 有如下优点:
- 无论游戏运行于何种操作系统(Windows、Mac、Linux等),资产路径都保持不变。
- AssetManager 会自动缓存和优化处理 OpenGL 对象。例如,当多个模型使用了同一个纹理时,该纹理并不会被多次提交给显卡。
- SDK的默认编译脚本会自动把资产目录下的文件打包到可执行jar文件中。
AssetManager 可以从这些地方加载资产:
- 当前程序的 classpath
- 项目的
asset
目录 - 打包成
zip
压缩文件的资源 - 通过URL访问HTTP资源
AssetManager 提供了多种方法,用于加载不同类型的资产。
- 3D模型,加载为
com.jme3.scene.Spatial
对象。 - 材质,加载为
com.jme3.material.Material
对象。 - 纹理,加载为
com.jme3.texture.Texture
对象。 - BMFont字体,加载为
com.jme3.font.BitmapFont
对象。 - 音频文件,加载为
com.jme3.audio.AudioNode
对象。
高级用户可以自己改写编译和打包脚本,可以在AssetManager中注册自定义资产路径,还可以自定义资产加载格式,这都取决于你。
资产路径
默认情况下,应该把游戏资产文件保存于项目的 MyGame/assets
目录中。AssetManager 加载资产时,将以 MyGame/assets
为当前工作目录, 取资产的相对路径,并且 大小写敏感 。
使用 SDK 创建的 JME3 工程结构如下:
MyGame/assets/ # 游戏资产保存在此目录中! <------
MyGame/build/ # SDK 自动生成的编译结果 (*)
MyGame/build.xml # 自定义的Ant编译脚本
MyGame/nbproject/ # SDK 默认的build.xml脚本和元数据 (*)
MyGame/dist/ # SDK 自动生成的可执行文件 (*)
MyGame/src/ # 保存Java代码源文件
MyGame/test/ # 保存测试代码源文件 (可选)
(*) 由 jMonkeyEngine SDK 自动管理 -- 不要修改!
MyGame/assets
的子文件夹,分别存放不同类型的游戏资产。
MyGame/assets/Interface # .font, .jpg, .png, .xml
MyGame/assets/MatDefs # .j3md
MyGame/assets/Materials # .j3m
MyGame/assets/Models # .blend, .j3o
MyGame/assets/Scenes # .j3o
MyGame/assets/Shaders # .j3f, .vert, .frag
MyGame/assets/Sounds # .ogg, .wav
MyGame/assets/Textures # .jpg, .png; 包括 .mesh.xml+.material, .mtl+.obj, .blend,
根据这个标准结构,把模型储存在 MyGame/assets/Models
目录中, 纹理储存于 MyGame/assets/Textures
中。
例如:
MyGame/assets/Models/Monkey/monkey.j3o
MyGame/assets/Textures/Monkey/DiffuseMap.png
在代码中加载模型时,使用的路径是 Models/Monkey/monkey.j3o
,模型内部所引用的纹理路径为 Textures/Monkey/DiffuseMap.png
。
获得AssetManager
在 JME3 程序中可以使用 assetManager
对象来加载资产,它是 com.jme3.asset.AssetManager
接口的一个实例。 assetManager
内部维护了资产根目录,并且默认包含了工程的 classpath ,因此可以加载classpath的任意资产。
任意类继承 com.jme3.app.SimpleApplication
后,都可以直接继承 assetManager
对象,也可以通过 app.getAssetManager()
来访问它。
下面的代码演示了如何使用 AssetManager 来加载资产。这行语句从 JME3 内置资产目录 Common/
中加载了一个材质对象。
Material mat = (Material) assetManager.loadAsset(
new AssetKey("Common/Materials/RedColor.j3m"));
这个材质文件被存储于 jME3-core.jar 文件中的某个地方。AssetManager 通过默认配置正确找到了 Common/..
路径下的资产,因此你不需要自己去制定该资产实际储存的完整文件路径。
另外,可以在 AssetManager 中配置其他的资产根目录,例如: F:\Assets
、 /usr/yan/home/resources
。这意味着你可以加载任意目录下的资产。
加载资产的方法
资产类型 | 方法 | 返回类型 |
---|---|---|
3D模型 | assetManager.loadModel("Models/Monkey/monkey.j3o") | Spatial |
材质 | assetManager.loadMaterial("Common/Materials/RedColor.j3m") 或 new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); |
Material |
纹理 | assetManager.loadTexture("Textures/Monkey/DiffuseMap.png") | Texture |
BMFont | assetManager.loadFont("Interface/Fonts/Default.fnt"); | BitmapFont |
音频文件 | new AudioNode(assetManager, "Sounds/Ambient/Nature.wav", DataType.Buffer); | AudioNode |
其他 | assetManager.loadAsset("Models/Monkey/monkey.j3o") | Object |
演示代码
下面的代码将演示如何加载项目 assets
目录中的资产。
这是前几章出现过的代码,通过 assetManager.loadModel("Models/Monkey/monkey.j3o");
语句加载了 MyGame/assets
目录下的猴头模型。
package mygame;
import com.jme3.app.SimpleApplication;
import com.jme3.light.AmbientLight;
import com.jme3.light.DirectionalLight;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.scene.Spatial;
/**
* 测试加载j3o模型
* @author yanmaoyuan
*/
public class Main extends SimpleApplication {
public static void main(String[] args) {
Main app = new Main();
app.start();
}
@Override
public void simpleInitApp() {
// 加载j3o模型
Spatial model = assetManager.loadModel("Models/Monkey/monkey.j3o");
rootNode.attachChild(model);
// 添加灯光
DirectionalLight sun = new DirectionalLight();
sun.setColor(new ColorRGBA(0.7f, 0.7f, 0.7f, 1f));
sun.setDirection(new Vector3f(-3, -4, -5).normalizeLocal());
rootNode.addLight(sun);
AmbientLight ambient = new AmbientLight();
ambient.setColor(new ColorRGBA(0.2f, 0.2f, 0.2f, 1f));
rootNode.addLight(ambient);
}
}
若使用 AppState,可以通过 app.getAssetManager()
来获得 assetManager
对象,再用它来加载资产。
package mygame;
import com.jme3.app.Application;
import com.jme3.app.SimpleApplication;
import com.jme3.app.state.BaseAppState;
import com.jme3.asset.AssetManager;
import com.jme3.light.AmbientLight;
import com.jme3.light.DirectionalLight;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
/**
* 测试加载j3o模型
* @author yanmaoyuan
*
*/
public class MyAppState extends BaseAppState {
private Node rootNode = new Node("scene");
private SimpleApplication simpleApp;
private AssetManager assetManager;
@Override
protected void initialize(Application app) {
this.simpleApp = (SimpleApplication) app;
this.assetManager = app.getAssetManager();// 获得 assetManager
// 加载j3o模型
Spatial model = assetManager.loadModel("Models/Monkey/monkey.j3o");
rootNode.attachChild(model);
// 添加灯光
DirectionalLight sun = new DirectionalLight();
sun.setColor(new ColorRGBA(0.7f, 0.7f, 0.7f, 1f));
sun.setDirection(new Vector3f(-3, -4, -5).normalizeLocal());
rootNode.addLight(sun);
AmbientLight ambient = new AmbientLight();
ambient.setColor(new ColorRGBA(0.2f, 0.2f, 0.2f, 1f));
rootNode.addLight(ambient);
}
@Override
protected void cleanup(Application app) {
// 清空场景
rootNode.detachAllChildren();
}
@Override
protected void onEnable() {
// 开启场景
simpleApp.getRootNode().attachChild(rootNode);
}
@Override
protected void onDisable() {
// 移除场景
rootNode.removeFromParent();
}
}