2017-06-21 14:04:19

Hello!
I have a question about Pyglet and game programming.
For example, take an example on which I was shown how Pyglet works:
import pyglet
from pyglet.window import key

#create window
window = pyglet.window.Window(640,480,caption='Example')
#clear window
window.clear()
#key input container
key_input = []
#load sound
sound = pyglet.media.load('example.wav',streaming=False)
#load image
picture = pyglet.image.load('example.png')

#main update loop
@window.event
def update(dt):
    global key_input
#play sound
    if 'SPACE press' in key_input:
        sound.play()
#quit program
    if 'ESCAPE press' in key_input:
        window.close()
#purge key presses for next update
    if len(key_input) > 0:
        key_input = []

#capture key presses
@window.event
def on_key_press(symbol,modifiers):
    key_input.append(key.symbol_string(symbol) + " press")
    print key.symbol_string(symbol) + " press"

#capture key releases
@window.event
def on_key_release(symbol,modifiers):
    key_input.append(key.symbol_string(symbol) + " release")
    print key.symbol_string(symbol) + " release"

#draw window
@window.event()
def on_draw():
    window.clear()
    picture.blit(0,0)


#schedule and run update function
pyglet.clock.schedule_interval(update, .01)

pyglet.app.run()
But how then to realize such things as a menu? If already in the main file I start to write the game itself.
Explain, or who has examples please give me!

2017-06-21 14:27:11

A menu is part of your game. I never start out writing a menu as the first thing I do with my game, however it is going to use the same concepts. You check for the arrow keys, if down is pressed, advance options by one and speak it, if up is pressed simply do the opposite.
The way your game handles the state it's in is up to you. But if these are your first games, I wouldn't consider this yet. Simply try to get things working, add more and more as time goes and as you learn. A menu usually gets in the way of developing a game either way, at least I think so, so don't bother with it until it's necessary. After all, you design the TV first and then the remote. Right?

--
Talon
Wanna play my Games? Listen to my Music? Follow me on Twitter, and say hi~
Code is poetry.

2017-06-21 14:38:54

But I want to start with this!
That is, you need some variables to determine the status?

2017-06-21 16:36:22

So in this case the topic title is wrong. The problem you're facing is not a pyglet problem, but a misunderstanding in the concept of your program. I usually handle it like the visual programmers do. You always have one window in front which contains exactly one view at the same time. Each view assembles one interface, that is either a menu, the game, a pause screen or whatever you like. Each of those views (that why object-oriented programming is extremely helpful here, but you aren't using this anyhow in your example, that's why I recommend learning these paradigms first) needs to get all pressed keys forwarded, so you can have multiple keys defined per view without interfering each other. The only thing you'll have to do then is making sure that there really is only one view active at the same time. And you'll have to think of a way you want to store keys and give them to the view. I wouldn't actually use the way you're going in your example, I would call a dedicated function inside this view whenever a key is pressed/released, just as you need it.
One tip by the way. Consider reading yourself through multiple tutorials considering game development in general and especially pyglet. Those tutorials will cover such details more specifically then we'll do here, and they're ment for people like you. You can save loads of time, your time waiting for a response from us, hoping that it will proof useful to you, and our time writing such long answers. Not that we don't want to do that, but I think there are people out there who invested loads of time in writing helpful tutorials to answer your questions in detail, while you just ignore them.
Best Regards.
Hijacker

2017-06-21 17:34:06

It is a pity that there are almost no examples in Python!
I know object-oriented programming in Python. But I do not know how to use it, and how to make a separate menu, a separate game.

2017-06-21 19:43:57

jonikster wrote:

It is a pity that there are almost no examples in Python!

That's nothing but wrong. There are loads of examples for python applications on the net, you just know how to search for them. Let's build your knowledge up right from the base:
Take a look at this one, this should guide you through OOP in Python
After that one, take a look at this specialiced one regarding pyglet
Or actually this one too
You see, there are loads of them on the net. Take some time and try googling for yourself, i'm sure you'll find something helpful.
Best Regards.
Hijacker

2017-06-21 20:26:01

I'm talking about the fact that there are no examples of audio games

2017-06-21 22:16:02

