GUI选择
实现Jmonkey的GUI有三四种方式,我尝试了三种,有
- Lemur
- tonegod
- nifty
最终选择了Nifty, 因为Lemur用java语法完成,不方便编写,用起来又复杂,读了半天文档也没明白;tonegod的参考资料又少,没看懂;而Nifty可以用xml和java做界面,对于开发过Android的我来说最方便,用起来也灵活,重点是它还开源,github的wiki里有详细的使用说明,用它来做GUI最方便。
Nifty与Jmonkey的集成
添加依赖
在jme中用nifty需要把jme3-niftygui的jar包导入项目,这个maven仓库好像没有,没关系,到jmonkey的sdk里把它复制到项目就行,然后在build.gradle的dependencies中添加:
compile files('libs/jme3-niftygui-3.2.0-v3.2-prealpha-sdk1-SNAPSHOT.jar') // 写jar包目录和jar包名称
// nifty
compile "com.github.nifty-gui:nifty:1.4.2"
compile "com.github.nifty-gui:nifty-style-black:1.4.2"
compile "com.github.nifty-gui:nifty-default-controls:1.4.2"
新建screens.xml
Nifty的好处在于可以用xml做显示界面。在resource文件里创建一个文件夹scenes,新建一个xml文件,叫screens.xml。
之所以叫screens,是因为所有的界面都可以在一个xml文件里,以<screen></screen>标签区分,给screen一个id就能用代码找到它。每一屏是一个screen。切换时通过nifty.gotoScreen("screen id")语句来实现切换。
xml有很多标签,跟Android一样,通过标签嵌套实现界面,nifty的xml里标签层级如下:
看懂这个图写起来就很容易了,screens.xml示例代码如下:
<?xml version="1.0" encoding="UTF-8"?>
<nifty xmlns="http://nifty-gui.lessvoid.com/nifty-gui">
<useStyles filename="nifty-default-styles.xml"/>
<useControls filename="nifty-default-controls.xml"/>
<screen id="start_screen" controller="com.happykai.demo.appstates.StartScreenState">
<layer id="layer" childLayout="center" backgroundImage="Textures/background.png">
<panel id="dialog" style="nifty-panel" childLayout="vertical" padding="18px,28px,28px,16px" width="80%"
height="70%" align="center" valign="center">
<effect>
<onStartScreen name="move" timeType="exp" factor="3.5" direction="top" mode="in" length="500"
inherit="true"/>
<onEndScreen name="move" timeType="exp" factor="3.5" direction="bottom" mode="out" length="500"
inherit="true"/>
<panel id="namePanel" childLayout="horizontal">
<text id="name_text" text="你的名字: " width="150px" align="left" textVAlign="center" textHAlign="left" style="nifty-label"/>
<control id="name_text_ctl" name="textfield" width="15%" text="300"/>
</panel>
<panel id="img_btn_panel" childLayout="horizontal">
<control id="name_text_ctl" name="button" width="15%" text="300"/>
<image id="img" align="right" filename="Textures/add.png" height="20px" width="20px"
visibleToMouse="true">
<interact onClick="addDropClick(2)"/>
</image>
</panel>
</effect>
</panel>
</layer>
</screen>
</nifty>
在nifty中,所有能与用户交互的控件都用<control></control>标签,通过name来区别控件,name是固定字段,有button,textfield,dropdown等,具体可以参考nifty的wiki,里面有每个控件详细的使用说明。
如果想给一个非control的控件加交互,比如一个image(官方的button很难看,想换成自己想要的button,不妨让美工做一个button,然后直接把图片放过来),在加一个<interact>子标签,如上面例子中的<interact onClick="addDropClick(2)"/>,然后再java中实现该代码即可,括号中的2是传入的参数。
新建AppState
从GUI到项目运行场景肯定需要一个场景切换,也是找了好久才找到Jmonkey里每一个场景是一个AppState,配套上nifty,就可以实现场景切换。GUI的AppState给它起名为StartScreenState。
- 新建StartScreenState.java,继承自AbstractAppState,实现ScreenController接口(实现该接口是为了与xml建立联系,与上面的xml中<screen>标签里的controller对应)。上面例子中的image点击函数addDropClick(2)就写在该java文件中。
public class StartScreenState extends AbstractAppState implements ScreenController {
private SimpleApplication app;
private AssetManager assetManager;
private InputManager inputManager;
private ViewPort guiViewPort;
private AudioRenderer audioRenderer;
private NiftyJmeDisplay niftyDisplay;
private Nifty nifty;
private Screen screen;
@Override
public void initialize(AppStateManager stateManager,
Application app) {
super.initialize(stateManager, app);
this.app = (SimpleApplication) app;
this.assetManager = this.app.getAssetManager();
this.inputManager = this.app.getInputManager();
this.guiViewPort = this.app.getGuiViewPort();
this.audioRenderer = this.app.getAudioRenderer();
this.niftyDisplay = new NiftyJmeDisplay(assetManager,
inputManager, audioRenderer, guiViewPort);
this.nifty = niftyDisplay.getNifty();
this.nifty.fromXml("Scenes/start_screen.xml",
"start", this);
this.screen = nifty.getScreen("start");
inputManager.setCursorVisible(true);
guiViewPort.addProcessor(niftyDisplay);
}
// 在intellij中该方法会显示没有用过(灰色),没关系,正常
public void addDropClick(String num) {
// do something
}
@Override
public void bind(@Nonnull Nifty nifty, @Nonnull Screen screen) {
}
@Override
public void onStartScreen() {
}
@Override
public void onEndScreen() {
}
}
在该文件里实现对控件的动态控制,比如获得textfield中输入的文字:
TextField textField = screen.findElementById("ctr_id").getNiftyControl(TextField.class);
String str = textField .getDisplayedText();
if (str.isEmpty()){
JOptionPane.showMessageDialog(
null,
"输入不能为空",
"错误!",
JOptionPane.ERROR_MESSAGE);
}
举一反三,其他诸如button、dropdown的control控制也是如此,先从screen上根据元素id找到元素,然后开始做自己需要的操作。
用java开发很好的一点就是可以用一切熟悉的java的东西,比如swing里的一些控件,像上例的输入错误框,如果用nifty弹出一个窗口,恐怕又好麻烦,但是用这个就相当简单了。当然jmonkey也可以用swing做图形界面,但是美观什么的就不一定了。
将AppState添加到Main中
创建完AppState后就把它加到SimpleApplication中,这是最后一步。
/**
* Created by Roman on 2017/10/12.
*/
public class Main extends SimpleApplication {
public static void main(String[] args) throws BackingStoreException {
// PrintStream ps= null;
// try {
// ps = new PrintStream(new FileOutputStream("log.txt"));
// } catch (FileNotFoundException e) {
// e.printStackTrace();
// }
// System.setOut(ps);
AppSettings settings = new AppSettings(true);
settings.setTitle("你的名字");
settings.setVSync(true);
settings.setWidth(1280);
settings.setHeight(800);
Main app = new Main();
app.setSettings(settings);
app.setDisplayStatView(false); // 设置状态小窗是否可见
app.setShowSettings(true); // 设置界面是否显示
app.setPauseOnLostFocus(false); // 设置程序后台运行,默认为true,即焦点不在程序上则停止显示渲染
app.start();
}
@Override
public void simpleInitApp() {
StartScreenState startScreenState = new StartScreenState();
stateManager.attach(startScreenState);
}
}
网友评论