diff --git a/Background.py b/Background.py new file mode 100644 index 0000000..0fd94f3 --- /dev/null +++ b/Background.py @@ -0,0 +1,48 @@ +""" +Background entity class +""" + + +import pygame +import os + +from BackgroundLayer import BackgroundLayer + + +class Background(): + imgDir = os.path.join(os.path.dirname(__file__), 'data') + backgroundImage = pygame.image.load( + os.path.join(imgDir, 'background.png') + )#.convert() + backgroundImages = ( + pygame.transform.scale( + backgroundImage.subsurface((0, 0, 800, 150)), (3200, 600) + ), + pygame.transform.scale( + backgroundImage.subsurface((0, 150, 800, 150)), (3200, 600) + ), + pygame.transform.scale( + backgroundImage.subsurface((0, 300, 800, 150)), (3200, 600) + ), + ) + for image in backgroundImages: + image.set_colorkey((255,0,255)) + + def __init__(self, mainGameClass): + pygame.sprite.Sprite.__init__(self) + + self.layers = ( + BackgroundLayer(Background.backgroundImages[0], mainGameClass, 0.2), + BackgroundLayer(Background.backgroundImages[1], mainGameClass, 0.5), + BackgroundLayer(Background.backgroundImages[2], mainGameClass, 1), + ) + + + def update(self): + for layer in self.layers: + layer.update() + + + def draw(self, surface): + for layer in self.layers: + layer.draw(surface) diff --git a/BackgroundLayer.py b/BackgroundLayer.py new file mode 100644 index 0000000..34f9db5 --- /dev/null +++ b/BackgroundLayer.py @@ -0,0 +1,31 @@ +""" +Background layer entity class +""" + + +import pygame + +from BackgroundLayerFrame import BackgroundLayerFrame + + +class BackgroundLayer(): + def __init__(self, image, mainGameClass, speedMultiplier): + offset = image.get_width() + + self.frames = pygame.sprite.Group() + + self.frames.add(BackgroundLayerFrame( + image, mainGameClass, (0, 0), speedMultiplier) + ) + self.frames.add(BackgroundLayerFrame( + image, mainGameClass, (offset, 0), speedMultiplier) + ) + + + def update(self): + for frame in self.frames: + frame.update() + + + def draw(self, surface): + self.frames.draw(surface) diff --git a/BackgroundLayerFrame.py b/BackgroundLayerFrame.py new file mode 100644 index 0000000..49d84cc --- /dev/null +++ b/BackgroundLayerFrame.py @@ -0,0 +1,29 @@ +""" +Background layer frame entity class +""" + + +import pygame + + +class BackgroundLayerFrame(pygame.sprite.Sprite): + def __init__(self, image, mainGameClass, offset, speedMultiplier): + pygame.sprite.Sprite.__init__(self) + + self.image = image + self.mainGameClass = mainGameClass + self.speedMultiplier = speedMultiplier + + self.rect = self.image.get_rect() + self.rect.center = (mainGameClass.getScreenWidth()/2 + offset[0], + mainGameClass.getScreenHeight()/2 + offset[1]) + + self.__doubleX = float(self.rect.x) + + + def update(self): + self.__doubleX -= self.mainGameClass.getGameSpeed()*self.speedMultiplier + if self.__doubleX < -self.rect.width: + self.__doubleX += self.rect.width*2 + + self.rect.x = self.__doubleX diff --git a/Cloud.py b/Cloud.py index a532a2d..2e7074b 100644 --- a/Cloud.py +++ b/Cloud.py @@ -8,19 +8,21 @@ import random class Cloud(pygame.sprite.Sprite): - def __init__(self, mainGameClass): + def __init__(self, mainGameClass, cloudType): pygame.sprite.Sprite.__init__(self) self.image = pygame.Surface((random.randint(150, 350), random.randint(50, 150))) - self.image.fill((random.randint(235, 255), - random.randint(235, 255), - random.randint(235, 255))) + + color = 255 - 15 * (3-cloudType) + self.image.fill((color, color, color)) + self.rect = self.image.get_rect() - self.rect.center = (mainGameClass.getScreenWidth() + self.rect.width, - mainGameClass.getScreenHeight()/2 - - random.randint(100, - mainGameClass.getScreenHeight()/2-100)) - self.speed = random.randint(1, 3)*mainGameClass.getGameSpeed() / 6 + self.rect.center = ( + mainGameClass.getScreenWidth() + self.rect.width, + mainGameClass.getScreenHeight()/2 - random.randint(100, + mainGameClass.getScreenHeight()/2-100) + 50*(2-cloudType) + ) + self.speed = cloudType*mainGameClass.getGameSpeed() / 6 self.__doubleX = float(self.rect.x) diff --git a/CollisionBox.py b/CollisionBox.py new file mode 100644 index 0000000..33de459 --- /dev/null +++ b/CollisionBox.py @@ -0,0 +1,24 @@ +""" +CollisionBox entity class +""" + +import pygame + + +class CollisionBox(pygame.sprite.Sprite): + def __init__(self, offsetX, offsetY, width, height, center): + pygame.sprite.Sprite.__init__(self) + + self.offset = (offsetX, offsetY) + self.size = (width, height) + self.rect = pygame.Rect(0, 0, width, height) + self.rect.center = center + + self.rect.x += self.offset[0] + self.rect.y += self.offset[1] + + def setY(self, y): + self.rect.y = y + self.offset[1] + + def setX(self, x): + self.rect.x = x + self.offset[0] diff --git a/Drakora.pyw b/Drakora.pyw index 1e4ae6b..99e1391 100644 --- a/Drakora.pyw +++ b/Drakora.pyw @@ -5,14 +5,17 @@ Main game class import pygame import random +import os from collections import deque +from Background import Background from Player import Player from StandingEnemy import StandingEnemy from FlyingEnemy import FlyingEnemy from Cloud import Cloud from Floor import Floor +from EndSceen import EndSceen class Drakora(): @@ -36,84 +39,116 @@ class Drakora(): return self.floorHeight + def speedUp(self): + self.__gameSpeed *= 2 + + + def speedDown(self): + if self.__gameSpeed > 2: self.__gameSpeed /= 2 + + + def speedReset(self): + self.__gameSpeed = 2 + + def addScore(self, score): self.__score += score if self.__score%self.speedUpRate == 0: - self.__gameSpeed += self.__score/self.speedUpRate + self.speedUp() self.speedUpLabelCD = self.targetFps + def getFont(self): + return self.font + + + def getTime(self): + return self.time + def newGame(self): + self.background = Background(self) + for enemy in self.enemies: enemy.kill() + for cloudGroup in self.cloudGroups: + for cloud in cloudGroup: + cloud.kill() + if self.player: self.player.kill() self.player = Player() - self.sprites.add(self.player) + self.players.add(self.player) self.__score = 0 self.isGameOver = False self.isPaused = False - self.__gameSpeed = 2 + self.speedReset() self.enemyCount = 0 self.enemyChance = 100.0 self.speedUpLabelCD = 0 self.nextEnemyMustBeFlying = False + self.enemyCD = self.getNextEnemyCD() + self.speedUpCheatLabelCD = 0 + self.speedDownCheatLabelCD = 0 + self.speedResetCheatLabelCD = 0 + + self.time = 0 + self.endSceen.newEndScreen() + def __init__(self): + random.seed() + pygame.init() + self.screenSize = (800, 600) + self.screen = pygame.display.set_mode(self.screenSize) + pygame.display.set_caption('Drakora') + self.clock = pygame.time.Clock() + self.buttonsPause = (pygame.K_p,) self.buttonsQuit = (pygame.K_F10,) self.buttonsNewGame = (pygame.K_RETURN,) - self.screenSize = (800, 600) self.targetFps = 120 - self.floorHeight = 50 + self.floorHeight = 64 + self.players = pygame.sprite.Group() self.floors = pygame.sprite.Group() self.enemies = pygame.sprite.Group() - self.clouds = pygame.sprite.Group() + self.cloudGroups = (pygame.sprite.Group(), + pygame.sprite.Group(), + pygame.sprite.Group(),) self.player = None + self.floors.add(Floor(self)) + self.speedUpRate = 25 self.godmodeCount = 0 self.isGodmode = False + self.drawBoxes = False - random.seed() - pygame.init() - self.screen = pygame.display.set_mode(self.screenSize) - pygame.display.set_caption('Drakora') - self.clock = pygame.time.Clock() + self.font = pygame.font.match_font('liberation mono') + self.fontScore = pygame.font.Font(self.font, 32) + self.fontMessage = pygame.font.Font(self.font, 56) + self.fontGodmode = pygame.font.Font(self.font, 12) - self.sprites = pygame.sprite.Group() - self.floors.add(Floor(self)) - self.sprites.add(self.floors) + self.charKeys = tuple( + pygame.key.key_code(chr(i)) for i in range(ord("a"), ord("z")) + ) - font = pygame.font.match_font('liberation mono') - self.fontScore = pygame.font.Font(font, 32) - self.fontMessage = pygame.font.Font(font, 56) - self.fontGodmode = pygame.font.Font(font, 12) - - self.charKeys = { - pygame.K_a:'a', pygame.K_b:'b', pygame.K_c:'c', pygame.K_d:'d', - pygame.K_e:'e', pygame.K_f:'f', pygame.K_g:'g', pygame.K_h:'h', - pygame.K_i:'i', pygame.K_j:'j', pygame.K_k:'k', pygame.K_l:'l', - pygame.K_m:'m', pygame.K_n:'n', pygame.K_o:'o', pygame.K_p:'p', - pygame.K_q:'q', pygame.K_r:'r', pygame.K_s:'s', pygame.K_t:'t', - pygame.K_u:'u', pygame.K_v:'v', pygame.K_w:'w', pygame.K_x:'x', - pygame.K_y:'y', pygame.K_z:'z', - } self.pressedKeys = deque(maxlen=10) self.isPressedKeysUpdated = True + self.endSceen = EndSceen(self) + self.newGame() @@ -129,33 +164,63 @@ class Drakora(): def render(self): - self.screen.fill((102, 153, 255)) - self.sprites.draw(self.screen) - self.floors.draw(self.screen) + self.screen.fill((61, 150, 223)) + for cloudGroup in self.cloudGroups[:2]: cloudGroup.draw(self.screen) + self.background.draw(self.screen) + for cloudGroup in self.cloudGroups[2:]: cloudGroup.draw(self.screen) + self.enemies.draw(self.screen) + self.players.draw(self.screen) - self.renderText('%d'%(self.__score), - self.fontScore, (255, 255, 255), - (self.getScreenWidth()/2,20)) + if self.drawBoxes: + for player in self.players: + for collision in player.getCollisionBoxes(): + pygame.draw.rect(self.screen, (255, 0, 0), collision.rect, 1) + for enemy in self.enemies: + for collision in enemy.getCollisionBoxes(): + pygame.draw.rect(self.screen, (255, 0, 0), collision.rect, 1) + for floor in self.floors: + pygame.draw.rect(self.screen, (255, 0, 0), floor.rect, 1) if self.isGameOver: - self.renderText('GAME OVER', - self.fontMessage, (255, 255, 255), - tuple(i/2 for i in self.screenSize)) - elif self.isPaused: - self.renderText('PAUSED', - self.fontMessage, (255, 255, 255), - tuple(i/2 for i in self.screenSize)) - elif self.speedUpLabelCD > 0: - self.speedUpLabelCD -= 1 - self.renderText('SPEED UP', - self.fontMessage, (255, 255, 255), - tuple(i/2 for i in self.screenSize)) + self.endSceen.render(); + else: + self.renderText('%d'%(self.__score), + self.fontScore, (255, 255, 255), + (self.getScreenWidth()/2,20)) + + if self.isPaused: + self.renderText('PAUSED', + self.fontMessage, (255, 255, 255), + tuple(i/2 for i in self.screenSize)) + elif self.speedUpLabelCD > 0: + self.speedUpLabelCD -= 1 + self.renderText('SPEED UP', + self.fontMessage, (255, 255, 255), + tuple(i/2 for i in self.screenSize)) if self.isGodmode: self.renderText('godmode', self.fontGodmode, (255, 255, 255), (self.getScreenWidth()/2,40)) + if self.speedUpCheatLabelCD: + self.speedUpCheatLabelCD -= 1 + self.renderText('speed up', + self.fontGodmode, (255, 255, 255), + (self.getScreenWidth()/2,60)) + + if self.speedDownCheatLabelCD: + self.speedDownCheatLabelCD -= 1 + self.renderText('speed down', + self.fontGodmode, (255, 255, 255), + (self.getScreenWidth()/2,60)) + + if self.speedResetCheatLabelCD: + self.speedResetCheatLabelCD -= 1 + self.renderText('speed reset', + self.fontGodmode, (255, 255, 255), + (self.getScreenWidth()/2,60)) + pygame.display.flip() @@ -171,23 +236,44 @@ class Drakora(): else: return 300 - def collideCheck(self): - if pygame.sprite.spritecollideany(self.player, self.enemies): - if not self.isGodmode: self.isGameOver = True + for enemy in self.enemies: + if pygame.sprite.groupcollide(self.player.getCollisionBoxes(), enemy.getCollisionBoxes(), None, None): + if not self.isGodmode: + self.isGameOver = True + break - self.player.isOnFloor = False + if self.player.isOnFloor: + self.player.rect.y += 1 + if not pygame.sprite.spritecollideany(self.player, self.floors): + self.player.isOnFloor = False + else: + if pygame.sprite.spritecollideany(self.player, self.floors): + self.player.isOnFloor = True - while pygame.sprite.spritecollideany(self.player, self.floors): - self.player.isOnFloor = True - self.player.rect.y -= 1 + if self.player.isOnFloor: + while pygame.sprite.spritecollideany(self.player, self.floors): + self.player.rect.y -= 1 def doCheats(self): if self.isPressedKeysUpdated: pressedKeysStr = ''.join(self.pressedKeys) + if pressedKeysStr.endswith('godmode'): self.isGodmode = not self.isGodmode + elif pressedKeysStr.endswith('speedup'): + self.speedUp() + self.speedUpCheatLabelCD = 60 + elif pressedKeysStr.endswith('speeddown'): + self.speedDown() + self.speedDownCheatLabelCD = 60 + elif pressedKeysStr.endswith('speedreset'): + self.speedReset() + self.speedResetCheatLabelCD = 60 + elif pressedKeysStr.endswith('drawboxes'): + self.drawBoxes = not self.drawBoxes + self.isPressedKeysUpdated = False @@ -196,6 +282,7 @@ class Drakora(): for event in pygame.event.get(): self.player.control(event) + self.endSceen.control(event) if event.type == pygame.QUIT: return False @@ -204,26 +291,32 @@ class Drakora(): if event.key in self.buttonsQuit: return False elif event.key in self.buttonsNewGame: - if self.isGameOver or self.isGodmode: self.newGame() + if self.isGodmode: self.newGame() elif event.key in self.buttonsPause: self.isPaused = not self.isPaused elif event.type == pygame.KEYUP: if event.key in self.charKeys: - self.pressedKeys.append(self.charKeys[event.key]) + self.pressedKeys.append(pygame.key.name(event.key)) self.isPressedKeysUpdated = True self.doCheats() if not self.isGameOver and not self.isPaused: - self.sprites.update() + self.time += 1/self.targetFps + self.background.update() + + for cloudGroup in self.cloudGroups: cloudGroup.update() + self.enemies.update() + self.players.update() + self.floors.update() self.enemyCD -= self.__gameSpeed if random.randint(1, 200) == 1: - cloud = Cloud(self) - self.clouds.add(cloud) - self.sprites.add(cloud) + cloudType = random.randint(0, 2) + cloud = Cloud(self, cloudType) + self.cloudGroups[cloudType].add(cloud) if self.enemyCD <= 0: self.enemyChance += (1/self.targetFps) * self.enemyChance/8 @@ -252,7 +345,6 @@ class Drakora(): self.enemyCD = self.getNextEnemyCD() self.enemies.add(enemy) - self.sprites.add(enemy) self.collideCheck() diff --git a/EndSceen.py b/EndSceen.py new file mode 100644 index 0000000..9bacafe --- /dev/null +++ b/EndSceen.py @@ -0,0 +1,235 @@ +""" +Enemy entity class +""" + +import pickle +import pygame +import hashlib +from cryptography.fernet import Fernet + + +class EndSceen(): + def __init__(self, mainGameClass): + self.fontGameOver = pygame.font.Font( + mainGameClass.getFont(), 56 + ) + self.fontLeaderBoard = pygame.font.Font( + mainGameClass.getFont(), 30 + ) + self.fontLeaderBoardActive = pygame.font.Font( + mainGameClass.getFont(), 30 + ) + self.fontLeaderBoardActive.underline = True + self.fontError = pygame.font.Font( + mainGameClass.getFont(), 15 + ) + + key = b'Lh2b2rragfwD8QR4VU-V2TmSuio4yp-WbFwo4tcoyzs=' + self.code = Fernet(key) + + self.game = mainGameClass + self.saveFileName = 'leaders.lb' + + def newEndScreen(self): + self.endScreenTimer = 0; + self.playerName = 'Player' + + self.scoresFromFile = [] + self.data = [] + self.sortedDataByScores = [] + + self.isBackButton = True + + try: + fileWithData = open(self.saveFileName, 'rb') + except IOError as e: + pass + else: + listPlayers = pickle.load(fileWithData) + + for line in listPlayers: + oneStr = self.code.decrypt(line).decode().split() + + if (len(oneStr) == 3): + self.data.append( + [oneStr[0][:10], int(oneStr[1]), float(oneStr[2])] + ) + + fileWithData.close() + + self.sortedDataByScores = sorted(enumerate(self.data), + key=lambda i: i[1][1], reverse=True) + + + def renderText(self, text, font, color, center, backColor=None): + render = font.render(text, True, color, backColor) + rect = render.get_rect() + rect.center = center + self.game.screen.blit(render, rect) + + def drawTableLB(self, number): + j = 1 + placeFlag = False + + for i in [i[0] for i in self.sortedDataByScores[:number]]: + if (self.game.getScore() > self.data[i][1] and not placeFlag): + self.renderText('>{0:3} {1:^10} {2:6d} {3:8.2f} '.format(j, + self.playerName[:10], self.game.getScore(), + self.game.getTime() + ), + self.fontLeaderBoard, (255, 255, 255), + (self.game.getScreenWidth()/2,100 + j*50)) + j += 1 + placeFlag = True + + if (j > number): + break + + formatDataForOnePlayer = ' {0:3} {1:^10} {2:6d} {3:8.2f} '.format( + j, *self.data[i]) + + self.renderText(formatDataForOnePlayer, + self.fontLeaderBoard, (255, 255, 255), + (self.game.getScreenWidth()/2,100 + j*50)) + + j += 1 + + if (j > number): + break + + if not placeFlag and j <= number: + self.renderText('>{0:3} {1:^10} {2:6d} {3:8.2f} '.format( + j, self.playerName[:10], self.game.getScore(), + self.game.getTime() + ), + self.fontLeaderBoard, (255, 255, 255), + (self.game.getScreenWidth()/2,100 + j*50)) + + + self.renderText(' {0:>3} {1:^10} {2:>6} {3:>8} '.format( + '..','.....', '..', '.....' + ), + self.fontLeaderBoard, (255, 255, 255), + (self.game.getScreenWidth()/2,100 + (number + 1)*50)) + + def getScorePosition(self, score): + counter = 1 + for i in self.sortedDataByScores: + if i[1][1] < score: + return counter + else: + counter += 1 + return counter + + + def render(self): + backGround = pygame.Surface(self.game.screenSize, pygame.SRCALPHA) + backGround.fill((0,0,0,200)) + self.game.screen.blit(backGround, (0,0)) + + self.renderText('GAME OVER', + self.fontGameOver, (255, 255, 255), + (self.game.getScreenWidth()/2,50)) + + self.renderText('Leaderboard', + self.fontLeaderBoard, (255, 255, 255), + (self.game.getScreenWidth()/2,100)) + + self.drawTableLB(5) + + cursorChar = ' ' + if self.endScreenTimer > self.game.targetFps / 3: + cursorChar = '_' + + if self.endScreenTimer > 2 * self.game.targetFps / 3: + self.endScreenTimer = 0 + + self.endScreenTimer += 1 + + if len(self.playerName) > 0: + self.renderText(' {0:3d} {1:^10} {2:6d} {3:8.2f} '.format( + self.getScorePosition(self.game.getScore()), + self.playerName[:10] + (cursorChar + if len(self.playerName) < 10 else ''), + self.game.getScore(), self.game.getTime() + ), + self.fontLeaderBoard, (255, 255, 255), + (self.game.getScreenWidth()/2,100 + (5 + 2)*50)) + else: + self.renderText(' {0:3d} {1:^10} {2:6d} {3:8.2f} '.format( + self.getScorePosition(self.game.getScore()), + self.playerName[:10] + (cursorChar + if len(self.playerName) < 10 else ''), + self.game.getScore(), self.game.getTime() + ), + self.fontLeaderBoard, (255, 255, 255), + (self.game.getScreenWidth()/2, 100 + + (5 + 2)*50), (200, 20, 20)) + + self.renderText(' {0:^30} '.format('Missing player name'), + self.fontError, (255, 255, 255), + (self.game.getScreenWidth()/2,100 + (5 + 2)*50 + 25)) + + self.renderText('Back', + self.fontLeaderBoard if not self.isBackButton else + self.fontLeaderBoardActive, (255, 255, 255), + (self.game.getScreenWidth()/2 - 100, + self.game.getScreenHeight() - 80)) + + self.renderText('Continue', + self.fontLeaderBoard if self.isBackButton else + self.fontLeaderBoardActive, (255, 255, 255), + (self.game.getScreenWidth()/2 + 100, + self.game.getScreenHeight() - 80)) + + def control(self, event): + if event.type == pygame.KEYDOWN and self.game.isGameOver: + if event.key == pygame.K_RIGHT: + self.isBackButton = False + + elif event.key == pygame.K_LEFT: + self.isBackButton = True + + elif event.key == pygame.K_RETURN: + if len(self.playerName) > 0: + self.saveResults() + + if self.isBackButton: + self.game.newGame() + else: + self.game.newGame() + + elif event.key == pygame.K_BACKSPACE: + self.playerName = self.playerName[:len(self.playerName) - 1] + + elif len( + pygame.key.name(event.key) + ) == 1 and len(self.playerName) < 10: + if pygame.key.get_mods() & pygame.KMOD_LSHIFT: + self.playerName += pygame.key.name(event.key).upper() + else: + self.playerName += pygame.key.name(event.key).lower() + + def saveResults(self): + newData = [] + + try: + fileWithData = open(self.saveFileName, 'rb') + except IOError as e: + pass + else: + tmpData = pickle.load(fileWithData) + fileWithData.close() + + for line in tmpData: + oneStr = self.code.decrypt(line).decode() + if len(oneStr.split()) == 3: + if not (oneStr.split()[0].rstrip() == self.playerName.rstrip()): + newData.append(line) + + newData.append(self.code.encrypt(('{0} {1} {2:.2f}\n'.format(self.playerName, + self.game.getScore(), self.game.getTime())).encode())) + + with open (self.saveFileName, 'wb') as fileWithData: + pickle.dump(newData, fileWithData) + fileWithData.close() diff --git a/Enemy.py b/Enemy.py index 3322e44..88d27f8 100644 --- a/Enemy.py +++ b/Enemy.py @@ -16,6 +16,12 @@ class Enemy(pygame.sprite.Sprite): self.height = (mainGameClass.getScreenHeight() - mainGameClass.getFloorHeight()) + self.collisionBoxes = pygame.sprite.Group() + + + def getCollisionBoxes(self): + return self.collisionBoxes + def update(self): if (self.rect.x < -self.rect.width): @@ -23,3 +29,6 @@ class Enemy(pygame.sprite.Sprite): self.thisGame.addScore(1) self.rect.x -= self.speed + + for i in self.collisionBoxes: + i.setX(self.rect.x) diff --git a/Floor.py b/Floor.py index c06b552..4cfd86e 100644 --- a/Floor.py +++ b/Floor.py @@ -11,7 +11,7 @@ class Floor(pygame.sprite.Sprite): pygame.sprite.Sprite.__init__(self) self.image = pygame.Surface((mainGameClass.getScreenWidth(), mainGameClass.getFloorHeight()*101)) - self.image.fill((255, 204, 102)) + self.image.fill((255, 229, 180)) self.rect = self.image.get_rect() self.rect.center = (mainGameClass.getScreenWidth()/2, mainGameClass.getScreenHeight() + diff --git a/FlyingEnemy.py b/FlyingEnemy.py index d78ae23..2cb767f 100644 --- a/FlyingEnemy.py +++ b/FlyingEnemy.py @@ -5,21 +5,56 @@ Flying enemy entity class import pygame import random +import math +import os + from Enemy import Enemy +from CollisionBox import CollisionBox class FlyingEnemy(Enemy): + imgDir = os.path.join(os.path.dirname(__file__), 'data') + senemyImage = pygame.image.load( + os.path.join(imgDir, 'fenemy.png') + )#.convert() + images = ( + pygame.transform.scale(senemyImage.subsurface((0, 0, 16, 8)),(64, 32)), + pygame.transform.scale(senemyImage.subsurface((16, 0, 16, 8)),(64, 32)), + pygame.transform.scale(senemyImage.subsurface((32, 0, 16, 8)),(64, 32)), + ) + for image in images: + image.set_colorkey((255,0,255)) + + def __init__(self, mainGameClass): Enemy.__init__(self, mainGameClass) - self.subtype = random.randint(1, 7) + self.updateCount = 0 + self.currentImage = 0 + + self.subtype = random.randint(1, 10) + + self.image = FlyingEnemy.images[self.currentImage] - self.image = pygame.Surface((50, 25)) - self.image.fill((51, 51, 0)) self.rect = self.image.get_rect() self.height -= self.rect.height/2 + 10 + 10*self.subtype self.rect.center = (mainGameClass.getScreenWidth() + self.rect.width, self.height) + collision = CollisionBox(2, 0, self.rect.w - 28, self.rect.h - 8, self.rect.center) + self.collisionBoxes.add(collision) + self.speed = self.thisGame.getGameSpeed()*2 + + + def update(self): + super().update() + + self.updateCount += 1 + if self.updateCount >= 22 - math.log2(self.thisGame.getGameSpeed()) * 2: + self.currentImage += 1 + if self.currentImage >= len(FlyingEnemy.images): + self.currentImage = 0 + self.image = FlyingEnemy.images[self.currentImage] + self.updateCount = 0 diff --git a/Player.py b/Player.py index 2e89c71..b5953cc 100644 --- a/Player.py +++ b/Player.py @@ -4,13 +4,93 @@ Player entity class import pygame +import math +import os +from CollisionBox import CollisionBox class Player(pygame.sprite.Sprite): + imgDir = os.path.join(os.path.dirname(__file__), 'data') + playerImage = pygame.image.load( + os.path.join(imgDir, 'player.png') + )#.convert() + walkImages = ( + pygame.transform.scale( + playerImage.subsurface((0, 0, 16, 24)), (64, 98) + ), + pygame.transform.scale( + playerImage.subsurface((16, 0, 16, 24)), (64, 98) + ), + pygame.transform.scale( + playerImage.subsurface((32, 0, 16, 24)), (64, 98) + ), + pygame.transform.scale( + playerImage.subsurface((48, 0, 16, 24)), (64, 98) + ), + ) + + upImages = ( + pygame.transform.scale( + playerImage.subsurface((0, 24, 16, 24)), (64, 98) + ), + pygame.transform.scale( + playerImage.subsurface((16, 24, 16, 24)), (64, 98) + ), + pygame.transform.scale( + playerImage.subsurface((32, 24, 16, 24)), (64, 98) + ), + pygame.transform.scale( + playerImage.subsurface((48, 24, 16, 24)), (64, 98) + ), + ) + + downImages = ( + pygame.transform.scale( + playerImage.subsurface((0, 48, 16, 24)), (64, 98) + ), + pygame.transform.scale( + playerImage.subsurface((16, 48, 16, 24)), (64, 98) + ), + pygame.transform.scale( + playerImage.subsurface((32, 48, 16, 24)), (64, 98) + ), + pygame.transform.scale( + playerImage.subsurface((48, 48, 16, 24)), (64, 98) + ), + ) + + crouchImages = ( + pygame.transform.scale( + playerImage.subsurface((0, 72, 16, 16)), (64, 64) + ), + pygame.transform.scale( + playerImage.subsurface((16, 72, 16, 16)), (64, 64) + ), + pygame.transform.scale( + playerImage.subsurface((32, 72, 16, 16)), (64, 64) + ), + pygame.transform.scale( + playerImage.subsurface((48, 72, 16, 16)), (64, 64) + ), + ) + + for array in (walkImages, upImages, downImages, crouchImages): + for image in array: + image.set_colorkey((255,0,255)) + + def getCollisionBoxes(self): + return self.collisionBoxes + def __init__(self): pygame.sprite.Sprite.__init__(self) - self.image = pygame.Surface((50, 75)) - self.image.fill((153, 151, 0)) + + self.currentWalkImage = 0 + self.currentUpImage = 0 + self.currentDownImage = 0 + self.currentCrouchImage = 0 + + self.image = Player.downImages[self.currentDownImage] + self.rect = self.image.get_rect() self.rect.center = (100, 400) self.speed = 0.0 @@ -23,19 +103,29 @@ class Player(pygame.sprite.Sprite): self.buttonsJump = (pygame.K_UP, pygame.K_SPACE,) self.buttonsCrouch = (pygame.K_DOWN,) self.gameSpeed = 1 + self.updateCount = 0 + + self.collisionBoxes = pygame.sprite.Group() + + collision = CollisionBox(0, 20, 60, 20, self.rect.center) + self.collisionBoxes.add(collision) + collision = CollisionBox(-10, 5, 30, 20, self.rect.center) + self.collisionBoxes.add(collision) + collision = CollisionBox(0, 35, 25, 40, self.rect.center) + self.collisionBoxes.add(collision) def crouch(self): if not self.isCrouching: self.isCrouching = True - self.rect = self.rect.inflate(0, -25) - # self.image.set_clip((50, 50)) + self.rect = self.rect.inflate(0, -32) def standup(self): if self.isCrouching: self.isCrouching = False - self.rect = self.rect.inflate(0, 25) + self.rect = self.rect.inflate(0, 32) + def updateSpeed(self, newGameSpeed): self.gameSpeed = newGameSpeed @@ -55,10 +145,7 @@ class Player(pygame.sprite.Sprite): def update(self): - if not self.speed: self.rect.y += 1 - - self.speed += 0.09 * self.gameSpeed - self.rect.y += self.speed + self.updateCount += 1 if not self.isDownJump: self.hoverCount = 0 @@ -80,10 +167,50 @@ class Player(pygame.sprite.Sprite): self.standup() if self.isJumping: - if self.isDownJump and self.hoverCount < 8: - self.speed -= (1 - self.speed/(15+ - self.hoverCount*3)) * self.gameSpeed/2 - self.hoverCount += 1 + if self.gameSpeed <= 2: maxHoverCount = 30 + elif self.gameSpeed <= 4: maxHoverCount = 23 + elif self.gameSpeed <= 8: maxHoverCount = 16 + elif self.gameSpeed <= 16: maxHoverCount = 9 + elif self.gameSpeed <= 32: maxHoverCount = 5 + elif self.gameSpeed <= 64: maxHoverCount = 2 + else: maxHoverCount = 1 + if self.isDownJump and self.hoverCount < maxHoverCount: + self.speed -= self.gameSpeed/8 * ( + (math.cos(2*math.pi*self.hoverCount/ + (2*maxHoverCount))+1)/2.5 + 0.2 + ) + self.hoverCount += 1 else: self.isJumping = False + else: + self.speed += 0.07 * self.gameSpeed + + self.rect.y += self.speed + + for i in self.collisionBoxes: + i.setY(self.rect.y) + + if self.updateCount >= 22 - math.log2(self.gameSpeed) * 2: + if self.isOnFloor: + if self.isCrouching: + self.currentCrouchImage += 1 + if self.currentCrouchImage >= len(Player.crouchImages): + self.currentCrouchImage = 0 + self.image = Player.crouchImages[self.currentCrouchImage] + else: + self.currentWalkImage += 1 + if self.currentWalkImage >= len(Player.walkImages): + self.currentWalkImage = 0 + self.image = Player.walkImages[self.currentWalkImage] + elif self.isJumping: + self.currentUpImage += 1 + if self.currentUpImage >= len(Player.upImages): + self.currentUpImage = 0 + self.image = Player.upImages[self.currentUpImage] + else: + self.currentDownImage += 1 + if self.currentDownImage >= len(Player.downImages): + self.currentDownImage = 0 + self.image = Player.downImages[self.currentDownImage] + self.updateCount = 0 diff --git a/StandingEnemy.py b/StandingEnemy.py index adda10f..807a180 100644 --- a/StandingEnemy.py +++ b/StandingEnemy.py @@ -5,27 +5,160 @@ Standing enemy entity class import pygame import random +import os + from Enemy import Enemy +from CollisionBox import CollisionBox class StandingEnemy(Enemy): + imgDir = os.path.join(os.path.dirname(__file__), 'data') + senemyImage = pygame.image.load( + os.path.join(imgDir, 'senemy.png') + )#.convert() + images = ( + ( + pygame.transform.scale( + senemyImage.subsurface((0, 0, 8, 24)), (32, 98) + ), + pygame.transform.scale( + senemyImage.subsurface((8, 0, 8, 24)), (32, 98) + ), + pygame.transform.scale( + senemyImage.subsurface((16, 0, 8, 24)), (32, 98) + ), + pygame.transform.scale( + senemyImage.subsurface((24, 0, 8, 24)), (32, 98) + ), + pygame.transform.scale( + senemyImage.subsurface((32, 0, 8, 24)), (32, 98) + ), + pygame.transform.scale( + senemyImage.subsurface((40, 0, 8, 24)), (32, 98) + ), + ), + ( + pygame.transform.scale( + senemyImage.subsurface((0, 24, 8, 16)), (32, 64) + ), + pygame.transform.scale( + senemyImage.subsurface((8, 24, 8, 16)), (32, 64) + ), + pygame.transform.scale( + senemyImage.subsurface((16, 24, 8, 16)), (32, 64) + ), + pygame.transform.scale( + senemyImage.subsurface((24, 24, 8, 16)), (32, 64) + ), + pygame.transform.scale( + senemyImage.subsurface((32, 24, 8, 16)), (32, 64) + ), + pygame.transform.scale( + senemyImage.subsurface((40, 24, 8, 16)), (32, 64) + ), + ), + ( + pygame.transform.scale( + senemyImage.subsurface((0, 40, 16, 16)), (64, 64) + ), + pygame.transform.scale( + senemyImage.subsurface((16, 40, 16, 16)), (64, 64) + ), + pygame.transform.scale( + senemyImage.subsurface((32, 40, 16, 16)), (64, 64) + ), + pygame.transform.scale( + senemyImage.subsurface((0, 56, 16, 16)), (64, 64) + ), + pygame.transform.scale( + senemyImage.subsurface((16, 56, 16, 16)), (64, 64) + ), + pygame.transform.scale( + senemyImage.subsurface((32, 56, 16, 16)), (64, 64) + ), + ), + ( + pygame.transform.scale( + senemyImage.subsurface((0, 72, 8, 8)), (32, 32) + ), + pygame.transform.scale( + senemyImage.subsurface((8, 72, 8, 8)), (32, 32) + ), + pygame.transform.scale( + senemyImage.subsurface((16, 72, 8, 8)), (32, 32) + ), + pygame.transform.scale( + senemyImage.subsurface((24, 72, 8, 8)), (32, 32) + ), + pygame.transform.scale( + senemyImage.subsurface((32, 72, 8, 8)), (32, 32) + ), + pygame.transform.scale( + senemyImage.subsurface((40, 72, 8, 8)), (32, 32) + ), + ), + ( + pygame.transform.scale( + senemyImage.subsurface((0, 80, 16, 8)), (64, 32) + ), + pygame.transform.scale( + senemyImage.subsurface((16, 80, 16, 8)), (64, 32) + ), + pygame.transform.scale( + senemyImage.subsurface((32, 80, 16, 8)), (64, 32) + ), + pygame.transform.scale( + senemyImage.subsurface((0, 88, 16, 8)), (64, 32) + ), + pygame.transform.scale( + senemyImage.subsurface((16, 88, 16, 8)), (64, 32) + ), + pygame.transform.scale( + senemyImage.subsurface((32, 88, 16, 8)), (64, 32) + ), + ), + ( + pygame.transform.scale( + senemyImage.subsurface((0, 96, 24, 8)), (98, 32) + ), + pygame.transform.scale( + senemyImage.subsurface((24, 96, 24, 8)), (98, 32) + ), + pygame.transform.scale( + senemyImage.subsurface((0, 104, 24, 8)), (98, 32) + ), + pygame.transform.scale( + senemyImage.subsurface((24, 104, 24, 8)), (98, 32) + ), + pygame.transform.scale( + senemyImage.subsurface((0, 112, 24, 8)), (98, 32) + ), + pygame.transform.scale( + senemyImage.subsurface((24, 112, 24, 8)), (98, 32) + ), + ), + ) + + def __init__(self, mainGameClass): Enemy.__init__(self, mainGameClass) - self.subtype = random.randint(1, 5) + for array in self.images: + for image in array: + image.set_colorkey((255,0,255)) - if self.subtype == 1: self.image = pygame.Surface((25, 75)) - elif self.subtype == 2: self.image = pygame.Surface((25, 25)) - elif self.subtype == 3: self.image = pygame.Surface((75, 25)) - elif self.subtype == 4: self.image = pygame.Surface((50, 25)) - elif self.subtype == 5: self.image = pygame.Surface((50, 50)) - else: self.image = pygame.Surface((25, 50)) - self.image.fill((0, 153, 0)) + self.subtype = random.randint(0, len(StandingEnemy.images) - 1) + + self.image = random.choice(StandingEnemy.images[self.subtype]) + self.rect = self.image.get_rect() self.height -= self.rect.height/2 self.rect.center = (mainGameClass.getScreenWidth() + self.rect.width, self.height) + collision = CollisionBox(9, 3, self.rect.w - 18, self.rect.h - 6, self.rect.center) + self.collisionBoxes.add(collision) + self.speed = self.thisGame.getGameSpeed() diff --git a/data/background.png b/data/background.png new file mode 100644 index 0000000..9f9a772 Binary files /dev/null and b/data/background.png differ diff --git a/data/background.xcf b/data/background.xcf new file mode 100644 index 0000000..3486362 Binary files /dev/null and b/data/background.xcf differ diff --git a/data/fenemy.png b/data/fenemy.png new file mode 100644 index 0000000..74769f2 Binary files /dev/null and b/data/fenemy.png differ diff --git a/data/fenemy.xcf b/data/fenemy.xcf new file mode 100644 index 0000000..10fa169 Binary files /dev/null and b/data/fenemy.xcf differ diff --git a/data/player.png b/data/player.png new file mode 100644 index 0000000..1e22269 Binary files /dev/null and b/data/player.png differ diff --git a/data/player.xcf b/data/player.xcf new file mode 100644 index 0000000..1bc749b Binary files /dev/null and b/data/player.xcf differ diff --git a/data/senemy.png b/data/senemy.png new file mode 100644 index 0000000..dfdc17f Binary files /dev/null and b/data/senemy.png differ diff --git a/data/senemy.xcf b/data/senemy.xcf new file mode 100644 index 0000000..3766c54 Binary files /dev/null and b/data/senemy.xcf differ diff --git a/leaders.lb b/leaders.lb new file mode 100644 index 0000000..1dd5a2c Binary files /dev/null and b/leaders.lb differ