Yeah, and that's what i'm talking about. Your problems aren't related to python or pyglet, they are about developing itself. Audio Games are limited games, they're even a teardown of games if you want it like that, since they don't contain any pictures, but all the other things are the same for audio games as for normal games. Since there are just limited tutorials of audio games out there, there is no other way than reading through usual game tutorials and googling around a bit, e.g. for finding a audio library which you think is perfect for your project (for testing and learning purposes the game-engine internal sound library should be enough), and downloading additional libraries like toklk or accessible output and such stuff. But all other things can be learned from usual game tutorials too. That's what you don't seem to understand. You won't always find the perfect answer to your single question, you always have to think the abstract way and try to reduce other stuff and turn it around until it looks the way you want it to. That's how programming works.
Best Regards.
Hijacker

2017-06-22 06:09:43

The underlying core logic of a game is generally the same between a graphical game or an audio game, the only real difference between them is the emphasis of the output methods. A menu for a visual game for example works the exact same way as for an audio game, its just that one displays a graphic and another plays a sound, this usually falls somewhere under software architecture or design. Its usually emphasized to pick up the fundamentals of a language before hand since it helps provide a better foundation for more advanced concepts and mechanics like this.

Generally its really much more convient to use classes as it makes it alot easier to work with discrete code segments that don't get tangled together, though you can do it without them much like in C. Here's two examples, one with classes the other without:

import pyglet
from pyglet.window import key

#main class
class Example(pyglet.window.Window):
    def __init__(self):
        super(Example, self).__init__(640, 480, resizable=False, fullscreen=False, caption="Example")
        self.clear()

        self.key_input = []

    #load the menu classes
        self.menu = {'title':title(),'game':game(),'options':options()}
    #set the state to start on the title menu
        self.state = 'title'

        pyglet.clock.schedule_interval(self.update, .01)


    def update(self,dt):
    #update the current active menu
        self.state = self.menu[self.state].update(self.key_input,self.state)
    #clear key buffer
        if len(self.key_input) > 0:
            self.key_input = []
    #draw screen
        self.draw()

    def draw(self):
        self.clear()

    def on_key_press(self,symbol,modifiers):
        self.key_input.append(key.symbol_string(symbol) + " press")
        if symbol == key.ESCAPE:
            self.close()

    def on_key_release(self,symbol,modifiers):
        self.key_input.append(key.symbol_string(symbol) + " release")


#title screen class
class title(object):
    def __init__(self):
    #currently selected option
        self.current = 0
        
    def update(self,key,state):
        if "DOWN press" in key:
            if self.current < 2:
                self.current += 1
            if self.current == 1:
                print "options"
            elif self.current == 2:
                print "quit"

        if "UP press" in key:
            if self.current > 0:
                self.current -= 1
            if self.current == 0:
                print "start game"
            elif self.current == 1:
                print "options"

        if "RETURN press" in key:
            if self.current == 0:
                print 'starting game'
            #if game is selected, change state to game menu
                return 'game'

            elif self.current == 1:
                print 'opening options'
            #if options selected, change state to options menu
                return 'options'
            elif self.current == 2:
                print 'quitting'
                self.close()
    #if the state hasn't changed, return the current state
        return state


#game logic
class game(object):
    def __init__(self):
        print 'game stuff'

    def update(self,key,state):
        return state


#options menu
class options(object):
    def __init__(self):
        print 'options stuff'

    def update(self,key,state):
        return state


if __name__ == '__main__':
    window = Example()
    pyglet.app.run()
import pyglet
from pyglet.window import key

#create window
window = pyglet.window.Window(640,480,caption='Example')
#clear window
window.clear()

#menu state
state = 'title'
#key input container
key_input = []
#currently selected menu item
menu = 0

#main update loop
@window.event
def update(dt):
    global menu
    global state
    global key_input

#title menu state
    if state == 'title':
        if "DOWN press" in key_input:
            if menu < 2:
                menu += 1
            if menu == 1:
                print "options"
            elif menu == 2:
                print "quit"

        if "UP press" in key_input:
            if menu > 0:
                menu -= 1
            if menu == 0:
                print "start game"
            elif menu == 1:
                print "options"

        if "RETURN press" in key_input:
            if menu == 0:
                print "starting game"
            #swirch to game state
                state = 'game'
            elif menu == 1:
                print "opening options"
            #switch to options state
                state = 'options'
            elif menu == 2:
                print "quitting"
                window.close()

#game state
    elif state == 'game':
        pass

#options state
    elif state == 'options':
        pass

#purge key presses for next update
    if len(key_input) > 0:
        key_input = []

