Hit Points and Health Bars

Screenshot of using sprites to shoot things
sprite_health.py
  1"""
  2Sprite Hit Points and Health Bars
  3
  4Artwork from http://kenney.nl
  5
  6If Python and Arcade are installed, this example can be run from the command line with:
  7python -m arcade.examples.sprite_health
  8"""
  9import random
 10import arcade
 11
 12SPRITE_SCALING_PLAYER = 0.5
 13SPRITE_SCALING_COIN = 0.2
 14SPRITE_SCALING_LASER = 0.8
 15COIN_COUNT = 50
 16
 17SCREEN_WIDTH = 800
 18SCREEN_HEIGHT = 600
 19SCREEN_TITLE = "Hit Points and Health Bars "
 20
 21BULLET_SPEED = 5
 22
 23HEALTHBAR_WIDTH = 25
 24HEALTHBAR_HEIGHT = 3
 25HEALTHBAR_OFFSET_Y = -10
 26
 27HEALTH_NUMBER_OFFSET_X = -10
 28HEALTH_NUMBER_OFFSET_Y = -25
 29
 30
 31class SpriteWithHealth(arcade.Sprite):
 32    """ Sprite with hit points """
 33
 34    def __init__(self, image, scale, max_health):
 35        super().__init__(image, scale)
 36
 37        # Add extra attributes for health
 38        self.max_health = max_health
 39        self.cur_health = max_health
 40
 41    def draw_health_number(self):
 42        """ Draw how many hit points we have """
 43
 44        health_string = f"{self.cur_health}/{self.max_health}"
 45        arcade.draw_text(health_string,
 46                         start_x=self.center_x + HEALTH_NUMBER_OFFSET_X,
 47                         start_y=self.center_y + HEALTH_NUMBER_OFFSET_Y,
 48                         font_size=12,
 49                         color=arcade.color.WHITE)
 50
 51    def draw_health_bar(self):
 52        """ Draw the health bar """
 53
 54        # Draw the 'unhealthy' background
 55        if self.cur_health < self.max_health:
 56            arcade.draw_rectangle_filled(center_x=self.center_x,
 57                                         center_y=self.center_y + HEALTHBAR_OFFSET_Y,
 58                                         width=HEALTHBAR_WIDTH,
 59                                         height=3,
 60                                         color=arcade.color.RED)
 61
 62        # Calculate width based on health
 63        health_width = HEALTHBAR_WIDTH * (self.cur_health / self.max_health)
 64
 65        arcade.draw_rectangle_filled(center_x=self.center_x - 0.5 * (HEALTHBAR_WIDTH - health_width),
 66                                     center_y=self.center_y - 10,
 67                                     width=health_width,
 68                                     height=HEALTHBAR_HEIGHT,
 69                                     color=arcade.color.GREEN)
 70
 71class MyGame(arcade.Window):
 72    """ Main application class. """
 73
 74    def __init__(self):
 75        """ Initializer """
 76        # Call the parent class initializer
 77        super().__init__(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE)
 78
 79        # Variables that will hold sprite lists
 80        self.player_list = None
 81        self.coin_list = None
 82        self.bullet_list = None
 83
 84        # Set up the player info
 85        self.player_sprite = None
 86        self.score = 0
 87
 88        # Don't show the mouse cursor
 89        self.set_mouse_visible(False)
 90
 91        # Load sounds. Sounds from kenney.nl
 92        self.gun_sound = arcade.load_sound(":resources:sounds/hurt5.wav")
 93        self.hit_sound = arcade.load_sound(":resources:sounds/hit4.wav")
 94        self.death_sound = arcade.load_sound(":resources:sounds/hit5.wav")
 95
 96        arcade.set_background_color(arcade.color.AMAZON)
 97
 98    def setup(self):
 99
