任何人都可以推荐如何在 pyglet 中的场景之间切换。IE
- 菜单 > 游戏
- 游戏 > 菜单
- 菜单 > 帮助
- 等
我能想到的唯一方法是使用不同的窗口,我很确定这将是完全错误的方法。或者通过重载窗口的所有事件函数。
对不起,如果我没有说清楚,但任何帮助将不胜感激
这是一个可能适合您的类结构的粗略示意图:
class Game(object):
"This class contains the Scene which is the current scene the user is look ing at."
def __init__(self):
self.current_level = 0
self.current_screen = MainMenu(self)
def load(self):
"Load progress from disk"
pass
def save(self):
"Save progress to disk"
pass
def clearCurrentScreen(self):
self.current_screen.clear()
self.window.remove_handlers()
def startCurrentScreen(self):
self.window.set_handler("on_key_press", self.current_screen.on_key_press)
# etc
self.current_screen.start()
def gotoNextLevel(self):
"called from within LevelPlayer when the player beats the level"
self.clearCurrentScreen()
self.current_level += 1
self.current_screen = LevelPlayer(self, game, self.current_level)
self.startCurrentScreen()
def startPlaying(self):
"called by the main menu when the user selects an option"
self.clearCurrentScreen()
self.current_screen = LevelPlayer(self, game, self.current_level)
self.startCurrentScreen()
def execute(self):
self.window = pyglet.window.Window()
self.startCurrentScene()
pyglet.app.run()
class Screen(object):
def __init__(self):
pass
def start():
pass
def clear():
"delete all graphical objects on screen, batches, groups, etc. Clear all state in pyglet."
pass
def on_key_press(self, key, etc):
pass
def on_draw(self):
pass
# etc
class LevelPlayer(Screen):
"This class contains all your game logic. This is the class that enables the user to play through a level."
def __init__(self, game, level_to_play):
pass
# be sure to implement methods from Screen
class MainMenu(Screen):
"This class presents the title screen and options for new game or continue."
def __init__(self, game):
self.game = game
def handleNewGame(self):
self.game.startPlaying()
def handleContinue(self):
self.game.load()
self.game.startPlaying()
# be sure to implement methods from Screen
game = Game()
game.execute()
因此,您有一个 Game 类,它拥有该窗口并管理向用户显示哪个屏幕。在这里,我使用“屏幕”来表示用户正在与之交互的内容,例如 MainMenu 或 LevelPlayer。这里的关键是 Screen 的 clear() 方法,您应该实现该方法来删除您正在显示的所有精灵、媒体、组和批次。您还必须在清除时删除窗口处理程序并将它们设置为启动。
你可以在这里看到这个解决方案:https ://github.com/superjoe30/lemming/tree/master/lemming
cocos2d.org 框架建立在 pyglet 之上,包含场景管理。
我不是很有经验,但是对于它的价值,我使用的方法如下。它不能识别明确的“状态”或“场景”,而是依赖于在我的游戏世界中添加(和删除)离散项目。每个这样的项目可能有自己的密钥处理程序,并且知道如何以及何时创建其他这样的项目。
一个具体的例子:
GameItem 是可以放入世界中的所有项目的子类。它是一个简单的属性集合,没有任何行为。它是游戏世界中的项目(如 Bush、Player 等)以及 HUD 项目(如 ScoreDisplay 和 MainMenu)的子类。
World 只是 GameItems 的集合。
我的“更新”函数会遍历世界上的所有项目,如果有,就调用它们的更新方法。
我的“绘制”函数类似地遍历世界上的所有项目,绘制每个项目。(其中许多可以通过简单地调用 pyglet 的 Batch.draw 之类的东西来整体绘制)
在应用程序启动时,我添加到世界的第一个项目之一是 MainMenu 对象。它有一个 on_key_down 方法。
World.add 查看正在添加的项目。如果一个项目有一个 on_key_down 方法,那么它将这个处理程序添加到 pyglet 键处理程序堆栈。(类似地,它在 World.remove 中撤消了此操作)(实际上,经过反思,我猜想 world.add 在添加项目时会引发一个事件。如果应用程序的键盘处理程序模块感兴趣,那么在收到其中一个事件时它会执行添加项目的关键处理程序,但这有点偶然的问题)
MainMenu.on_key_handler 方法查看按下的键,如果它是启动游戏的键,那么它会进行一系列调用:
# Do everything needed to start the game
# For dramatic pacing, any of these might be scheduled to be
# called in a second or so, using pyglet.clock.schedule_once
world.add(player)
camera.to_follow(player)
world.add(scoredisplay)
# Finally, remove the main menu from the world
# This will stop showing it on screen
# and it will remove its keyboard event handler
world.remove_item(self)
这只是一个简单的例子,但希望你能看到主菜单不是开始游戏,而是通过将它们添加到世界中来显示二级菜单,或者任何类似的东西。
进入游戏后,您只需对不再希望显示的所有项目调用“world.remove”,然后对新场景中的所有项目调用“world.add”,即可更改“场景”。
使用这种技术的游戏示例是之前的 pyweek 条目 SinisterDucks: http ://code.google.com/p/brokenspell/管理菜单、屏幕游戏等的技术)
我最终使用的解决方案是给主窗口一个堆栈并将所有事件传递给堆栈顶部的项目。
IE
class GameWindow(pyglet.window.Window):
def __init__(self,*args, **kwargs):
pyglet.window.Window.__init__(self, *args, **kwargs)
self.states = [PlayLevel(self)] ## Starting State
def on_draw(self):
if hasattr(self.states[-1],"on_draw"):
self.states[-1].on_draw()
def on_mouse_press(self,*args):
if hasattr(self.states[-1],"on_mouse_press"):
self.states[-1].on_mouse_press(*args)
等等。对于我使用的所有其他事件
我目前正在编写一些函数来GameWindow
管理从堆栈中推送和弹出场景