#capture key presses
@window.event
def on_key_press(symbol,modifiers):
    key_input.append(key.symbol_string(symbol) + " press")
    if symbol == key.ESCAPE:
        window.close()

#capture key releases
@window.event
def on_key_release(symbol,modifiers):
    key_input.append(key.symbol_string(symbol) + " release")


#draw window
@window.event()
def on_draw():
    window.clear()


#schedule and run update function
pyglet.clock.schedule_interval(update, .01)

pyglet.app.run()
-BrushTone v1.3.3: Accessible Paint Tool
-AudiMesh3D v1.0.0: Accessible 3D Model Viewer

2017-06-24 03:38:57

While it's true that there aren't lots of python audiogame examples, there are a few. Also, as stated above, part of being a programmer is... Well... Programming. If you can't find an example that does what you want, then get your hands dirty and start experimenting. Find something that works and keep optimizing it, adding features as you want / need them.

To get you started, here are a few files from a game I'm working on. These are basics (screens and menus), so feel free to modify them; they assume you have a game class, an instance of that class with a sound manager (I use a custom libaudioverse wrapper, but you can easily make this use pyglet's sound functions), and an output object with an output method (I use accessible_output2 for this).
It also assumes you've made certain choices (on_keys instead of motion events for scrolling, game instance with an instance of screen stack, etc).

Also, while you should feel free to modify this code so it fits your game, if you leave it unmodified please don't claim that it is entirely yours; I don't expect any kind of attribution, but I really hate when people plagiarize.

That being said, on to the code:

# screens/__init__.py

# Basic screen module

from pyglet.window import key

class Screen(object):
    def __init__(self, game, escapable=True, *a, **k):
        """Base class that represents one screen in the game;
        this can be a menu, inventory list, normal gameplay, etc.
        When a screen is made active, it's 'activate' method gets run. This needs to bind any hotkeys / mouse / joystick events.
        Likewise when it is popped off the stack, 'deactivate' runs, and this needs to remove any events that were previously set for this screen, stop any music, etc.
        Args and options:
            game: a reference to the game object which has a sound manager, screen stack, etc.
            escapable: a boolean that determines if pressing escape when this screen is active will allow the event to propogate.
                If the user shouldn't be able to exit this menu with escape (e.g., exit by choosing an option from a menu), set this to false.
        """
        self.game = game
        self.escapable=escapable

    def activate(self, push_self=True):
        """Base class activate method; handles adding all events in the current screen to the window
        """
        if push_self:
            self.game.window.push_handlers(self)
        self.already_popped = False

    def deactivate(self, remove_self=True):
        """Base class deactivate method; handles removing all previously added screen-specific events that belong to this screen.
        """
        if remove_self:
            self.game.window.remove_handlers(self)

    def on_key_press(self, symbol, modifiers):
        """Event that runs when any key is pressed; children should use super() to get the default functionality before they add their own
        This is also important because this method properly handles inescapable screens (where using escape isn't a valid way to exit the screen).
        """
        if symbol == key.ESCAPE:
            if self.escapable:
                self.game.screens.pop()
            # return true on principal, so that we don't exit
            return True

class ScreenStack(object):
    """Class that manages a stack of screens and activation / deactivation of pushed / popped ones.
    """

    def __init__(self, game):
        self.game = game
        self.screens = []

    def push(self, screen):
        """Make the provided screen the current one, deactivating the previous one"""
        if self.screens:
            self.screens[-1].deactivate()
        self.screens.append(screen)
        screen.activate()
        self.game.screen = screen

    def pop(self):
        """Remove the current screen from the stack, and run the necessary methods to deactivate the screen in question and restore the previous one.
        """
        screen = self.screens.pop()
        screen.deactivate()
        self.screens[-1].activate()
        self.game.screen = self.screens[-1]


# screens/menu.py
# Module that holds menu-specific screens
from pyglet.window import key

import libaudioverse as lav

from sound import Sound
from . import Screen

