""" ZOMBIE FEEDER - Dodge zombies - Throw brains created by Scott Swain """ import arcade from arcade.gui import * import math import random import os import pyautogui from datetime import datetime, timedelta # Set the working folder to the # same folder this python file is in. try: file_path = os.path.abspath(".") except Exception: import sys file_path = sys._MEIPASS os.chdir(file_path) # Seed random number generator # using internal clock. random.seed(datetime.now()) # SET UP CONSTANTS SCREEN_TITLE = "Zombie Feeder" # Mouse detection MOUSE_DETECT = True # Beginning difficulty level, which can be # changed via the "-" and "+(=)" buttons. DIFFICULTY = 4 # Bullet speed depends some on difficulty BULLET_SPEED = 11 - (DIFFICULTY/2) # How many enemies? ENEMY_COUNT_INITIAL = 8 ENEMY_SPEED = 2 + (DIFFICULTY/12) # Set the following to true for # harder game play where enraged # enemies are immune to obstacles. ENEMY_ENRAGED_IMMUNE_TO_BLOCKS = True # How many bounces before an # enemy becomes immune to blocks? ENEMY_FRUSTRATION_THRESHOLD = 160 # Allow enemies to "teleport" # from any edge of the screen # to opposite edge. # Set to False for easier, where # the enemies will "bounce" from # the screen edge. ENEMY_SCREEN_EDGE_TRAVERSE = True # Beginning size of all the Sprites # on the screen. SCALE = 0.25 PLAYER_STARTING_LIVES = 4 PLAYER_IMMUNE_TO_BLOCKS = True MONITOR_RES_WIDTH, MONITOR_RES_HEIGHT = pyautogui.size() SCREEN_WIDTH = 1920 SCREEN_HEIGHT = 1080 # Make sure SCREEN_WIDTH is not bigger than monitor width. if SCREEN_WIDTH > MONITOR_RES_WIDTH: SCREEN_WIDTH = MONITOR_RES_WIDTH # Make sure SCREEN_HEIGHT is not bigger than monitor width. if SCREEN_HEIGHT > MONITOR_RES_HEIGHT: SCREEN_HEIGHT = MONITOR_RES_HEIGHT # Number of obstacles are based on the screen width. BLOCKS_NUMBER = int(SCREEN_WIDTH/20) # Set up screen edges. SPACE_OFFSCREEN = 1 LIMIT_LEFT = -SPACE_OFFSCREEN LIMIT_RIGHT = SCREEN_WIDTH + SPACE_OFFSCREEN LIMIT_BOTTOM = -SPACE_OFFSCREEN LIMIT_TOP = SCREEN_HEIGHT + SPACE_OFFSCREEN # Draw screens from database. # If set to False, screens will # be drawn using the random function # to place obstacles. SCREEN_FROM_DATABASE = False ''' SCREEN BUTTONS ''' # BUTTON - RESTART class ButtonRestart(TextButton): def __init__(self, game, x=10, y=10, width=100, height=40, text="Restart", theme=None): super().__init__(x, y, width, height, text, theme=theme) self.game = game def on_press(self): self.pressed = True def on_release(self): if self.pressed: self.pressed = False self.game.start_new_game() # BUTTON - PAUSE class ButtonPause(TextButton): def __init__(self, game, x=10, y=10, width=100, height=40, text="Pause", theme=None): super().__init__(x, y, width, height, text, theme=theme) self.game = game def on_press(self): self.pressed = True def on_release(self): if self.pressed: if self.game.pause == True: self.game.pause = False self.text = "Pause" else: self.game.pause = True self.text = "Resume" self.pressed = False # Sprite sets its angle to the direction it is traveling in. class TurnSprite(arcade.Sprite): def update(self): super().update() # Rotate sprite. self.angle = math.degrees(math.atan2(self.change_y, self.change_x)) # Sprite that represents the player. # derives from arcade.Sprite. class PlayerSprite(arcade.Sprite): # Set up the player. def __init__(self, filename, scale): # Call the parent Sprite constructor super().__init__(filename, scale) self.theme = None # Initialize player movement variables. # Angle comes in automatically from the parent class. self.thrust = 0 self.speed = 0 self.max_speed = 5 self.drag = 0.045 # Initialize respawning variables self.respawning = 0 # Initialize difficulty variable self.difficulty = DIFFICULTY # Initialize "Firing right now?" self.firing = False # For continuous firing. self.firing_counter = 0 # Set the player to respawn. self.respawn() # Called when Player dies so need to make a new player. def respawn(self): # self.respawning is a timer for invulnerability. # If we are in the middle of respawning, this is non-zero. self.respawning = 1 # Place player in center of the screen. self.center_x = SCREEN_WIDTH / 2 self.center_y = SCREEN_HEIGHT / 2 self.angle = 0 # Update player position, speed, and opacity. def update(self): # Update respawning counter. if self.respawning: self.respawning += 1 # Use respawn counter to set player opacity (alpha property). self.alpha = self.respawning # When respawn counter reaches past 250, # set player to be fully visible. if self.respawning > 250: self.respawning = 0 # Alpha of 255 means 100% visible. self.alpha = 255 # If the player is moving, add gravity-like "drag". if self.speed > 0: self.speed -= self.drag # Make sure player speed is not negative # after it was reduced by drag: if self.speed < 0: self.speed = 0 if self.speed < 0: self.speed += self.drag if self.speed > 0: self.speed = 0 self.speed += self.thrust # Make sure player speed does # not get out of hand. if self.speed > self.max_speed: self.speed = self.max_speed if self.speed < -self.max_speed: self.speed = -self.max_speed # Change Player direction based on angle and speed. self.change_x = -math.sin(math.radians(self.angle)) * self.speed self.change_y = math.cos(math.radians(self.angle)) * self.speed self.center_x += self.change_x self.center_y += self.change_y # If the player goes off-screen, teleport # them to the other side of the window if self.right < 0: self.left = SCREEN_WIDTH if self.left > SCREEN_WIDTH: self.right = 0 if self.bottom < 0: self.top = SCREEN_HEIGHT if self.top > SCREEN_HEIGHT: self.bottom = 0 # Call the parent class. super().update() # Sprite that represents an enemy. class EnemySprite(arcade.Sprite): # Initialize enemy size, movement-type timers, and speed def __init__(self, image_file_name, scale): super().__init__(image_file_name, scale=scale) self.timer_rand = 0 self.timer_smart = 0 self.speed = 0 self.url_image_primary = image_file_name self.url_image_secondary = "" self.immunity = False # Move the enemy and check for screen boundary. def update(self): # If enemy hits screen boundary, # cause a "bounce" toward opposite direction. super().update() if ENEMY_SCREEN_EDGE_TRAVERSE == False: if self.center_x < LIMIT_LEFT: self.center_x = LIMIT_LEFT self.change_x *= 1 if self.center_x > LIMIT_RIGHT: self.center_x = LIMIT_RIGHT self.change_x *= -1 if self.center_y > LIMIT_TOP: self.center_y = LIMIT_TOP self.change_y *= -1 if self.center_y < LIMIT_BOTTOM: self.center_y = LIMIT_BOTTOM self.change_y *= 1 else: # If the player goes off-screen, teleport # them to the other side of the window if self.right < 0: self.left = SCREEN_WIDTH if self.left > SCREEN_WIDTH: self.right = 0 if self.bottom < 0: self.top = SCREEN_HEIGHT if self.top > SCREEN_HEIGHT: self.bottom = 0 # Class to represent bullet. # Derived from arcade.TurnSprite which is a # sprite that aligns to its direction. class bulletSprite(TurnSprite): def update(self): super().update() if self.center_x < -100 or self.center_x > SCREEN_WIDTH + 100 or self.center_y > SCREEN_HEIGHT + 150 or self.center_y < -150: self.remove_from_sprite_lists() # Main application class class GameClass(arcade.Window): def __init__(self): super().__init__(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE) # Center the location of our game screen self.set_location(int((MONITOR_RES_WIDTH - SCREEN_WIDTH)/2), int((MONITOR_RES_HEIGHT - SCREEN_HEIGHT)/2)) self.frame_count = 0 self.pause = False self.game_over = False # Set up the player score, sprite, and lives. self.score = 0 self.player_sprite = None self.lives = 1 # Sounds self.toggle_sound_on = True self.sound_song = arcade.load_sound("./resources/sounds/song-burpy.mp3") self.sound_throw = arcade.load_sound("./resources/sounds/woosh.mp3") self.sound_gasp_of_death = arcade.load_sound("./resources/sounds/gasp.mp3") self.sound_bullet = arcade.load_sound("./resources/sounds/bullet.mp3") self.sound_powerup = arcade.load_sound("./resources/sounds/powerup.mp3") self.sound_munch = arcade.load_sound("./resources/sounds/munch.mp3") self.sound_burp = arcade.load_sound("./resources/sounds/burp.mp3") self.sound_char_00_enraged = arcade.load_sound("./resources/sounds/enraged-fem.mp3") self.sound_char_01_enraged = arcade.load_sound("./resources/sounds/enraged-fem.mp3") self.sound_char_02_enraged = arcade.load_sound("./resources/sounds/enraged-fem.mp3") self.sound_char_03_enraged = arcade.load_sound("./resources/sounds/enraged-guy.mp3") self.sound_char_04_enraged = arcade.load_sound("./resources/sounds/enraged-guy.mp3") self.sound_char_05_enraged = arcade.load_sound("./resources/sounds/enraged-guy.mp3") self.sound_char_06_enraged = arcade.load_sound("./resources/sounds/enraged-guy.mp3") self.sound_char_07_enraged = arcade.load_sound("./resources/sounds/enraged-guy.mp3") # Set window background color to black. arcade.set_background_color(arcade.color.BLACK) def set_button_textures(self): normal = "./resources/images/button-normal.png" hover = "./resources/images/button-hover.png" clicked = "./resources/images/button-clicked.png" locked = "./resources/images/button-locked.png" self.theme.add_button_textures(normal, hover, clicked, locked) def setup_theme(self): self.theme = Theme() self.theme.set_font(16, arcade.color.WHITE) self.set_button_textures() def set_buttons(self): self.button_list.append(ButtonRestart(self, 65, SCREEN_HEIGHT - 90, 110, 35, theme=self.theme)) self.button_list.append(ButtonPause(self, 65, SCREEN_HEIGHT - 130, 110, 35, theme=self.theme)) def setup_buttons(self): self.setup_theme() self.set_buttons() # Set up the game and initialize the variables. def start_new_game(self): self.setup_buttons() self.frame_count = 0 self.game_over = False # Set up all Sprite lists. self.list_all_sprites = arcade.SpriteList() self.list_enemies = arcade.SpriteList() self.list_bullets = arcade.SpriteList() self.list_player_lives = arcade.SpriteList() self.list_blocks = arcade.SpriteList() #self.setup_theme() #self.set_buttons() # Set up title screen sprite image. self.title = PlayerSprite("./resources/images/title.png", SCALE * 2.5) # Set up the player. self.score = 0 self.player_sprite = PlayerSprite("./resources/images/player.png", SCALE) self.list_all_sprites.append(self.player_sprite) self.lives = PLAYER_STARTING_LIVES # Firing right now? No. self.firing = False # Continuous firing self.firing_counter = 0 # Play the song that will go for entire game. arcade.play_sound(self.sound_song) # Play the powerup sound so it is in memory for quick use later. arcade.play_sound(self.sound_powerup) self.toggle_sound_on = True if SCREEN_FROM_DATABASE == False: # Place ice blocks on the screen using random. for i in range(BLOCKS_NUMBER): if random.randint(1,2) == 1: block = arcade.Sprite("./resources/images/block-red.png", SCALE) else: block = arcade.Sprite("./resources/images/block-blue.png", SCALE) x = random.randint(15, SCREEN_WIDTH) y = random.randint(15, SCREEN_HEIGHT) b_do = False while b_do == False: x = random.randint(15, SCREEN_WIDTH) y = random.randint(15, SCREEN_HEIGHT) b_do = True if x < SCREEN_WIDTH/6 and (y < SCREEN_HEIGHT/9 or y > SCREEN_HEIGHT-(SCREEN_HEIGHT/9)): b_do = False block.center_x = x block.center_y = y self.list_all_sprites.append(block) self.list_blocks.append(block) else: # Place ice blocks on the screen using database. pass # Set up the little icons that represent the player lives. cur_pos = 0 for i in range(self.lives): life = arcade.Sprite("./resources/images/player-tiny.png", SCALE) life.center_x = cur_pos + life.width life.center_y = life.height cur_pos += life.width self.list_all_sprites.append(life) self.list_player_lives.append(life) # Make the enemies image_list = ("./resources/images/char-z-fem-01-blue-front.png", "./resources/images/char-z-fem-01-purple-front.png", "./resources/images/char-z-fem-01-yellow-front.png", "./resources/images/char-z-guy-01-green-front.png", "./resources/images/char-z-guy-01-orange-front.png", "./resources/images/char-z-guy-02-front.png", "./resources/images/char-z-guy-03-front.png", "./resources/images/char-z-guy-04-front.png") image_list_2 = ("./resources/images/char-z-fem-01-blue-enraged.png", "./resources/images/char-z-fem-01-purple-enraged.png", "./resources/images/char-z-fem-01-yellow-enraged.png", "./resources/images/char-z-guy-01-green-enraged.png", "./resources/images/char-z-guy-01-orange-enraged.png", "./resources/images/char-z-guy-02-enraged.png", "./resources/images/char-z-guy-03-enraged.png", "./resources/images/char-z-guy-04-enraged.png") # If no enraged sound, place "z" in front of name. name_list = ("char-z-fem-01-blue", "char-z-fem-01-purple", "char-z-fem-01-yellow", "char-z-guy-01-green", "char-z-guy-01-orange", "char-z-guy-02", "char-z-guy-03", "char-z-guy-04") for i in range(ENEMY_COUNT_INITIAL): image_no = i enemy_sprite = EnemySprite(image_list[image_no], SCALE) enemy_sprite.guid = name_list[image_no] enemy_sprite.speed = 2 + (DIFFICULTY/12) enemy_sprite.immunity = False enemy_sprite.enraged = False enemy_sprite.frustration = 0 enemy_sprite.which_sound = "self.sound_char_" + str(i).zfill(2) + "_enraged" enemy_sprite.scale = SCALE enemy_sprite.timer_rand = 0 enemy_sprite.timer_smart = 0 enemy_sprite.url_image_primary = image_list[image_no] enemy_sprite.url_image_secondary = image_list_2[image_no] texturey = arcade.load_texture(image_list_2[image_no]) enemy_sprite.texture_enraged = texturey enemy_sprite.center_y = 800 enemy_sprite.center_x = int((SCREEN_WIDTH/8 * (i+1))-(SCREEN_WIDTH/13.9)) # enemy_sprite.change_x = int(random.random() * 2 + (DIFFICULTY/10) - 1) # enemy_sprite.change_y = int(random.random() * 2 + (DIFFICULTY/10) - 1) enemy_sprite.change_x = 0 enemy_sprite.change_y = 0 self.list_all_sprites.append(enemy_sprite) self.list_enemies.append(enemy_sprite) # Set up a bullet sprite self.bullet_sprite_base = arcade.Sprite("./resources/images/bullet.png", SCALE) # self.setup_buttons() # Render the game screen. def on_draw(self): # This command must occur before we start drawing arcade.start_render() # Draw all the sprites. self.list_all_sprites.draw() # Draw our title image in the center of the screen. if self.player_sprite.respawning: self.title.center_x = SCREEN_WIDTH/2 self.title.center_y = SCREEN_HEIGHT/2 self.title.alpha = 255 self.title.draw() # Remove title image from screen once Player # has finished respawning. else: # For first spawn, show title screen longer if self.lives < PLAYER_STARTING_LIVES: self.title.alpha = 0 else: temp = self.title.alpha - 0.5 if temp < 0: temp = 0 self.title.alpha = temp # arcade.play_sound(self.sound_powerup) self.title.draw() # Put stats, etc on the screen. output = f"Throw brain: space or left mouse" arcade.draw_text(output, 10, SCREEN_HEIGHT-25, arcade.color.WHITE, 14) output = f"Harder: press =" arcade.draw_text(output, 10, SCREEN_HEIGHT-45, arcade.color.WHITE, 14) output = f"Easier: press -" arcade.draw_text(output, 10, SCREEN_HEIGHT-65, arcade.color.WHITE, 14) # output = f"Music on/off: press m" # arcade.draw_text(output, 10, SCREEN_HEIGHT-85, arcade.color.WHITE, 14) output = f"Difficulty: {self.player_sprite.difficulty}" arcade.draw_text(output, 10, 60, arcade.color.WHITE, 14) output = f"Score: {self.score}" arcade.draw_text(output, 10, 40, arcade.color.WHITE, 14) # Draw the buttons for button in self.button_list: button.draw() if self.eaten: if self.lives > 0: # output = "Eaten by an enemy" pass if self.game_over: output = "GAME OVER" arcade.draw_text(output, SCREEN_WIDTH/2, SCREEN_HEIGHT/2, arcade.color.RED, font_size=46, anchor_x="center", anchor_y="center") def bulletFired(self): # Initialize the new sprite with the pre-loaded "bullet_sprite_base" # bullet_sprite = self.bullet_sprite_base bullet_sprite = bulletSprite("./resources/images/bullet.png", SCALE) # Set the bullet guid property. bullet_sprite.guid = "brain" # Assign a speed to the bullet. bullet_speed = BULLET_SPEED # Set a direction for the bullet to fly in. bullet_sprite.change_y = math.cos(math.radians(self.player_sprite.angle)) * bullet_speed bullet_sprite.change_x = -math.sin(math.radians(self.player_sprite.angle)) * bullet_speed # Set location of the bullet. bullet_sprite.center_x = self.player_sprite.center_x bullet_sprite.center_y = self.player_sprite.center_y # Update the bullet sprite in memory. bullet_sprite.update() # Add the new bullet to the two relevant sprite lists. self.list_all_sprites.append(bullet_sprite) self.list_bullets.append(bullet_sprite) # Play a throwing sound. arcade.play_sound(self.sound_throw) if MOUSE_DETECT: def check_mouse_press_for_buttons(self, x, y, button_list): """ Given an x, y, see if we need to register any button clicks. """ for button in button_list: if x > button.center_x + button.width / 2: continue if x < button.center_x - button.width / 2: continue if y > button.center_y + button.height / 2: continue if y < button.center_y - button.height / 2: continue button.on_press() def check_mouse_release_for_buttons(self, _x, _y, button_list): """ If a mouse button has been released, see if we need to process any release events. """ for button in button_list: if button.pressed: button.on_release() def on_mouse_release(self, x, y, button, modifiers): self.check_mouse_release_for_buttons(x, y, self.button_list) if button == arcade.MOUSE_BUTTON_RIGHT: self.player_sprite.thrust = 0 self.player_sprite.change_angle = 0 if button == arcade.MOUSE_BUTTON_LEFT: self.firing = False self.firing_counter = 0 def on_mouse_motion(self, x, y, dx, dy): move_x = 0 move_y = 0 # Calculate the distance and direction # between player and mouse cursor. # In order to do so, we will add up both the # vertical distance, represented by y, and # horizontal distance, represented by x. i_distance = 0 if x < self.player_sprite.center_x: move_x = -1 i_distance += self.player_sprite.center_x - x # self.player_sprite.change_angle = 2 if x > self.player_sprite.center_x: move_x = 1 i_distance += x - self.player_sprite.center_x # self.player_sprite.change_angle = -2 if y < self.player_sprite.center_y: move_y = -1 i_distance += self.player_sprite.center_y - y # self.player_sprite.change_angle = -2 if y > self.player_sprite.center_y: move_y = 1 i_distance += y - self.player_sprite.center_y # self.player_sprite.change_angle = 2 # The code commented out below allows for the player # to move without clicks; moving toward the cursor. # This can make controlling the character and aiming # more difficult. ''' if i_distance > 40: self.player_sprite.thrust = 0.0001 * i_distance else: self.player_sprite.thrust = 0 ''' if i_distance < 90: self.player_sprite.thrust = 0 self.speed = 0 x_difference = x - self.player_sprite.center_x y_difference = y - self.player_sprite.center_y angle = math.atan2(y_difference, x_difference) self.player_sprite.angle = math.degrees(angle) - 90 def on_mouse_press(self, x, y, button, modifiers): # LEFT CLICK self.check_mouse_press_for_buttons(x, y, self.button_list) # Notice we are making sure the player can not # fire bullets while still respawning. if (button == arcade.MOUSE_BUTTON_LEFT or self.firing == True) and not self.player_sprite.respawning: self.firing = True self.bulletFired() # RIGHT CLICK # IF they clicked the right mouse button, they # will move toward the mouse cursor. # Move the center of the player toward the mouse x, y # First figure out direction to travel, based # on the mouse cursor's position on the GUI. if button == arcade.MOUSE_BUTTON_RIGHT: move_x = 0 move_y = 0 # We are going to look at the distance between # the player and the mouse cursor to determine velocity. # In order to do so, we will add up both the vertical # distance, represented by y, and the horizontal # distance, represented by x. i_distance = 0 if x < self.player_sprite.center_x: move_x = -1 i_distance += self.player_sprite.center_x - x # self.player_sprite.change_angle = 2 if x > self.player_sprite.center_x: move_x = 1 i_distance += x - self.player_sprite.center_x # self.player_sprite.change_angle = -2 if y < self.player_sprite.center_y: move_y = -1 i_distance += self.player_sprite.center_y - y # self.player_sprite.change_angle = -2 if y > self.player_sprite.center_y: move_y = 1 i_distance += y - self.player_sprite.center_y # self.player_sprite.change_angle = 2 if i_distance > 60: self.player_sprite.thrust = 0.0007 * i_distance else: self.player_sprite.thrust = 0 self.speed = 0 x_difference = x - self.player_sprite.center_x y_difference = y - self.player_sprite.center_y angle = math.atan2(y_difference, x_difference) self.player_sprite.angle = math.degrees(angle) - 90 # If the player is moving, add gravity-like "drag". if self.speed > 0: self.speed -= self.drag # Make sure player speed is not negative # after it was reduced by drag: if self.speed < 0: self.speed = 0 if self.speed < 0: self.speed += self.drag if self.speed > 0: self.speed = 0 self.speed += self.thrust # Make sure player speed does # not get out of hand. if self.speed > self.max_speed: self.speed = self.max_speed if self.speed < -self.max_speed: self.speed = -self.max_speed # When any key is pressed: def on_key_press(self, symbol, modifiers): # symbol is the key being pressed. # If the player hit the space bar and # not in respawning mode, shoot a bullet. if symbol == arcade.key.SPACE and not self.player_sprite.respawning: # Assign an image to the new sprite. bullet_sprite = bulletSprite("./resources/images/bullet.png", SCALE) # Name the sprite. bullet_sprite.guid = "brain" # Assign a speed to the sprite. bullet_speed = BULLET_SPEED # Set direction. bullet_sprite.change_y = \ math.cos(math.radians(self.player_sprite.angle)) * bullet_speed bullet_sprite.change_x = \ -math.sin(math.radians(self.player_sprite.angle)) \ * bullet_speed # Set location. bullet_sprite.center_x = self.player_sprite.center_x bullet_sprite.center_y = self.player_sprite.center_y # Update the sprite in memory. bullet_sprite.update() # Add new sprite to the two relevant sprite lists. self.list_all_sprites.append(bullet_sprite) self.list_bullets.append(bullet_sprite) # Play a throwing sound. arcade.play_sound(self.sound_throw) # For when sound on/off becomes available in Arcade library: ''' elif symbol == arcade.key.M: if self.toggle_sound_on == True: arcade.stop_sound(self.sound_song) self.toggle_sound_on = False else: arcade.play_sound(self.sound_song) self.toggle_sound_on = True ''' # If they pressed the left cursor control key or the "A" key, # change player facing angle 2 degrees counter clockwise. if symbol == arcade.key.LEFT or symbol == arcade.key.A: self.player_sprite.change_angle = 2 # print(str(self.player_sprite.angle)) # If they pressed the right cursor control key or the "D" key, # change player facing angle 2 degrees counter counter-clockwise. elif symbol == arcade.key.RIGHT or symbol == arcade.key.D: self.player_sprite.change_angle = -2 # print(str(self.player_sprite.angle)) # If they pressed the UP cursor or the "W" key, # increase thrust. elif symbol == arcade.key.UP or symbol == arcade.key.W: self.player_sprite.thrust = 0.15 # If they pressed the DOWN cursor or the "S" key, # decrease thrust toward opposite direction. elif symbol == arcade.key.DOWN or symbol == arcade.key.S: self.player_sprite.thrust = -.2 # Increase game speed and difficulty. # We chose the "equal" key instead of the "plus" # key here so the Player does not have to use the # SHIFT along with "equal" key to get a "+" result. elif symbol == arcade.key.EQUAL: self.player_sprite.difficulty += 1 self.player_sprite.update() if self.player_sprite.difficulty > 15: self.player_sprite.difficulty = 15 # Decrease game difficulty. elif symbol == arcade.key.MINUS: self.player_sprite.difficulty -= 1 self.player_sprite.update() if self.player_sprite.difficulty < 1: self.player_sprite.difficulty = 1 # When any movement key is released. def on_key_release(self, symbol, modifiers): # If LEFT cursor or "A" UNpressed: Set change angle to zero if symbol == arcade.key.LEFT or symbol == arcade.key.A: self.player_sprite.change_angle = 0 # If RIGHT cursor or "D" UNpressed: Set change angle to zero elif symbol == arcade.key.RIGHT or symbol == arcade.key.D: self.player_sprite.change_angle = 0 # If UP cursor or "W" UNpressed: Set thrust to zero elif symbol == arcade.key.UP or symbol == arcade.key.W: self.player_sprite.thrust = 0 # If DOWN cursor or "S" UNpressed: Set thrust to zero elif symbol == arcade.key.DOWN or symbol == arcade.key.S: self.player_sprite.thrust = 0 # Move all sprites: def on_update(self, x_delta): if self.pause: return self.frame_count += 1 fps = x_delta * 3600 # If you want to see your FPS, # uncomment the print statement below. # print("fps: " + str(fps)) # Set up enemy_speedy variable for local-to-this-function use. # enemy_speedy = 0 if not self.game_over: self.list_all_sprites.update() # Cycle through all bullets currently on screen. for bullet in self.list_bullets: # Check for bullet collision with enemy enemies = arcade.check_for_collision_with_list(bullet, self.list_enemies) # Cycle through all (if any) enemies hit by current bullet. i = -1 for enemy in enemies: i += 1 # Give Player points for hitting enemy based on difficulty level. self.score += int(100 * self.player_sprite.difficulty) # Stop enemy that was hit enemy.change_x = 0 enemy.change_y = 0 url_image_primary = enemy.url_image_primary # Grow the enemy size. new_scale = enemy.scale + 0.07 # When the enemy gets to a certain size, # they become "enraged". # print("scale: " + str(new_scale)) if new_scale > 0.66: new_scale = 0.7 enemy.enraged = True # enraged sound enabled for THIS enemy? if url_image_primary.find(enemy.guid) > -1: # following builds this: "self.sound_char_02_enraged" build_sound_name = enemy.which_sound arcade.play_sound(eval(build_sound_name)) else: arcade.play_sound(self.sound_powerup) # Change image for "enraged" version with red eyes. # url_image_primary = url_image_primary.replace("front","enraged") # enemy.texture = arcade.load_texture(enemy.url_image_secondary) enemy.texture = enemy.texture_enraged else: arcade.play_sound(self.sound_powerup) # arcade.play_sound(self.sound_munch) # arcade.play_sound(self.sound_) enemy.scale = new_scale # If you want enemy speed to increase when they # are hit, uncommment the following line # new_enemy_sprite.speed = enemy.speed + 0.1 enemy.change_x = 0 enemy.change_y = 0 enemy.timer_rand = int(fps * (12 - self.player_sprite.difficulty)) enemy.timer_smart = 0 enemy.update() # Delete the bullet that collided with an enemy. bullet.remove_from_sprite_lists() # if player not invulnerable (respawning): if not self.player_sprite.respawning: # get player position so enemies can move toward player player_pos_x = self.player_sprite.center_x player_pos_y = self.player_sprite.center_y # Continuous firing if self.firing == True: self.firing_counter += 1 if self.firing_counter > 40: self.firing_counter = 0 self.bulletFired() # Enemy movement enemy_number = 0 for enemy in self.list_enemies: enemy_number += 1 # enemy_speedy = enemy.speed enemy.speed = 2 + (self.player_sprite.difficulty/12) + enemy.scale/2.2 random.seed(datetime.now() + timedelta(0, enemy_number)) # Update enemy movement timers. enemy.timer_rand -= 1 enemy.timer_smart -= 1 # Set up/reset variables for enemy direction of movement. dir_x = 0 dir_y = 0 # Did both enemy movement direction timers run out? if enemy.timer_rand < 1 and enemy.timer_smart < 1: # Random number based on difficulty so below # we can decide if the enemy will move randomly # or toward the Player. random_or_smart = random.randint(1, 20 + (self.player_sprite.difficulty * 2)) else: # Make sure no random movment happens. random_or_smart = 1000 # Decide to move the enemy either randomly or "intelligently". # Lower the "20" if you want random movement more often. if random_or_smart < 20: # How long to continue in the random direction? enemy.timer_rand = int(fps * 7) # ~ 7 seconds enemy.timer_smart = 0 # Random 8 directions N, S, E, W, NE, SE, NW, SW direction = random.randint(1, 8) if direction == 1: dir_y = 1 elif direction == 2: dir_x = 1 dir_y = 1 elif direction == 3: dir_x = 1 elif direction == 4: dir_x = -1 dir_y = 1 elif direction == 5: dir_y = -1 elif direction == 6: dir_y = -1 dir_x = 1 elif direction == 7: dir_x = -1 elif direction == 8: dir_x = -1 dir_y = -1 enemy.change_x = dir_x * (enemy.speed - 2) enemy.change_y = dir_y * (enemy.speed - 2) elif enemy.timer_rand < 1: enemy.timer_rand = 0 # If smart movement timer runs out, # reset it. if enemy.timer_smart < 1: # Set smart movement timer to random number between # 1 second and 3 seconds. enemy.timer_smart = random.randint(int(fps * 1), int(fps * 4)) y_pos = enemy.center_y x_pos = enemy.center_x # If Player is above enemy, set y direction to up. if player_pos_y > y_pos: dir_y = 1 # If Player is to the right of enemy, set x direction to right. if player_pos_x > x_pos: dir_x = 1 # If Player is below enemy, set y direction to down. if player_pos_y < y_pos: dir_y = -1 # If Player is to the left of enemy, set x direction to left. if player_pos_x < x_pos: dir_x = -1 # Set enemy x and y directions based on above four tests, modified with speed. enemy.change_x = dir_x * (enemy.speed - 2) enemy.change_y = dir_y * (enemy.speed - 2) # Set new position for THIS enemy. enemy.center_x += enemy.change_x enemy.center_y += enemy.change_y # Check for collision between this enemy and all ice blocks. if enemy.immunity == False: any_collisions = arcade.check_for_collision_with_list(enemy, self.list_blocks) if len(any_collisions) > 0: # THIS enemy collided with an obstruction. if enemy.enraged == True: enemy.frustration += 1 if enemy.frustration > ENEMY_FRUSTRATION_THRESHOLD - (self.player_sprite.difficulty * 15): enemy.immunity = True # Reverse direction with added random factor. # The added random factor helps the enemy # get around the block they hit. random.seed(datetime.now() + timedelta(0,enemy_number)) x_rand = random.randint(1, 50) if x_rand < 25: dir_x *= -2 else: dir_y *= -2 # Change enemy direction based on above and enemy speed. enemy.change_x = dir_x * (enemy.speed) enemy.change_y = dir_y * (enemy.speed) # Change enemy position based on the above direction change. enemy.center_x += enemy.change_x enemy.center_y += enemy.change_y enemy.timer_rand = 0 # Set smart timer to ~4 seconds of this direction so the # enemy for sure gets away from the ice block they hit. enemy.timer_smart = int(fps * 4) # Check for enemy collisions with each other. any_collisions = arcade.check_for_collision_with_list(enemy, self.list_enemies) if len(any_collisions) > 0: # THIS enemy collided with another enemy. # Reverse direction with added random factor. # The added random factor helps the enemy # get around the block they hit. random.seed(datetime.now() + timedelta(0,enemy_number)) x_rand = random.randint(1, 50) if x_rand < 25: dir_x *= -2 else: dir_y *= -2 # Change enemy direction based on above and enemy speed. enemy.change_x = dir_x * (enemy.speed) enemy.change_y = dir_y * (enemy.speed) # Change enemy position based on the above direction change. enemy.center_x += enemy.change_x enemy.center_y += enemy.change_y enemy.timer_rand = 0 # Set smart timer to ~4 seconds of this direction so the # enemy for sure gets away from the ice block they hit. enemy.timer_smart = int(fps * 4) enemy.update() if PLAYER_IMMUNE_TO_BLOCKS == False: # Check for collision between player and all blocks. any_collisions = arcade.check_for_collision_with_list(self.player_sprite, self.list_blocks) if len(any_collisions) > 0: # Player hit a block, so change facing # angle to opposite of what it was. self.player_sprite.angle *= -1 self.player_sprite.change_x = -math.sin(math.radians(self.player_sprite.angle)) * self.player_sprite.speed self.player_sprite.change_y = math.cos(math.radians(self.player_sprite.angle)) * self.player_sprite.speed self.player_sprite.center_x += self.player_sprite.change_x self.player_sprite.center_y += self.player_sprite.change_y # Check for collision between player and all enemies enemies = arcade.check_for_collision_with_list(self.player_sprite, self.list_enemies) # If list of enemies hit created above has at least one enemy: if len(enemies) > 0: arcade.play_sound(self.sound_gasp_of_death) arcade.play_sound(self.sound_munch) arcade.play_sound(self.sound_burp) self.eaten = True # Remove a life from count if self.lives > 0: self.lives -= 1 self.player_sprite.respawn() # If you want the collision to destroy the enemy, add this code: # enemies[0].remove_from_sprite_lists() self.list_player_lives.pop().remove_from_sprite_lists() else: self.game_over = True else: self.eaten = False # Primary starting function def main(): game = GameClass() #game.setup_buttons() game.start_new_game() arcade.run() if __name__ == "__main__": main()