初始化设置
首先,创建Main类,作为JME3程序的启动入口。
package mygame;
import com.jme3.app.SimpleApplication;
public class Main extends SimpleApplication {
@Override
public void simpleInitApp() {
// TODO Auto-generated method stub
}
public static void main(String[] args) {
Main app = new Main();
app.start();
}
}
运行程序,选择分辨率后就会看到一个黑漆漆的窗口。没什么好说的。
重点
本文的重点是实体系统(Entity System),所以在编写具体的游戏内容前,让我们先把Zay-ES框架初始化。
package mygame;
import com.jme3.app.state.AbstractAppState;
import com.simsilica.es.EntityData;
import com.simsilica.es.base.DefaultEntityData;
public class EntityDataState extends AbstractAppState {
private EntityData entityData;
public EntityDataState() {
this(new DefaultEntityData());
}
public EntityDataState(EntityData ed) {
this.entityData = ed;
}
public EntityData getEntityData() {
return entityData;
}
@Override
public void cleanup() {
entityData.close();
entityData = null; // 不允许复用
}
}
关于AppState的用法也没什么需要特别解释的,这段代码相当简单。
还是黑屏?
我的意思是...好吧,一个没有视觉表现的游戏确实称不上多有趣。能在屏幕上看到一些东西,并根据玩家的操作给予反馈,总能帮助我们开心起来。
一艘太空船
我们需要一些能在Blender中处理的模型,然后导入到JME3中。
首先我们需要一个太空船,所以请启动Blender自己建模吧。好吧,我并不打算让你浪费时间,所以我已经在google drive上分享了一个模型。这并不是说你就不能用自己的模型了,随你喜欢。
如果你已经有模型了,就把这个 blend 文件放在"Models"资源目录下,然后在JME3中右键单击这个blender模型,选择"Convert to j3o Binary"。
译注:原作者使用Blender建模了一个太空船模型,并使用JME3 SDK的模型转换功能生成了j3o文件。我把源文件和转换好的模型都上传到了百度网盘,分享给大家。
译注2:如果你不使用JME3 SDK开发游戏,可以根据下图的结构来存放SpaceShip.j3o文件。
模型工厂
在你解决上面的问题后,就要准备加载模型了。在JME3中使用专门的模型工厂(ModelFactory)类来获取模型,是个非常不错的想法,这会让很多事情变得更简单。
package mygame;
import com.jme3.asset.AssetManager;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
public class ModelFactory {
private final AssetManager assetManager;
public ModelFactory(AssetManager assetManager) {
this.assetManager = assetManager;
}
public Spatial create(String name) {
Node visual = new Node("Visual");
Node model = (Node) assetManager.loadModel("Models/" + name + ".j3o");
visual.attachChild(model);
return visual;
}
}
这个实现的思路是把j3o文件都放在Models目录下,然后根据模型的名称去加载模型文件。我觉得没有必要解释太多,看代码就清楚了。当然你可以把这个工厂类设计得更完善,更加面向对象或者别的什么东西,我不在乎。
快速原型
现在我们想在屏幕上看到这艘太空船。为此,我们开始编写游戏的显示系统(表示层),我将其称为 VisualAppState,代码如下。
package mygame;
import com.jme3.app.Application;
import com.jme3.app.SimpleApplication;
import com.jme3.app.state.AbstractAppState;
import com.jme3.app.state.AppStateManager;
import com.jme3.light.DirectionalLight;
import com.jme3.math.Vector3f;
import com.jme3.scene.Spatial;
public class VisualAppState extends AbstractAppState {
private SimpleApplication app;
private ModelFactory modelFactory;
@Override
public void initialize(AppStateManager stateManager, Application app) {
super.initialize(stateManager, app);
this.app = (SimpleApplication) app;
// 初始化摄像机,从Z轴正上方往下看。
app.getCamera().lookAt(Vector3f.UNIT_Z, Vector3f.UNIT_Y);
app.getCamera().setLocation(new Vector3f(0, 0, 60));
// 添加定向光源
DirectionalLight light = new DirectionalLight();
light.setDirection(new Vector3f(1, 1, -1));
this.app.getRootNode().addLight(light);
// 加载太空船模型
modelFactory = new ModelFactory(this.app.getAssetManager());
Spatial myVisual = modelFactory.create("SpaceShip");
this.app.getRootNode().attachChild(myVisual);
}
@Override
public void cleanup() {
}
@Override
public void update(float tpf) {
}
}
我假设你的太空船模型保存路径为 Models/SpaceShip.j3o。
如果你的模型使用的是感光材质(Lighting.j3md),那么就会需要在场景中增加光源,我添加了一个定向光源。然后,在Main类中注册我们写好的两个AppState类,代码如下:
public Main() {
super(new VisualAppState(),
new EntityDataState());
}
好了,运行程序然后看看结果。
到目前为止,程序中还没有太多与ES有关的东西,不过我们已经为开发第一个真正的ES游戏做好了准备。实际上,我们还需要让VisualAppState变得更丰满一些,再增加一些各种功能的GameAppState。