class MenuScreen(Screen):
    def __init__(self, prompt="", choices=None, dynamic=False, dynamic_callback=None, quick=False, sound_volume=None, music_volume=None, selection_sound=None, activation_sound=None, boundary_sound=None, open_sound=None, close_sound=None, music=None, *args, **kwargs):
        """Represents a standard menu with volume-controlable sounds and background music and first-letter navigation.
        Args and options:
            Prompt: The message first spoken when the menu opens, and can be repeated with space.
            Choices: a list of menu options in the form of tuples (menutext, associated_callback).
                The associated callback will run when it's menutext is selected from the menu.
                If dynamic is set to true, this option should just be a list of strings.
            dynamic: If this is a dynamic menu. False by default.
                Dynamic menus are where the player needs to select from a list of choices that will not always be the same, so callbacks for individual items aren't defined in code.
                Rather, one callback is provided and the item itself is passed as an argument to it.
                An example of when such a menu would be useful is when selecting items from a list of files.
            dynamic_callback: The callback to pass the current item (as a string) to. Set to none by default, and only useful when dynamic is true.
            quick: If this menu should not persist after an item is activated. False bydefault.
                When this is set to true, when an item is chosen, this menu will pop itself off the stack before running the callback.
                This is intended for short-lived menus that, for example have a list of options to change and once the player presses enter on them, should go away and either leave them in the menu that just opened, or drop back to the previous screen instead of staying in the menu.
            sound_volume: The volume for all menu sounds; set to None by default, which means 1.0 or 100 percent.
            music_volume: The volume for background music, represented as a float between 0.0 and 1.0 for normal volume levels. None by default, which means 1.0, or 100 percent.
            selection_sound: Plays each time the item changes.
            boundary_sound: Plays when the botum or top of the menu is reached.
            activation_sound: Plays when an item from the menu is chosen.
            open_sound: Plays when the menu is first opened.
            close_sound: Plays only if no item is chosen and the menu is closed (e.g. Escape).
            music: Will be played on a loop in the background if provided.
        """
        super(MenuScreen, self).__init__(*args, **kwargs)
        self.prompt = prompt
        if choices is None:
            choices = []
        self.choices = choices
        self.dynamic = dynamic
        self.dynamic_callback = dynamic_callback
        self.quick = quick
        self.sound_volume = sound_volume
        self.music_volume = music_volume
        self.selection_sound = selection_sound
        self.activation_sound = activation_sound
        self.boundary_sound = boundary_sound
        self.open_sound = open_sound
        self.close_sound = close_sound
        self.music = music
        self.music_node = None
        self.index = 0

    def current_item(self):
        if not self.choices:
            return
        self.index %= len(self.choices)
        return self.choices[self.index]

    def next_item(self):
        if self.index + 1 >= len(self.choices):
            self.play_boundary()
        self.index += 1
        self.read_current_item()

    def previous_item(self):
        if self.index - 1 < 0:
            self.play_boundary()
        self.index -= 1
        self.read_current_item()

    def read_current_item(self, play_selection_sound=True, interrupt=True):
        if self.dynamic == False:
            item = self.current_item()[0]
        else: # this is a dynamic menu, no need to extract text from a tuple
            item = self.current_item()
        if item is None:
            return
        if play_selection_sound == True:
            self.play_selection()
        self.game.output.output(str(item), interrupt)

    def first_item(self):
        self.index = 0
        self.read_current_item()

    def last_item(self):
        self.index = len(self.choices)
        self.read_current_item()

    def activate(self):
        """Method that runs when the menu is first opened"""
        super(MenuScreen, self).activate()
        self.item_activated=False # always reset upon menu open
        self.play_open()
        if self.music is not None:
            self.music_node = self.game.sound_manager.play_ambient(self.music, self.music_volume)
        self.read_prompt()
        self.read_current_item(play_selection_sound=False, interrupt=False)

    def read_prompt(self):
        self.game.output.output(self.prompt)

    def on_key_press(self, symbol, modifiers):
        r = super(MenuScreen, self).on_key_press(symbol, modifiers) # do default behavior
        if r is not None: # catch the return value
            return r
        if symbol == key.DOWN:
            self.next_item()
        elif symbol == key.UP:
            self.previous_item()
        elif symbol == key.HOME:
            self.first_item()
        elif symbol == key.END:
            self.last_item()
        elif symbol == key.ENTER:
            self.activate_item()
        elif symbol == key.SPACE:
            self.read_prompt()
        char = key.symbol_string(symbol).lower()
        for num, item in enumerate(self.choices):
            if self.dynamic == False:
                item = item[0] # since this isn't a dynamic menu, the menu text is the first item in the tuple
            if unicode(item).lower().startswith(char):
                self.index = num
                self.read_current_item()

    def activate_item(self, run_callback=True):
        """Method that gets run when a user presses enter on a menu item.
        args:
            run_callback: if true (which is the default), the callback (dynamic or for this specific item) is ran; otherwise it isn't. Everything else happens normally (sounds playing, screen gets popped if this is a quick instance).
                This is so subclasses can call a function a certain way, or use a different way of storing a reference to a function in the choices list and still get the other "default" functionality of a menu.
        """
        item = self.current_item()
        if item is None:
            return
        self.play_activation()
        self.item_activated = True # don't play menu close sound
        if self.quick: # this screen shouldn't persist on the stack anymore, since we are about to activate something
            # we do this first because the callback we activate
            # could push another menu onto the stack, and then we'd just
            # pop it off by mistake
            self.game.screens.pop()
        if run_callback:
            if self.dynamic == True:
                self.dynamic_callback(item)
            else: # call the associated item's callback
                if item[1] is not None:
                    item[1]() # run the associated callback

    def play_boundary(self):
        if self.boundary_sound:
            self.game.sound_manager.play_UI(self.boundary_sound, self.sound_volume)

    def play_selection(self):
        if self.selection_sound is not None:
            self.game.sound_manager.play_UI(self.selection_sound, self.sound_volume)

    def play_activation(self):
        if self.activation_sound is not None:
            self.game.sound_manager.play_UI(self.activation_sound, self.sound_volume)

    def play_open(self):
        """Play the menu open sound"""
        if self.open_sound is not None:
            self.game.sound_manager.play_UI(self.open_sound, self.sound_volume)

    def play_close(self):
        """Play the menu close sound, but only if a menu item wasn't activated"""
        if self.close_sound is not None and self.item_activated == False:
            self.game.sound_manager.play_UI(self.close_sound, self.sound_volume)

    def deactivate(self):
        """Stop any background music and if an item wasn't chosen, play the menu close sound"""
        super(MenuScreen, self).deactivate() # inherit deactivate code
        if self.music is not None and self.music_node is not None:
            self.music_node.stop()
        if self.item_activated == True:
            self.play_close()

    def exit_menu(self, *args, **kwargs):
        """Method for use in quick menus that takes any arguments and just does nothing
        This works because quick menus close themselves (pop off the stack) when an item is activated, or when escape is pressed.
        """
        pass


