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。

启动如下:

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

posted @ 2024-07-11 15:37  JhonKkk  阅读(56)  评论(0)    收藏  举报