JMonkeyEngine中是如何使用AppState来管理和实现游戏场景切换的?

2021-06-09 18:18:47 0点赞 0收藏 0评论

什么是AppState?

一般来说JME中的AppState是为了解决复杂游戏场景中各种游戏元素的管理问题,当游戏越来越大,越来越复杂的时候,游戏中的各种元素(例如:模型、环境、事件、特效等), 将会变得越来越难以管理和控制。

AppState的存在就可以用来将游戏场景中的各种元素分离、解耦到不同的AppState下进行运行, 再通过将不同的AppState组合到一起放到游戏中,就可以组成不同状态的游戏场景。

先看一下AppState在Application中的存在及生命周期是怎样的?

一个JME游戏应用中可以存在多个AppState, 通过使用以下两个方法来将AppState添加到游戏或从游戏中移除。

stateManager.attach(AppState appState);
stateManager.detach(AppState appState);
每个AppState的一个完整生命周期会经历:initialize -> update -> cleanup这几个方法。

当AppState被添加(attach)到游戏中时, initialize方法会被调用一次,以初始化AppState
然后AppState会在游戏中不停的循环执行update方法。
直到有人调用了stateManager的detach方法将AppState从游戏中移除,此时AppState的cleanup方法会被调用一次,以清理及释放该AppState所产生的资源,然后该AppState就会被彻底移除

AppState的实现原则
AppState的实现原则一般应该是这样的:

当你在AppState的initialize方法或update方法中向游戏中添加了任何资源后,在cleanup方法就要确保将这些资源从游戏中移除或清理,否则AppState在移除后可能会残留一些游戏元素在游戏中占用资源,这可能会导致内存问题及性能影响。
每个AppState应该实现各自不同的功能,各个AppState之间应该尽量独立互不影响,从而将游戏中的复杂度拆分到不同的AppState中。比如当添加或从游戏中移除一个AppState时,不应该导致其它AppState出错或崩溃。

AppState的使用示例
下面拿一个示例来说明,例如,我们可以实现这样一个游戏,这个游戏中包含以下AppState:

SceneAppStateA 游戏场景A, 存放游戏元素,如人物、房子、地形、植物、动物等。
SceneAppStateB 游戏场景B, 存放游戏元素,如人物、房子、地形、植物、动物等。
RainEnvAppState 环境, 下雨环境,可以在AppState中添加雨水声效、用于渲染雨水的特效过滤器等等。
SnowEnvAppState 环境, 下雪环境,可以在AppState中添加雪花飘飘的特效、声效等。
UIAppState 游戏UI界面
那么现在如果你想要初始化一个游戏场景,要实现一个让场景A下雨的游戏的话,就通过这样来操作:

@Override
public void simpleInitApp() {
stateManager.attach(sceneAppStateA);
stateManager.attach(rainEnvAppState);
stateManager.attach(uiAppState);
}

那么得到的Application中AppState的状态就像是上面这样的: A场景正在下雨中。

如果要让场景A下雪,则可以调用像类似下面这样的方法来从落雨场景切换到下雪的场景。

public void changeToSnowEnv() {
stateManawww.cungun.comger.detach(rainEnvAppState)
stateManager.attach(snowEnvAppState);
}

那么得到的Application中AppState的状态就像是上面这样的: A场景现在正在下雪。

同样的,如果你要从场景A转换场景B,例如:你在游戏中有一个传送门,可以让你从A地图传送到B地图,那么你就可以在传送的时候调用像下面这样的方法来切换到场景B:

public void changeToSceneB() {
stateManager.detach(sceneAppStateA)
stateManager.attach(sceneAppStateB);
}

那么得到的Application中AppState的状态就像是上面这样的:一个正在下雪的场景B。

代码示例
那么下面使用完整的代码来示例如何在游戏中进行场景切换,主要的重点是放在AppState的切换以及实现AppState时的原则上,所以代码写得很简单,在明白了这些简单原理之后,我想,谁都可以把它变得更加复杂。

这个示例中演示了如何在游戏中切换场景A和场景B(通过按键AB切换)

package mygame;

import com.jme3.app.SimpleApplication;
import com.jme3.input.KeyInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;

/**

SimpleGame用于演示如何使用JME的AppState来实现切换场景A和场景B的功能。

@author huliqing
*/
public class SimpleGame extends SimpleApplication {

private final AppStateA sceneA = new AppStateA();
private final AppStateB sceneB = new AppStateB();

@Override
public void simpleInitApp() {

// 注册按键事件:A、B
// 用这两个按键来实现切换到A和B场景。
getInputManager().addMapping("typeA", new KeyTrigger(KeyInput.KEY_A));
getInputManager().addMapping("typeB", new KeyTrigger(KeyInput.KEY_B));
getInputManager().addListener(new ActionListener() {
@Override
public void onAction(String name, boolean isPressed, float tpf) {
if (name.equals("typeA")) {
// 当按了键盘A键的时候把场景B移除,然后把场景A添加上去。
getStateManager().detach(sceneB);
getStateManager().attach(sceneA);
} else if (name.equals("typeB")) {
// 当按了键盘B键的时候把场景A移除,然后把场景B添加上去。
getStateManager().detach(sceneA);
getStateManager().attach(sceneB);
}
}
}, "typeA", "typeB");

}

public static void main(String[] args) {
SimpleGame app = new SimpleGame();
app.start();
}
}
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.material.Material;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.shape.Box;

