JMonkeyEngine3——NiftyGui层级结构
前言
在JMonkeyEngine3——NiftyGUI介绍一文中,我们介绍了JME3中如何使用NiftyGui,以及NiftyGui的基本结构,这一篇文章将更具体的介绍Nifty中的层级结构,介绍screen,layer,panel的关系,并介绍两种不同启动屏幕和多个xml文件使用的方式。
Nifty Gui 层级
我们在工程中新建一个Nifty Gui文件,命名为NiftyGui01,打开后默认代码如下:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <nifty xmlns="http://nifty-gui.lessvoid.com/nifty-gui" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://raw.githubusercontent.com/void256/nifty-gui/1.4/nifty-core/src/main/resources/nifty.xsd https://raw.githubusercontent.com/void256/nifty-gui/1.4/nifty-core/src/main/resources/nifty.xsd"> 3 <!-- +++++++++++++++++++++++++++++++++++++++ --> 4 <!-- start screen --> 5 <!-- +++++++++++++++++++++++++++++++++++++++ --> 6 <screen id="GScreen0" controller="mygame.Main"> 7 <layer id="GLayer0" childLayout="absolute"> 8 </layer> 9 </screen> 10 </nifty>
这里可以看到,一个Nifty Gui xml文件的结构是<nifty>标签开始,然后是<screen>标签,紧接着是<layer>标签,先有<screen>后有<layer>,而且<screen>必须以<layer>作为直接子层级,不能用其他组件作为<screen>的直接子层级。
由前面文章可知,没有引用默认controls库和默认styles库,是无法正常渲染出NiftyGui的,我们修改xml为如下代码:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <nifty xmlns="http://nifty-gui.lessvoid.com/nifty-gui" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://raw.githubusercontent.com/void256/nifty-gui/1.4/nifty-core/src/main/resources/nifty.xsd https://raw.githubusercontent.com/void256/nifty-gui/1.4/nifty-core/src/main/resources/nifty.xsd"> 3 <!-- +++++++++++++++++++++++++++++++++++++++ --> 4 <!-- start screen --> 5 <!-- +++++++++++++++++++++++++++++++++++++++ --> 6 7 <!-- 引入默认控件库和默认样式库 --> 8 <useControls filename="nifty-default-controls.xml"/> 9 <useStyles filename="nifty-default-styles.xml"/> 10 11 <screen id="screen0"> 12 <!-- 这个layer0我们设置背景颜色为白色 --> 13 <layer id="layer0" backgroundColor="#ffff" childLayout="absolute"> 14 </layer> 15 16 <!-- 这个layer1我们设置北京颜色为红色 --> 17 <!-- 同一个screen中,layerId不能相同,并且layer不能嵌套,只能并级 --> 18 <!-- 同一个screen的layer会进行重叠覆盖screen内容,即使为layer1设置了width/height也没用,会填满整个screen --> 19 <!-- 通常一个screen不会包含2个layer以上,一般只有一个,如果一个screen需要多个layer,则通过java代码hide()/show()进行显隐控制要渲染一个screen中的哪个layer, 20 默认一个screen中所有layers都会渲染,层级的最后一个layer会覆盖screen的内容,这里id=layer1是screen0第二个layer,所以渲染完layer0后会渲染layer1,layer1内容完全覆盖 21 screen0 --> 22 <layer id="layer1" width="50.0%" height="50.0%" backgroundColor="#ff0000" childLayout="absolute"> 23 </layer> 24 </screen> 25 26 <screen id="screen1"> 27 <!-- 这个layer0我们设置背景色为绿色 --> 28 <!-- 从这里可以看出,同一个xml文件中,layer的id可以重复,因为这两个layer0被两个不同id的screen隔离了,所以可以通过不同screen来获取id为layer0的layer对象 --> 29 <layer id="layer0" backgroundColor="#00ff00" childLayout="absolute"> 30 </layer> 31 </screen> 32 </nifty>
上面的注释已经很好的解释了如何在一个xml中添加多个screen,一个screen如何包含多个layer,一个screen中layer的渲染关系,以及layerId是否可以重复等等问题。
回到java代码,我们通过如下方式显示screen0,此时发现显示的是红色:
1 import com.jme3.app.SimpleApplication; 2 import com.jme3.niftygui.NiftyJmeDisplay; 3 import de.lessvoid.nifty.Nifty; 4 5 /** 6 * @date 2024年7月11日14点25分 7 * @author JohnKkk 8 */ 9 public class NiftyGui01 extends SimpleApplication{ 10 11 private Nifty m_Nifty; 12 13 @Override 14 public void simpleInitApp() { 15 // 初始化Nifty 16 NiftyJmeDisplay niftyDisplay = NiftyJmeDisplay.newNiftyJmeDisplay( 17 assetManager, 18 inputManager, 19 audioRenderer, 20 guiViewPort); 21 m_Nifty = niftyDisplay.getNifty(); 22 // 将NiftyGUI显示对象添加到JME3中 23 guiViewPort.addProcessor(niftyDisplay); 24 25 // 加载xml布局文件,设置默认屏幕为screen0 26 m_Nifty.fromXml("Interface/NiftyGui01.xml", "screen0"); 27 } 28 29 public static void main(String[] args) { 30 NiftyGui01 niftyGui01 = new NiftyGui01(); 31 niftyGui01.start(); 32 } 33 }

从xml可知,screen0有两个layer(layer0和layer1),在java代码中我们加载了xml并设置默认启动的screen为id=screen0这个screen,NiftyGui渲染screen0时,首先渲染layer0,然后渲染layer1(按照层级元素顺序),所以最后显示红色(因为layer1背景色为红色)。
如果我们要隐藏layer1,则可以通过如下代码:
m_Nifty.getScreen("screen0").getLayerElements().get(1).hide();
这里我们知道layer1是screen0的第二个layer,所以直接通过index=1获取,然后调用hide(),再次运行出现白色(即screen0的layer0背景色):

由于layer无法嵌套,而且会覆盖渲染,所以我们通常使用panel来提供容器包含一组组件(类似swing,我们通常会添加panel,然后再在panel里放元素),当然,你也可以不需要panel,直接在layer中添加按钮,标签,文本等组件。
如下是我们在screen0的layer0添加了两个panel:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <nifty xmlns="http://nifty-gui.lessvoid.com/nifty-gui" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://raw.githubusercontent.com/void256/nifty-gui/1.4/nifty-core/src/main/resources/nifty.xsd https://raw.githubusercontent.com/void256/nifty-gui/1.4/nifty-core/src/main/resources/nifty.xsd"> 3 <!-- +++++++++++++++++++++++++++++++++++++++ --> 4 <!-- start screen --> 5 <!-- +++++++++++++++++++++++++++++++++++++++ --> 6 7 <!-- 引入默认控件库和默认样式库 --> 8 <useControls filename="nifty-default-controls.xml"/> 9 <useStyles filename="nifty-default-styles.xml"/> 10 11 <screen id="screen0"> 12 <!-- 这个layer0我们设置背景颜色为白色 --> 13 <layer id="layer0" backgroundColor="#ffff" childLayout="absolute"> 14 <panel id="panel0" childLayout="absolute" width="50%" backgroundColor="#33ffffff" height="30%" x="29" y="27" style="nifty-panel-simple"/> 15 <panel id="panel1" childLayout="absolute" width="50%" backgroundColor="#00ff33ff" height="30%" x="267" y="231" style="nifty-panel-simple"/> 16 </layer> 17 18 <!-- 这个layer1我们设置北京颜色为红色 --> 19 <!-- 同一个screen中,layerId不能相同,并且layer不能嵌套,只能并级 --> 20 <!-- 同一个screen的layer会进行重叠覆盖screen内容,即使为layer1设置了width/height也没用,会填满整个screen --> 21 <!-- 通常一个screen不会包含2个layer以上,一般只有一个,如果一个screen需要多个layer,则通过java代码hide()/show()进行显隐控制要渲染一个screen中的哪个layer, 22 默认一个screen中所有layers都会渲染,层级的最后一个layer会覆盖screen的内容,这里id=layer1是screen0第二个layer,所以渲染完layer0后会渲染layer1,layer1内容完全覆盖 23 screen0 --> 24 <layer id="layer1" width="50.0%" height="50.0%" backgroundColor="#ff0000" childLayout="absolute"> 25 </layer> 26 </screen> 27 28 <screen id="screen1"> 29 <!-- 这个layer0我们设置背景色为绿色 --> 30 <!-- 从这里可以看出,同一个xml文件中,layer的id可以重复,因为这两个layer0被两个不同id的screen隔离了,所以可以通过不同screen来获取id为layer0的layer对象 --> 31 <layer id="layer0" backgroundColor="#00ff00" childLayout="absolute"> 32 </layer> 33 </screen> 34 </nifty>
此时启动如下(记得隐藏layer1):

切换不同Screen
由于我们可以在一个xml中添加多个screen,想象一下,我们创建了一个GameMainMenuGui(游戏主菜单),其中第一个screen包含“开始游戏”,“设置”,“退出游戏”,在点击“设置”时,希望界面切换为“设置页面”(第二个screen)。
我们在上面的xml中已经添加了两个screen(id分别为screen0和screen1),修改java代码:
1 import com.jme3.app.SimpleApplication; 2 import com.jme3.niftygui.NiftyJmeDisplay; 3 import de.lessvoid.nifty.Nifty; 4 5 /** 6 * @date 2024年7月11日14点25分 7 * @author JohnKkk 8 */ 9 public class NiftyGui01 extends SimpleApplication{ 10 11 private Nifty m_Nifty; 12 13 @Override 14 public void simpleInitApp() { 15 // 初始化Nifty 16 NiftyJmeDisplay niftyDisplay = NiftyJmeDisplay.newNiftyJmeDisplay( 17 assetManager, 18 inputManager, 19 audioRenderer, 20 guiViewPort); 21 m_Nifty = niftyDisplay.getNifty(); 22 // 将NiftyGUI显示对象添加到JME3中 23 guiViewPort.addProcessor(niftyDisplay); 24 25 // 加载xml布局文件,设置默认屏幕为screen0 26 m_Nifty.fromXml("Interface/NiftyGui01.xml", ""); 27 m_Nifty.getScreen("screen0").getLayerElements().get(1).hide(); 28 } 29 30 public static void main(String[] args) { 31 NiftyGui01 niftyGui01 = new NiftyGui01(); 32 niftyGui01.start(); 33 } 34 }
请注意第26行,fromXml()第二个参数我们调整为""空字符串,此时启动将不会渲染任何NiftyGui(即显示黑色),因为我们没有指定要渲染哪个screen,我们可以通过如下:
1 @Override 2 public void simpleInitApp() { 3 // 初始化Nifty 4 NiftyJmeDisplay niftyDisplay = NiftyJmeDisplay.newNiftyJmeDisplay( 5 assetManager, 6 inputManager, 7 audioRenderer, 8 guiViewPort); 9 m_Nifty = niftyDisplay.getNifty(); 10 // 将NiftyGUI显示对象添加到JME3中 11 guiViewPort.addProcessor(niftyDisplay); 12 13 // 加载xml布局文件,设置默认屏幕为screen0 14 m_Nifty.fromXml("Interface/NiftyGui01.xml", ""); 15 m_Nifty.getScreen("screen0").getLayerElements().get(1).hide(); 16 m_Nifty.gotoScreen("screen0"); 17 }
注意第16行代码,调用gotoScreen("screen0")指定渲染screen0,那么我们连续调用两次gotoScreen(),是否会渲染两个screen呢?如下:
1 public void simpleInitApp() { 2 // 初始化Nifty 3 NiftyJmeDisplay niftyDisplay = NiftyJmeDisplay.newNiftyJmeDisplay( 4 assetManager, 5 inputManager, 6 audioRenderer, 7 guiViewPort); 8 m_Nifty = niftyDisplay.getNifty(); 9 // 将NiftyGUI显示对象添加到JME3中 10 guiViewPort.addProcessor(niftyDisplay); 11 12 // 加载xml布局文件,设置默认屏幕为screen0 13 m_Nifty.fromXml("Interface/NiftyGui01.xml", ""); 14 m_Nifty.getScreen("screen0").getLayerElements().get(1).hide(); 15 m_Nifty.gotoScreen("screen0"); 16 m_Nifty.gotoScreen("screen1"); 17 }
此时只会渲染id=screen1的screen,从这里可知,NiftyGui同一时刻只能渲染一个screen。
Nifty Gui多xml文件
我们再创建一个Gui xml文件,命名为NiftyGui011,如下:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <nifty xmlns="http://nifty-gui.lessvoid.com/nifty-gui" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://raw.githubusercontent.com/void256/nifty-gui/1.4/nifty-core/src/main/resources/nifty.xsd https://raw.githubusercontent.com/void256/nifty-gui/1.4/nifty-core/src/main/resources/nifty.xsd"> 3 <!-- +++++++++++++++++++++++++++++++++++++++ --> 4 <!-- start screen --> 5 <!-- +++++++++++++++++++++++++++++++++++++++ --> 6 7 <!-- 引入默认控件库和默认样式库 --> 8 <useControls filename="nifty-default-controls.xml"/> 9 <useStyles filename="nifty-default-styles.xml"/> 10 11 <screen id="screen2" controller="mygame.Main"> 12 <layer id="layer0" childLayout="absolute" backgroundColor="#00ffff" > 13 </layer> 14 </screen> 15 </nifty>
这里添加了一个id为screen2的screen,并设置背景色为#00ffff,调整java代码,如下:
1 @Override 2 public void simpleInitApp() { 3 // 初始化Nifty 4 NiftyJmeDisplay niftyDisplay = NiftyJmeDisplay.newNiftyJmeDisplay( 5 assetManager, 6 inputManager, 7 audioRenderer, 8 guiViewPort); 9 m_Nifty = niftyDisplay.getNifty(); 10 // 将NiftyGUI显示对象添加到JME3中 11 guiViewPort.addProcessor(niftyDisplay); 12 13 // // 加载xml布局文件,设置默认屏幕为screen0 14 // m_Nifty.fromXml("Interface/NiftyGui01.xml", ""); 15 // m_Nifty.getScreen("screen0").getLayerElements().get(1).hide(); 16 // m_Nifty.gotoScreen("screen0"); 17 // m_Nifty.gotoScreen("screen1"); 18 19 // 添加多个xml 20 m_Nifty.addXml("Interface/NiftyGui01.xml"); 21 m_Nifty.addXml("Interface/NiftyGui011.xml"); 22 // 启动id为screen2的screen 23 m_Nifty.gotoScreen("screen2"); 24 }
注意第20~23行,我们通过addXml()方法添加了多个xml文件,然后内存中存在了screen0,screen1,screen2三个id的screen,接着启动screen2,这也就为何NiftyGui011.xml添加的screen为screen2了,因为id必须唯一,不然内存就会有相同screen。
启动如下:

关于层级的内容,就暂时介绍到这里了。

浙公网安备 33010602011771号