Переключение сцен с pyglet - PullRequest
3 голосов
/ 07 апреля 2011

Кто-нибудь может порекомендовать, как переключаться между сценами в pyglet.Т.е.

  • меню> игра
  • игра> меню
  • меню> помощь
  • т. Д.

Единственный способчто я могу думать, чтобы сделать это изо всех сил, используя разные окна, что, я уверен, было бы совершенно неправильным способом сделать это.Или перегружая все функции событий окна.

Извините, если я не прояснил себя, но любая помощь будет признательна

Ответы [ 4 ]

2 голосов
/ 08 апреля 2011

Фреймворк cocos2d.org построен на pyglet и включает в себя управление сценами.

2 голосов
/ 07 апреля 2011

Вот примерная схема структуры класса, которая может работать для вас:

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.Ключевым моментом здесь является метод clear () для Screen, который вы должны реализовать для удаления всех отображаемых спрайтов, мультимедиа, групп и пакетов.Вы также должны убрать обработчики окон при очистке и установить их при запуске.

Вы можете увидеть это решение в действии здесь: https://github.com/superjoe30/lemming/tree/master/lemming

1 голос
/ 08 апреля 2011

Я не очень опытный, но для чего он стоит, метод, который я использую, заключается в следующем.Он не распознает явные «состояния» или «сцены» как таковые, а скорее полагается на добавление (и удаление) отдельных предметов в мой игровой мир.Каждый такой элемент может иметь свои собственные ключевые обработчики и знает, как и когда создавать другие такие элементы.

Конкретный пример:

GameItem является подклассом для всех элементов, которые можно поместить вМир.Это простая коллекция атрибутов, без поведения.Он подразделяется на элементы в игровом мире, такие как Буш, Плеер и т. Д., А также на элементы HUD, такие как ScoreDisplay и MainMenu.

Мир - это просто коллекция GameItems.

Мое «обновление»Функция выполняет итерацию по всем элементам в мире, вызывая их метод обновления, если они есть.

Моя функция 'draw' аналогичным образом выполняет итерацию по всем элементам в мире, рисуя каждый из них.(многие из них могут быть нарисованы массово, просто вызывая что-то вроде pyglet's Batch.draw)

Прямо при запуске приложения одним из первых элементов, добавляемых в мир, является объект MainMenu.У него есть метод on_key_down.

World.add просматривает добавляемый элемент.Если у элемента есть метод on_key_down, он добавляет этот обработчик в стек обработчиков ключа pyglet.(Точно так же это отменяет это в World.remove) (На самом деле, при отражении, я предполагаю, что world.add вызывает событие при добавлении элемента. Если модуль обработчика клавиатуры приложения заинтересован, то при получении одного из этих событий он затем выполняетдобавление ключа элемента, но это немного случайно в вопросе)

Метод MainMenu.on_key_handler смотрит на нажатую клавишу, и если это клавиша для запуска игры, то он делает серию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)

Это простой пример, но, надеюсь, вы увидите, как, вместо запуска игры, главное меню может вместо этого отображать вторичные меню, добавляя их в мир или что-то подобное.

Попав в игру, вы можете изменить «сцены», просто вызвав «world.remove» для всех предметов, которые вы больше не хотите видеть, и вызвав «world.add» для всех предметов в новой сцене..

Примером игры, которая использует эту технику, является предыдущая запись в Pyweek SinisterDucks: http://code.google.com/p/brokenspell/ (хотя, если честно,он не имеет четких «сцен» во время игры.Он использует эту технику для управления меню, игрой за экраном и т. Д.)

0 голосов
/ 08 апреля 2011

Решение, которое я использовал в итоге, состоит в том, чтобы дать главному окну стек и заставить его передавать все события элементам на вершине стека.

т.е.

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,Для всех других событий, которые я использую

, в настоящее время я нахожусь в процессе написания некоторых функций для входа в GameWindow, которые будут управлять перемещением и выталкиванием сцен из стека

...