diff --git a/Cloud.py b/Cloud.py new file mode 100644 index 0000000..a532a2d --- /dev/null +++ b/Cloud.py @@ -0,0 +1,33 @@ +""" +Cloud entity class +""" + + +import pygame +import random + + +class Cloud(pygame.sprite.Sprite): + def __init__(self, mainGameClass): + 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))) + 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.__doubleX = float(self.rect.x) + + + def update(self): + if (self.rect.x < -self.rect.width): + self.kill() + + self.__doubleX -= self.speed + self.rect.x = self.__doubleX diff --git a/Drakora.pyw b/Drakora.pyw index 7526c32..1e4ae6b 100644 --- a/Drakora.pyw +++ b/Drakora.pyw @@ -1,322 +1,273 @@ """ -First test Pygame project +Main game class +""" -Written in Python 3.X using Pygame library -""" import pygame import random -buttonsPause = (pygame.K_p,) -buttonsQuit = (pygame.K_F10,) -buttonsNewGame = (pygame.K_RETURN,) -buttonsJump = (pygame.K_UP, pygame.K_SPACE,) -buttonsCrouch = (pygame.K_DOWN,) +from collections import deque -screenSize = (800, 600) -targetFps = 60 +from Player import Player +from StandingEnemy import StandingEnemy +from FlyingEnemy import FlyingEnemy +from Cloud import Cloud +from Floor import Floor -floorHeight = 50 -gameSpeed = 0.0 -score = 0 -isGameOver = False -isPaused = False +class Drakora(): + def getGameSpeed(self): + return self.__gameSpeed -isDownJump = False -isDownCrouch = False -enemyCD = 0 -enemyChance = 0.0 + def getScore(self): + return self.__score + + + def getScreenWidth(self): + return self.screenSize[0] + + + def getScreenHeight(self): + return self.screenSize[1] + + + def getFloorHeight(self): + return self.floorHeight + + + def addScore(self, score): + self.__score += score + + if self.__score%self.speedUpRate == 0: + self.__gameSpeed += self.__score/self.speedUpRate + self.speedUpLabelCD = self.targetFps + + + def newGame(self): + for enemy in self.enemies: + enemy.kill() + + if self.player: self.player.kill() + + self.player = Player() + self.sprites.add(self.player) + + self.__score = 0 + self.isGameOver = False + self.isPaused = False + + self.__gameSpeed = 2 + + self.enemyCount = 0 + self.enemyChance = 100.0 + + self.speedUpLabelCD = 0 + self.nextEnemyMustBeFlying = False + self.enemyCD = self.getNextEnemyCD() -floors = pygame.sprite.Group() -enemies = pygame.sprite.Group() -clouds = pygame.sprite.Group() -player = None -class Floor(pygame.sprite.Sprite): def __init__(self): - pygame.sprite.Sprite.__init__(self) - self.image = pygame.Surface((screenSize[0], floorHeight)) - self.image.fill((255, 204, 102)) - self.rect = self.image.get_rect() - self.rect.center = (screenSize[0]/2, screenSize[1]-floorHeight/2) + self.buttonsPause = (pygame.K_p,) + self.buttonsQuit = (pygame.K_F10,) + self.buttonsNewGame = (pygame.K_RETURN,) -class Cloud(pygame.sprite.Sprite): - def __init__(self): - 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))) - self.rect = self.image.get_rect() - self.rect.center = (screenSize[0] + self.rect.width, - screenSize[1]/2 - - random.randint(100, screenSize[1]/2-100)) - self.speed = random.randint(150, 300)/100 + self.screenSize = (800, 600) + self.targetFps = 120 - def update(self): - self.rect.x -= gameSpeed*self.speed - if (self.rect.x < -self.rect.width): - self.kill() + self.floorHeight = 50 -class Player(pygame.sprite.Sprite): - def __init__(self): - pygame.sprite.Sprite.__init__(self) - self.image = pygame.Surface((50, 75)) - self.image.fill((153, 151, 0)) - self.rect = self.image.get_rect() - self.rect.center = (100, 400) - self.speed = 0.0 - self.isJumping = False - self.isCrouching = False - self.hoverCount = 0 + self.floors = pygame.sprite.Group() + self.enemies = pygame.sprite.Group() + self.clouds = pygame.sprite.Group() + self.player = None - def crouch(self): - if not self.isCrouching: - self.isCrouching = True - self.rect = self.rect.inflate(0, -25) + self.speedUpRate = 25 - def standup(self): - if self.isCrouching: - self.isCrouching = False - self.rect = self.rect.inflate(0, 25) + self.godmodeCount = 0 + self.isGodmode = False - def update(self): - global isGameOver + random.seed() + pygame.init() + self.screen = pygame.display.set_mode(self.screenSize) + pygame.display.set_caption('Drakora') + self.clock = pygame.time.Clock() - if pygame.sprite.spritecollideany(player, enemies): - isGameOver = True - pass + self.sprites = pygame.sprite.Group() + self.floors.add(Floor(self)) + self.sprites.add(self.floors) - if not self.speed: self.rect.y += 1 + 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.speed += 0.35 - self.rect.y += self.speed + 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 - isOnFloor = False - while pygame.sprite.spritecollideany(player, floors): - isOnFloor = True - self.rect.y -= 1 - - if not isDownJump: - self.hoverCount = 0 - - if isOnFloor: - self.speed = 0 - - if isDownJump: - self.isJumping = True - - if self.isCrouching: - self.standup() - - elif isDownCrouch: - if not self.isCrouching: - self.crouch() - - elif self.isCrouching: - self.standup() + self.newGame() - if self.isJumping: - if isDownJump and self.hoverCount < 10: - self.speed -= 1 - self.speed/(15+self.hoverCount*3) - self.hoverCount += 1 - - else: - self.isJumping = False + def __del__(self): + pygame.quit() + def renderText(self, text, font, color, center): + render = font.render(text, True, color) + rect = render.get_rect() + rect.center = center + self.screen.blit(render, rect) -class Enemy(pygame.sprite.Sprite): - def setNextEnemyType(self): - if score < 10: - self.type = 1 - elif score < 25: - if random.randint(1, 100) < 95: self.type = 1 - else: self.type = 2 + def render(self): + self.screen.fill((102, 153, 255)) + self.sprites.draw(self.screen) + self.floors.draw(self.screen) - elif score < 50: - if random.randint(1, 100) < 85: self.type = 1 - else: self.type = 2 + self.renderText('%d'%(self.__score), + self.fontScore, (255, 255, 255), + (self.getScreenWidth()/2,20)) + 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)) + + if self.isGodmode: + self.renderText('godmode', + self.fontGodmode, (255, 255, 255), + (self.getScreenWidth()/2,40)) + + pygame.display.flip() + + + def getNextEnemyCD(self): + if self.enemyCount == 0: + return 1000 + elif self.enemyCount <= 5: + return 800 - 100*self.enemyCount + elif self.enemyCount%self.speedUpRate == 0: + return 1000 + elif self.nextEnemyMustBeFlying: + return 600 else: - if random.randint(1, 100) < 75: self.type = 1 - else: self.type = 2 - - def setNextEnemySubtype(self): - if self.type == 1: - self.subtype = random.randint(1, 5) - elif self.type == 2: - self.subtype = random.randint(1, 3) - - def __init__(self): - pygame.sprite.Sprite.__init__(self) - - self.setNextEnemyType() - self.setNextEnemySubtype() - - self.height = screenSize[1] - floorHeight - - if self.type == 1: - 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.rect = self.image.get_rect() - self.height -= self.rect.height/2 - - elif self.type == 2: - 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 + 25*self.subtype - - self.rect.center = (screenSize[0] + self.rect.width, self.height) - - def update(self): - global score, gameSpeed - self.rect.x -= gameSpeed - if (self.rect.x < -self.rect.width): - self.kill() - score += 1 - gameSpeed += 0.025 - -def newGame(): - global player, floor, enemies, sprites, score - global gameSpeed, isGameOver, enemyCD, enemyChance - - for enemy in enemies: - enemy.kill() - - if player: player.kill() - - player = Player() - sprites.add(player) - - gameSpeed = 3.0 - score = 0 - isGameOver = False - isPaused = False - - enemyCD = 0 - enemyChance = 100.0 + return 300 -def init(): - global player, floor, enemies, sprites, score + def collideCheck(self): + if pygame.sprite.spritecollideany(self.player, self.enemies): + if not self.isGodmode: self.isGameOver = True - random.seed() - pygame.init() - screen = pygame.display.set_mode(screenSize) - pygame.display.set_caption('Drakora') - clock = pygame.time.Clock() + self.player.isOnFloor = False - sprites = pygame.sprite.Group() - floors.add(Floor()) - sprites.add(floors) - - newGame() - - return screen, clock, sprites - -def deinit(): - pygame.quit() - -def render(screen, sprites): - screen.fill((102, 153, 255)) - sprites.draw(screen) - - font = pygame.font.Font(pygame.font.match_font('liberation mono'), 32) - text = font.render('%d'%(score), True, (255, 255, 255)) - rect = text.get_rect() - rect.midtop = (rect.width/2+10,10) - screen.blit(text, rect) - - if isGameOver: - font = pygame.font.Font(pygame.font.match_font('liberation mono'), 56) - text = font.render('GAME OVER', True, (255, 255, 255)) - rect = text.get_rect() - rect.midtop = tuple(i/2 for i in screenSize) - screen.blit(text, rect) - elif isPaused: - font = pygame.font.Font(pygame.font.match_font('liberation mono'), 56) - text = font.render('PAUSED', True, (255, 255, 255)) - rect = text.get_rect() - rect.midtop = tuple(i/2 for i in screenSize) - screen.blit(text, rect) + while pygame.sprite.spritecollideany(self.player, self.floors): + self.player.isOnFloor = True + self.player.rect.y -= 1 - pygame.display.flip() + def doCheats(self): + if self.isPressedKeysUpdated: + pressedKeysStr = ''.join(self.pressedKeys) + if pressedKeysStr.endswith('godmode'): + self.isGodmode = not self.isGodmode + self.isPressedKeysUpdated = False -def logic(clock, sprites): - global enemyCD, enemyChance, isDownJump, isDownCrouch, isPaused + def logic(self): + self.player.updateSpeed(self.__gameSpeed) - for event in pygame.event.get(): - if event.type == pygame.QUIT: - return False + for event in pygame.event.get(): + self.player.control(event) - elif event.type == pygame.KEYDOWN: - if event.key in buttonsQuit: + if event.type == pygame.QUIT: return False - if event.key in buttonsCrouch: - isDownCrouch = True - elif event.key in buttonsJump: - isDownJump = True - elif event.key in buttonsNewGame: - if isGameOver: newGame() - elif event.key in buttonsPause: - isPaused = not isPaused - elif event.type == pygame.KEYUP: - if event.key in buttonsCrouch: - isDownCrouch = False - if event.key in buttonsJump: - isDownJump = False + elif event.type == pygame.KEYDOWN: + if event.key in self.buttonsQuit: + return False + elif event.key in self.buttonsNewGame: + if self.isGameOver or self.isGodmode: self.newGame() + elif event.key in self.buttonsPause: + self.isPaused = not self.isPaused - if not isGameOver and not isPaused: - sprites.update() + elif event.type == pygame.KEYUP: + if event.key in self.charKeys: + self.pressedKeys.append(self.charKeys[event.key]) + self.isPressedKeysUpdated = True - enemyCD -= gameSpeed + self.doCheats() - if random.randint(1, 100) == 1: - cloud = Cloud() - clouds.add(cloud) - sprites.add(cloud) + if not self.isGameOver and not self.isPaused: + self.sprites.update() - if enemyCD <= 0: - enemyChance += (1/targetFps) * enemyChance/8 + self.enemyCD -= self.__gameSpeed - if random.randint(1, 100) < enemyChance: - enemyCD = 200 - enemyChance = 1 - enemy = Enemy() - enemies.add(enemy) - sprites.add(enemy) + if random.randint(1, 200) == 1: + cloud = Cloud(self) + self.clouds.add(cloud) + self.sprites.add(cloud) + + if self.enemyCD <= 0: + self.enemyChance += (1/self.targetFps) * self.enemyChance/8 + + if random.randint(1, 150) < self.enemyChance: + self.enemyCount += 1 + self.enemyChance = 1 + + if self.nextEnemyMustBeFlying: + enemy = FlyingEnemy(self) + else: + enemy = StandingEnemy(self) + + if self.__score < 10: + self.nextEnemyMustBeFlying = False + + elif self.__score < 20: + self.nextEnemyMustBeFlying = random.randint(1, 100) > 95 + + elif self.__score < 40: + self.nextEnemyMustBeFlying = random.randint(1, 100) > 85 + + else: + self.nextEnemyMustBeFlying = random.randint(1, 100) > 75 + + self.enemyCD = self.getNextEnemyCD() + + self.enemies.add(enemy) + self.sprites.add(enemy) + + self.collideCheck() + + return True - clock.tick(targetFps) + def play(self): + isRunning = True + while isRunning: + self.clock.tick(self.targetFps) + self.render() + isRunning = self.logic() - return True - -def main_loop(screen, clock, sprites): - global isGameOver - - isRunning = True - - while isRunning: - isRunning = logic(clock, sprites) - render(screen, sprites) if __name__ == '__main__': - screen, clock, sprites = init() - main_loop(screen, clock, sprites) - deinit() + drakora = Drakora() + drakora.play() + del Drakora diff --git a/Enemy.py b/Enemy.py new file mode 100644 index 0000000..3322e44 --- /dev/null +++ b/Enemy.py @@ -0,0 +1,25 @@ +""" +Enemy entity class +""" + + +import pygame +import random + + +class Enemy(pygame.sprite.Sprite): + def __init__(self, mainGameClass): + pygame.sprite.Sprite.__init__(self) + + self.thisGame = mainGameClass + + self.height = (mainGameClass.getScreenHeight() + - mainGameClass.getFloorHeight()) + + + def update(self): + if (self.rect.x < -self.rect.width): + self.kill() + self.thisGame.addScore(1) + + self.rect.x -= self.speed diff --git a/Floor.py b/Floor.py new file mode 100644 index 0000000..c06b552 --- /dev/null +++ b/Floor.py @@ -0,0 +1,18 @@ +""" +Floor entity class +""" + + +import pygame + + +class Floor(pygame.sprite.Sprite): + def __init__(self, mainGameClass): + pygame.sprite.Sprite.__init__(self) + self.image = pygame.Surface((mainGameClass.getScreenWidth(), + mainGameClass.getFloorHeight()*101)) + self.image.fill((255, 204, 102)) + self.rect = self.image.get_rect() + self.rect.center = (mainGameClass.getScreenWidth()/2, + mainGameClass.getScreenHeight() + + mainGameClass.getFloorHeight()*49.5) diff --git a/FlyingEnemy.py b/FlyingEnemy.py new file mode 100644 index 0000000..d78ae23 --- /dev/null +++ b/FlyingEnemy.py @@ -0,0 +1,25 @@ +""" +Flying enemy entity class +""" + + +import pygame +import random +from Enemy import Enemy + + +class FlyingEnemy(Enemy): + def __init__(self, mainGameClass): + Enemy.__init__(self, mainGameClass) + + self.subtype = random.randint(1, 7) + + 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) + + self.speed = self.thisGame.getGameSpeed()*2 diff --git a/Player.py b/Player.py new file mode 100644 index 0000000..2e89c71 --- /dev/null +++ b/Player.py @@ -0,0 +1,89 @@ +""" +Player entity class +""" + + +import pygame + + +class Player(pygame.sprite.Sprite): + def __init__(self): + pygame.sprite.Sprite.__init__(self) + self.image = pygame.Surface((50, 75)) + self.image.fill((153, 151, 0)) + self.rect = self.image.get_rect() + self.rect.center = (100, 400) + self.speed = 0.0 + self.isJumping = False + self.isCrouching = False + self.hoverCount = 0 + self.isOnFloor = False + self.isDownJump = False + self.isDownCrouch = False + self.buttonsJump = (pygame.K_UP, pygame.K_SPACE,) + self.buttonsCrouch = (pygame.K_DOWN,) + self.gameSpeed = 1 + + + def crouch(self): + if not self.isCrouching: + self.isCrouching = True + self.rect = self.rect.inflate(0, -25) + # self.image.set_clip((50, 50)) + + + def standup(self): + if self.isCrouching: + self.isCrouching = False + self.rect = self.rect.inflate(0, 25) + + def updateSpeed(self, newGameSpeed): + self.gameSpeed = newGameSpeed + + def control(self, event): + if event.type == pygame.KEYDOWN: + if event.key in self.buttonsCrouch: + self.isDownCrouch = True + elif event.key in self.buttonsJump: + self.isDownJump = True + + elif event.type == pygame.KEYUP: + if event.key in self.buttonsCrouch: + self.isDownCrouch = False + elif event.key in self.buttonsJump: + self.isDownJump = False + + + def update(self): + if not self.speed: self.rect.y += 1 + + self.speed += 0.09 * self.gameSpeed + self.rect.y += self.speed + + if not self.isDownJump: + self.hoverCount = 0 + + if self.isOnFloor: + self.speed = 0 + + if self.isDownJump: + self.isJumping = True + + if self.isCrouching: + self.standup() + + elif self.isDownCrouch: + if not self.isCrouching: + self.crouch() + + elif self.isCrouching: + 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 + + else: + self.isJumping = False diff --git a/StandingEnemy.py b/StandingEnemy.py new file mode 100644 index 0000000..adda10f --- /dev/null +++ b/StandingEnemy.py @@ -0,0 +1,31 @@ +""" +Standing enemy entity class +""" + + +import pygame +import random +from Enemy import Enemy + + +class StandingEnemy(Enemy): + def __init__(self, mainGameClass): + Enemy.__init__(self, mainGameClass) + + self.subtype = random.randint(1, 5) + + 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.rect = self.image.get_rect() + self.height -= self.rect.height/2 + + self.rect.center = (mainGameClass.getScreenWidth() + self.rect.width, + self.height) + + self.speed = self.thisGame.getGameSpeed()