/**

AppStateA用来模拟场景A, 显示一个立方体.

@author huliqing
*/
public class AppStateA extends AbstractAppState{

// 这个节点可以作为当前AppState的本地根节点。
// 在当前AppState被添加到游戏的时候把这个节点添加到场景中。
// 在当前AppState被从游戏中移除时要把这个根节点从游戏中移除。
private Node localRoot;

@Override
public void initialize(AppStateManager stateManager, Application app) {
super.initialize(stateManager, app);
// 初始化当前AppState的本地根节点,并把这个根节点添加到游戏主场景中。
// 后面所有在当前AppState中创建的物体都要添加到这个本地根节点中。
localRoot = new Node();
((SimpleApplication)app).getRootNode().attachChild(localRoot);

// 创建当前AppState场景的物体,并把物体添加到当前的AppState场景本地根节点(localRoot)中.
Box box = new Box(0.5f, 0.5f, 0.5f);
Geometry geo = new Geometry("testBox", box);
geo.setMaterial(new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md"));
localRoot.attachChild(geo);

// ... 添加其它物体(略)
}

// 当AppState被从游戏中移除时,cleanup方法会被调用,这里要把AppState的根节点从游戏中移除.
// 因为当前AppState场景内中创建的所有物体都是放在localRoot下的,所以直接把localRoot移除就可以了。
@Override
public void cleanup() {
localRoot.removeFromParent();
super.cleanup();
}

}
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.material.Material;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.shape.Sphere;

/**

AppStateB用来模拟一个场景B, 显示一个球体(原理和AppStateA是完全一样的).

@author huliqing
*/
public class AppStateB extends AbstractAppState{

private Node localRoot;

@Override
public void initialize(AppStateManager stateManager, Application app) {
super.initialize(stateManager, app);
localRoot = new Node();
((SimpleApplication)app).getRootNode().attachChild(localRoot);

Sphere sphere = new Sphere(20, 20, 1);
Geometry geo = new Geometry("testShpere", sphere);
geo.setMaterial(new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md"));
localRoot.attachChild(geo);

// ... 添加其它物体(略)
}

@Override
public void cleanup() {
localRoot.removeFromParent();
super.cleanup();
}
}

展开 收起

Microsoft 微软 Office 2019 家庭学生版

Microsoft 微软 Office 2019 家庭学生版

189元起

《3D绳结》iOS 生活技能类App

《3D绳结》iOS 生活技能类App

暂无报价

Internet Download Manager 序列号注册激活码

Internet Download Manager 序列号注册激活码

28元起

NS switch 向下走 going under 下行 存档修改金钱技能

NS switch 向下走 going under 下行 存档修改金钱技能

10元起

微软 Microsoft 365 家庭版 15个月加长版电子秘钥 1年订阅 多至6人 正版Office 1T云存储 限PC/手机组合购买

微软 Microsoft 365 家庭版 15个月加长版电子秘钥 1年订阅 多至6人 正版Office 1T云存储 限PC/手机组合购买

628元起

国行机专用 任天堂Switch健身环大冒险游戏卡中文兑换码国行游戏机ns体感套装运动环健身圈舞力全开实体卡带 标准版

国行机专用 任天堂Switch健身环大冒险游戏卡中文兑换码国行游戏机ns体感套装运动环健身圈舞力全开实体卡带 标准版

478元起

Office 365 家庭版

Office 365 家庭版

269元起

WPS 超级会员 年卡

WPS 超级会员 年卡

279元起

《国家地理 每日精选》iOS数字版软件

《国家地理 每日精选》iOS数字版软件

1元起

任天堂Switch游戏 NS塞尔达传说 荒野之息 旷野之息 中文现货

任天堂Switch游戏 NS塞尔达传说 荒野之息 旷野之息 中文现货

310元起

《Picsew》iOS数字版软件

《Picsew》iOS数字版软件

1元起

《kirakira+》 iOS软件

《kirakira+》 iOS软件

暂无报价

《扫描全能王付费版》iOS数字版软件

《扫描全能王付费版》iOS数字版软件

1元起

《拍照取字 专业版》iOS数字版软件

《拍照取字 专业版》iOS数字版软件

1元起

Microsoft 微软 Office 365 个人版 1年订阅

Microsoft 微软 Office 365 个人版 1年订阅

209元起

《DARK SOULS III》(黑暗之魂3 )PC数字版游戏

《DARK SOULS III》(黑暗之魂3 )PC数字版游戏

67元起
0评论

发表评论请 登录
评论举报

请选择举报理由

相关好价推荐
查看更多好价

相关文章推荐

更多精彩文章
更多精彩文章
相关好价
最新文章 热门文章
0
扫一下,分享更方便,购买更轻松