From 2ebb47e8a753ec4fe2f498d79606d3628de73c4c Mon Sep 17 00:00:00 2001 From: Alan Aguiar Date: Thu, 23 Feb 2012 22:49:11 +0000 Subject: add all files --- diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..56aac6d --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +*.pyc +*.py~ +*.pyo + diff --git a/documentos/Guión principal.doc b/documentos/Guión principal.doc new file mode 100644 index 0000000..1b6aa11 --- /dev/null +++ b/documentos/Guión principal.doc Binary files differ diff --git a/src/CButton.py b/src/CButton.py new file mode 100755 index 0000000..f45ca15 --- /dev/null +++ b/src/CButton.py @@ -0,0 +1,37 @@ +import pygame +import CLabel +from CLabel import * + +class CButton(CLabel): + """ a button based on the label + same properties as label + + active: True if user is clicking on sprite + False if user is not currently clicking + clicked: True when user releases mouse over a + currently active button + """ + + def __init__(self): + CLabel.__init__(self) + self.active = False + self.clicked = False + self.bgColor = (0xCC, 0xCC, 0xCC) + + def update(self): + CLabel.update(self) + + self.clicked = False + + #TODO: Make a CMouse class and check for isPressed() and click(). + + #check for mouse input + if pygame.mouse.get_pressed() == (1, 0, 0): + if self.rect.collidepoint(pygame.mouse.get_pos()): + self.active = True + + #check for mouse release + if self.active == True: + if pygame.mouse.get_pressed() == (0, 0, 0): + self.active = False + if self.rect.collidepoint(pygame.mouse.get_pos()): + self.clicked = True diff --git a/src/CCreditsState.py b/src/CCreditsState.py new file mode 100755 index 0000000..5061dea --- /dev/null +++ b/src/CCreditsState.py @@ -0,0 +1,56 @@ +import CMenuState +from CMenuState import * + +from CGameState import * +import CMultiLabel +from CMultiLabel import * +from CGame import * +import CButton +from CButton import * + +class CCreditsState(CGameState): + + mBackground = None + mInstructions = None + #mX = 10 + mButtonPlay = None + + def init(self): + CGameState.init(self) + self.mInstructions = CMultiLabel() + CGame().addChild(self.mInstructions) + #print self.mX + + self.mButtonPlay = CButton() + self.mButtonPlay.bgColor = (0x99, 0x99, 0x66) + self.mButtonPlay.font = pygame.font.Font("fipps.ttf", 20) + self.mButtonPlay.center = (400, 600) + self.mButtonPlay.size = (200, 40) + self.mButtonPlay.text = "BACK Credits" + CGame().addChild(self.mButtonPlay) + + self.mBackground = CImage.loadImage("assets/images/back_credits.png", False) + CGame().setBackground(self.mBackground) + + def update(self): + #print "menu update" + CGameState.update(self) + + if self.mButtonPlay.clicked: + print "clicked credits" + ms = CMenuState.CMenuState() + CGame().setState(ms) + + #def render(self): + # CGameState.render(self) + # print "CMenuState render" + + def destroy(self): + CGameState.destroy(self) + CGame().removeChild(self.mButtonPlay) + self.mButtonPlay = None + self.mBackground = None + print "CMenuState destroy" + + def doEvents(self, aEvent): + print aEvent.type \ No newline at end of file diff --git a/src/CGame.py b/src/CGame.py new file mode 100755 index 0000000..40c3179 --- /dev/null +++ b/src/CGame.py @@ -0,0 +1,155 @@ +import pygame +#from pygame.locals import * +import pygame.font +import pygame.display +import pygame.sprite +import CSuperSprite +from CSuperSprite import * +import CSprite +from CSprite import * +from pygame.locals import * +import CMultiLabel +from CMultiLabel import * +import gc + +class CGame(object): + + mInstance = None + mState = None + mScreen = None + mBackground = None + mSampleSprite = None + mSprites = None + mGroups = None + mMainSprites = None + mClock = None + mQuit = False + + def __new__(self, *args, **kargs): + if (self.mInstance is None): + self.mInstance = object.__new__(self, *args, **kargs) + #self.setState(self.mInstance, aState) + self.init(self.mInstance) + #else: + # print "Warning: CGame(): You are not allowed to instantiate it more than once." + return self.mInstance + + def inst(self): + return self.mInstance + + def setState(self, aState): + if (self.mState != None): + self.mState.destroy() + self.mState = None + print gc.collect(), " deleted objects" + + self.mState = aState + self.mState.init() + + def destroy(self): + if (self.mState != None): + self.mState.destroy() + self.mState = None + self.mBackground = None + self.mInstance = None + print "destroy" + + def init(self): + print "init pygame..." + pygame.init() + #pygame.font.init() + + #screen = pygame.display.set_mode((1200, 900), FULLSCREEN) + self.mScreen = pygame.display.set_mode((1200, 900)) + pygame.display.set_caption("Game") + + self.mBackground = pygame.Surface(self.mScreen.get_size()) + self.mBackground.fill((255, 0, 0)) + + #self.mBackground = CImage.loadImage("assets/images/back_menu.png", False) + + self.mSampleSprite = CSuperSprite(self) + self.mSampleSprite.setSpeed(3) + self.mSampleSprite.setAngle(0) + self.mSampleSprite.boundAction = self.mSampleSprite.WRAP + + + self.mAllSprites = pygame.sprite.Group() + + + #self.mGroups = [] + #self.mSprites = [self.mSampleSprite] + #self.mMainSprites = pygame.sprite.OrderedUpdates(self.mSprites) + #self.mGroups.append(self.mMainSprites) + + self.mS2 = CSprite() + #self.mS2.setDX(10) + self.mS2.velX = 30 + self.mS2.velY = 0 + self.mS2.accelY = 1 + self.mS2.maxSpeed = 200 + + self.mScreen.blit(self.mBackground, (0, 0)) + self.mClock = pygame.time.Clock() + self.mQuit = False + + self.mAllSprites.add(self.mSampleSprite) + self.mAllSprites.add(self.mS2) + + + def gameLoop(self): + print "start game loop here" + while not self.mQuit: + + self.mClock.tick(30) + #print ("FPS: %.0f" % self.mClock.get_fps()) + + for event in pygame.event.get(): + if event.type == pygame.QUIT: + self.mQuit = True + elif event.type == KEYDOWN: + if event.key == K_ESCAPE: + self.mQuit = True + + self.doEvents(event) + + #self.mState.preUpdate() + self.mState.update() + + self.mAllSprites.clear(self.mScreen, self.mBackground) + self.mAllSprites.update() + self.mAllSprites.draw(self.mScreen) + + #for group in self.mAllSprites: + # group.clear(self.mScreen, self.mBackground) + # group.update() + # group.draw(self.mScreen) + + #self.mState.postUpdate() + + pygame.display.flip() + + def doEvents(self, event): + """ overwrite this method to add your own events. + works like normal event handling, passes event + object + """ + pass + + def setSprites(self, aSpritesArray): + self.mSprites = aSpritesArray + #self.mGroups = [] + #self.mMainSprites = pygame.sprite.OrderedUpdates(self.mSprites) + #self.mGroups.append(self.mMainSprites) + + # Add a sprite to the sprite list. + def addChild(self, aSprite): + self.mAllSprites.add(aSprite) + + def removeChild(self, aSprite): + self.mAllSprites.remove(aSprite) + + def setBackground(self, aBackgroundImage): + self.mBackground = None + self.mBackground = aBackgroundImage + self.mScreen.blit(self.mBackground, (0, 0)) \ No newline at end of file diff --git a/src/CGameState.py b/src/CGameState.py new file mode 100755 index 0000000..c40af7e --- /dev/null +++ b/src/CGameState.py @@ -0,0 +1,13 @@ +class CGameState(object): + def init(self): + print "CGameState init" + + def update(self): + pass + #print "CGameState update" + + #def render(self): + # print "CGameState render" + + def destroy(self): + print "CGameState destroy" \ No newline at end of file diff --git a/src/CImage.py b/src/CImage.py new file mode 100755 index 0000000..7630c15 --- /dev/null +++ b/src/CImage.py @@ -0,0 +1,29 @@ +import pygame + +# ------------------------------------------------------------------------------ +# loadImage(). +# Loads an image. +# +# Parameters: +# aImageFilename: Image file path to load. +# aIsTransparent: If the image is transparent (True) or not (True, by default). +# +# Returns: The loaded image. +# ------------------------------------------------------------------------------ +def loadImage(aImageFilename, aIsTransparent = True): + + try: image = pygame.image.load(aImageFilename) + except pygame.error, message: + raise SystemExit, message + + if aIsTransparent: + image = image.convert_alpha() + + # TODO: This is doubt... (taken from a tutorial), don't work? + #image = image.convert() + #color = image.get_at((0,0)) + #image.set_colorkey(color, RLEACCEL) + else: + image = image.convert() + + return image \ No newline at end of file diff --git a/src/CLabel.py b/src/CLabel.py new file mode 100755 index 0000000..c762868 --- /dev/null +++ b/src/CLabel.py @@ -0,0 +1,32 @@ +import pygame + +class CLabel(pygame.sprite.Sprite): + """ a basic label + properties: + font: font to use + text: text to display + fgColor: foreground color + bgColor: background color + center: position of label's center + size: (width, height) of label + """ + + def __init__(self, fontName = "freesansbold.ttf"): + pygame.sprite.Sprite.__init__(self) + self.font = pygame.font.Font(fontName, 20) + self.text = "Button" + self.fgColor = ((0x00, 0x00, 0x00)) + self.bgColor = ((0xFF, 0xFF, 0xFF)) + self.center = (400, 100) + self.size = (150, 30) + + def update(self): + self.image = pygame.Surface(self.size) + self.image.fill(self.bgColor) + fontSurface = self.font.render(self.text, True, self.fgColor, self.bgColor) + #center the text + xPos = (self.image.get_width() - fontSurface.get_width())/2 + + self.image.blit(fontSurface, (xPos, 0)) + self.rect = self.image.get_rect() + self.rect.center = self.center \ No newline at end of file diff --git a/src/CMath.py b/src/CMath.py new file mode 100755 index 0000000..b514234 --- /dev/null +++ b/src/CMath.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python +# -*- coding: cp1252 -*- + +import math + +#------------------------------------------------------------------------------- +# toStandardAngle(). +# Returns the given angle in the 0-359 range. +# +# Parameters: +# aAngle: Angle to check. +# +# Returns: The same angle in the 0-359 range. +#------------------------------------------------------------------------------- +def toStandardAngle(aAngle): + aAngle = aAngle % 360; + if (aAngle < 0): + aAngle = aAngle + 360 + return(aAngle) + +#------------------------------------------------------------------------------- +# radToDeg(). +# Convert the angle given in radians to degrees. +# +# Parameters: +# aAngle: Angle in radians to be converted. +# +# Returns: The angle in degrees. +#------------------------------------------------------------------------------- +def radToDeg(aAngle): + return aAngle * 180 / math.pi + +#------------------------------------------------------------------------------- +# degToRad(). +# Convert the angle given in degrees to radians. +# +# Parameters: +# aAngle: Angle in degrees to be converted. +# +# Returns: The angle in radians. +#------------------------------------------------------------------------------- +def degToRad(aAngle): + return aAngle * math.pi / 180 \ No newline at end of file diff --git a/src/CMenuState.py b/src/CMenuState.py new file mode 100755 index 0000000..7c7616f --- /dev/null +++ b/src/CMenuState.py @@ -0,0 +1,65 @@ +from CGameState import * +import CMultiLabel +from CMultiLabel import * +from CGame import * +import CButton +from CButton import * +import CCreditsState +from CCreditsState import * + +class CMenuState(CGameState): + + mBackground = None + mInstructions = None + #mX = 10 + mButtonPlay = None + + #def __init__(self): + # ''' + # Constructor + # ''' + + def init(self): + CGameState.init(self) + self.mInstructions = CMultiLabel() + CGame().addChild(self.mInstructions) + #print self.mX + + self.mButtonPlay = CButton() + #TODO: Create a function to create image. + self.mButtonPlay.bgColor = (0x99, 0x99, 0x66) + self.mButtonPlay.font = pygame.font.Font("fipps.ttf", 20) + self.mButtonPlay.center = (110, 420) + self.mButtonPlay.size = (200, 40) + self.mButtonPlay.text = "JUGAR" + CGame().addChild(self.mButtonPlay) + + self.mBackground = CImage.loadImage("assets/images/back_menu.png", False) + CGame().setBackground(self.mBackground) + + def update(self): + #print "menu update" + CGameState.update(self) + + if self.mButtonPlay.clicked: + print "clicked menu" + #cs = CHelpState() + cs = CCreditsState() + CGame().setState(cs) + + #def render(self): + # CGameState.render(self) + # print "CMenuState render" + + def destroy(self): + CGameState.destroy(self) + #self.mInstructions.destroy() + self.mInstructions = None + CGame().removeChild(self.mButtonPlay) + #self.mButtonPlay.destroy() + self.mButtonPlay = None + self.mBackground = None + print "CMenuState destroy" + + def doEvents(self, aEvent): + print aEvent.type \ No newline at end of file diff --git a/src/CMultiLabel.py b/src/CMultiLabel.py new file mode 100755 index 0000000..3371a7c --- /dev/null +++ b/src/CMultiLabel.py @@ -0,0 +1,44 @@ +import pygame + +class CMultiLabel(pygame.sprite.Sprite): + """ accepts a list of strings, creates a multi-line + label to display text + same properties as label except textLines + is a list of strings. There is no text + property. + Set the size manually. Vertical size should be at + least 30 pixels per line (with the default font) + """ + + def __init__(self): + pygame.sprite.Sprite.__init__(self) + self.textLines = ["This", "is", "sample", "text"] + #self.font = pygame.font.Font("freesansbold.ttf", 20) + #TODO: Esto no debe ir aca. Porque este no anda y el de CSuperSprite si ? + #pygame.font.init() + #print "CMultilabel" + #print pygame.font.get_init() + self.font = pygame.font.Font("goodfoot.ttf", 30) + self.fgColor = ((0x00, 0x00, 0x00)) + self.bgColor = ((0xFF, 0xFF, 0xFF)) + self.center = (100, 100) + self.size = (150, 100) + + self.image = pygame.Surface(self.size) + self.image.fill(self.bgColor) + numLines = len(self.textLines) + vSize = self.image.get_height() / numLines + + for lineNum in range(numLines): + currentLine = self.textLines[lineNum] + fontSurface = self.font.render(currentLine, True, self.fgColor, self.bgColor) + #center the text + xPos = (self.image.get_width() - fontSurface.get_width())/2 + yPos = lineNum * vSize + self.image.blit(fontSurface, (xPos, yPos)) + + self.rect = self.image.get_rect() + self.rect.center = self.center + + #def update(self): + #print "update de multilabel" diff --git a/src/CSprite.py b/src/CSprite.py new file mode 100755 index 0000000..6a27e5a --- /dev/null +++ b/src/CSprite.py @@ -0,0 +1,542 @@ +#!/usr/bin/env python +# -*- coding: cp1252 -*- + +import pygame +import math +import CImage +import CMath + +# TODO: Cambiar las conversiones de grados a radianes y viceversa usando las funciones. + +# TODO: This class is a rotating sprite. update() in each frame rotates the sprite +# image, so this is inneficient for sprites that does not rotate continuoulsy. +class CSprite(pygame.sprite.Sprite): + + x = 0 + y = 0 + velX = 0 + velY = 0 + accelX = 0 + accelY = 0 + + """ An enhanced Sprite class + expects a gameEngine.Scene class as its one parameter + Use methods to change image, direction, speed + Will automatically travel in direction and speed indicated + Automatically rotates to point in indicated direction + Five kinds of boundary collision + """ + + def __init__(self): + pygame.sprite.Sprite.__init__(self) + +# self.mGroup = aGroup + + self.x = 0 + self.y = 0 + self.velX = 0 + self.velY = 0 + self.accelX = 0 + self.accelY = 0 + + + + # Components of the velocity vector. + self.dx = 0 + self.dy = 0 + + # Speed of the sprite. + self.mSpeed = 0 + + self.maxSpeed = 10 + self.minSpeed = -3 + + # TODO: Take this values from a constants class. + self.setBounds(0, 0, 1200, 900) + + # Constants for the actions then the sprite reaches a border. + CSprite.WRAP = 0 # Wrap around the edges. + CSprite.BOUNCE = 1 # Bounce off the screen changing direction. + CSprite.STOP = 2 # Stop at the edge of the screen. + CSprite.HIDE = 3 # Move off-stage and stop. + CSprite.CONTINUE = 4 # Move on forever. + + # Action for the sprite when it reaches a border. + self.mBoundAction = CSprite.WRAP + + #create a default text image as a placeholder + #This will usually be changed by a setImage call + #self.font = pygame.font.Font("freesansbold.ttf", 30) + self.font = pygame.font.Font("goodfoot.ttf", 30) + self.mImageMaster = self.font.render(">sprite>", True, (0, 0,0), (0xFF, 0xFF, 0xFF)) + + # Set the image of the sprite. + self.image = self.mImageMaster + self.rect = self.image.get_rect() + + # Set the position of the image. + # oldCenter is used to draw the trace in drawTrace(). + # oldCenter is the position of the sprite in the previous frame. + self.oldCenter = (self.x, self.y) + self.rect.center = (self.x, self.y) + + # Angle of rotation in degrees used for movement calculations. + self.mAngle = 0 + # Angle of rotation in degrees of the sprite image (usually the same as mAngle). + self.mRotation = 0 + + self.pressed = False + self.states = {} + self.currentState = "default" + + def setXY(self, aX, aY): + self.x = aX + self.y = aY + self.rect.center = (self.x, self.y) + + def update(self): + self.oldCenter = self.rect.center + # Run the logic for the sprite. + self.updateLogic() + # Calculate next position based on angle and velocity. + self.__updatePosition() + # Rotate the image according to the angle of the sprite. + self.__rotateSpriteImage() + self.checkBounds() + self.rect.center = (self.x, self.y) + # TODO: Test this. Need to pass a reference to background to draw. + # self.drawTrace((255,0,0)) + + self.velX = self.velX + self.accelX + self.velY = self.velY + self.accelY + + #TODO: Arreglar con vectores. + if (self.velX > self.maxSpeed): + self.velX = self.maxSpeed + if (self.velY > self.maxSpeed): + self.velY = self.maxSpeed + + self.x = self.x + self.velX + self.y = self.y + self.velY + + + #--------------------------------------------------------------------------- + # updateLogic(). + # Override this method to implement the sprite's response to events. + # This is the function that contains the logic of the sprite (it's behaviour). + # + # Parameters: + # Nothing. + # + # Returns: Nothing. + #--------------------------------------------------------------------------- + def updateLogic(self): + pass + + #--------------------------------------------------------------------------- + # __updatePosition(). + # Calculate the next position of the sprite based on angle and velocity. + # + # Parameters: + # Nothing. + # + # Returns: Nothing. + #--------------------------------------------------------------------------- + def __updatePosition(self): + theta = CMath.degToRad(self.mAngle) + self.dx = math.cos(theta) * self.mSpeed + self.dy = math.sin(theta) * self.mSpeed + self.dy *= -1 + + self.x += self.dx + self.y += self.dy + + #--------------------------------------------------------------------------- + # __rotateSpriteImage(). + # Rotates the sprite image according to the rotation attribute. + # The registration point is assumed to be in the center of the image. + # This function is called in update() every frame. + # + # Parameters: + # Nothing. + # + # Returns: Nothing. + #--------------------------------------------------------------------------- + def __rotateSpriteImage(self): + oldCenter = self.rect.center + self.oldCenter = oldCenter + self.image = pygame.transform.rotate(self.mImageMaster, self.mRotation) + self.rect = self.image.get_rect() + self.rect.center = oldCenter + # Debug: Draw the collision circle. + #pygame.draw.circle(self.image, (255,0,0), (self.rect.w/2 , self.rect.h/2), self.radius, 2) + + def setSpeed(self, speed): + """ immediately sets the objects speed to the + given value. + """ + self.mSpeed = speed + + def speedUp(self, amount): + """ changes speed by the given amount + Use a negative value to slow down + """ + self.mSpeed += amount + if self.mSpeed < self.minSpeed: + self.mSpeed = self.minSpeed + if self.mSpeed > self.maxSpeed: + self.mSpeed = self.maxSpeed + + #TODO + def setAngle(self, dir): + """ sets both the direction of motion + and visual rotation to the given angle + If you want to set one or the other, + set them directly. Angle measured in degrees + """ + self.mAngle = dir + self.mRotation = dir + + #--------------------------------------------------------------------------- + # turnBy(). + # Turn by the sprite by given number of degrees. Changes both angles (the + # angle of the sprite and the rotation attribute of the image). A positive + # angle is counter-clockwise and a negative angle is clockwise. + # + # Parameters: + # aAngleInc: Number of degrees to add to the current rotation angle. + # + # Returns: Nothing. + #--------------------------------------------------------------------------- + def turnBy(self, aAngleInc): + self.mAngle = CMath.toStandardAngle(self.mAngle + aAngleInc) + self.mRotation = self.mAngle + + # TODO: Es igual que la anterior pero solo para mRotation + # Estas cuentas estan mal, hay que usar toStandardAngle(). + def rotateBy(self, amt): + """ change visual orientation by given + number of degrees. Does not change direction + of travel. + """ + self.mRotation += amt + if self.mRotation > 360: + self.mRotation = amt + if self.mRotation < 0: + self.mRotation = 360 - amt + + #--------------------------------------------------------------------------- + # setImage(). + # Loads the given file name as the master image that then is rotated. + # The sprite must be facing east (angle 0). In the main loop the sprite is + # rotated automatically. + # + # Parameters: + # aImageFilename: File path of the sprite image to be loaded. + # aIsTransparent: If the image is transparent (True) or not (True, by default). + # + # Returns: Nothing. + #--------------------------------------------------------------------------- + def setImage (self, aImageFilename, aIsTransparent=True): + #TODO: loadImage esta en la clase CImage. + self.mImageMaster = CImage.loadImage(aImageFilename, aIsTransparent) + #self.mImageMaster = self.mImageMaster.convert() + self.image = self.mImageMaster + self.rect = self.image.get_rect() + + def setDX(self, dx): + """ changes dx value and updates vector """ + self.dx = dx + self.updateVector() + + def addDX(self, amt): + """ adds amt to dx, updates vector """ + self.dx += amt + self.updateVector() + + def setDY(self, dy): + """ changes dy value and updates vector """ + self.dy = dy + self.updateVector() + + def addDY(self, amt): + """ adds amt to dy and updates vector """ + self.dy += amt + self.updateVector() + + def setComponents(self, components): + """ expects (dx, dy) for components + change speed and angle according to dx, dy values """ + + (self.dx, self.dy) = components + self.updateVector() + + def setBoundAction (self, aBoundAction): + self.mBoundAction = aBoundAction + + def getBoundAction(self): + return self.mBoundAction + + def setPosition (self, position): + """ place the sprite directly at the given position + expects an (x, y) tuple + """ + (self.x, self.y) = position + + def moveBy (self, vector): + """ move the sprite by the (dx, dy) values in vector + automatically calls checkBounds. Doesn't change + speed or angle settings. + """ + (dx, dy) = vector + self.x += dx + self.y += dy + self.checkBounds() + + def forward(self, amt): + """ move amt pixels in the current direction + of travel + """ + + #calculate dx dy based on current direction + radians = self.mAngle * math.pi / 180 + dx = amt * math.cos(radians) + dy = amt * math.sin(radians) * -1 + + self.x += dx + self.y += dy + + def addForce(self, amt, angle): + """ apply amt of thrust in angle. + change speed and dir accordingly + add a force straight down to simulate gravity + in rotation direction to simulate spacecraft thrust + in dir direction to accelerate forward + at an angle for retro-rockets, etc. + """ + + #calculate dx dy based on angle + radians = angle * math.pi / 180 + dx = amt * math.cos(radians) + dy = amt * math.sin(radians) * -1 + + self.dx += dx + self.dy += dy + self.updateVector() + + def updateVector(self): + #calculate new speed and angle based on dx, dy + #call this any time you change dx or dy + + self.mSpeed = math.sqrt((self.dx * self.dx) + (self.dy * self.dy)) + + dy = self.dy * -1 + dx = self.dx + + radians = math.atan2(dy, dx) + self.mAngle = radians / math.pi * 180 + + def setSpeedLimits(self, max, min): + """ determines maximum and minimum + speeds you will allow through + speedUp() method. You can still + directly set any speed you want + with setSpeed() Default values: + max: 10 + min: -3 + """ + self.maxSpeed = max + self.minSpeed = min + + def dataTrace(self): + """ utility method for debugging + print major properties + extend to add your own properties + """ + print "x: %d, y: %d, speed: %.2f, dir: %.f, dx: %.2f, dy: %.2f" % \ + (self.x, self.y, self.mSpeed, self.mAngle, self.dx, self.dy) + + def mouseDown(self): + """ boolean function. Returns True if the mouse is + clicked over the sprite, False otherwise + """ + self.pressed = False + if pygame.mouse.get_pressed() == (1, 0, 0): + if self.rect.collidepoint(pygame.mouse.get_pos()): + self.pressed = True + return self.pressed + + def clicked(self): + """ Boolean function. Returns True only if mouse + is pressed and released over sprite + """ + released = False + if self.pressed: + if pygame.mouse.get_pressed() == (0, 0, 0): + if self.rect.collidepoint(pygame.mouse.get_pos()): + released = True + return released + + def collidesWith(self, target): + """ boolean function. Returns True if the sprite + is currently colliding with the target sprite, + False otherwise + """ + collision = False + if self.rect.colliderect(target.rect): + collision = True + return collision + + def collidesGroup(self, target): + """ wrapper for pygame.sprite.collideany + simplifies checking sprite - group collisions + returns result of collision check (sprite from group + that was hit or None) + """ + collision = pygame.sprite.spritecollideany(self, target) + return collision + + def distanceTo(self, point): + """ returns distance to any point in pixels + can be used in circular collision detection + """ + (pointx, pointy) = point + dx = self.x - pointx + dy = self.y - pointy + + dist = math.sqrt((dx * dx) + (dy * dy)) + return dist + + def dirTo(self, point): + """ returns direction (in degrees) to + a point """ + + (pointx, pointy) = point + dx = self.x - pointx + dy = self.y - pointy + dy *= -1 + + radians = math.atan2(dy, dx) + dir = radians * 180 / math.pi + dir += 180 + return dir + + #TODO: no hay scene, ver como agarra el background... + def drawTrace(self, color=(0x00, 0x00, 0x00)): + """ traces a line between previous position + and current position of object + """ + pygame.draw.line(self.scene.background, color, self.oldCenter, + self.rect.center, 3) + self.screen.blit(self.scene.background, (0, 0)) + + def addState(self, stateName, stateImageFile): + """ Creates a new sprite state with the associated name + and image. Useful to build multi-state sprites. + """ + #load the image + # TODO: Use the loading function. + tempImage = pygame.image.load(stateImageFile) + tempImage.convert() + self.states[stateName] = tempImage + + def setState(self, stateName): + """ attempts to set the sprite to the indicated state + (image) + """ + self.mImageMaster = self.states[stateName] + self.rect = self.mImageMaster.get_rect() + self.currentState = stateName + + def getState(self): + """ returns the current state name + (default if no states have been explicitly set) + """ + return self.currentState + + #--------------------------------------------------------------------------- + # setBounds(). + # Sets the boundaries used in checkBounds() to implement sprite behaviour + # when it reaches the edge of the screen or this bound rectangle. + # + # Parameters: + # aMinX: Horizontal coordinate of the left edge. + # aMaxX: Horizontal coordinate of the right edge. + # aMinY: Vertical coordinate of the top edge. + # aMaxY: Vertical coordinate of the bottom edge. + # + # Returns: Nothing. + #--------------------------------------------------------------------------- + def setBounds(self, aMinX, aMinY, aMaxX, aMaxY): + self.mMinX = aMinX + self.mMaxX = aMaxX + self.mMinY = aMinY + self.mMaxY = aMaxY + + def checkBounds(self): + """ checks boundary and acts based on + self.BoundAction. + WRAP: wrap around screen (default) + BOUNCE: bounce off screen + STOP: stop at edge of screen + HIDE: move off stage and wait + CONTINUE: keep going at present course and speed + + automatically called by update + """ + + # TODO + scrWidth = self.mMaxX + scrHeight = self.mMaxY + #print scrWidth, scrHeight + + #create variables to simplify checking + offRight = offLeft = offTop = offBottom = offScreen = False + + if self.x > scrWidth: + offRight = True + if self.x < 0: + offLeft = True + if self.y > scrHeight: + offBottom = True + if self.y < 0: + offTop = True + + if offRight or offLeft or offTop or offBottom: + offScreen = True + + if self.mBoundAction == self.WRAP: + if offRight: + self.x = 0 + if offLeft: + self.x = scrWidth + if offBottom: + self.y = 0 + if offTop: + self.y = scrHeight + + elif self.mBoundAction == self.BOUNCE: + if offLeft or offRight: + self.dx *= -1 + if offTop or offBottom: + self.dy *= -1 + + self.updateVector() + self.mRotation = self.mAngle + + elif self.mBoundAction == self.STOP: + if offScreen: + self.mSpeed = 0 + + elif self.mBoundAction == self.HIDE: + if offScreen: + self.mSpeed = 0 + self.setPosition((-1000, -1000)) + + elif self.mBoundAction == self.CONTINUE: + pass + + else: + # assume it's continue - keep going forever + pass + diff --git a/src/CSuperSprite.py b/src/CSuperSprite.py new file mode 100755 index 0000000..6105541 --- /dev/null +++ b/src/CSuperSprite.py @@ -0,0 +1,427 @@ +import pygame +import math + +class CSuperSprite(pygame.sprite.Sprite): + """ An enhanced Sprite class + expects a gameEngine.Scene class as its one parameter + Use methods to change image, direction, speed + Will automatically travel in direction and speed indicated + Automatically rotates to point in indicated direction + Five kinds of boundary collision + """ + +# TODO: No pasar scene, sino que en el constructor usar self.mScene = CGame().inst().getScreen() + def __init__(self, scene): + pygame.sprite.Sprite.__init__(self) + self.scene = scene + self.screen = scene.mScreen + + #create constants + self.WRAP = 0 + self.BOUNCE = 1 + self.STOP = 2 + self.HIDE = 3 + self.CONTINUE = 4 + + #create a default text image as a placeholder + #This will usually be changed by a setImage call + print "Csupersprite" + print pygame.font.get_init() + self.font = pygame.font.Font("goodfoot.ttf", 30) + self.imageMaster = self.font.render(">sprite>", True, (0, 0,0), (0xFF, 0xFF, 0xFF)) + self.image = self.imageMaster + self.rect = self.image.get_rect() + + #create properties + #most will be changed through method calls + self.x = 200 + self.y = 200 + self.dx = 0 + self.dy = 0 + self.dir = 0 + self.rotation = 0 + self.speed = 0 + self.maxSpeed = 10 + self.minSpeed = -3 + self.boundAction = self.WRAP + self.pressed = False + self.oldCenter = (100, 100) + self.states = {} + self.currentState = "default" + + def update(self): + self.oldCenter = self.rect.center + self.checkEvents() + self.__rotate() + self.__calcVector() + self.__calcPosition() + self.checkBounds() + self.rect.center = (self.x, self.y) + + def checkEvents(self): + """ overwrite this method to add your own event code """ + pass + + def __rotate(self): + """ PRIVATE METHOD + change visual orientation based on + rotation property. + automatically called in update. + change rotation property directly or with + rotateBy(), setAngle() methods + """ + oldCenter = self.rect.center + self.oldCenter = oldCenter + self.image = pygame.transform.rotate(self.imageMaster, self.rotation) + self.rect = self.image.get_rect() + self.rect.center = oldCenter + + def __calcVector(self): + """ calculates dx and dy based on speed, dir + automatically called in update + """ + theta = self.dir / 180.0 * math.pi + self.dx = math.cos(theta) * self.speed + self.dy = math.sin(theta) * self.speed + self.dy *= -1 + + def __calcPosition(self): + """ calculates the sprites position adding + dx and dy to x and y. + automatically called in update + """ + self.x += self.dx + self.y += self.dy + + def checkBounds(self): + """ checks boundary and acts based on + self.BoundAction. + WRAP: wrap around screen (default) + BOUNCE: bounce off screen + STOP: stop at edge of screen + HIDE: move off stage and wait + CONTINUE: keep going at present course and speed + + automatically called by update + """ + + scrWidth = self.screen.get_width() + scrHeight = self.screen.get_height() + + #create variables to simplify checking + offRight = offLeft = offTop = offBottom = offScreen = False + + if self.x > scrWidth: + offRight = True + if self.x < 0: + offLeft = True + if self.y > scrHeight: + offBottom = True + if self.y < 0: + offTop = True + + if offRight or offLeft or offTop or offBottom: + offScreen = True + + if self.boundAction == self.WRAP: + if offRight: + self.x = 0 + if offLeft: + self.x = scrWidth + if offBottom: + self.y = 0 + if offTop: + self.y = scrHeight + + elif self.boundAction == self.BOUNCE: + if offLeft or offRight: + self.dx *= -1 + if offTop or offBottom: + self.dy *= -1 + + self.updateVector() + self.rotation = self.dir + + elif self.boundAction == self.STOP: + if offScreen: + self.speed = 0 + + elif self.boundAction == self.HIDE: + if offScreen: + self.speed = 0 + self.setPosition((-1000, -1000)) + + elif self.boundAction == self.CONTINUE: + pass + + else: + # assume it's continue - keep going forever + pass + + def setSpeed(self, speed): + """ immediately sets the objects speed to the + given value. + """ + self.speed = speed + + def speedUp(self, amount): + """ changes speed by the given amount + Use a negative value to slow down + """ + self.speed += amount + if self.speed < self.minSpeed: + self.speed = self.minSpeed + if self.speed > self.maxSpeed: + self.speed = self.maxSpeed + + def setAngle(self, dir): + """ sets both the direction of motion + and visual rotation to the given angle + If you want to set one or the other, + set them directly. Angle measured in degrees + """ + self.dir = dir + self.rotation = dir + + def turnBy (self, amt): + """ turn by given number of degrees. Changes + both motion and visual rotation. Positive is + counter-clockwise, negative is clockwise + """ + self.dir += amt + if self.dir > 360: + self.dir = amt + if self.dir < 0: + self.dir = 360 - amt + self.rotation = self.dir + + def rotateBy(self, amt): + """ change visual orientation by given + number of degrees. Does not change direction + of travel. + """ + self.rotation += amt + if self.rotation > 360: + self.rotation = amt + if self.rotation < 0: + self.rotation = 360 - amt + + def setImage (self, image): + """ loads the given file name as the master image + default setting should be facing east. Image + will be rotated automatically """ + self.imageMaster = pygame.image.load(image) + self.imageMaster = self.imageMaster.convert() + + def setDX(self, dx): + """ changes dx value and updates vector """ + self.dx = dx + self.updateVector() + + def addDX(self, amt): + """ adds amt to dx, updates vector """ + self.dx += amt + self.updateVector() + + def setDY(self, dy): + """ changes dy value and updates vector """ + self.dy = dy + self.updateVector() + + def addDY(self, amt): + """ adds amt to dy and updates vector """ + self.dy += amt + self.updateVector() + + def setComponents(self, components): + """ expects (dx, dy) for components + change speed and angle according to dx, dy values """ + + (self.dx, self.dy) = components + self.updateVector() + + def setBoundAction (self, action): + """ sets action for boundary. Values are + self.WRAP (wrap around edge - default) + self.BOUNCE (bounce off screen changing direction) + self.STOP (stop at edge of screen) + self.HIDE (move off-stage and stop) + self.CONTINUE (move on forever) + Any other value allows the sprite to move on forever + """ + self.boundAction = action + + def setPosition (self, position): + """ place the sprite directly at the given position + expects an (x, y) tuple + """ + (self.x, self.y) = position + + def moveBy (self, vector): + """ move the sprite by the (dx, dy) values in vector + automatically calls checkBounds. Doesn't change + speed or angle settings. + """ + (dx, dy) = vector + self.x += dx + self.y += dy + self.checkBounds() + + def forward(self, amt): + """ move amt pixels in the current direction + of travel + """ + + #calculate dx dy based on current direction + radians = self.dir * math.pi / 180 + dx = amt * math.cos(radians) + dy = amt * math.sin(radians) * -1 + + self.x += dx + self.y += dy + + def addForce(self, amt, angle): + """ apply amt of thrust in angle. + change speed and dir accordingly + add a force straight down to simulate gravity + in rotation direction to simulate spacecraft thrust + in dir direction to accelerate forward + at an angle for retro-rockets, etc. + """ + + #calculate dx dy based on angle + radians = angle * math.pi / 180 + dx = amt * math.cos(radians) + dy = amt * math.sin(radians) * -1 + + self.dx += dx + self.dy += dy + self.updateVector() + + def updateVector(self): + #calculate new speed and angle based on dx, dy + #call this any time you change dx or dy + + self.speed = math.sqrt((self.dx * self.dx) + (self.dy * self.dy)) + + dy = self.dy * -1 + dx = self.dx + + radians = math.atan2(dy, dx) + self.dir = radians / math.pi * 180 + + def setSpeedLimits(self, max, min): + """ determines maximum and minimum + speeds you will allow through + speedUp() method. You can still + directly set any speed you want + with setSpeed() Default values: + max: 10 + min: -3 + """ + self.maxSpeed = max + self.minSpeed = min + + def dataTrace(self): + """ utility method for debugging + print major properties + extend to add your own properties + """ + print "x: %d, y: %d, speed: %.2f, dir: %.f, dx: %.2f, dy: %.2f" % \ + (self.x, self.y, self.speed, self.dir, self.dx, self.dy) + + def mouseDown(self): + """ boolean function. Returns True if the mouse is + clicked over the sprite, False otherwise + """ + self.pressed = False + if pygame.mouse.get_pressed() == (1, 0, 0): + if self.rect.collidepoint(pygame.mouse.get_pos()): + self.pressed = True + return self.pressed + + def clicked(self): + """ Boolean function. Returns True only if mouse + is pressed and released over sprite + """ + released = False + if self.pressed: + if pygame.mouse.get_pressed() == (0, 0, 0): + if self.rect.collidepoint(pygame.mouse.get_pos()): + released = True + return released + + def collidesWith(self, target): + """ boolean function. Returns True if the sprite + is currently colliding with the target sprite, + False otherwise + """ + collision = False + if self.rect.colliderect(target.rect): + collision = True + return collision + + def collidesGroup(self, target): + """ wrapper for pygame.sprite.collideany + simplifies checking sprite - group collisions + returns result of collision check (sprite from group + that was hit or None) + """ + collision = pygame.sprite.spritecollideany(self, target) + return collision + + def distanceTo(self, point): + """ returns distance to any point in pixels + can be used in circular collision detection + """ + (pointx, pointy) = point + dx = self.x - pointx + dy = self.y - pointy + + dist = math.sqrt((dx * dx) + (dy * dy)) + return dist + + def dirTo(self, point): + """ returns direction (in degrees) to + a point """ + + (pointx, pointy) = point + dx = self.x - pointx + dy = self.y - pointy + dy *= -1 + + radians = math.atan2(dy, dx) + dir = radians * 180 / math.pi + dir += 180 + return dir + + def drawTrace(self, color=(0x00, 0x00, 0x00)): + """ traces a line between previous position + and current position of object + """ + pygame.draw.line(self.scene.background, color, self.oldCenter, + self.rect.center, 3) + self.screen.blit(self.scene.background, (0, 0)) + + def addState(self, stateName, stateImageFile): + """ Creates a new sprite state with the associated name + and image. Useful to build multi-state sprites. + """ + #load the image + tempImage = pygame.image.load(stateImageFile) + tempImage.convert() + self.states[stateName] = tempImage + + def setState(self, stateName): + """ attempts to set the sprite to the indicated state + (image) + """ + self.imageMaster = self.states[stateName] + self.rect = self.imageMaster.get_rect() + self.currentState = stateName + + def getState(self): + """ returns the current state name + (default if no states have been explicitly set) + """ + return self.currentState diff --git a/src/Main.py b/src/Main.py new file mode 100755 index 0000000..e0e82c3 --- /dev/null +++ b/src/Main.py @@ -0,0 +1,26 @@ +import CMenuState +from CMenuState import * +import CGame +from CGame import * + +def main(): + + g = CGame() + + ms = CMenuState() + g.setState(ms) + + g.gameLoop() + g.destroy() + + #Change state: + #ls = CLevelState(); + #CGame.setState(ls); + + #Singleton test. + #j = CGame(None) + #print g == j + +# Execute main() if this is the main program. +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/src/RUN.bat b/src/RUN.bat new file mode 100644 index 0000000..d1be5b1 --- /dev/null +++ b/src/RUN.bat @@ -0,0 +1,3 @@ +del *.pyc +cd "C:\workspace\CeibalJamEducacionSexual\src" +C:\Programs\Python27\python.exe Main.py \ No newline at end of file diff --git a/src/assets/images/back_credits.png b/src/assets/images/back_credits.png new file mode 100644 index 0000000..364b729 --- /dev/null +++ b/src/assets/images/back_credits.png Binary files differ diff --git a/src/assets/images/back_game.png b/src/assets/images/back_game.png new file mode 100644 index 0000000..de4edb0 --- /dev/null +++ b/src/assets/images/back_game.png Binary files differ diff --git a/src/assets/images/back_help.png b/src/assets/images/back_help.png new file mode 100644 index 0000000..ed50b21 --- /dev/null +++ b/src/assets/images/back_help.png Binary files differ diff --git a/src/assets/images/back_menu.png b/src/assets/images/back_menu.png new file mode 100644 index 0000000..a7a2ee5 --- /dev/null +++ b/src/assets/images/back_menu.png Binary files differ diff --git a/src/fipps.ttf b/src/fipps.ttf new file mode 100644 index 0000000..504d742 --- /dev/null +++ b/src/fipps.ttf Binary files differ diff --git a/src/goodfoot.ttf b/src/goodfoot.ttf new file mode 100644 index 0000000..a7a1e3b --- /dev/null +++ b/src/goodfoot.ttf Binary files differ -- cgit v0.9.1