Readers like you help support MUO. When you make a purchase using links on our site, we may earn an affiliate commission. Read More.

Enemies play a crucial role in creating engaging and challenging games. They provide obstacles and adversaries for players, making the gaming experience more exciting. Python's Arcade library offers a straightforward way to incorporate enemies into your games.

Create a Simple Game

Before starting, make sure you have pip installed on your device. Use this command to install the arcade library:

 pip install arcade 

After that, start by creating a simple game where the player can move left and right using the arrow keys.

MAKEUSEOF VIDEO OF THE DAY
SCROLL TO CONTINUE WITH CONTENT

The code used in this article is available in this GitHub repository and is free for you to use under the MIT license.

 import arcade

# Window dimensions
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600

# Player attributes
PLAYER_RADIUS = 25
PLAYER_SPEED = 5

class GameWindow(arcade.Window):
    def __init__(self, width, height):
        super().__init__(width, height)
        arcade.set_background_color(arcade.color.WHITE)
        self.player_x = width // 2

    def on_draw(self):
        arcade.start_render()
        arcade.draw_circle_filled(self.player_x, PLAYER_RADIUS, PLAYER_RADIUS, arcade.color.BLUE)

    def on_key_press(self, key, modifiers):
        if key == arcade.key.LEFT:
            self.player_x -= PLAYER_SPEED
        elif key == arcade.key.RIGHT:
            self.player_x += PLAYER_SPEED

    def update(self, delta_time):
        pass

def main():
    window = GameWindow(SCREEN_WIDTH, SCREEN_HEIGHT)
    arcade.run()

if __name__ == "__main__":
    main()

Creating a Simple Enemy

To create an enemy that kills the player upon collision, create another circle on the screen. In the on_draw function, you can draw this enemy circle and check for collisions in the update method. You can also use sprites for enemies.

 # Add to GameWindow class

class GameWindow(arcade.Window):
    # ...

    def __init__(self, width, height):
        # ...

        # Enemy attributes
        self.enemy_x = width // 2
        self.enemy_y = height - PLAYER_RADIUS
        self.enemy_radius = 20

    def on_draw(self):
        # ...
        arcade.draw_circle_filled(self.enemy_x, self.enemy_y, self.enemy_radius, arcade.color.RED)

    def update(self, delta_time):
        if self.is_collision(self.player_x, self.player_y, self.enemy_x, self.enemy_y, PLAYER_RADIUS, self.enemy_radius):
            print("Game Over!")
    
    def is_collision(self, x1, y1, x2, y2, radius1, radius2):
        distance_squared = (x1 - x2) ** 2 + (y1 - y2) ** 2
        radius_sum_squared = (radius1 + radius2) ** 2
        return distance_squared <= radius_sum_squared

Making Enemy Follow the Player

In some games, enemies can chase the player, adding a dynamic element to the gameplay. To create a following enemy, you need to update its position based on the player's position. Whenever the player moves, the enemy moves in the same direction. You can achieve this by modifying the update method. Create a new file named enemy-follow-player.py and add the code with the below updates:

 # Add to GameWindow class

class GameWindow(arcade.Window):
    # ...

    def update(self, delta_time):
        if self.player_x < self.enemy_x:
            self.enemy_x -= PLAYER_SPEED
        elif self.player_x > self.enemy_x:
            self.enemy_x += PLAYER_SPEED

        if self.is_collision(self.player_x, self.player_y,
                            self.enemy_x, self.enemy_y,
                            PLAYER_RADIUS, ENEMY_RADIUS):
           print("Game Over!")
  
    def is_collision(self, x1, y1, x2, y2, radius1, radius2):
        distance_squared = (x1 - x2) ** 2 + (y1 - y2) ** 2
        radius_sum_squared = (radius1 + radius2) ** 2
        return distance_squared <= radius_sum_squared

Below is the output:

enemy following player in an arcade game

Adding Enemy Bullets

To create an enemy that shoots bullets, create a Bullet class and a list to keep track of active bullets. The enemy will periodically create a new bullet and update its position. Create a new file named bullets.py and add the code with the below updates:

 # Add to GameWindow class

class Bullet:
    def __init__(self, x, y, radius, speed):
        self.x = x
        self.y = y
        self.radius = radius
        self.speed = speed

    def update(self):
        self.y -= self.speed

