def main(): init() global width, height, animator size = width, height = 1920, 1080 screen = pygame.display.set_mode(size, FULLSCREEN) gameClock = time.Clock() animator = Animation() #load default background background = pygame.sprite.Group() bg1 = SpriteRemix.Background(transform.scale(image.load("Assets\\backgrounds\outsidebg.png").convert(),(1920,1080))) bg2 = SpriteRemix.Background(transform.scale(image.load("Assets\\backgrounds\outsidebg.png").convert(),(1920,1080))) bg1.stateVal = 1 #slowscroll bg2.stateVal = 1 #slowscroll bg1.add(background) bg2.add(background) #load ui, TODO: encapsulate this shit ui = pygame.sprite.Group() health = SpriteRemix.UI(transform.scale(image.load("Assets\\sprites\\ui\\health.png").convert(),(596,72))) healthbar = SpriteRemix.UI(transform.scale(image.load("Assets\\sprites\\ui\\healthbar.png").convert_alpha(),(840,84))) health.add(ui) healthbar.add(ui) #create cursor and add it to a sprite group, can only hold 1 cursor at a time cursors = pygame.sprite.GroupSingle() crsr = SpriteRemix.Cursor(transform.scale(pygame.image.load("Assets\\sprites\\cursors\\crosshair1.png").convert_alpha(),(70,70))) crsr.add(cursors) #create pc and add it to a sprite group #TODO: need an initializer class for player that loads projectiles and weapons and shit pc = pygame.sprite.Group() playerSprite = PlayerCharacterSprite() animator.load(playerSprite) playerSprite.add(pc) #weapon, this shit is f*****g retarded pcAccessory = pygame.sprite.Group() playerWeapon = SpriteRemix.Weapon() animator.load(playerWeapon) playerWeapon.add(pcAccessory) #create baddies and add them to a sprite group baddies = sprite.Group() baddySprite = EnemyCharacterSprite("notzigrunt") animator.load(baddySprite) baddySprite.add(baddies) #create doodads and add them to a sprite group doodads = sprite.Group() box = SpriteRemix.Doodad(pygame.image.load("Assets\\sprites\\doodads\\box.png").convert()) #alsoBox = Doodad(pygame.image.load("Assets\\sprites\\doodads\\box.png").convert()) box.add(doodads) #alsoBox.add(doodads) #initialize projectile sprite group (obv nothing to put here at startup projectiles = sprite.Group() #floating combat text combatTextArr = [] #place everything bg1.rect.topleft = [-1920,0] bg2.rect.topleft = [0,0] healthbar.rect.topleft = [50,50] health.rect.topleft = [healthbar.rect.left+239, healthbar.rect.top+5] playerSprite.rect.bottomleft = [100,height-50] playerWeapon.rect.midright = playerSprite.rect.midleft baddySprite.rect.bottom = height baddySprite.rect.left = 960 box.rect.left = 540 box.rect.bottom = height '''alsoBox.rect.left = 920 alsoBox.rect.bottom = height''' #create a list of all sprite groups entities = [pc.sprites(), baddies.sprites()] sprites = [pc, pcAccessory, baddies, doodads, projectiles, background, ui, cursors] while 1: now = time.get_ticks() #this for loop processes all inputs in the event queue events = pygame.event.get() for event in events: #close window and quit if x is clicked or esc is pressed if event.type == QUIT or (event.type == KEYDOWN and event.key == K_ESCAPE): quit() sys.exit() #track the cursor if event.type == MOUSEMOTION: crsr.rect.centerx = event.pos[0] crsr.rect.centery = event.pos[1] #if no input is given, this remains True, animation reflects that. if not playerSprite.state["ducking"]: playerSprite.state["idle"] = True #only control pc if pc not dead #may be simplified by banning control input events when pc dies. if not playerSprite.state["dying"] and not playerSprite.state["dead"]: #movement d-right a-left space-jump if not playerSprite.state["ducking"]: if event.type == KEYUP and event.key == K_d: playerSprite.rightDash = now Movement.accel(playerSprite, -playerSprite.velocity[0]) Movement.coast(playerSprite, playerSprite.velocity[0]) if playerSprite.velocity[0] == 0: playerSprite.state["running"] = False playerSprite.idleTime = 0 playerSprite.state["idle"] = False elif event.type == KEYUP and event.key == K_a: playerSprite.leftDash = now Movement.accel(playerSprite, -playerSprite.velocity[0]) Movement.coast(playerSprite, playerSprite.velocity[0]) if playerSprite.velocity[0] == 0: playerSprite.state["running"] = False playerSprite.idleTime = 0 playerSprite.state["idle"] = False elif event.type == KEYDOWN and event.key == K_d: if now - playerSprite.rightDash > 250: Movement.accel(playerSprite, 12) else: Movement.accel(playerSprite, 24) playerSprite.leftDash = 0 playerSprite.xflip = False if not playerSprite.state["jumping"] and not playerSprite.state["falling"]: playerSprite.state["running"] = True playerSprite.idleTime = 0 playerSprite.state["idle"] = False elif event.type == KEYDOWN and event.key == K_a: if now - playerSprite.leftDash > 250: Movement.accel(playerSprite, -12) else: Movement.accel(playerSprite, -24) playerSprite.rightDash = 0 playerSprite.xflip = True if not playerSprite.state["jumping"] and not playerSprite.state["falling"]: playerSprite.state["running"] = True playerSprite.idleTime = 0 playerSprite.state["idle"] = False if playerSprite.velocity[0] == 0 and playerSprite.velocity[1] == 0: if event.type == KEYUP and event.key == K_s: playerSprite.idleTime = 0 playerSprite.state["ducking"] = False playerSprite.state["idle"] = False elif event.type == KEYDOWN and event.key == K_s: #crouching provides traction playerSprite.xcoast = playerSprite.xcoast/2.0 playerSprite.state["ducking"] = True playerSprite.idleTime = 0 playerSprite.state["idle"] = False if event.type == KEYUP and event.key == K_SPACE: playerSprite.velocity[1] = max(0,playerSprite.velocity[1]) playerSprite.state["jumping"] = False playerSprite.idleTime = 0 playerSprite.state["idle"] = False if event.type == KEYDOWN and event.key == K_SPACE: Movement.jump(playerSprite) playerSprite.state["idle"] = False playerSprite.state["jumping"] = True playerSprite.idleTime = 0 playerSprite.state["idle"] = False #melee attack if event.type == MOUSEBUTTONDOWN and event.button == 1 and now - playerSprite.lastMelee > 300: playerSprite.state["attacking"] = True playerSprite.last["meleed"] = now playerSprite.idleTime = 0 playerWeapon.hostile = True playerSprite.state["idle"] = False if event.type == MOUSEBUTTONUP and event.button == 1: playerWeapon.hostile = False playerSprite.state["idle"] = False playerSprite.state["attacking"] = False #ranged attack if event.type == MOUSEBUTTONDOWN and event.button == 3 and playerSprite.ammo > 0 and now - playerSprite.lastShot > 250: playerSprite.ammo -= 1 projLoc = [playerSprite.rect.right, playerSprite.rect.bottom-130] newProj = SpriteRemix.Projectile(projLoc, event.pos, speed=45) animator.load(newProj) newProj.add(projectiles) newProj.rect.center = projLoc playerSprite.last["shot"] = now playerSprite.state["shooting"] = True playerSprite.idleTime = 0 playerSprite.state["idle"] = False #ragdoll pc else: playerSprite.xcoast = playerSprite.velocity[0] playerSprite.ycoast = playerSprite.velocity[1] playerSprite.velocity = [0,0] if playerSprite.state["idle"]: playerSprite.idleTime += gameClock.get_time() if playerSprite.idleTime >= 2000: playerSprite.state["idle"] = True elif playerSprite.idleTime >= 300: playerSprite.state["ready"] = True #baddy behavior '''if (now%1000 < 20) and baddySprite.stateVal != 1: Movement.jump(baddySprite)''' #replenish ammo over time if (now %100 < 20) and playerSprite.ammo < 4: playerSprite.ammo += 1 if (now % 5000 < 20): print(playerSprite.state) #sprites move, but these moves haven't been drawn yet for i in range(len(sprites)-2): groupList = sprites[i].sprites() for aSprite in groupList: if aSprite.xcoast > 0: if aSprite.xcoast > .6: aSprite.xcoast += min(-aSprite.xcoast*.1,-.6) else: aSprite.xcoast = 0 elif aSprite.xcoast < 0: if aSprite.xcoast < -.6: aSprite.xcoast += max(-aSprite.xcoast*.1,.6) else: aSprite.xcoast = 0 if aSprite.ycoast > 0: if aSprite.ycoast > .6: aSprite.ycoast += min(-aSprite.ycoast*.1,-.6) else: aSprite.ycoast = 0 elif aSprite.ycoast < 0: if aSprite.ycoast < -.6: aSprite.ycoast += max(-aSprite.ycoast*.1,.6) else: aSprite.ycoast = 0 aSprite.rect = aSprite.rect.move([aSprite.velocity[0]+aSprite.xcoast,aSprite.velocity[1]+aSprite.ycoast]) # keeps characters in frame and handles collisions resolveFrame(sprites,entities,combatTextArr) # position the pc's weapon # TODO: encapsulate this, preferably in Animation once I figure out why it wasn't working there. playerWeapon.state = playerSprite.state if playerSprite.xflip: if playerWeapon.state["dead"] or playerWeapon.state["idle"]: playerWeapon.rect.topleft = [0,0] elif playerWeapon.state["attacking"] or playerWeapon.state["shooting"]: playerWeapon.rect.midright = [playerSprite.rect.midleft[0]+8,playerSprite.rect.midleft[1]-62] else: playerWeapon.rect.midleft = [playerSprite.rect.midright[0],playerSprite.rect.midright[1]+58] playerWeapon.xflip = True else: if playerWeapon.state["dead"] or playerWeapon.state["idle"]: playerWeapon.rect.topleft = [0,0] elif playerWeapon.state["attacking"] or playerWeapon.state["shooting"]: playerWeapon.rect.midleft = [playerSprite.rect.midright[0]-8,playerSprite.rect.midright[1]-62] else: playerWeapon.rect.midright = [playerSprite.rect.midleft[0],playerSprite.rect.midleft[1]+58] playerWeapon.xflip = False # only animate characters and projectiles so far (i = 0 is pc, i = 1 is baddies, i = 3 is projectiles, i = 4 is background) animator.animate([sprites[0].sprites(), sprites[1].sprites(), sprites[2].sprites(), sprites[4].sprites(), sprites[5].sprites()], now) # refresh screen by drawing over previous frame with background screen.blit(bg1.image, bg1.rect) screen.blit(bg2.image, bg2.rect) # draw active CombatText objects and remove faded ones for combatText in combatTextArr[:]: if combatText.progress(now): combatText.draw(screen) else: combatTextArr.remove(combatText) # draw all the rest of the in-use assets for i in range(len(sprites)): if i != 5: #don't draw UI # only draw visible sprites in each group # NOTE: this is probably bad, as I'd assume .draw() (sprite method that blits all sprites in a sprite group)is better # optimized, but we can't make it optionally draw # sprites unless we change everything to DirtySprites (a type built into pygame) for aSprite in sprites[i].sprites(): if aSprite.visible: screen.blit(aSprite.image,aSprite.rect) # draw UI last if health.rect.width > 5.96*playerSprite.health: health.image = transform.scale(health.image, (max(0,health.rect.width-3),health.rect.height)) health.rect = health.image.get_rect() health.rect.topleft = (289,56) screen.blit(health.image, health.rect) screen.blit(healthbar.image, healthbar.rect) gameClock.tick(60) #game over check if playerSprite.health <= 0: defaultText = font.Font(None,120) gameOverSurface = defaultText.render("Game Over man, Game Over!", True, (255,0,0)) gameOverRect = gameOverSurface.get_rect() gameOverRect.center = (960,540) screen.blit(gameOverSurface, gameOverRect) playerSprite.state["dead"] = True #victory check enemies = sprites[2].sprites() allDead = True for enemy in enemies: if enemy.stateVal != 4: allDead = False if allDead: defaultText = font.Font(None,200) conglaturationSurface = defaultText.render("Conglaturation", True, (255,255,255)) conglaturationRect = conglaturationSurface.get_rect() conglaturationRect.center = (960,540) screen.blit(conglaturationSurface, conglaturationRect) pygame.display.flip()
class Game: def __init__(self): #define the screen related constants and set-up the sprite manager self.width = WIDTH self.height = HEIGHT self.tile = TILE self.fps = FPS self.state = MENU self.sprite_manager = SpriteManager(self) def create_window(self): #initialize the pygame window pygame.init() pygame.mixer.init() #create the screen and clock self.screen = pygame.display.set_mode((self.width, self.height)) self.clock = pygame.time.Clock() #define a font self.font = pygame.font.Font(None, TILE) def load_map(self): #load the map, add tiles and sprite self.map = Map(self, "map.txt") self.map.add_tiles() self.map.add_sprites() #set the current sprite manager's sprites self.sprite_manager.add_sprites(self.all_sprites) def load_helpers(self): #load the camera, animator and renderer classes self.camera = Camera(self.map.width, self.map.height) self.animator = Animation(self) self.Renderer = Renderer(self) def new_groups(self): #define new groups self.walls = [] self.tiles = [] self.all_sprites = pygame.sprite.Group() self.characters = pygame.sprite.Group() self.animations = pygame.sprite.Group() self.hitboxes = pygame.sprite.Group() self.items = pygame.sprite.Group() def new_game(self): #create a new game self.new_groups() self.load_map() self.load_helpers() def state_transition(self, next_state): # transition to the next state and update the sprite manager's currently active sprites based on # the new game state self.state = next_state if next_state == INVENTORY: self.sprite_manager.add_sprites(self.player.inventory) self.order_player_inventory() elif next_state == CHARACTER_SCREEN: self.sprite_manager.add_sprites(self.player.equipped) elif next_state == RUNNING: self.sprite_manager.add_sprites(self.all_sprites) def update(self): #update the sprites and the camera view self.sprite_manager.active_sprites.update() self.items.update() self.camera.update(self.player) def order_player_inventory(self): #order the player's items in the inventory. #need to make sure this properly wraps around the screen once the width of the screen is exceeded. for i, item in enumerate(self.player.inventory): item.x = i * TILE item.y = 0 def mouse_click_collision(self, position): #create a single pixel rectangle located at the position and check whether it collides with #and of the sprites in the sprite_manager's active sprites. If there is a collision, the sprite #is returned. #//NOTE// I couldn't seem to get built-in sprite.collidepoint method to work so I opted to create #a single pixel rectangle and this seems to do the job. pos_rect = pygame.Rect(position[0], position[1],1,1) for sprite in self.sprite_manager.active_sprites: sprite_rect = pygame.Rect(sprite.x, sprite.y, TILE, TILE) if pos_rect.colliderect(sprite_rect): return sprite def events(self): #get the event based on user input. The game's state is updated by calling the state_transition method. #the if/elif block is broken down by the state and the relevant method is called after user input. #I'm not happy with this as it's getting longer and longer so refactoring is on the to-do list. for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() sys.exit() if self.state == MENU: # start menu if event.type == pygame.KEYDOWN: if event.key == pygame.K_1: self.state_transition(RUNNING) elif event.key == pygame.K_2: pygame.quit() sys.exit() elif self.state == PAUSED: # paused if event.type == pygame.KEYDOWN: if event.key == pygame.K_ESCAPE: self.state_transition(RUNNING) elif event.key == pygame.K_1: pass elif event.key == pygame.K_2: pass elif self.state == RUNNING: # playing if event.type == pygame.KEYDOWN: if event.key == pygame.K_ESCAPE: self.state_transition(PAUSED) elif event.key == pygame.K_r: self.state_transition(INVENTORY) elif event.key == pygame.K_c: self.state_transition(CHARACTER_SCREEN) elif event.key == pygame.K_SPACE: self.player.attack(self.dt) elif event.key == pygame.K_e: self.pick_up_item() elif self.state == INVENTORY: # inventory if event.type == pygame.KEYDOWN: if event.key == pygame.K_ESCAPE or event.key == pygame.K_r: self.state_transition(RUNNING) if event.key == pygame.K_c: self.state_transition(CHARACTER_SCREEN) if event.type == pygame.MOUSEBUTTONDOWN: item = self.mouse_click_collision(pygame.mouse.get_pos()) if item: if event.button == LEFT: self.equip_item(item) elif event.button == RIGHT: self.drop_item(item) elif self.state == CHARACTER_SCREEN: # character screen if event.type == pygame.KEYDOWN: if event.key == pygame.K_ESCAPE or event.key == pygame.K_c: self.state_transition(RUNNING) elif event.key == pygame.K_i: self.state_transition(INVENTORY) if event.type == pygame.MOUSEBUTTONDOWN: item = self.mouse_click_collision(pygame.mouse.get_pos()) if item: if event.button == LEFT: self.unequip_item(item) elif event.button == RIGHT: self.drop_item(item) def equip_item(self, item): #determine if the item is a weapon or a piece of armour. Update the item's (x,y) position based on #where the character screen will show the body and weapon slots. The player's hand/body is checked to #determine whether an item is being held/worn. If not, the item is added to the relevant slot and to #the equipped group. It is then removed from the player's inventory and the sprite manager's active #sprite group. If an item is currently being held/worn, the new item is removed from the inventory and #sprite manager's active sprites. The held/worn item is then removed from the equipped group and added #to the inventory and sprite manager's active sprites. The new item is then added the equipped group # and finally the player's hand/body item is set as the item. if isinstance(item, Weapon): item.x = 6*TILE item.y = 7*TILE if not self.player.hand: self.player.hand = item self.player.equipped.add(item) self.player.inventory.remove(item) self.sprite_manager.active_sprites.remove(item) else: self.player.inventory.remove(item) self.sprite_manager.active_sprites.remove(item) self.player.equipped.remove(self.player.hand) self.player.inventory.add(self.player.hand) self.sprite_manager.active_sprites.add(self.player.hand) self.player.equipped.add(item) self.player.hand = item elif isinstance(item, Armour): item.x = 7*TILE item.y = 7*TILE if not self.player.body: self.player.body = item self.player.equipped.add(item) self.player.inventory.remove(item) self.sprite_manager.active_sprites.remove(item) else: self.player.inventory.remove(item) self.sprite_manager.active_sprites.remove(item) self.player.equipped.remove(self.player.body) self.player.inventory.add(self.player.body) self.sprite_manager.active_sprites.add(self.player.body) self.player.equipped.add(item) self.player.body = item self.order_player_inventory() def unequip_item(self, item): #removes the item from the equipped group and the sprite manager's active sprites self.player.equipped.remove(item) self.sprite_manager.active_sprites.remove(item) #check if the item is either a Weapon or a piece of Armour. The item is added to the inventory and #the relevant slot (hand/body) is set to None. if isinstance(item, Weapon): self.player.inventory.add(item) self.player.hand = None elif isinstance(item, Armour): self.player.inventory.add(item) self.player.body = None def drop_item(self, item): #sets the item's x,y coordinates as the same as the player's. item.x = self.player.x item.y = self.player.y #goes through the items in the player's inventory and the player's equipped items and removes from the #relevant group and also removes from the sprite manager's active sprites. if item in self.player.inventory: self.player.inventory.remove(item) elif item in self.player.equipped: self.player.equipped.remove(item) self.sprite_manager.active_sprites.remove(item) #adds the item to the game's all_sprites and the game's items groups. self.all_sprites.add(item) self.items.add(item) def pick_up_item(self): #cycles through the items and determines whether there is a collision between the player and the item's #rectangle. If there is, the item is added to the player's inventory and removed from the game's items, #all_sprites and the sprite manager's active sprites. for item in self.items: if pygame.Rect(self.player.x, self.player.y, TILE, TILE).colliderect(pygame.Rect(item.x, item.y, TILE, TILE)): if not self.inventory_limit_reached(item): self.player.inventory.add(item) self.items.remove(item) self.all_sprites.remove(item) self.sprite_manager.active_sprites.remove(item) def inventory_limit_reached(self, item): #creates the local weight variable and determines the weight of the items in the player's inventory #and equipped groups. It then addes the new item's weight and checks if the sum is less than or equal #to the player's encumberance limit. weight = 0 for item_ in self.player.inventory: weight += item_.weight for item_ in self.player.equipped: weight += item_.weight weight += item.weight if weight <= self.player.encumberance: return False def game_loop(self): #create a game window, initialize a new game and set the playing parameter to true. self.create_window() self.new_game() self.playing = True #enter the game loop while self.player.is_alive() and self.playing: self.show_fps = self.font.render(str(int(self.clock.get_fps())), True, WHITE) self.clock.tick(self.fps) self.dt = self.clock.tick(self.fps) / 1000 self.events() if self.state == MENU: self.Renderer.draw_start_menu() elif self.state == RUNNING: self.update() self.animator.animate(self.dt) self.Renderer.draw_game() elif self.state == PAUSED: self.Renderer.draw_pause() elif self.state == INVENTORY: self.Renderer.draw_inventory() elif self.state == CHARACTER_SCREEN: self.Renderer.draw_character_screen() if not self.player.is_alive(): self.Renderer.draw_game_over()
def main(): init() global width, height, animator size = width, height = 1920, 1080 screen = pygame.display.set_mode(size, FULLSCREEN) gameClock = time.Clock() animator = Animation() #load default background background = pygame.sprite.Group() bg1 = SpriteRemix.Background( transform.scale( image.load("Assets\\backgrounds\outsidebg.png").convert(), (1920, 1080))) bg2 = SpriteRemix.Background( transform.scale( image.load("Assets\\backgrounds\outsidebg.png").convert(), (1920, 1080))) bg1.stateVal = 1 #slowscroll bg2.stateVal = 1 #slowscroll bg1.add(background) bg2.add(background) #load ui, TODO: encapsulate this shit ui = pygame.sprite.Group() health = SpriteRemix.UI( transform.scale( image.load("Assets\\sprites\\ui\\health.png").convert(), (596, 72))) healthbar = SpriteRemix.UI( transform.scale( image.load("Assets\\sprites\\ui\\healthbar.png").convert_alpha(), (840, 84))) health.add(ui) healthbar.add(ui) #create cursor and add it to a sprite group, can only hold 1 cursor at a time cursors = pygame.sprite.GroupSingle() crsr = SpriteRemix.Cursor( transform.scale( pygame.image.load( "Assets\\sprites\\cursors\\crosshair1.png").convert_alpha(), (70, 70))) crsr.add(cursors) #create pc and add it to a sprite group #TODO: need an initializer class for player that loads projectiles and weapons and shit pc = pygame.sprite.Group() playerSprite = PlayerCharacterSprite() animator.load(playerSprite) playerSprite.add(pc) #weapon, this shit is f*****g retarded pcAccessory = pygame.sprite.Group() playerWeapon = SpriteRemix.Weapon() animator.load(playerWeapon) playerWeapon.add(pcAccessory) #create baddies and add them to a sprite group baddies = sprite.Group() baddySprite = EnemyCharacterSprite("notzigrunt") animator.load(baddySprite) baddySprite.add(baddies) #create doodads and add them to a sprite group doodads = sprite.Group() box = SpriteRemix.Doodad( pygame.image.load("Assets\\sprites\\doodads\\box.png").convert()) #alsoBox = Doodad(pygame.image.load("Assets\\sprites\\doodads\\box.png").convert()) box.add(doodads) #alsoBox.add(doodads) #initialize projectile sprite group (obv nothing to put here at startup projectiles = sprite.Group() #floating combat text combatTextArr = [] #place everything bg1.rect.topleft = [-1920, 0] bg2.rect.topleft = [0, 0] healthbar.rect.topleft = [50, 50] health.rect.topleft = [healthbar.rect.left + 239, healthbar.rect.top + 5] playerSprite.rect.bottomleft = [100, height - 50] playerWeapon.rect.midright = playerSprite.rect.midleft baddySprite.rect.bottom = height baddySprite.rect.left = 960 box.rect.left = 540 box.rect.bottom = height '''alsoBox.rect.left = 920 alsoBox.rect.bottom = height''' #create a list of all sprite groups entities = [pc.sprites(), baddies.sprites()] sprites = [ pc, pcAccessory, baddies, doodads, projectiles, background, ui, cursors ] while 1: now = time.get_ticks() #this for loop processes all inputs in the event queue events = pygame.event.get() for event in events: #close window and quit if x is clicked or esc is pressed if event.type == QUIT or (event.type == KEYDOWN and event.key == K_ESCAPE): quit() sys.exit() #track the cursor if event.type == MOUSEMOTION: crsr.rect.centerx = event.pos[0] crsr.rect.centery = event.pos[1] #if no input is given, this remains True, animation reflects that. if not playerSprite.state["ducking"]: playerSprite.state["idle"] = True #only control pc if pc not dead #may be simplified by banning control input events when pc dies. if not playerSprite.state["dying"] and not playerSprite.state[ "dead"]: #movement d-right a-left space-jump if not playerSprite.state["ducking"]: if event.type == KEYUP and event.key == K_d: playerSprite.rightDash = now Movement.accel(playerSprite, -playerSprite.velocity[0]) Movement.coast(playerSprite, playerSprite.velocity[0]) if playerSprite.velocity[0] == 0: playerSprite.state["running"] = False playerSprite.idleTime = 0 playerSprite.state["idle"] = False elif event.type == KEYUP and event.key == K_a: playerSprite.leftDash = now Movement.accel(playerSprite, -playerSprite.velocity[0]) Movement.coast(playerSprite, playerSprite.velocity[0]) if playerSprite.velocity[0] == 0: playerSprite.state["running"] = False playerSprite.idleTime = 0 playerSprite.state["idle"] = False elif event.type == KEYDOWN and event.key == K_d: if now - playerSprite.rightDash > 250: Movement.accel(playerSprite, 12) else: Movement.accel(playerSprite, 24) playerSprite.leftDash = 0 playerSprite.xflip = False if not playerSprite.state[ "jumping"] and not playerSprite.state[ "falling"]: playerSprite.state["running"] = True playerSprite.idleTime = 0 playerSprite.state["idle"] = False elif event.type == KEYDOWN and event.key == K_a: if now - playerSprite.leftDash > 250: Movement.accel(playerSprite, -12) else: Movement.accel(playerSprite, -24) playerSprite.rightDash = 0 playerSprite.xflip = True if not playerSprite.state[ "jumping"] and not playerSprite.state[ "falling"]: playerSprite.state["running"] = True playerSprite.idleTime = 0 playerSprite.state["idle"] = False if playerSprite.velocity[0] == 0 and playerSprite.velocity[ 1] == 0: if event.type == KEYUP and event.key == K_s: playerSprite.idleTime = 0 playerSprite.state["ducking"] = False playerSprite.state["idle"] = False elif event.type == KEYDOWN and event.key == K_s: #crouching provides traction playerSprite.xcoast = playerSprite.xcoast / 2.0 playerSprite.state["ducking"] = True playerSprite.idleTime = 0 playerSprite.state["idle"] = False if event.type == KEYUP and event.key == K_SPACE: playerSprite.velocity[1] = max(0, playerSprite.velocity[1]) playerSprite.state["jumping"] = False playerSprite.idleTime = 0 playerSprite.state["idle"] = False if event.type == KEYDOWN and event.key == K_SPACE: Movement.jump(playerSprite) playerSprite.state["idle"] = False playerSprite.state["jumping"] = True playerSprite.idleTime = 0 playerSprite.state["idle"] = False #melee attack if event.type == MOUSEBUTTONDOWN and event.button == 1 and now - playerSprite.lastMelee > 300: playerSprite.state["attacking"] = True playerSprite.last["meleed"] = now playerSprite.idleTime = 0 playerWeapon.hostile = True playerSprite.state["idle"] = False if event.type == MOUSEBUTTONUP and event.button == 1: playerWeapon.hostile = False playerSprite.state["idle"] = False playerSprite.state["attacking"] = False #ranged attack if event.type == MOUSEBUTTONDOWN and event.button == 3 and playerSprite.ammo > 0 and now - playerSprite.lastShot > 250: playerSprite.ammo -= 1 projLoc = [ playerSprite.rect.right, playerSprite.rect.bottom - 130 ] newProj = SpriteRemix.Projectile(projLoc, event.pos, speed=45) animator.load(newProj) newProj.add(projectiles) newProj.rect.center = projLoc playerSprite.last["shot"] = now playerSprite.state["shooting"] = True playerSprite.idleTime = 0 playerSprite.state["idle"] = False #ragdoll pc else: playerSprite.xcoast = playerSprite.velocity[0] playerSprite.ycoast = playerSprite.velocity[1] playerSprite.velocity = [0, 0] if playerSprite.state["idle"]: playerSprite.idleTime += gameClock.get_time() if playerSprite.idleTime >= 2000: playerSprite.state["idle"] = True elif playerSprite.idleTime >= 300: playerSprite.state["ready"] = True #baddy behavior '''if (now%1000 < 20) and baddySprite.stateVal != 1: Movement.jump(baddySprite)''' #replenish ammo over time if (now % 100 < 20) and playerSprite.ammo < 4: playerSprite.ammo += 1 if (now % 5000 < 20): print(playerSprite.state) #sprites move, but these moves haven't been drawn yet for i in range(len(sprites) - 2): groupList = sprites[i].sprites() for aSprite in groupList: if aSprite.xcoast > 0: if aSprite.xcoast > .6: aSprite.xcoast += min(-aSprite.xcoast * .1, -.6) else: aSprite.xcoast = 0 elif aSprite.xcoast < 0: if aSprite.xcoast < -.6: aSprite.xcoast += max(-aSprite.xcoast * .1, .6) else: aSprite.xcoast = 0 if aSprite.ycoast > 0: if aSprite.ycoast > .6: aSprite.ycoast += min(-aSprite.ycoast * .1, -.6) else: aSprite.ycoast = 0 elif aSprite.ycoast < 0: if aSprite.ycoast < -.6: aSprite.ycoast += max(-aSprite.ycoast * .1, .6) else: aSprite.ycoast = 0 aSprite.rect = aSprite.rect.move([ aSprite.velocity[0] + aSprite.xcoast, aSprite.velocity[1] + aSprite.ycoast ]) # keeps characters in frame and handles collisions resolveFrame(sprites, entities, combatTextArr) # position the pc's weapon # TODO: encapsulate this, preferably in Animation once I figure out why it wasn't working there. playerWeapon.state = playerSprite.state if playerSprite.xflip: if playerWeapon.state["dead"] or playerWeapon.state["idle"]: playerWeapon.rect.topleft = [0, 0] elif playerWeapon.state["attacking"] or playerWeapon.state[ "shooting"]: playerWeapon.rect.midright = [ playerSprite.rect.midleft[0] + 8, playerSprite.rect.midleft[1] - 62 ] else: playerWeapon.rect.midleft = [ playerSprite.rect.midright[0], playerSprite.rect.midright[1] + 58 ] playerWeapon.xflip = True else: if playerWeapon.state["dead"] or playerWeapon.state["idle"]: playerWeapon.rect.topleft = [0, 0] elif playerWeapon.state["attacking"] or playerWeapon.state[ "shooting"]: playerWeapon.rect.midleft = [ playerSprite.rect.midright[0] - 8, playerSprite.rect.midright[1] - 62 ] else: playerWeapon.rect.midright = [ playerSprite.rect.midleft[0], playerSprite.rect.midleft[1] + 58 ] playerWeapon.xflip = False # only animate characters and projectiles so far (i = 0 is pc, i = 1 is baddies, i = 3 is projectiles, i = 4 is background) animator.animate([ sprites[0].sprites(), sprites[1].sprites(), sprites[2].sprites(), sprites[4].sprites(), sprites[5].sprites() ], now) # refresh screen by drawing over previous frame with background screen.blit(bg1.image, bg1.rect) screen.blit(bg2.image, bg2.rect) # draw active CombatText objects and remove faded ones for combatText in combatTextArr[:]: if combatText.progress(now): combatText.draw(screen) else: combatTextArr.remove(combatText) # draw all the rest of the in-use assets for i in range(len(sprites)): if i != 5: #don't draw UI # only draw visible sprites in each group # NOTE: this is probably bad, as I'd assume .draw() (sprite method that blits all sprites in a sprite group)is better # optimized, but we can't make it optionally draw # sprites unless we change everything to DirtySprites (a type built into pygame) for aSprite in sprites[i].sprites(): if aSprite.visible: screen.blit(aSprite.image, aSprite.rect) # draw UI last if health.rect.width > 5.96 * playerSprite.health: health.image = transform.scale( health.image, (max(0, health.rect.width - 3), health.rect.height)) health.rect = health.image.get_rect() health.rect.topleft = (289, 56) screen.blit(health.image, health.rect) screen.blit(healthbar.image, healthbar.rect) gameClock.tick(60) #game over check if playerSprite.health <= 0: defaultText = font.Font(None, 120) gameOverSurface = defaultText.render("Game Over man, Game Over!", True, (255, 0, 0)) gameOverRect = gameOverSurface.get_rect() gameOverRect.center = (960, 540) screen.blit(gameOverSurface, gameOverRect) playerSprite.state["dead"] = True #victory check enemies = sprites[2].sprites() allDead = True for enemy in enemies: if enemy.stateVal != 4: allDead = False if allDead: defaultText = font.Font(None, 200) conglaturationSurface = defaultText.render("Conglaturation", True, (255, 255, 255)) conglaturationRect = conglaturationSurface.get_rect() conglaturationRect.center = (960, 540) screen.blit(conglaturationSurface, conglaturationRect) pygame.display.flip()