在游戏开发中,经常涉及到场景的转换,从本质上来说,场景的转换非常类似舞台剧。因此对于场景的控制,简单粗暴直观的写法:
class SceneManager(object):
def __init__(self):
self.m_state = None
def change_scene(self, statename):
self.m_state = statename
if self.m_state == "菜单":
print("LoadLevel MainMenuScene")
elif self.m_state == "主场景":
print("LoadLevel MainScene")
def update_scene(self):
if self.m_state == "开始":
print("update 开始 scene")
elif self.m_state == "菜单":
print("update MainMenuScene")
elif self.m_state == "主场景":
print("update MainScene"
ok,这样简单粗暴的解决了问题,场景很少很简单,当然是没问题的。但有以下缺点:只要增加一个新的场景,就意味着change_scene函数和update_scene函数都需要加入对应的代码。每一个场景类继承的父类可能不同,容易造成SceneManager过度依赖其他类。为了解决这个问题,使用状态模式来解决,状态模式除了能解决场景切换的问题,其实当我们玩英雄联盟,接触豹女和杰斯,同理,也是这样的一个情况。
状态模式
看不懂箭头的线,可搜索设计模式UML图,即可了解关系。
StateOwner也就是对应图上的Context
class StateOwner:
def __init__(self):
self.m_state = None
def request(self, value):
self.m_state.handle(value)
def setstate(self, state):
print("steState-------->{}".format(state.__class__.__name__))
self.m_state = state
各种状态的写法如下:
class State:
def __init__(self, the_stateowner):
self.m_stateowner = the_stateowner
def handle(self, value):
pass
class StateA(State):
def handle(self, value):
print("stateA Handle")
if value > 10:
print("value > 10 ,状态改变")
self.m_stateowner.setstate(StateB(self.m_stateowner))
class StateB(State):
def handle(self, value):
print("stateB Handle")
if value > 20:
print("value > 20 ,状态改变")
self.m_stateowner.setstate(StateC(self.m_stateowner))
class StateC(State):
def handle(self, value):
print("stateC Handle")
if value > 30:
print("value > 30 ,状态改变")
self.m_stateowner.setstate(StateA(self.m_stateowner))
测试的案例如下:
def Test():
"""
# 最简单的状态模式代码,可以比较简单的替代switch 模式下的状态转换
:return: None
"""
stateowner = Stateowner()
stateowner.setstate(StateA(stateowner))
stateowner.request(5)
stateowner.request(15)
stateowner.request(25)
stateowner.request(35)
Test()
下面是游戏实战应用,某游戏把游戏进程分成了三个过程:开始场景、主画面场景、战斗场景。设计一个基础的场景类Scene,StartScene、MainMenuScene、BattleScene继承Scene,Scene有三个成员函数:scenebegin 、 sceneend、 sceneupdate。
scenebegin:负责资源的加载和游戏参数的设置;
sceneend:释放游戏不再使用的资源,重新设置游戏场景状态。
sceneupdate:该方法是在每一帧被调用,场景定时更新功能。下面是代码示例:
class Scene(object):
def __init__(self, scene_mgr):
self.scene_mgr = scene_mgr
# 当前场景的名称
@property
def scenename(self):
return self._scenename
@scenename.setter
def scenename(self, name):
self._scenename = name
def scenebegin(self):
"""子类重写"""
pass
def sceneend(self):
"""子类重写"""
pass
def update(self):
"""子类重写"""
pass
class StartScene(Scene):
def __init__(self):
super(StartScene, self).__init__(self.scene_mgr)
self.scenename = "StartScene"
def scenebegin(self):
print("Begin load StartScene model and res")
print("Begin load ui")
print("Begin bind ui")
def sceneend(self):
print("destroy StartScene model and res")
print("destroy StartScene ui")
def update(self):
print("Update StartScene")
class MainMenuScene(Scene):
def __init__(self):
super(MainMenuScene, self).__init__(self.scene_mgr)
self.scenename = "MainMenuScene"
def scenebegin(self):
print("Begin load MainMenuScene model and res")
print("Begin load ui")
print("Begin bind ui")
def sceneend(self):
print("destroy MainMenuScene model and res")
print("destroy MainMenuScene ui")
def update(self):
print("Update MainMenuScene")
class BattleScene(Scene):
def __init__(self):
super(BattleScene, self).__init__(self.scene_mgr)
self.scenename = "BattleScene"
def scenebegin(self):
print("Begin load BattleScene model and res")
print("Begin BattleScene ui")
print("Begin BattleScene ui")
def sceneend(self):
print("destroy BattleScene model and res")
print("destroy BattleScene ui")
def update(self):
print("Update BattleScene") # 输入
def input_process(self):
pass
除了以上的,还需要一个游戏主循环Game和场景管理器SceneMgr,在Game脚本中,定义并初始化SceneMgr,并且设置了第一个游戏的状态,StartScene,然后在Game中定时更新SceneMgr的update方法,并定时更新场景。
from Script.State_Patterns.Application import Scene
class SceneMgr:
def __init__(self):
self._scene = None
self.is_scene_begin = False
def setscene(self, scene, loadscenename):
print("SetScene:".format(scene.scenename))
if self._scene: # 结束上一个scene
self._scene.sceneend()
self.is_scene_begin = False
self._scene = scene
self.loadscene(loadscenename)
def scene_update(self):
if self._scene:
self._scene.sceneUpdate()
def loadscene(self, loadsceneame):
if not loadsceneame:
return
if self._scene and not self.is_scene_begin:
self._scene.scenebegin()
self.is_scene_begin = True
class Game(object):
def __init__(self):
self.scene_mgr = SceneMgr()
def awake(self):
pass
def start(self):
self.scene_mgr.setscene(Scene.StartScene(self.scene_mgr,""))
def update(self):
self.scene_mgr.scene_update()
以上就是状态模式的简单介绍,除了场景的管理使用该种模式,也可应用于
- 角色AI:控制AI在不同状态下的行为
- 关卡进行状态:通关类的游戏,包含数据加载、关卡信息显示、倒数通知、关卡进行、结束、分数计算。