使用 pyglet 切换场景

发布于 2024-10-30 16:31:09 字数 202 浏览 2 评论 0原文

任何人都可以推荐如何在 pyglet 中的场景之间切换。 即

  • 菜单>游戏
  • 游戏>菜单
  • 菜单>帮助

我能想到的唯一方法是使用不同的窗口,我很确定这将是完全错误的方法。或者通过重载所有窗口的事件函数。

抱歉,如果我没有说清楚,但我们将不胜感激

Can anybody recommend how to switch between scenes in pyglet.
I.e.

  • menu > game
  • game > menu
  • menu > help
  • ect

The only way that i can think to do it off the top of my head is by using different windows, which i am quite sure would be the complete wrong way to do it. Or by overloading all of the window's event functions.

Sorry if i haven't made myself clear but any help would be appreciated

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

谷夏 2024-11-06 16:31:09

cocos2d.org 框架基于 pyglet 构建,包含场景管理。

The cocos2d.org framework is built on pyglet and includes scene management.

蘑菇王子 2024-11-06 16:31:09

以下是可能适合您的类结构的粗略示意图:

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 类,该类拥有该窗口并管理向用户显示哪个屏幕。在这里,我使用“屏幕”来表示用户正在与之交互的内容,例如主菜单或关卡播放器。这里的关键是 Screen 的 clear() 方法,您应该实现该方法来删除您正在显示的所有精灵、媒体、组和批次。您还必须在清除时删除窗口处理程序并在启动时设置它们。

您可以在此处查看此解决方案的实际效果: https://github.com/superjoe30/lemming/树/主人/旅鼠

Here is a rough schematic of a class structure that might work for you:

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()

So you have a Game class who owns the window and that manages which Screen is displayed to the user. Here I use "Screen" to mean what the user is interacting with, for example a MainMenu, or a LevelPlayer. The key here is the clear() method of Screen, which you should implement to delete all the sprites, media, groups, and batches that you were displaying. You also have to remove the window handlers on clear and set them on start.

You can see this solution in action here: https://github.com/superjoe30/lemming/tree/master/lemming

攒一口袋星星 2024-11-06 16:31:09

我的经验不是很丰富,但就其价值而言,我使用的方法如下。它不识别明确的“状态”或“场景”本身,而是依赖于在我的游戏世界中添加(和删除)离散项目。每个这样的项目可能有自己的密钥处理程序,并且知道如何以及何时创建其他这样的项目。

一个具体的例子:

GameItem 是所有可以放入世界的物品的子类。它是一个简单的属性集合,没有任何行为。它由游戏世界中的项目(例如 Bush、Player 等)以及 HUD 项目(例如 ScoreDisplay 和 MainMenu)进行子类化。

世界只是游戏项目的集合。

我的“更新”函数迭代世界上的所有项目,如果有的话调用它们的更新方法。

我的“绘制”函数类似地迭代世界上的所有项目,绘制每个项目。 (其中许多可以通过简单地调用像 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/
(不过,公平地说,它在游戏过程中并没有明显的“场景”。它只是使用此技术来管理菜单、游戏结束屏幕等)

I'm not very experienced, but for what it's worth, the method I use is as follows. It does not recognise explicit 'states' or 'scenes' as such, but rather it relies on the adding (and removal) of discrete items into my game world. Each such item may have its own key handlers, and knows how and when to create other such items.

A specific example:

GameItem is a subclass for all items that can be put into the world. It is a simple collection of attributes, with no behaviour. It is subclassed by items in the game world like Bush, Player, etc, and also by HUD items like ScoreDisplay and MainMenu.

World is just a collection of GameItems.

My 'update' function iterates through all items in the world, calling their update method if they have one.

My 'draw' function similarly iterates through all items in the world, drawing each of them. (many of them might be drawn en-masse by simply calling something like pyglet's Batch.draw)

Right at application start-up, one of the first items I add to the world is a MainMenu object. It has an on_key_down method.

World.add looks at the item being added. If an item has an on_key_down method, then it adds this handler to the pyglet key handlers stack. (Similarly, it undoes this in World.remove) (Actually, on reflection, I guess world.add raises an event when it adds an item. If the application's keyboard handler module is interested, then on recieving one of these events it then does the adding of the item's key hander, but this is kinda incidental to the question)

The MainMenu.on_key_handler method looks at the pressed key, and if it's the key to start the game, then it makes a series of calls:

# 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)

This is just a simple example, but hopefully you can see how, instead of starting the game, the mainmenu could instead display secondary menus by adding them to the world, or any such thing.

Once in the game, you can change 'scenes' by simply calling 'world.remove' on all items that you no longer want visible, and calling 'world.add' on all the items in the new scene.

An example of a game that uses this technique is previous pyweek entry SinisterDucks:
http://code.google.com/p/brokenspell/
(although, to be fair, it does not feature distinct 'scenes' during gameplay. It merely usesthis technique to manage menus, game over screen, etc)

爱冒险 2024-11-06 16:31:09

我最终使用的解决方案是为主窗口提供一个堆栈,并将所有事件传递给堆栈顶部的项目。

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 中的函数,这些函数将管理堆栈中的推送和弹出场景

The solution i ended up using is by giving the main window a stack and having it pass all events out to items on the top of the stack.

i.e.

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)

ect. For all of the other events that i use

i am currently in the process of writing up some functions to go in GameWindow that will manage pushing and popping scenes from the stack

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文