class Zombie(object): # Call constructor def __init__(self, screenWidth, screenHeight, spawnx, spawny, vel, health, image, drawBounds): # SET PARAMETER VARIABLES # self.screenWidth = screenWidth self.screenHeight = screenHeight self.x = spawnx self.y = spawny self.vel = vel self.health = health self.maxHealth = health self.drawBounds = drawBounds # SET PARAMETER VARIABLES # # CREATE SIZE OF THE IMAGE # self.scaleWidth = self.screenWidth / 1280 self.scaleHeight = self.screenHeight / 768 self.image = image if self.scaleWidth != 1 or self.scaleHeight != 1: self.image = pygame.transform.scale( self.image, (int(self.image.get_width() * self.scaleWidth), int(self.image.get_height() * self.scaleWidth))) # yes i know that's two scalewidths self.image = pygame.transform.scale( self.image, (int(self.image.get_rect().width * 0.75), int(self.image.get_rect().height * 0.75))) # rescale image # CREATE SIZE OF THE IMAGE # # SET BASIC VARIABLES # self.zombie = self.image self.isAlive = True self.dx = 0 self.dy = 0 self.Rect = pygame.Rect( (self.x, self.y), (self.zombie.get_width(), self.zombie.get_height())) self.originalRectWidth = self.Rect.width # I keep originals because it width/height changes as the zombie rotates. Which makes the health bars look bad. self.originalRectHeight = self.Rect.height self.isFrozen = False self.frozenParticleTimer = None # SET BASIC VARIABLES # # ZOMBIE ATTACK SYSTEM # self.canAttack = True self.existingAttackTimer = False self.attackTimer = None # ZOMBIE ATTACK SYSTEM # # SET ZOMBIE-COLLISION RECTANGLES # self.left_Rect = pygame.Rect( (self.Rect.x - 1, self.Rect.y), (1, self.Rect.height)) # Make the rect to the left of main rect self.right_Rect = pygame.Rect( (self.Rect.x + self.Rect.width + 1, self.Rect.y), (1, self.Rect.height)) # Make the rect to the right of main rect self.top_Rect = pygame.Rect( (self.Rect.x, self.Rect.y - 1), (self.Rect.width, 1)) # Make the rect to the top of main rect self.bottom_Rect = pygame.Rect( (self.Rect.x, self.Rect.y + self.Rect.height), (self.Rect.width, 1)) # Make the rect to the bottom of main rect # SET RECTANGLES # # SET WALL-COLLISION RECTANGLES # self.colRectWidth = self.Rect.width * 0.60 self.colRectHeight = self.Rect.height * 0.60 self.colRectX = self.Rect.center[0] - (self.colRectWidth / 2) self.colRectY = self.Rect.center[1] - (self.colRectHeight / 2) self.col_left_Rect = pygame.Rect( (self.colRectX, self.colRectY), (1, self.colRectHeight)) # left wall ( smaller for collision ) self.col_right_Rect = pygame.Rect( (self.colRectX + self.colRectWidth - 1, self.colRectY), (1, self.colRectHeight)) # right wall ( smaller for collision ) self.col_top_Rect = pygame.Rect( (self.colRectX, self.colRectY - 1), (self.colRectWidth, 1)) # top wall ( smaller for collision ) self.col_bottom_Rect = pygame.Rect( (self.colRectX, self.colRectY + self.colRectHeight - 1), (self.colRectWidth, 1)) # bottom wall ( smaller for collision ) # SET WALL-COLLISION RECTANGLES # # COLLISION BOUND VARIABLES # self.leftWallCollided = False self.rightWallCollided = False self.topWallCollided = False self.bottomWallCollided = False # COLLISION BOUND VARIABLES # # HEALTH BAR # self.healthBarWidth = self.Rect.width self.healthBar = pygame.Rect((self.x, self.y - 1), (self.Rect.width, 1)) # HEALTH BAR # # ON FIRE BASED DATA # self.onFire = False self.fireDamageTimer = None self.onFireOffTimer = None # ON FIRE BASED DATA # # Get width def getWidth(self): return self.Rect.width # Get height def getHeight(self): return self.Rect.height # Set Displacement def setD(self, dx, dy): self.dx = dx self.dy = dy # Set Displacement X def setDX(self, dx): self.dx = dx # Set Displacement Y def setDY(self, dy): self.dy = dy # Get zombie rectangle def getRect(self, r): return self.Rect # Get zombie collision rectangle def getCollisionRect(self): return pygame.Rect((self.colRectX, self.colRectY), (self.colRectWidth, self.colRectHeight)) # Get zombie wall rects def getWall(self, wall): # wall --> (1 = left, 2 = right, 3 = top, 4 = bottom) if wall == 1: return self.left_Rect elif wall == 2: return self.right_Rect elif wall == 3: return self.top_Rect elif wall == 4: return self.bottom_Rect # Get zombie collision wall rects def getBlockCollisionWall( self, wall): # wall --> (1 = left, 2 = right, 3 = top, 4 = bottom) if wall == 1: return self.col_left_Rect elif wall == 2: return self.col_right_Rect elif wall == 3: return self.col_right_Rect elif wall == 4: return self.col_right_Rect # Update wall collider rectangles: def updateWallColliderRectangles(self): self.colRectWidth = self.Rect.width * 0.60 self.colRectHeight = self.Rect.height * 0.60 self.colRectX = self.Rect.center[0] - (self.colRectWidth / 2) self.colRectY = self.Rect.center[1] - (self.colRectHeight / 2) self.col_left_Rect = pygame.Rect( (self.colRectX, self.colRectY), (1, self.colRectHeight)) # left wall ( smaller for collision ) self.col_right_Rect = pygame.Rect( (self.colRectX + self.colRectWidth - 1, self.colRectY), (1, self.colRectHeight)) # right wall ( smaller for collision ) self.col_top_Rect = pygame.Rect( (self.colRectX, self.colRectY - 1), (self.colRectWidth, 1)) # top wall ( smaller for collision ) self.col_bottom_Rect = pygame.Rect( (self.colRectX, self.colRectY + self.colRectHeight - 1), (self.colRectWidth, 1)) # bottom wall ( smaller for collision ) # Get if a collision is bound: def getCollisionBound( self, wall): # wall --> (1 = left, 2 = right, 3 = top, 4 = bottom) if wall == 1: return self.leftWallCollided elif wall == 2: return self.rightWallCollided elif wall == 3: return self.topWallCollided elif wall == 4: return self.bottomWallCollided # Set a collision bound: def setCollisionBound( self, wall, _bool ): # wall --> (1 = left, 2 = right, 3 = top, 4 = bottom) || _bool --> (True, False) if wall == 1: self.leftWallCollided = _bool elif wall == 2: self.rightWallCollided = _bool elif wall == 3: self.topWallCollided = _bool elif wall == 4: self.bottomWallCollided = _bool # Collision movement prevention: def checkWallCollision(self, playerRect): if self.leftWallCollided == True or self.rightWallCollided == True: self.setDX(0) if self.topWallCollided == True or self.bottomWallCollided == True: self.setDY(0) # Check double colliders ( prevent corner bugs ) def checkDoubleWallCollision(self): if self.topWallCollided == True and self.leftWallCollided == True and self.bottomWallCollided == True and self.rightWallCollided == True: # If every wall has collided middleVector = Vec2d( int(self.screenWidth / 2), int(self.screenHeight / 2)) # create a vector of the screen middle zombieVector = Vec2d( int(self.Rect.center[0]), int(self.Rect.center[1])) # create a vector of the zombie zombieToMiddleVector = Vec2d( middleVector - zombieVector ) # create a vector of the direction between middle and zombie zombieToMiddleVector = zombieToMiddleVector.normalized( ) # normalize to the shortest length zombiepos = self.x, self.y # throw zombie coordinates in a tuple so they can be adjusted via zombieToMiddleVector zombiepos += zombieToMiddleVector * (self.getVelocity() * 2 ) # translate the zombie self.x, self.y = zombiepos # unpack the tuple back into the x,y coordinates of the zombie # Set an attack timer def setAttackTimer(self, attackDelay, elapsedSeconds): self.attackTimer = Timer(attackDelay, elapsedSeconds) self.existingAttackTimer = True # Get if the zombie can attack def getAttackStatus(self): return self.canAttack # Set if the zombie can attack def setAttackAbility(self, status): self.canAttack = status # Get Zombie X def getX(self): return self.x # Get Zombie Y def getY(self): return self.y # Get Zombie Displacement X def getDX(self): return self.dx # Get Zombie Displacement Y def getDY(self): return self.dy # Get Zombie Displacement def getD(self): return (self.dx, self.dy) # Get Zombie Velocity def getVelocity(self): return self.vel # Get Zombie Rect def getRect(self): return self.Rect # Get Zombie life status def getLifeStatus(self): return self.isAlive # Set Zombie life status def setLifeStatus(self, status): self.isAlive = status # Translate Zombie Location def translate(self, dx, dy): self.x += dx self.y += dy # Translate zombie x coordinate def translateX(self, dx): self.x += dx # Translate zombie y coordinate def translateY(self, dy): self.y += dy # Rotation Common Function: def rotateToAngle( self, x1, y1, x2, y2 ): # (x,y)1 is the coordinates to rotate too | (x,y)2 is the point your rotating too return 360 - math.atan2(y2 - y1, x2 - x1) * 180 / math.pi # Change Health Function: def changeHealth(self, health): self.health += health # Get zombie health def getHealth(self): return self.health # Set if the zombie is frozen or not def setFrozen(self, isFrozen, elapsedSeconds): self.isFrozen = isFrozen if self.isFrozen == True: # if the program is setting the zombie frozen (True) self.frozenParticleTimer = Timer(2, elapsedSeconds) # Get whether the zombie is frozen or not def getFrozen(self): return self.isFrozen # Set the zombie on fire def setOnFire(self, game_Clock): if self.onFire != True: # if the zombie isn't already on fire self.onFire = True self.fireDamageTimer = Timer(1, game_Clock.getElapsedSeconds()) self.onFireOffTimer = Timer(4, game_Clock.getElapsedSeconds()) # Rotate Zombie def rotate(self, angle): self.zombie = pygame.transform.rotate( self.image, angle) # Create a Transformation of the original image self.Rect = self.zombie.get_rect( center=(self.x, self.y)) # Recenter to the position """ RESET RECTANGLES """ self.left_Rect = pygame.Rect( (self.Rect.x - 1, self.Rect.y), (1, self.Rect.height)) # Make the rect to the left of main rect self.right_Rect = pygame.Rect( (self.Rect.x + self.Rect.width + 1, self.Rect.y), (1, self.Rect.height)) # Make the rect to the right of main rect self.top_Rect = pygame.Rect( (self.Rect.x, self.Rect.y - 1), (self.Rect.width, 1)) # Make the rect to the top of main rect self.bottom_Rect = pygame.Rect( (self.Rect.x, self.Rect.y + self.Rect.height), (self.Rect.width, 1)) # Make the rect to the bottom of main rect """ RESET RECTANGLES """ # Path zombie to player def pathFind(self, playerRect): self.setD(0, 0) # Start Displacement at 0 if self.Rect.colliderect( playerRect ) != True: # See if the zombie is not overlapping the player if self.x > playerRect.center[ 0] + 2: # see if zombie is to the right of player, add 2 to end stutter area self.setDX(-self.getVelocity()) if self.x < playerRect.center[ 0] - 2: # see if zombie is to the left of player, subtract 2 to end stutter area self.setDX(self.getVelocity()) if self.y > playerRect.center[ 1] + 2: # see if player is on top of zombie, add 2 to end stutter area self.setDY(-self.getVelocity()) if self.y < playerRect.center[ 1] - 2: # see if player is under zombie , subtract 2 to end stutter area self.setDY(self.getVelocity()) # Update neccessary zombie logic def update(self, playerRect, game_Clock, zombieParticleManager): """ FIND PATH TO PLAYER: """ self.pathFind(playerRect) """ ROTATE ZOMBIE TO WHERE IT'S MOVING OR TO THE PLAYER IF THEY'RE OVERLAPPING """ rotationAngle = 0 # Default it at 0 if self.Rect.colliderect( playerRect): # check if your overlapping the player rotationAngle = self.rotateToAngle( self.getX(), self.getY(), playerRect.center[0], playerRect.center[1]) # rotate to player else: rotationAngle = self.rotateToAngle( self.getX(), self.getY(), self.getX() + self.dx, self.getY() + self.dy) # rotate to travel direction self.rotate(rotationAngle) """ ROTATE ZOMBIE TO WHERE IT'S MOVING OR TO THE PLAYER IF THEY'RE OVERLAPPING """ """ CHECK IF THE ZOMBIE IS ON FIRE AND FROZEN, ACT ACCORDINGLY """ if self.getFrozen( ) == True and self.onFire == True: # if the zombie is frozen and on fire self.setFrozen( False, game_Clock.getElapsedSeconds()) # unfreeze the zombie self.onFire = False # make the zombie no longer on fire """ CHECK IF THE ZOMBIE IS ON FIRE AND FROZEN, ACT ACCORDINGLY """ """ IF THE ZOMBIE IS ON FIRE, UPDATE ACCORDINGLY """ if self.onFire == True: # if the zombie is on fire if self.onFireOffTimer.getAlert( ) == True: # if the zombie is finished being on fire self.onFire = False # Take the zombie off being on fire else: # if the zombie is still on fire self.onFireOffTimer.update(game_Clock.getElapsedSeconds( )) # update the timer to take the zombie off fire if self.fireDamageTimer.getAlert( ) == True: # if a seconds elapsed and it's time to take damage self.changeHealth(-1) # lose 1 hp self.fireDamageTimer = Timer( 1, game_Clock.getElapsedSeconds()) zombieParticleManager.addParticles( self.getRect().center[0], self.getRect().center[1], (226, 88, 34), self.getWidth() / 2, self.getHeight() / 2) # spawn fire particles else: # if it hasn't self.fireDamageTimer.update(game_Clock.getElapsedSeconds( )) # update the take damage timer """ IF THE ZOMIBE IS ON FIRE, UPDATE ACCORDINGLY """ """ CHECK IF THE ZOMBIE IS EVEN ALIVE """ if self.health <= 0: self.setLifeStatus(False) """ CHECK IF THE ZOMBIE IS EVEN ALIVE """ """ CHECK IF THE ZOMBIE CAN ATTACK """ if self.existingAttackTimer == True: if self.attackTimer.getAlert() == True: self.existingAttackTimer = False self.attackTimer = None self.setAttackAbility(True) else: self.attackTimer.update(game_Clock.getElapsedSeconds()) self.setAttackAbility(False) else: self.setAttackAbility(True) """ CHECK IF THE ZOMBIE CAN ATTACK """ """ UPDATE HEALTH BAR """ missingHp = float(self.getHealth() / self.maxHealth) self.healthBarWidth = float(self.originalRectWidth * missingHp) healthBarX = self.getX() - (self.originalRectWidth / 2) healthBarY = self.getY() - (self.originalRectHeight / 2) self.healthBar = pygame.Rect((int(healthBarX), int(healthBarY)), (int(self.healthBarWidth), 2)) """ UPDATE HEALTH BAR """ self.updateWallColliderRectangles( ) # Update collision rectangles for adjusted zombie # Update post collision logic def finalUpdate(self, playerRect, game_Clock): if self.getFrozen() == True: # if the zombie is frozen if self.frozenParticleTimer != None: # if a frozen particle timer exists if self.frozenParticleTimer.getAlert( ) == True: # if the frozen particle timer is finished self.frozenParticleTimer = Timer( 2, game_Clock.getElapsedSeconds()) zombieParticleManager.addParticles( self.getRect().center[0], self.getRect().center[1], (0, 191, 255), self.getWidth() / 2, self.getHeight() / 2) # spawn ice particles else: self.frozenParticleTimer = Timer( 2, game_Clock.getElapsedSeconds()) # set a timer else: # if not self.translate(self.dx, self.dy) # Translate zombie """ ROTATE ZOMBIE TO WHERE IT'S MOVING OR TO THE PLAYER IF THEY'RE OVERLAPPING """ rotationAngle = 0 # Default it at 0 if self.Rect.colliderect( playerRect): # check if your overlapping the player rotationAngle = self.rotateToAngle( self.getX(), self.getY(), playerRect.center[0], playerRect.center[1]) # rotate to player else: rotationAngle = self.rotateToAngle( self.getX(), self.getY(), self.getX() + self.dx, self.getY() + self.dy) # rotate to travel direction self.rotate(rotationAngle) """ ROTATE ZOMBIE TO WHERE IT'S MOVING OR TO THE PLAYER IF THEY'RE OVERLAPPING """ # Draw the zombie def draw(self, canvas): canvas.blit(self.zombie, self.getRect()) if self.maxHealth > 1: # draw the health bar if it actually has health pygame.draw.rect(canvas, (255, 0, 0), self.healthBar, 0) # draw the health bar if self.drawBounds == True: boundColor = (255, 50, 50) pygame.draw.rect(canvas, boundColor, self.col_left_Rect, 1) pygame.draw.rect(canvas, boundColor, self.col_right_Rect, 1) pygame.draw.rect(canvas, boundColor, self.col_top_Rect, 1) pygame.draw.rect(canvas, boundColor, self.col_bottom_Rect, 1)
class Level(object): # Call constructor: def __init__(self, screenWidth, screenHeight, cryptnum, accuracyLevel, magAmmo, fps, tileWidth, tileHeight, blockImage, spawnerImage, backgroundImage, arrowImage, playerSpawnX, playerSpawnY, zombieImage, drawBounds, maxZombies, zombieHealth, zombieVelMin, zombieVelMax, zombieSpawnTimeMin, zombieSpawnTimeMax): """ Constructor Arguments: screen width screen height cryptnum accuracyLevel magAmmo fps tile width tile height blockImage spawnerImage backgroundImage arrowImage playerSpawnX playerSpawnY zombieImage drawbounds | developer tool maxZombies zombieHealth zombieMinVel zombieMaxVel zombieSpawnTimeMin zombieSpawnTimeMax """ # Basic Level Data: self.levelLoaded = False self.screenWidth = screenWidth self.screenHeight = screenHeight self.cryptnum = cryptnum self.fps = fps self.tileWidth = tileWidth self.tileHeight = tileHeight self.isMousePressed = False self.mousex = self.mousey = 0 # Load Images: self.blockImage = blockImage self.spawnerImage = spawnerImage self.backgroundImage = backgroundImage self.block = pygame.transform.scale( self.blockImage, (self.tileWidth, self.tileHeight)) # transform to fit tile self.zblock = pygame.transform.scale( self.spawnerImage, (self.tileWidth, self.tileHeight)) # transform to fit tile self.background = pygame.transform.scale( self.backgroundImage, (self.screenWidth, self.screenHeight)) # transform to fit tile self.zombieImage = zombieImage self.tileZombie = pygame.transform.scale( self.zombieImage, (int(self.tileWidth * 0.60), int(self.tileHeight * 0.60))) self.distractionOrb = pygame.image.load( "Data/images/distractionorb.png") self.distractionOrb = pygame.transform.scale( self.distractionOrb, (self.tileWidth, self.tileHeight)) # scale to fit a tile self.grenadeImage = pygame.image.load("Data/images/grenade.png") self.bladeImage = pygame.image.load("Data/images/blade.png") # Set the player spawn x,y: self.playerSpawnX = playerSpawnX self.playerSpawnY = playerSpawnY # Choose randomized Level self.levelDesigns = LevelDesigns() self.levelDesigns.generateLevels() self.level = random.randint(1, self.levelDesigns.getLevelAmount()) # Get game-progression Data self.maxZombies = maxZombies self.zombieHealth = zombieHealth self.zombieVelMin = zombieVelMin self.zombieVelMax = zombieVelMax self.zombieSpawnTimeMin = zombieSpawnTimeMin self.zombieSpawnTimeMax = zombieSpawnTimeMax self.zombieAttackDelay = 2 self.accuracyLevel = accuracyLevel self.magammo = magAmmo self.ammoSize = 20 # Level Data: self.levelBlit = False self.Rects = [] self.zombieSpawners = [] self.rotatingZombies = [] self.isLevelFinished = False # level finished variable self.roomEntrance = "" #to keep track of where the room was entered self.roomEntranceSet = False # keep track of the entrance was properly recorded self.notifyFont = pygame.font.SysFont("Verdana", 36) self.bulletType = "normal" self.addGrenade = False self.addBlade = False self.addIceTile = False self.addDistractionOrb = False # Distraction Orb self.distractionOrbActive = False self.distractionOrbTimer = None self.distractionOrbRect = pygame.Rect( (0, 0), (self.tileWidth, self.tileHeight)) # coordinate rectangle # Initalize Level Based Objects: self.stringManager = StringManager() self.bulletManager = BulletManager(self.screenWidth, self.screenHeight, self.notifyFont, self.ammoSize, self.magammo, 2) self.zombieManager = ZombieManager(self.screenWidth, self.screenHeight, self.zombieAttackDelay, zombieImage, drawBounds) self.zombieParticleManager = ZombieParticleManager() self.bloodExplosionManager = BloodExplosionManager( self.screenWidth, self.screenHeight) self.fireTileManager = FireTileManager(self.screenWidth, self.screenHeight, self.tileWidth, self.tileHeight) self.iceTileManager = IceTileManager(self.screenWidth, self.screenHeight, self.tileWidth, self.tileHeight) self.grenadeManager = GrenadeManager(self.tileWidth, self.tileHeight, self.grenadeImage) self.bladeManager = BladeManager(self.screenWidth, self.screenHeight, self.tileWidth, self.tileHeight, self.bladeImage) self.gameClock = Clock() # End-level arrow data: self.arrowImage = arrowImage self.arrows = [] self.arrows.append( Arrow(self.arrowImage, (self.screenWidth / 2) - (self.tileWidth / 2), (self.tileHeight * 2) / 2, 90, 1, 20)) # create the top arrow self.arrows.append( Arrow(self.arrowImage, (self.screenWidth / 2) - (self.tileWidth / 2), self.screenHeight - ((self.tileHeight * 2) / 2), -90, 1, 20)) # create the bottom arrow self.arrows.append( Arrow(self.arrowImage, (self.tileWidth * 3) / 2, self.screenHeight / 2, 180, 2, 20)) # create the left arrow self.arrows.append( Arrow(self.arrowImage, self.screenWidth - ((self.tileWidth * 3) / 2), self.screenHeight / 2, 0, 2, 20)) # create the right arrow # Get level progression function (whether it's finished or not): def getLevelProgression(self): return self.isLevelFinished # Set the player spawn based off of level: def spawnPlayer(self, player): player.setX(self.playerSpawnX) player.setY(self.playerSpawnY) # Get tile size def getTileSize(self): return (self.tileWidth, self.tileHeight) # Load the level data to create blocks and spawners: def loadLevel(self): if self.level == 1: # Check if level chosen was level 1 levelData = self.levelDesigns.getLevel1( ) # Get the level Data of level 1 elif self.level == 2: # Check if the level chosen was level 2 levelData = self.levelDesigns.getLevel2( ) # Get the level Data of level 2 elif self.level == 3: # Check if the level chosen was level 3 levelData = self.levelDesigns.getLevel3( ) # Get the level Data of level 3 elif self.level == 4: # Check if level chosen was level 4 levelData = self.levelDesigns.getLevel4( ) # Get the level Data of level 4 elif self.level == 5: # Check if level chosen was level 5 levelData = self.levelDesigns.getLevel5( ) # Get the level Data of level 5 elif self.level == 6: # Check if level chosen was level 6 levelData = self.levelDesigns.getLevel6( ) # Get the level Data of level 6 elif self.level == 7: # Check if level chosen was level 7 levelData = self.levelDesigns.getLevel7( ) # Get the level Data of level 7 elif self.level == 8: # Check if level chosen was level 8 levelData = self.levelDesigns.getLevel8( ) # Get the level Data of level 8 elif self.level == 9: # Check if level chosen was level 9 levelData = self.levelDesigns.getLevel9( ) # Get the level Data of level 9 elif self.level == 10: # Check if level chosen was level 10 levelData = self.levelDesigns.getLevel10( ) # Get the level Data of level 10 x = 0 # Start X at 0 y = 0 # Start Y at 0 for row in levelData: # run a for loop for all the rows in level data for col in row: # run a for loop for all the colums in the row if col == "1": # check if the column section is labeled 1 self.Rects.append( pygame.Rect((x, y), (self.tileWidth, self.tileHeight))) # append a rectangle if col == "2": # check if the column section is labeled 2 self.Rects.append( pygame.Rect((x, y), (self.tileWidth, self.tileHeight))) # append a rectangle if col == "3": # check if the column section is labeled 3 self.zombieSpawners.append( ZombieSpawner( x, y, self.zombieManager, int(self.maxZombies / self.levelDesigns.getSpawnerAmount( self.level)), self.zombieSpawnTimeMin, self.zombieSpawnTimeMax, self.zombieVelMin, self.zombieVelMax, self.zombieHealth) ) # Initalize a zombie spawner with given data self.rotatingZombies.append(0) x += self.tileWidth # adjust x y += self.tileHeight # adjust y x = 0 # reset row self.levelData = levelData self.levelLoaded = True # Record where the room was entered for post-battle room transitioning def recordRoomEntrance(self, playerRect): if self.playerSpawnX == self.screenWidth - self.tileWidth: # if the player spawn x was the east entrance self.roomEntrance = "east" elif self.playerSpawnX == self.tileWidth: # if the player spawn x was the west entrance self.roomEntrance = "west" elif self.playerSpawnY >= self.screenHeight - self.tileHeight: # if the player spawn y was the south entrance self.roomEntrance = "south" elif self.playerSpawnY == 0: # if the player spawn y was the north entrance self.roomEntrance = "north" # Pass pygame events: def passEvent(self, event, soundManager): if event.type == pygame.MOUSEBUTTONDOWN: self.isMousePressed = True if event.type == pygame.MOUSEBUTTONUP: self.isMousePressed = False if event.type == pygame.MOUSEMOTION: self.mousex, self.mousey = event.pos if event.type == pygame.KEYDOWN: if event.key == pygame.K_r: self.bulletManager._reload(self.getGameClock(), self.stringManager, soundManager) # Use an item by calling it's ID def useItemById(self, item): if item == "distractionorb": self.addDistractionOrb = True elif item == "grenade": self.addGrenade = True elif item == "blade": self.addBlade = True elif item == "icetile": self.addIceTile = True # Update the current bullet type set in main def updateCurrentBulletType(self, bulletType): self.bulletType = bulletType # Check if a point collides with any of the blocks def checkPath(self, x, y): r = pygame.Rect((x, y), (1, 1)) for block in range(len(self.Rects)): if r.colliderect(self.Rects[block]): return False return True # Get game clock def getGameClock(self): return self.gameClock # Get total ammunition from bullet amanger def getAmmunition(self): return (self.bulletManager.getAmmo(), self.bulletManager.getMagazines()) # Set the accuracy level def setAccuracyLevel(self, accuracyLevel): self.accuracyLevel = accuracyLevel # Get the accuracy level def getAccuracyLevel(self): return self.accuracyLevel # Get the tile where the distraction orb will be based off of the mouse location def distractionOrb_setLocation(self, mousex, mousey): for i in range( int(self.screenHeight / self.tileHeight )): # run a for loop for the amount of tiles on the y axis for z in range( int(self.screenWidth / self.tileWidth) ): # run a for loop for the amount of tiles on the x axis tileRect = pygame.Rect( (z * self.tileWidth, i * self.tileHeight), (self.tileWidth, self.tileHeight )) # generate the tile as a pygame rectangle if tileRect.collidepoint( mousex, mousey ) == True: # check if the mouse lands on the tile self.distractionOrbRect = tileRect # place tile # Set distraction orb active def distractionOrb_setActive(self, activity): self.distractionOrbActive = activity self.distractionOrbTimer = Timer( 10, self.getGameClock().getElapsedSeconds()) # Add a magazine to the bullet manager def addMagazine(self, magazines): self.bulletManager.addMagazines(magazines) # Check if a point doesn't land on a level block def checkPointBlockCollision(self, x, y): for block in range(len(self.Rects)): # run a for loop for all blocks if self.Rects[block].collidepoint( x, y) == True: # if the point lands on the block return True # say that the point lands on one of the blocks for spawner in range(len(self.zombieSpawners) ): # run a for loop for all zombie spawners spawnerRect = pygame.Rect( (self.zombieSpawners[spawner].getX(), self.zombieSpawners[spawner].getY()), (self.tileWidth, self.tileHeight)) # generate a rect of spawner if spawnerRect.collidepoint( x, y) == True: # if the point lands on the block return True # say that the point lands on one of the spawners return False # return False if it hasn't returned true yet, because it means it hasn't landed on any blocks # Update level data & logic: def update(self, player, soundManager): if self.levelLoaded == False: # Check if the level was loaded self.loadLevel() newLevelString = "Crypt: %d" % self.cryptnum textInstance = self.notifyFont.render( newLevelString, True, (255, 0, 0)) # for size reference self.stringManager.addText( newLevelString, (0, 255, 0), self.notifyFont, ((self.screenWidth / 2) - (textInstance.get_width() / 2), self.screenHeight - (self.screenHeight * 0.75)), 4, -3, self.getGameClock()) # add the text for a new crypt if self.roomEntranceSet == False: # if the entrance hasn't been recorded self.recordRoomEntrance(player.getRect()) # set the room entrance self.roomEntranceSet = True self.gameClock.update(self.fps) self.zombieManager.update( player, self.gameClock, self.zombieParticleManager, self.distractionOrbActive, self.distractionOrbRect) # Update zombie manager """ CHECK IF THE LEVEL IS FINISHED """ if self.zombieManager.getZombiesKilled( ) >= self.maxZombies + 4: # check if the amount of zombies killed = the amount of every existing zombies self.isLevelFinished = True """ CHECK IF THE LEVEL IS FINISHED """ """ UPDATE DISTRACTION ORB """ if self.addDistractionOrb == True: # if the player pressed Q self.addDistractionOrb = False # switch/off to kill spam self.distractionOrb_setLocation(self.mousex, self.mousey) # place location self.distractionOrb_setActive( True) # set the distraction orb in the level active if self.distractionOrbActive == True: # if there currently is a distraction orb if self.distractionOrbTimer.getAlert( ) == True: # if the distraction orb is finished and must despawn self.distractionOrbActive = False # turn off the distraction orb else: # if not self.distractionOrbTimer.update(self.getGameClock( ).getElapsedSeconds()) # update the distraction orb timer """ UPDATE DISTRACTION ORB """ """ UPDATE GRENADES """ if self.addGrenade == True: self.addGrenade = False self.grenadeManager.addGrenade(player.getRect().center[0], player.getRect().center[1], self.mousex, self.mousey) # spawn a grenade self.grenadeManager.update(self.Rects, self.zombieManager.getZombies(), player) """ UPDATE GRENADES """ """ UPDATE BLADES """ if self.addBlade == True: # if the player pressed C self.addBlade = False # turn off to kill spam self.bladeManager.addBlade(self.mousex, self.mousey, self.getGameClock()) # add blade """ UPDATE BLADES """ """ ADD ICE TILE """ if self.addIceTile == True: # if player pressed v self.addIceTile = False # turn off to kill spam self.iceTileManager.addTile(self.mousex, self.mousey, self.getGameClock()) # add a tile """ ADD ICE TILE """ """ SHOOT A BULLET """ if self.isMousePressed == True and player.getRunningStatus( ) == False and player.getRect().collidepoint( self.mousex, self.mousey ) == False and self.bulletManager.isReloading( ) == False: # Check if player clicked and if the player isn't running and check if the mouse isn't overlapping the player and they aren't reloading soundManager.playSound("bang") # play the bullet shoot sound self.isMousePressed = False # Set to false to prevent bullet Spam self.bulletManager.addBullet(player.getX(), player.getY(), self.mousex, self.mousey, self.getAccuracyLevel(), self.bulletType) # create a bullet """ CHECK PLAYER COLLISION WITH WALLS """ for i in range(1, 5): # run a for loop for all player walls player.setCollisionBound( i, False) # default all wall collisions to be false for block in range(len( self.Rects)): # run a for loop for all existing blocks for wall in range(1, 5): # run a for loop for all walls if player.getWall(wall).colliderect( self.Rects[block] ): # Check if the current wall collided with the current block player.setCollisionBound(wall, True) """ CHECK PLAYER COLLISION WITH WALLS """ """ CHECK IF THE ZOMBIES COLLIDED WITH THE FIRE & ICE TILES """ self.zombieManager.checkFireTileCollision( self.fireTileManager, self.getGameClock()) # update to set zombies on fire self.zombieManager.checkIceTileCollision( self.iceTileManager, self.getGameClock()) # update to set zombies frozen """ CHECK IF THE ZOMBIES COLLIDED WITH THE FIRE & ICE TILES """ """ CHECK BULLET COLLISION WITH WALLS """ if self.bulletManager.getBulletAmount() > 0: # check if bullets exist bulletX = self.bulletManager.getBulletLocationX( ) # import bullet x array bulletY = self.bulletManager.getBulletLocationY( ) # import bullet y array for bullet in range(self.bulletManager.getBulletAmount() ): # run a for loop for all bullets if self.bulletManager.getBulletActivity( bullet ) == True: # check if the bullet is active before any relevant code happens bx = bulletX[bullet] - int( self.bulletManager.getBulletRadius(bullet) / 2) # Set the bullet X as if it was a rectangle by = bulletY[bullet] - int( self.bulletManager.getBulletRadius(bullet) / 2) # Set the bullet Y as if it was a rectangle bl = self.bulletManager.getBulletRadius( bullet ) * 2 # Set the Width & Height (Length) of the bullet as if it was a rectangle bulletRect = pygame.Rect( (bx, by), (bl, bl)) # Create the Rectangle with the created Data for block in range(len( self.Rects)): # run a for loop for all blocks if bulletRect.colliderect(self.Rects[block]) == True: if self.bulletManager.getBulletType( bullet) != "bouncy": self.bulletManager.setBulletActivity( bullet, False) else: # if the bullet type is bouncy if self.bulletManager.getBouncyBulletBounces( bullet ) >= 3: # if it's bounced 3 times self.bulletManager.setBulletActivity( bullet, False) # set the bullet inactive else: _block = self.Rects[block] blockTop = pygame.Rect( (_block.x - 1, _block.y - 1), (_block.width + 1, 3)) blockBottom = pygame.Rect( (_block.x, _block.y + _block.height - 1), (_block.width + 1, 2)) blockLeft = pygame.Rect( (_block.x - 1, _block.y - 1), (2, _block.height + 1)) blockRight = pygame.Rect( (_block.x + _block.width - 1, _block.y - 1), (3, _block.height + 1)) if blockTop.colliderect( bulletRect ) or blockBottom.colliderect(bulletRect): self.bulletManager.flipVectorY( bullet) # flip direction Y if blockLeft.colliderect( bulletRect ) or blockRight.colliderect(bulletRect): self.bulletManager.flipVectorX( bullet) # flip direction X self.bulletManager.lungeBullet(bullet) self.bulletManager.addBouncyBulletBounce( bullet) """ CHECK BULLET COLLISION WITH WALLS """ """ IF A BLOCK IS INCOMING. GO AROUND IT PATHFINDING""" for zombie in range(len(self.zombieManager.getZombies()) ): # run a for loop for all zombies if self.zombieManager.getZombies()[zombie].getLifeStatus( ) == True: # check if the zombie is alive before you do anything with it for block in range(len( self.Rects)): # run a for loop for all blocks if self.zombieManager.getZombies( )[zombie].getCollisionRect().colliderect( self.Rects[block] ) == True: # Check if the zombie is colliding with the block in the first place differenceX = self.zombieManager.getZombies( )[zombie].getCollisionRect( ).center[0] - self.Rects[block].center[0] differenceY = self.zombieManager.getZombies( )[zombie].getCollisionRect( ).center[1] - self.Rects[block].center[1] if differenceX < 0: differenceX *= -1 if differenceY < 0: differenceY *= -1 if differenceX <= self.Rects[ block].width / 2 and differenceX >= 0 and differenceY <= self.Rects[ block].height / 2 and differenceY >= 0: # Check if the zombie's collision rectangle's midleft x is in between the block center and the right side of the block if self.zombieManager.getZombies()[zombie].getRect( ).midleft[0] < self.Rects[block].center[0] + self.Rects[ block].width and self.zombieManager.getZombies( )[zombie].getCollisionRect( ).midleft[0] > self.Rects[block].center[0]: self.zombieManager.getZombies( )[zombie].setCollisionBound( 1, True ) # Tell the zombie's left wall is collided zombieLeftSide = self.zombieManager.getZombies( )[zombie].getCollisionRect().midleft[0] self.zombieManager.getZombies( )[zombie].translate( self.Rects[block].midright[0] - zombieLeftSide, 0 ) # Translate the zombie away from the wall ( to the right) # Check if the zombie's collision rectangle's midright x is in between the block center and the left side of the block if self.zombieManager.getZombies()[zombie].getRect( ).midright[0] > self.Rects[block].center[ 0] - self.Rects[ block].width and self.zombieManager.getZombies( )[zombie].getCollisionRect().midright[ 0] < self.Rects[block].center[0]: self.zombieManager.getZombies( )[zombie].setCollisionBound( 2, True ) # Tell the zombie's right wall is collided zombieRightSide = self.zombieManager.getZombies( )[zombie].getCollisionRect().midright[0] self.zombieManager.getZombies( )[zombie].translate( self.Rects[block].midleft[0] - zombieRightSide, 0 ) # Translate the zombie away from the wall ( to the left ) # Check if the zombie's collision rectangle's midtop y is in between the block center and the bottom side of the block if self.zombieManager.getZombies()[zombie].getRect( ).midtop[1] < self.Rects[block].center[1] + self.Rects[ block].height and self.zombieManager.getZombies( )[zombie].getCollisionRect( ).midtop[1] > self.Rects[block].center[1]: self.zombieManager.getZombies( )[zombie].setCollisionBound( 3, True ) # Tell the zombie's top wall is collided zombieTopSide = self.zombieManager.getZombies( )[zombie].getCollisionRect().midtop[1] self.zombieManager.getZombies( )[zombie].translate( 0, self.Rects[block].midbottom[1] - zombieTopSide ) # Translate the zombie away from the wall ( to the bottom ) # Check if the zombie's collision rectangle's midbottom y is in between the block center and the top side of the block elif self.zombieManager.getZombies( )[zombie].getRect().midbottom[1] > self.Rects[ block].center[1] - self.Rects[ block].height and self.zombieManager.getZombies( )[zombie].getCollisionRect().midbottom[ 1] < self.Rects[block].center[1]: self.zombieManager.getZombies( )[zombie].setCollisionBound( 4, True ) # Tell the zombie's bottom wall is collided zombieBottomSide = self.zombieManager.getZombies( )[zombie].getCollisionRect().midbottom[1] self.zombieManager.getZombies( )[zombie].translate( 0, self.Rects[block].midtop[1] - zombieBottomSide) """ IF A BLOCK IS INCOMING, GO AROUND IT PATHFINDING """ """ CHECK ZOMBIE COLLISION WITH WALLS """ for zombie in range(len(self.zombieManager.getZombies())): if self.zombieManager.getZombies()[zombie].getLifeStatus() == True: if self.zombieManager.getZombies()[zombie].getRect( ).colliderect(player.getRect( )) != True: # if they are not colliding with the player currentZombie = self.zombieManager.getZombies()[zombie] for block in range(len(self.Rects)): if currentZombie.getDX( ) > 0: # if the zombie's current disp. is heading right midRightRect = pygame.Rect( (currentZombie.getCollisionRect().midright[0] + currentZombie.getVelocity(), currentZombie.getCollisionRect().midright[1]), (1, 1)) # set a rectangle in upcoming unit if midRightRect.colliderect( self.Rects[block] ) == True: # if the area they are approaching has a block currentZombie.setD( 0, -currentZombie.getVelocity() ) # stop the zombie from going in that direction and have them head upwards if currentZombie.getDX( ) < 0: # if the zombie's current disp. is heading left midLeftRect = pygame.Rect( (currentZombie.getCollisionRect().midleft[0] - currentZombie.getVelocity(), currentZombie.getCollisionRect().midleft[1]), (1, 1)) # set a rectangle in upcoming unit if midLeftRect.colliderect( self.Rects[block] ) == True: # if the area they are approaching has a block currentZombie.setD( 0, currentZombie.getVelocity() ) # stop the zombie from going in that direction and have them head downwards if currentZombie.getDY( ) > 0: # if the zombie's current disp. is heading down midBottomRect = pygame.Rect( (currentZombie.getCollisionRect().midbottom[0], currentZombie.getCollisionRect().midbottom[1] + currentZombie.getVelocity()), (1, 1)) # set a rectangle in upcoming direction if midBottomRect.colliderect( self.Rects[block] ) == True: # if the area they are approaching has a block currentZombie.setD( currentZombie.getVelocity(), 0 ) # stop the zombie from going in that direction and have them head to the right if currentZombie.getDY( ) < 0: # if the zombie's current disp. is heading up midTopRect = pygame.Rect( (currentZombie.getCollisionRect().midtop[0], currentZombie.getCollisionRect().midtop[1] - currentZombie.getVelocity()), (1, 1)) # set a rectangle in upcoming direction if midTopRect.colliderect( self.Rects[block] ) == True: # if the area they are approaching has a block currentZombie.setD( -currentZombie.getVelocity(), 0 ) # stop the zombie from going in that direction and have them head to the left #if currentZombie.getDX() > 0 and currentZombie.getDY() > 0: # if the zombie is going northeast direction #northEastRect = pygame.Rect((currentZombie.getCollisionRect().),()) """ CHECK ZOMBIE COLLISION WITH WALLS """ """ MANAGE COLLISION WITH BLOOD PARTICLES """ for particle in range(self.bloodExplosionManager.getLength()): if self.bloodExplosionManager.getParticleActive(particle) == True: if player.getRect().collidepoint( self.bloodExplosionManager.getX(particle), self.bloodExplosionManager.getY(particle) ) == True: # if the player rect overlaps the current particle self.bloodExplosionManager.setParticleActive( particle, False) # set that particle inactive for block in range(len( self.Rects)): # run a for loop for all blocks if self.Rects[block].collidepoint( self.bloodExplosionManager.getX(particle), self.bloodExplosionManager.getY(particle) ) == True: # if the current block overlaps current particle self.bloodExplosionManager.setParticleActive( particle, False) # set that particle inactive """ MANAGE COLLISION WITH BLOOD PARTICLES """ """ CHECK IF ANY ICE TILES / FIRE TILES OVERLAP, DELETE IF SO """ for iceTile in range(len(self.iceTileManager.getTiles()) ): # run a for loop for all ice tiles if self.iceTileManager.getActive( iceTile) == True: # if the ice tile is active for fireTile in range(len(self.fireTileManager.getTiles()) ): # run a for loop for all fire tiles if self.fireTileManager.getActive( fireTile) == True: # if the fire tile is active if self.iceTileManager.getTiles()[iceTile].colliderect( self.fireTileManager.getTiles()[fireTile] ) == True: # if the ice tile is overlapping with the fire tile self.iceTileManager.setActive( iceTile, False) # set ice tile inactive self.fireTileManager.setActive( fireTile, False) # set fire tile inactive """ CHECK IF ANY ICE TILES / FIRE TILES OVERLAP, DELETE IF SO """ """ UPDATE ARROW TRANSLATIONS """ if self.getLevelProgression() == True: # if the level was completed for arrow in range(len( self.arrows)): # run a for loop for all arrows self.arrows[arrow].update(self.gameClock.getElapsedFrames() ) # update the arrows translations """ UPDATE ARROW TRANSLATIONS """ """ UPDATING ROTATING ZOMBIES IN SPAWNERS """ for zombie in range(len(self.zombieSpawners)): self.rotatingZombies[zombie] += 6 if self.rotatingZombies[zombie] >= 360: self.rotatingZombies[zombie] = 0 """ UPDATING ROTATING ZOMBIES IN SPAWNERS """ """ MANAGE LEVEL RESPONSIBILITIES """ if self.isLevelFinished == False: # If the level isn't finished (secondary measure): for spawner in range(len(self.zombieSpawners) ): # Run a for loop for all zombie spawners self.zombieSpawners[spawner].update( self.gameClock) # Update Zombie Spawners self.bulletManager.update(self.getGameClock(), self.stringManager, soundManager) # Update bullets if self.distractionOrbActive == True: # if the distraction orb is active self.zombieManager.finalUpdate( self.distractionOrbRect, self.getGameClock( )) # post-collision zombie update, have it face D_ORB else: # if the distraction orb is not active self.zombieManager.finalUpdate( player.getRect(), self.getGameClock()) # Post-collision zombie update self.zombieManager.checkBulletCollision( soundManager, self.bulletManager.getBulletLocationX(), self.bulletManager.getBulletLocationY(), self.bulletManager, player, self.bloodExplosionManager, self.fireTileManager, self.bulletType, self.getGameClock( )) # check the bullet collision between the bullets and zombies self.stringManager.update(self.getGameClock()) self.bloodExplosionManager.update() self.zombieParticleManager.update() self.fireTileManager.update(self.getGameClock()) self.iceTileManager.update(self.getGameClock()) self.bladeManager.update(self.zombieManager.getZombies(), player, self.getGameClock()) """ MANAGE LEVEL RESPONSIBILITIES """ # Check zombie to player collision def checkZombiePlayerCollision(self, player, soundManager): for zombie in range(len(self.zombieManager.getZombies()) ): # run a for loop for all zombies if self.zombieManager.getZombies()[zombie].getLifeStatus() == True: if self.zombieManager.getZombies()[zombie].getAttackStatus( ) == True: if self.zombieManager.getZombies()[zombie].getRect( ).colliderect(player.getRect( )): # if the current zombie is colliding with the player soundManager.playSound( "attack") # play the zombie attack sound player.giveHealth(-1) # take 1 hp away from the player playerVec = Vec2d(player.getRect().center[0], player.getRect().center[1]) zombieVec = Vec2d( self.zombieManager.getZombies() [zombie].getRect().center[0], self.zombieManager.getZombies() [zombie].getRect().center[1]) playerToZombieVec = Vec2d(playerVec - zombieVec) playerToZombieVec = playerToZombieVec.normalized() # translate to the player ( Lunge like ) by half the width and height of it's collision rectangle self.zombieManager.getZombies()[zombie].translate( playerToZombieVec[0] * (player.getRect().width / 2), playerToZombieVec[1] * (player.getRect().height / 2)) self.zombieManager.setZombieAttacked( zombie, self.getGameClock()) # Draw the zombie speech string: zombieQuotes = [ "Scratch!", "Swipe!", "Chomp!", "Slash!", "Whack!", "Slam!", "Grrgah!", "Kick!", "Bite!", "Stomp!" ] zombieSpeech = random.randint( 0, 9) # Select out of the 4 speeches zombieSpeech = zombieQuotes[zombieSpeech] font = pygame.font.SysFont("Trebuchet MS", 10) self.stringManager.addText( zombieSpeech, (255, 25, 25), font, self.zombieManager.getZombies() [zombie].getRect().center, 1, -1, self.getGameClock()) font = None # Delete from memory # Get the velocity of the last spawned zombie def getLatestZombieVelocity(self): return self.zombieManager.getZombies()[ len(self.zombieManager.getZombies()) - 1].getVelocity() # Get the amount of zombies spawned: def getZombiesSpawned(self): zombiesSpawned = 0 for spawner in range(len(self.zombieSpawners)): zombiesSpawned += self.zombieSpawners[spawner].getZombiesSpawned() return zombiesSpawned # Draw relevant level data (Zombies, bullet's, blocks, spawners) def draw(self, canvas, playerRect): canvas.blit(self.background, (0, 0)) # draw background image # Draw arrows: if self.getLevelProgression() == True: # if level is finished if self.getRoomEntrance( playerRect ) != "north": # if the player entrance isn't north self.arrows[0].draw(canvas) # draw north arrow if self.getRoomEntrance( playerRect ) != "south": # if the player entrance isn't south self.arrows[1].draw(canvas) # draw south arrow if self.getRoomEntrance( playerRect) != "west": # if the player entrance isn't west self.arrows[2].draw(canvas) # draw west arrow if self.getRoomEntrance( playerRect) != "east": # if the player entrance isn't east self.arrows[3].draw(canvas) # draw east arrow for rect in range(len(self.Rects)): # for loop to run all rects canvas.blit( self.block, (self.Rects[rect].x, self.Rects[rect].y)) #draw a block for spawner in range(len(self.zombieSpawners)): pygame.draw.rect(canvas, (153, 0, 0), (self.zombieSpawners[spawner].getX(), self.zombieSpawners[spawner].getY(), self.tileWidth, self.tileHeight), 0) zombie = pygame.transform.rotate(self.tileZombie, self.rotatingZombies[spawner]) zombieRect = zombie.get_rect( center=(self.zombieSpawners[spawner].getX() + int(self.tileWidth / 2), self.zombieSpawners[spawner].getY() + int(self.tileHeight / 2))) if self.zombieSpawners[spawner].getActive() == True: canvas.blit(zombie, zombieRect) canvas.blit(self.zblock, (self.zombieSpawners[spawner].getX(), self.zombieSpawners[spawner].getY())) if self.distractionOrbActive == True: # if there is currently a distraction orb placed canvas.blit(self.distractionOrb, self.distractionOrbRect) # draw the distraction Orb self.bladeManager.draw(canvas) self.iceTileManager.draw(canvas) # draw ice tiles self.fireTileManager.draw(canvas) # draw fire tiles self.bulletManager.draw(canvas, playerRect) # draw bullets self.zombieManager.draw(canvas) # draw zombies self.grenadeManager.draw(canvas) # draw grenades self.bloodExplosionManager.draw(canvas) # draw blood explosions self.zombieParticleManager.draw( canvas) # draw zombie fire/frost particles self.stringManager.draw(canvas) # draw texts # Get where the room entrance was: def getRoomEntrance(self, playerRect): if self.roomEntranceSet == False: # if the room entrance wasn't recorded yet self.recordRoomEntrance(playerRect) # record the rooms entrance self.roomEntranceSet = True # say that the room entrance was recorded return self.roomEntrance # Dispose of level (Data, set everything to inactive) def dispose(self): for spawner in range(len(self.zombieSpawners)): self.zombieSpawners[spawner].dispose() self.zombieManager.dispose( ) # dispose of all zombies and zombieManager self.bulletManager.dispose( ) # dispose of all bullets and bulletManager self.stringManager.dispose() # dispose of all the strings self.bloodExplosionManager.dispose() # dispose of all blood explosions self.zombieParticleManager.dispose() # dispose of all zombie particles
class ZombieSpawner(object): # Call Constructor def __init__(self, x, y, zombieManager, maxZombies, spawnTimeMin, spawnTimeMax, minVel, maxVel, hp): self.x = x self.y = y self.zombieManager = zombieManager self.maxZombies = maxZombies self.zombiesSpawned = 0 self.spawnTimeMin = spawnTimeMin self.spawnTimeMax = spawnTimeMax self.minVel = minVel self.maxVel = maxVel self.hp = hp self.spawnZombie = False self.zombieSpawned = True self.firstZombieSpawned = False self.spawnerActive = True # Get spawner location x def getX(self): return self.x # Get spawner location y def getY(self): return self.y # Get activity def getActive(self): return self.spawnerActive # Get amount of zombies spawner has spawned: def getZombiesSpawned(self): return self.zombiesSpawned # Spawn Zombie def spawn(self): self.zombieSpawned = False # say the zombie hasnt spawned yet vel = random.randint(self.minVel, self.maxVel) self.zombieManager.addZombie(self.x, self.y, vel, self.hp) self.zombiesSpawned += 1 self.zombieSpawned = True # Begin Timer def begin(self, game_clock): self.timeTillNextZombie = random.randint( self.spawnTimeMin, self.spawnTimeMax) # get the time till get a next zombie self.timer = Timer( self.timeTillNextZombie, game_clock.getElapsedSeconds() ) # begin the timer, at the length of the var above and give the currents seconds elapsed # Manage Zombies def update(self, game_clock): if self.spawnerActive == True: if self.zombiesSpawned <= self.maxZombies: if self.firstZombieSpawned == False: # Check if the first zombie has spawned self.firstZombieSpawned = True # Say that the first zombie has spawned self.spawn() # spawn the first zombie if self.zombieSpawned == True: # check if a zombie has finished spawning self.zombieSpawned = False # turn it off to reduce spam self.begin(game_clock) # begin a timer for the next zombie self.timer.update( game_clock.getElapsedSeconds() ) # Update the timer, give the elapsed seconds in the _internal.gameclock if self.timer.getAlert( ) == True: # check if the timer finished self.spawn() # spawn a new zombie else: self.spawnerActive = False # Dispose of spawner def dispose(self): self.spawnerActive = False
class Blade(object): # Call constructor def __init__(self, rect, image, timeLength, secondsElapsed): self.Rect = rect self.image = image self.texture = self.image #self.texture is the transform of self.image self.rotation = 0 self.rotationVel = 12 self.active = True self.existenceTimer = Timer(timeLength, secondsElapsed) self.zombiesDamaged = [] self.zombiesDamagedTimer = [] # Get if the blade is active def getActive(self): return self.active # Set if the blade is active def setActive(self, activity): self.active = activity # Get the rectangle def getRect(self): return self.Rect # Set the rectangle def setRect(self, rect): self.Rect = rect # Check if you can attack a zombie def canAttack(self, zombie, secondsElapsed): for attackedZombie in range(len(self.zombiesDamaged)): # run a for loop for all attacked zombies if self.zombiesDamaged[attackedZombie] == zombie: # if the current attacked zombie is the current zombie for currentTimer in range(len(self.zombiesDamagedTimer)): # run a for loop for all zombie attack timers timer = self.zombiesDamagedTimer[currentTimer] # unpack tuple if timer[0] == zombie: # if the timer is assigned for this current zombie break # end the timer for loop timer = None # if it's reached this point than the zombie has no timer if timer != None: # if a timer was found if timer[1].getAlert() == True: # if it's attack timer has finished return True # say it can attack else: timer[1].update(secondsElapsed) # update the timer return False # say it can't attack return True # if it's gotten to this point, it has no timer therefore can attack # Update the blade def update(self, zombies, player, game_Clock): if self.existenceTimer.getAlert() == True: # if the blade is finished self.setActive(False) # Set the blade inactive else: # UPDATE BLADE: self.existenceTimer.update(game_Clock.getElapsedSeconds()) # update existence timer # Rotate blade: self.rotation += self.rotationVel self.texture = pygame.transform.rotate(self.image, self.rotation) self.setRect(self.texture.get_rect(center=(self.getRect().center))) # Center blade # Check collision with zombies: for zombie in range(len(zombies)): # run a for loop for all zombies if zombies[zombie].getLifeStatus() == True: # check if the zombie is active if self.Rect.colliderect(zombies[zombie].getRect()) == True and self.canAttack(zombie, game_Clock.getElapsedSeconds()) == True: # if the blade collides with the zombie and can attack it zombies[zombie].changeHealth(-2) player.addScore(2) # give the player 2 score self.zombiesDamaged.append(zombie) self.zombiesDamagedTimer.append((zombie, Timer(1, game_Clock.getElapsedSeconds()))) # set a timer for when the blade can attack the zombie again # Draw the blade def draw(self, canvas): canvas.blit(self.texture, self.getRect()) # draw blade with rotation
class BulletManager(object): # Call constructor def __init__(self, screenWidth, screenHeight, notifyFont, ammo, magAmmo, reloadTime): self.screenWidth = screenWidth self.screenHeight = screenHeight self.bullets = 0 self.bulletx = [] self.bullety = [] self.bulletv = [] self.bullet_isActive = [] self.bulletType = [] self.bulletSpeed = 8 self.bulletStartingRadius = 5 self.bulletRadius = [] self.bouncyBulletBounces = [] self.reloading = False self.magSize = ammo # set the max ammo in a mag self.ammo = ammo # ammo per mag self.magAmmo = magAmmo # ammo in magazines self.magAmmoDeducted = 0 # ammo taken from magazines when reloading self.reloadTime = reloadTime self.reloadTimer = None self.outOfAmmo = False self.notifyFont = notifyFont # Create a bullet def createBullet(self, spawnx, spawny, mousex, mousey, accuracyLevel, bulletType): self.bulletType.append(bulletType) self.bullet_isActive.append(True) displacement = 0 if bulletType == "spray": displacement = random.randint(0, 16) self.bulletx.append(spawnx - displacement) # Add a bullet x self.bullety.append(spawny - displacement) # Add a bullet y self.bulletRadius.append( self.bulletStartingRadius) # Add a bullet radius self.bouncyBulletBounces.append(0) if bulletType == "spray": _accuracyLevel = accuracyLevel + random.randint(20, 40) else: _accuracyLevel = accuracyLevel accuracy = random.randint(0, _accuracyLevel) playerVector = Vec2d(spawnx, spawny) directionX = random.randint(mousex - accuracy, mousex + accuracy) directionY = random.randint(mousey - accuracy, mousey + accuracy) directionVector = Vec2d(directionX, directionY) self.bulletv.append(Vec2d(directionVector - playerVector)) # Add a bullet vector self.bulletv[self.bullets] = self.bulletv[self.bullets].normalized( ) # normalize the vector just made to minimal length self.bullets += 1 # Increase bullets by 1 (for offset usage) self.ammo -= 1 # take away 1 ammo # Create a new bullet method def addBullet(self, spawnx, spawny, mousex, mousey, accuracyLevel, bulletType): if self.ammo > 0: if bulletType == "spray": # if the bullet type is spray for i in range(3): # create 3 bullets self.createBullet(spawnx, spawny, mousex, mousey, accuracyLevel, bulletType) else: self.createBullet(spawnx, spawny, mousex, mousey, accuracyLevel, bulletType) # Return bullet array location (x) def getBulletLocationX(self): return self.bulletx # Bullet x array # Return bullet array location (y) def getBulletLocationY(self): return self.bullety # Bullet y array # Get specific location of bullet (x, y) def getSpecificBulletLocation(self, b): return (self.bulletx[b], self.bullety[b]) # Get specific vector of bullet (v) def getSpecificBulletVector(self, b): return self.bulletv[b] # Set specific vector bullet (v) def setSpecificBulletVector(self, b, v): self.bulletv[b] = v # Flip the Y direction of a bullet def flipVectorY(self, b): vectorX = self.getSpecificBulletVector(b).x vectorY = self.getSpecificBulletVector(b).y vectorY *= -1 vector = (vectorX, vectorY) self.setSpecificBulletVector(b, Vec2d(vector)) # Flip the X direction of a bullet def flipVectorX(self, b): vectorX = self.getSpecificBulletVector(b).x vectorY = self.getSpecificBulletVector(b).y vectorX *= -1 vector = (vectorX, vectorY) self.setSpecificBulletVector(b, Vec2d(vector)) # Flip the vector def flipVector(self, b): vector = self.getSpecificBulletVector(b) vector *= -1 self.setSpecificBulletVector(b, Vec2d(vector)) # Set specific location of bullet (x, y) def setSpecificBulletLocation(self, b, x, y): self.bulletx[b] = x self.bullety[b] = y # Return bullet array radius (r) def getBulletRadius(self, bullet): return self.bulletRadius[bullet] # Set the radius of the bullet def setBulletRadius(self, bullet, radius): self.bulletRadius[bullet] = radius # Set the activity of the bullet def setBulletActivity(self, bullet, activity): self.bullet_isActive[bullet] = activity # Get the activity of the bullet def getBulletActivity(self, bullet): return self.bullet_isActive[bullet] # Get the number of bullets existing def getBulletAmount(self): return self.bullets # Get bullet activity def getBulletActivity(self, b): return self.bullet_isActive[b] # Get bullet type def getBulletType(self, b): return self.bulletType[b] # Get the amount of times a bouncy bullet has bounced def getBouncyBulletBounces(self, b): return self.bouncyBulletBounces[b] # Add a bouncy bullet bounce def addBouncyBulletBounce(self, b): self.bouncyBulletBounces[b] += 1 # Get ammunition def getAmmo(self): return self.ammo # Get magazines def getMagazines(self): return self.magAmmo # Add magazines def addMagazines(self, magazines): self.magAmmo += self.magSize * magazines # Get reloading status def isReloading(self): return self.reloading # Lunge a bouncy bullet away from the block def lungeBullet(self, b): bulletpos = self.bulletx[b], self.bullety[b] # throw loc in tuple bulletpos += self.bulletv[b] * (self.bulletRadius[b] * 6 ) # add to the tuple via vector tuple self.bulletx[b], self.bullety[ b] = bulletpos # unpack tuple back to original variables # Reload ammo def _reload(self, game_Clock, stringManager, soundManager): soundManager.playSound("reload") # play the reload sound self.reloadTimer = Timer( self.reloadTime, game_Clock.getElapsedSeconds()) # start the reloading timer self.reloading = True # notify that they are currently reloading if self.magAmmo >= self.magSize: # if they have enough ammo to deduct a full magazine self.magAmmo -= self.magSize - self.ammo # deduct 1 magazine self.magAmmoDeducted = self.magSize - self.ammo else: # if not self.magAmmoDeducted = self.magAmmo self.magAmmo = 0 self.ammo = 0 # take away ammo just incase the player reloading with excess self.outOfAmmo = False # set that the player still has ammo # notify player through string manager that player is reloading # textInstance = self.notifyFont.render( "Reloading!...", True, (255, 0, 0)) # for size reference stringManager.addText("Reloading!...", (0, 255, 0), self.notifyFont, ((self.screenWidth / 2) - (textInstance.get_width() / 2), self.screenHeight - (self.screenHeight * 0.75)), 4, -3, game_Clock) # notify player through string manager that player is reloading # # Update method: def update(self, game_Clock, stringManager, soundManager): if self.bullets > 0: # check if bullets exist # UPDATE BULLETS: for i in range(self.bullets): # for loop of all bullets if self.bullety[i] < -10 or self.bullety[ i] > self.screenHeight + 10: #Only translate if it's within bounds self.bullet_isActive[i] = False if self.bullet_isActive[i] == True: """ Upcoming Tuple transfer. This may seem inefficient but it's like getters and setters, technically superior.""" bulletpos = self.bulletx[i], self.bullety[ i] # throw loc in tuple bulletpos += self.bulletv[ i] * self.bulletSpeed # add to the tuple via vector tuple self.bulletx[i], self.bullety[ i] = bulletpos # unpack tuple back to original variables """ This process is called a tuple transfer. Since it's safer then referencing the vector tuple by it's index""" # UPDATE RELOAD SYSTEM: if self.ammo <= 0: # if the player finished their magazine if self.magAmmo > 0 and self.reloading == False: # check if they have magazines left and the reload start wasn't already called self._reload(game_Clock, stringManager, soundManager) else: self.outOfAmmo = True # set that the player is out of ammo if self.reloading == True: if self.reloadTimer.getAlert( ) == True: # check if the timer finished self.ammo = self.magAmmoDeducted # give player ammo self.reloading = False # notify manager that it's finished reloading self.reloadTimer = None # delete timer else: # if the timer hasn't finished self.reloadTimer.update( game_Clock.getElapsedSeconds()) # update timer # Draw method: def draw(self, canvas, playerRect): if self.bullets > 0: # see if bullets exist for i in range(self.bullets): # Loop for all bullets if self.bullet_isActive[ i] == True: # Check if the bullet is active b_rect = pygame.Rect( (self.bulletx[i], self.bullety[i]), (self.bulletRadius[i], self.bulletRadius[i] )) # Create temporary rectangle for current bullet if b_rect.colliderect( playerRect ) != True: # Condition: If the bullet rect isn't overlapping player rect if self.getBulletType(i) == "normal": color = (0, 0, 0) # black elif self.getBulletType(i) == "bouncy": color = (255, 105, 180) # hot pink elif self.getBulletType(i) == "explosive": color = (160, 82, 45) # sienna brown elif self.getBulletType(i) == "spray": color = (255, 255, 0) # yellow elif self.getBulletType(i) == "flame": color = (255, 69, 0) # orangish red pygame.draw.circle( canvas, color, (int(self.bulletx[i]), int(self.bullety[i])), self.getBulletRadius(i), 0) # Draw bullet # Dispose of all bullets: def dispose(self): for bullet in range( self.getBulletAmount()): # run a for loop for all bullets self.setBulletActivity(bullet, False) # kill all bullets # Kill all arrays self.bulletRadius = [] self.bulletx = [] self.bullety = [] self.bulletv = [] self.bullet_isActive = []