class SoundBrowserMenuScreen(MenuScreen):
    def __init__(self, relative_paths=True, *args, **kwargs):
        """A menu who's choices are sound files.
        Just about everything about this menu is standard, accept that all sounds and music options are automatically overridden and set to None so as to not interfere with listening to the selected sound, and the menu is made dynamic.
        The only option that changes is choices;
        instead of normal menu text like "play the game", the first item of each tuple should be a valid sound path, as accepted by the sound manager unless relative_paths is false, in which case the file paths given in choices are interpreted relative to the current working directory, not to sounds_path.
        Each sound will be played when it's name is selected, until it ends, another one is chosen, or the menu is closed.
        """
        kwargs['selection_sound'] = None
        kwargs['activation_sound'] = None
        kwargs['boundary_sound'] = None
        kwargs['open_sound'] = None
        kwargs['close_sound'] = None
        kwargs['music'] = None
        super(SoundBrowserMenuScreen, self).__init__(dynamic=True, quick=True, *args, **kwargs)
        self.relative_paths = relative_paths
        self.sound = Sound(lav.BufferNode(self.game.sound_manager.server))
        self.sound.buffer_node.connect(0, self.game.sound_manager.server)

    def read_current_item(self, *args, **kwargs):
        """Add to the original functionality of this method by playing the item as well (since the name is a sound path).
        """
        super(SoundBrowserMenuScreen, self).read_current_item(*args, **kwargs)
        # stop and swap buffers attached to the buffer node this instance has, and start it playing again
        item = self.current_item()
        b = self.game.sound_manager.get_buffer(item, self.relative_paths)
        if self.sound.is_playing():
            self.sound.stop()
        self.sound.buffer_node.position = 0
        self.sound.buffer_node.buffer = b
        self.sound.play()

    def deactivate(self):
        """Standard screen / menu deactivate method, just with code that stops any playing sounds.
        """
        super(SoundBrowserMenuScreen, self).deactivate()
        # if self.sound.is_playing():
        self.sound.stop()

Regards,
Blademan
Twitter: @bladehunter2213