class GameWindow(arcade.Window):
    # ...

    def __init__(self, width, height):
        # ...

        # Enemy attributes
        self.bullets = []
        self.bullet_radius = 5
        self.bullet_speed = 3
        self.bullet_cooldown = 60 # Number of frames between bullet spawns
        self.bullet_timer = 0

    def on_draw(self):
        # ...
        for bullet in self.bullets:
            arcade.draw_circle_filled(bullet.x, bullet.y,
           self.bullet_radius, arcade.color.BLACK)

    def update(self, delta_time):
        # ...

        self.bullet_timer += 1
        if self.bullet_timer >= self.bullet_cooldown:
            self.bullets.append(Bullet(self.enemy_x, self.enemy_y - self.enemy_radius,
self.bullet_radius, self.bullet_speed))
            self.bullet_timer = 0

        for bullet in self.bullets:
            bullet.update()
            if self.is_collision(self.player_x, self.player_y, self.enemy_x,
self.enemy_y, PLAYER_RADIUS, ENEMY_RADIUS):
            print("Game Over!")
    
    def is_collision(self, x1, y1, x2, y2, radius1, radius2):
        distance_squared = (x1 - x2) ** 2 + (y1 - y2) ** 2
        radius_sum_squared = (radius1 + radius2) ** 2
        return distance_squared <= radius_sum_squared

Below is the output:

enemy shooting bullets towards player

Adding Health Points for Enemies

In many games, enemies can possess health points (HP), allowing them to sustain multiple hits before being defeated. Adding health points to enemies can introduce strategic gameplay elements and provide a sense of progression and challenge. Create a new file named heath-point.py and add the code with the below updates:

 # Window dimensions
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600

# Player attributes
PLAYER_RADIUS = 25
PLAYER_SPEED = 5

# Enemy attributes
ENEMY_RADIUS = 20
ENEMY_HEALTH = 100

class GameWindow(arcade.Window):
    def __init__(self, width, height):
        super().__init__(width, height)
        arcade.set_background_color(arcade.color.WHITE)
        self.player_x = width // 2
        self.player_y = height // 2
        self.enemy_x = width // 2
        self.enemy_y = height - PLAYER_RADIUS
        self.enemy_health = ENEMY_HEALTH
        print(self.enemy_health)
    def on_draw(self):
        arcade.start_render()
        arcade.draw_circle_filled(self.player_x,
                                  self.player_y,
                                  PLAYER_RADIUS,
                                  arcade.color.BLUE)
        if self.enemy_health > 0:
            arcade.draw_circle_filled(self.enemy_x,
                                      self.enemy_y,
                                      ENEMY_RADIUS,
                                      arcade.color.RED)

    def update(self, delta_time):
        if self.is_collision(self.player_x, self.player_y,
                             self.enemy_x, self.enemy_y,
                             PLAYER_RADIUS, ENEMY_RADIUS):
            self.enemy_health -= 10
            print(self.enemy_health)
        

The ENEMY_HEALTH constant has a value of 100 to represent the enemy's initial health points. When the player collides with the enemy, you can deduct some points from the enemy's health. To display the updated health value, you can print a text object self.health_text that shows the current enemy health.

By incorporating health points for enemies, you can introduce a layer of challenge and strategy for players. The displayed health value provides visual feedback and allows players to track the enemy's remaining health.

Additionally, you can expand the code by adding further logic and visuals, such as displaying health bars or implementing defeat conditions when the enemy's health reaches zero.

Best Practices for Creating Enemies

When designing enemies for your game, it's important to consider several best practices to ensure they contribute to a challenging and enjoyable gameplay experience. Here are some guidelines to follow when creating enemies:

Diverse Attributes

Create enemies with varying attributes such as speed, size, health, and attack power. Different enemy types should pose different levels of difficulty, requiring players to adapt their strategies accordingly. By introducing a mix of enemy attributes, you can keep the gameplay fresh and engaging.

Unique Behaviors

Give each enemy type its own unique behavior patterns. Some enemies may move in a predictable manner, while others might exhibit more complex or erratic movements. Consider incorporating enemy AI algorithms to make their behavior more intelligent and unpredictable, adding an extra layer of challenge for players.

Health Points (HP)

Implement health points for enemies to introduce a sense of progression and durability. This allows enemies to sustain multiple hits before being defeated. By assigning varying amounts of HP to different enemy types, you can create a hierarchy of difficulty and encourage players to strategize and prioritize their targets.

Make Games More Fun With Enemies

Adding enemies to your games can significantly enhance the gameplay experience. They introduce challenges and motivate players to improve their skills. Enemies can come in various forms, from simple obstacles to complex AI-driven adversaries. By implementing enemies effectively, you can make your games more engaging and enjoyable for players.