Source code for actors.spriteActor

import sys
import os
sys.path.append(os.path.dirname(os.path.realpath(__file__))+"/../CommonFunctions")
from setCalico import *
from utilityFunctions import *
from baseActor import BaseActor
from makeShapeFunctions import makeColRec, makePic, makeDebugPicture, makeDebugColor

[docs]class SpriteActor(BaseActor): """ Actor class for Sprite on collision shape objects. Since I was unable to get the calico Sprite class to work properly, this is my own, very simple, implementation of a Sprite like class. """ def __init__(self, position=(0,0), base=None, shape=None, files=None, obstructs=False, bodyType=None, collision=None, separation=None, visible=None, scale=1.0, debug=False, rotation=0, **kwargs): """ Constructs a SpriteActor. Args: position: Tuple (x, y) indicating the starting position of the shape. base: Main argument. Can send pictures, list of pictures, or a shape. shape: Used if you want a separate collision object for this actor. files: A list of file names, each pointing to an image. Each image will form one 'costume' for this 'Sprite'. Not really needed. Can be supplied to base. obstructs: Boolean indicating whether this object obstructs the movement of other objects. If 'obstructs' is set to True with a 'shape' that does not have a body, a warning will be printed and the object will not obstruct anything. bodyType: String indicating the type of body that should be added to the physics simulator. Possible values are: 'static' and 'dynamic'. collision: Function of the form func(myfixture, otherfixture, contact), called when the 'shape' collides with anything. separation: Function of the form func(myfixture, otherfixture), called when the 'shape' separates from anything. visible: Boolean indicating whether this Sprite Actor should be visible. scale: A float, indicating by what factor images should be scaled. debug: Boolean indicating whether to paint this object in debug mode. rotation: Float indicating by how many radians the sprite actor should be rotated. Keyword Args: interact: Function of the form func(self, items), called when this object is interacted with. use: Function of the form func(self) called when this object is used. pickup: Anything, generally will be the object that is returned to the player upon pickup. If set to True, will return the Actor object itself instead. If set to True, and a value for returned is povided, will return whatever value returned was set to. (deprecated) If pickup is the string "self", a reference to this instance will be returned instead, just as if pickup was set to True. returned: Anything, will be the object that is returned to the player if pickup is set to True. onPickup: Function of the form func(self) called when this object is picked up by the player. Note: passing a value for onPickup is NOT enough to enable the player to pickup this object. description: A description of this object, used when this object is printed. If left blank, the class and memory address of this object is printed. tag: The tag of the actor, usually a string helpful for identifying what kind of actor you are dealing with. """ #: The main shape of the sprite actor self.shape = None #: Boolean indicating whether or not this Sprite Actor should obstruct movement #: Change it before adding the Actor to the world. self.obstructs = None #: The collision function that will be called when this Actor collides with #: anything in the world. Change it before adding the Actor to the world. self.collision = None #: The separation function that will be called when this Actor separates from #: anything in the world. Change it before adding the Actor to the world. self.separation = None #: The radius from where this actor will respond to the talk() command. #: Not used by default. self.talkRadius = None #: The list of customes available for this Actor. self.costumes = None #: The current costume of this Actor. self.currentCostume = None #: The index of the current costume of this Actor. self.currentCostumeIndex = None #: The list of customes used for the current animation cycle. #: Note that this is a list of indices, not costumes. Based on these indices, #: the actual costumes will be retrieved from the costumes list. self.animationCostumes = None #: The index of the current animation costume. self.animationIndex = None #: Booleans indicating whether the current animation should cycle or not. self.cycle = None #: Callback function excuted at the end of a full animation cycle. self.onEndOfAnimation # Synonyms for keyword arguments if "vis" in kwargs: visible = kwargs["vis"] del kwargs["vis"] if "desc" in kwargs: description = kwargs["desc"] del kwargs["desc"] # Initialize the base class BaseActor.__init__(self, **kwargs) # If the user did not provide a base, but did provide a shape, the shape should be the base if (not base) and shape: base = shape shape = None # If the base is an instance of a shape, but not a Picture, use it as the shape for this image if isinstance(base, Shape) and (not isinstance(base, Picture)): shape = base # If the base is a picture, make it the avatar of this sprite if isinstance(base, Picture): files = [base] # If the base is an instance of string, assume it is a filename if isinstance(base, str): files = [base] # If the base is iterable and not a string, assume it is a list of filenames elif hasattr(base, "__iter__"): files = base # Set costumes (if any) self.costumes = [] if files: for fileName in files: costume = makePic(fileName, scale) costume.visible = False self.costumes.append(costume) # If the shape is not defined, create one if not shape: if len(self.costumes) > 0: w=getWidth(self.costumes[0]) h=getHeight(self.costumes[0]) shape = makeColRec(w, h) else: shape = makeColRec(50, 50) # Set class specific attributes self.shape = shape self.obstructs = obstructs self.collision = collision self.separation = separation if bodyType is not None: self.shape.bodyType = bodyType if visible is not None: self.shape.visible = visible # Move shape into position self.moveTo(position[0], position[1]) # Rotate shape self.rotateTo(rotation) # Max distance away to talk to the actor self.talkRadius=100 #Set current costume if len(self.costumes) > 0: self.currentCostume = self.costumes[0] else: self.currentCostume = self.shape self.currentCostumeIndex=0 self.currentCostume.visible = True for costume in self.costumes: costume.draw(self.shape) self.animationCostumes = [0] self.animationIndex = 0 self.cycle = True self.onEndOfAnimation = None #Enable debug if debug: self.debugMode()
[docs] def draw(self, levelWindow): """ Adds this object to the level window, and thus the world. Args: levelWindow: A LevelWindow object. """ #Set level window self.levelWindow = levelWindow #Draw shape if self.shape: self._drawShape(self.shape, self.levelWindow) #Install collision callbacks if self.collision: self.installCollision(self.collision, self.shape) if self.separation: self.installSeparation(self.separation, self.shape) if self.canInteract: self.installCollision(self.levelWindow.interactCollide, self.shape) self.installSeparation(self.levelWindow.interactSeparate, self.shape) if self.canPickup: self.installCollision(self.levelWindow.pickupCollide, self.shape) self.installSeparation(self.levelWindow.pickupSeparate, self.shape)
[docs] def undraw(self): """ Removes the shape and speech bubble of this actor from the world. Note: be carefull where you remove objects from the world, since removing objects while they are being used can lead to unstable behavior. The level thread is the recommended place to do so. """ self.shape.undraw()
[docs] def getAvatar(self): """ Returns the first costume in the costumes list or, if the costumes list is empty, returns the shape of this Actor instead. Return: A Calico shape object, usually a Figure. """ if len(self.costumes) > 0: return self.costumes[0] else: return self.shape
[docs] def getX(self): """ Returns the x coordinate of this object. Return: A float indicating the x coordinate of this object. """ return self.shape.center.x
[docs] def getY(self): """ Returns the y coordinate of this object. Return: A float indicating the y coordinate of this object. """ return self.shape.center.y
[docs] def move(self, x, y): """ Moves this object by (x, y). Args: x: Float indicating horizontal displacement. Negative values move left, positive values move right. y: Float indicating vertical displacement. Negative values move up, positive values move down. """ self.moveTo(self.getX() + x, self.getY() + y)
[docs] def moveTo(self, x, y): """ Moves this object to the coordinate (x, y). Args: x: Float for the x coordinate. y: Float for the y coordinate. """ self.shape.moveTo(x, y)
[docs] def getRotation(self): """ Returns the rotation of this object. Returns: rotation of this object. """ return self.shape.rotation
[docs] def rotate(self, angle): """ Rotates this actor by a certain angle. Args: angle: Float indicating the angle to rotate. """ self.shape.rotate(angle)
[docs] def rotateTo(self, angle): """ Rotates this actor to a certain angle. Args: angle: Float indicating the angle to rotate to. """ self.shape.rotateTo(angle)
[docs] def hit(self, x, y): """ Returns whether the supplied coordinate hits the shape. Args: x: A float indicating an x coordinate. y: A float indicating a y coordinate. Returns: True if the coordinate (x, y) falls onto the shape. """ return self.shape.hit(x, y)
[docs] def visible(self): """ Returns whether this object is visible. Returns: True if this object is visible, False otherwise. """ return self.shape.visible
[docs] def hide(self): """ Hides this object. """ self.shape.visible = False
[docs] def show(self): """ Shows this object. """ self.shape.visible = True
def _drawShape(self, shape, window): """ Adds a shape, or, if the shape is a group, all its children to the world. """ if isinstance(shape, Group): for item in shape.items: self._drawShape(item, window) else: shape.draw(window.worldFrame) shape.addToPhysics() if shape.body and not self.obstructs: shape.body.IsSensor = True elif not shape.body and self.obstructs: warnings.warn("Obstructs is True, but shape has no body: shape cannot obstruct.")
[docs] def inRange(self, x, y): """ Checks whether the provided coordinate is within talkRadius of this Actor. Args: x: Float indicating the horizontal aspect of the coordinate. y: Float indicating the horizontal aspect of the coordinate. Return: Boolean indicating whether the provided coordinate was in talkRadius of this Actor. """ print(abs(x - self.shape.x)) print(abs(y - self.shape.y)) if abs(x - self.shape.x) > self.talkRadius: return False if abs(y - self.shape.y) > self.talkRadius: return False return True
[docs] def debugMode(self): """ Enables or disables debug mode. In debug mode, many objects that are invisible are now visible and transparant. Args: debug: Boolean indicating whether to enable (True) or disable (False) debug mode. """ #if self.debug == debug: return debug = True self.debug = debug for custome in self.costumes: custome = makeDebugPicture(custome, debug) self.shape.fill = makeDebugColor(255,0,0, 150,debug)
[docs] def speak(self, text = None, action = None, portrait = None): """ Makes this object speak. User initiated 'talk()' callbacks will go directly to the speech bubble, meaning this function is only for if you want to manually make this object say something. Args: text: A string containing the text to be displayed. action: A function executed at the end of this function. """ if self.levelWindow: if not portrait: portrait = Picture(self.currentCostume) portrait.border = 0 self.levelWindow.printToSpeechBox(text, portrait) if action: action()
[docs] def changeCostume(self, index): """ Makes a different shape visible. Args: index: The index of the shape. """ self.currentCostumeIndex=index self.currentCostume.visible = False self.currentCostume = self.costumes[index] self.currentCostume.visible = True
[docs] def flipCostumeHoriz(self,index): """ Flips the indicated costume horizontal. Args: index: The index of the costume to flip. """ self.costumes[index].flipHorizontal()
[docs] def flipCostumeVert(self,index): """ Flips the indicated costume vertically. Args: index: The index of the costume to flip. """ self.costumes[index].flipVertical()
[docs] def animate(self): """ Performs one frame of the animation of this Sprite Actor. One frame of animation means that the current costume is changed to the costume at the index at the animationIndex of the animationCostumes list. The animationIndex is then incremented by one. If the animationIndex reaches the end of the animationCostumes list, the animationIndex will either be reset (if cycle is True), or the onEndOfAnimation callback is called. Return: True if the animation is still ongoing, or False if this was the last frame of the animation and cycle is False. """ self.changeCostume(self.animationCostumes[self.animationIndex]) self.animationIndex += 1 if self.animationIndex >= len(self.animationCostumes): if self.cycle: self.animationIndex = 0 else: self.animationIndex -= 1 if self.onEndOfAnimation is not None: self.onEndOfAnimation() return False return True