Source

fungus / fungus_scene.py

Full commit
#!/usr/bin/env python
# encoding: utf-8

"""An example for a fungus scene definition. 

Ideas: 
- Keyboard control via a dict similar to the command dict in Mercurial: Keyboard symbols or combinations (as tuple) as keys and methods of the scene as values. Convenience functions which add a whole set of actor control keys. This allows for dynamic key rebinding. 

"""

#### Call the correct fungus_game when called from the command line or clicked in a GUI ####

if __name__ == "__main__": 
    # Call this Scene via fungus_game
    # For this to work, the main scene inside the module MUST be the class with the name "Scene"
    from fungus_core import call_this_scene
    # pass the commandline args
    from sys import argv
    call_this_scene(__file__, argv)


#### Imports ####

from fungus_core import Sprite
from pyglet.window import key

#### API definitions ####

### A "Scene method not implemented" Exception class. 

class MethodNotImplemented(Exception):
    """A warning to display if any necessary scripting function isn't implemented."""
    def __init__(self, func, implementation = None):
        self.func = func
        self.implementation = implementation

    def __str__(self):
        if self.implementation is None:
            return "The method " + str(self.func) + " must be implemented."
        else:
            return "The method " + str(self.func) + " must be implemented." + "\nThe simplest way is to just add the following lines to your class:" + self.implementation

### A base Scene class to inherit from (API definition)

class BaseScene(object): 
    """A dummy scene - mostly just the Scene API."""
    def __init__(self, core, *args, **kwds): 
        """Initialize the scene with a core object for basic functions."""
	
        ## Necessary attributes for any scene. 
        #: The core provides basic functions. It gets passed to every scene as first argument. 
        self.core = core
        #: Visible sprites. 
        self.visible = []
        #: Colliding sprites - this seperation allows for invisible colliders. 
        self.colliding = []
        #: Overlay sprites. They are above all other sprites (included for convenience, since most games need an overlay of sorts)
        self.overlay = []
        #: A scene to switch to on the next screen update. 
        self.switch_to_scene = False
        
    def update(self): 
        """Update the stats of all scene objects. """
        raise MethodNotImplemented(self.update, implementation="""    def update(self): 
        pass""")
    
    def on_key_press(self, symbol, modifiers): 
        """Forwarded keyboard input."""
        # Use the escape key as a means to exit the game. 
        if symbol == key.ESCAPE: 
            self.core.win.has_exit = True
        else: 
            pass
    
    def on_key_release(self, symbol, modifiers): 
        """Forwarded keyboard input."""
        pass
    
    def on_mouse_motion(self, x, y, dx, dy):
        """The basic mouse event."""
        pass
    
    def on_mouse_press(self, x, y, buttons, modifiers): 
        """Forwarded keyboard input."""
        pass
    
    def on_mouse_drag(self, x, y, dx, dy, buttons, modifiers): 
        """Forwarded keyboard input."""
        pass
    
    def on_mouse_release(self, x, y, buttons, modifiers): 
        """Forwarded keyboard input."""
        pass

    def on_mouse_scroll(self, x, y, scroll_x, scroll_y):
        pass

    def on_mouse_enter(self, x, y):
        pass

    def on_mouse_leave(self, x, y):
        pass


#### An example scene ####

### Things needed for the scene

IMAGE_BLOB = "blob.png"

### The Scene itself. 

class Scene(BaseScene): 
    """A dummy scene - mostly just the Scene API."""
    def __init__(self, core, *args, **kwds): 
        """Initialize the scene with a core object for basic functions."""
        
        ## Get the necessary attributes for any scene. 
        # This gets the 'visible', 'colliding' and 'overlay' lists 
        # as well as the scene switch 'switch_to_scene' 
        # which can be assigned a scene to switch to. 
        super(Scene, self).__init__(core, *args, **kwds)
	
        ## Tests - not necessary for every scene. 
        # Add a blob to the visible items. 	
        self.blob = self.core.sprite(IMAGE_BLOB, x=212, y=208,
                                     update_func=self.blob_update)

        self.visible.append(self.blob)
	# and give it some random velocity
	from random import random
	self.random = random
	self.blob.dy = 3*random()
	self.blob.dx = 3*random()
	# also we want to be able to spawn blobs
	self.spawns = []

    def blob_update(self, x, y, dx, dy): 
        """Update the tank position."""
        # Move the tank down. 
        # If we hit an edge, we turn around and spawn another blob which can't be controlled. 
        if y < 0:
	    dy *= -1
	    y += 1 # makes sure we don't "stick"
	elif y + self.blob.height > self.core.win.height: 
	    dy *= -1
	    y -= 1
        if x < 0: 
	    dx *= -1
	    x += 1
	elif x + self.blob.width > self.core.win.width:
	    dx *= -1
	    x -= 1
	    
        return x, y, dx, dy
	
    def update(self): 
        """Update the stats of all scene objects. 

Don't blit them, though. That's done by the Game itself.

To show something, add it to the self.visible list. 
To add a collider, add it to the self.colliding list. 
To add an overlay sprite, add it to the self.overlay list. 
"""	
        self.blob.update()