100        """ Set up the game and initialize the variables. """
101
102        # Sprite lists
103        self.player_list = arcade.SpriteList()
104        self.coin_list = arcade.SpriteList()
105        self.bullet_list = arcade.SpriteList()
106
107        # Set up the player
108        self.score = 0
109
110        # Image from kenney.nl
111        self.player_sprite = arcade.Sprite(":resources:images/animated_characters/female_person/femalePerson_idle.png", SPRITE_SCALING_PLAYER)
112        self.player_sprite.center_x = 50
113        self.player_sprite.center_y = 70
114        self.player_list.append(self.player_sprite)
115
116        # Create the coins
117        for i in range(COIN_COUNT):
118
119            # Create the coin instance
120            # Coin image from kenney.nl
121            coin = SpriteWithHealth(":resources:images/items/coinGold.png",
122                                    SPRITE_SCALING_COIN,
123                                    max_health=5)
124
125            # Position the coin
126            coin.center_x = random.randrange(SCREEN_WIDTH)
127            coin.center_y = random.randrange(150, SCREEN_HEIGHT)
128
129            # Add the coin to the lists
130            self.coin_list.append(coin)
131
132        # Set the background color
133        arcade.set_background_color(arcade.color.AMAZON)
134
135    def on_draw(self):
136        """
137        Render the screen.
138        """
139
140        # This command has to happen before we start drawing
141        arcade.start_render()
142
143        # Draw all the sprites.
144        self.coin_list.draw()
145        self.bullet_list.draw()
146        self.player_list.draw()
147
148        for coin in self.coin_list:
149            coin.draw_health_number()
150            coin.draw_health_bar()
151
152        # Render the text
153        arcade.draw_text(f"Score: {self.score}", 10, 20, arcade.color.WHITE, 14)
154
155    def on_mouse_motion(self, x, y, dx, dy):
156        """
157        Called whenever the mouse moves.
158        """
159        self.player_sprite.center_x = x
160
161    def on_mouse_press(self, x, y, button, modifiers):
162        """
163        Called whenever the mouse button is clicked.
164        """
165        # Gunshot sound
166        arcade.play_sound(self.gun_sound)
167        # Create a bullet
168        bullet = arcade.Sprite(":resources:images/space_shooter/laserBlue01.png", SPRITE_SCALING_LASER)
169
170        # The image points to the right, and we want it to point up. So
171        # rotate it.
172        bullet.angle = 90
173
174        # Give the bullet a speed
175        bullet.change_y = BULLET_SPEED
176
177        # Position the bullet
178        bullet.center_x = self.player_sprite.center_x
179        bullet.bottom = self.player_sprite.top
180
181        # Add the bullet to the appropriate lists
182        self.bullet_list.append(bullet)
183
184    def on_update(self, delta_time):
185        """ Movement and game logic """
186
187        # Call update on bullet sprites
188        self.bullet_list.update()
189
190        # Loop through each bullet
191        for bullet in self.bullet_list:
192
193            # Check this bullet to see if it hit a coin
194            hit_list = arcade.check_for_collision_with_list(bullet, self.coin_list)
195
196            # If it did, get rid of the bullet
197            if len(hit_list) > 0:
198                bullet.remove_from_sprite_lists()
199
200            # For every coin we hit, process
201            for coin in hit_list:
202                # Make sure this is the right type of class
203                if not isinstance(coin, SpriteWithHealth):
204                    raise TypeError("List contents must be all ints")
205
206                # Remove one health point
207                coin.cur_health -= 1
208
209                # Check health
210                if coin.cur_health <= 0:
211                    # Dead
212                    coin.remove_from_sprite_lists()
213                    self.score += 1
214                    arcade.play_sound(self.death_sound)
215                else:
216                    # Not dead
217                    arcade.play_sound(self.hit_sound)
218
219            # If the bullet flies off-screen, remove it.
220            if bullet.bottom > SCREEN_HEIGHT:
221                bullet.remove_from_sprite_lists()
222
223
224def main():
225    """ Main Program """
226    window = MyGame()
227    window.setup()
228    arcade.run()
229
230
231if __name__ == "__main__":
232    main()