DEV Community

Kajiru
Kajiru

Posted on

Getting Started with 2D Games Using Arcade Library (Part 12): Switching Animations

Switching Animations

This time, we’ll look at a sample implementation.
The player’s animation changes depending on the movement direction.

Adding Ninja Images

Add the following images into the ninja folder under the images directory.

1. Back View

Image File Name Image File Name Image File Name
 back_01.png  back_02.png  back_03.png
 back_04.png  back_05.png

2. Running to the Left

Image File Name Image File Name Image File Name
 left_01.png  left_02.png  left_03.png
 left_04.png  left_05.png

3. Running to the Right

Image File Name Image File Name Image File Name
 right_01.png  right_02.png  right_03.png
 right_04.png  right_05.png

The folder structure should look like this:

# Folder structure
working_directory/
 ├ main.py
 ├ sprite.py
 └ images/
    ├ bg_temple.png
    ├ coin/
    └ ninja/  # Folder for ninja images
       ├ front_01.png
       ├ front_02.png
       ├ front_03.png
       ├ front_04.png
       ├ front_05.png
       ├ back_01.png
       ├ back_02.png
       ├ back_03.png
       ├ back_04.png
       ├ back_05.png
       ├ left_01.png
       ├ left_02.png
       ├ left_03.png
       ├ left_04.png
       ├ left_05.png
       ├ right_01.png
       ├ right_02.png
       ├ right_03.png
       ├ right_04.png
       └ right_05.png
Enter fullscreen mode Exit fullscreen mode

Complete Code

Below is the complete code implementing all features so far.
You can copy and run it as-is.

# sprite.py (complete code)
import arcade
import math

class BaseSprite(arcade.Sprite):

    def __init__(self, filename, x, y):
        super().__init__(filename)
        # Position
        self.center_x = x
        self.center_y = y
        # Velocity
        self.vx = 0
        self.vy = 0
        # Animation
        self.anim_counter = 0
        self.anim_interval = 4
        self.anim_index = 0
        self.anim_key = ""      # current animation key
        self.anim_pause = True # whether animation is paused
        self.anims = {}        # animation dictionary

    def update(self, delta_time):
        """Update"""
        self.center_x += self.vx * delta_time
        self.center_y += self.vy * delta_time
        # Animation
        self.update_animation()

    def move(self, spd, deg, tag=""):
        """Move sprite"""
        rad = deg * math.pi / 180
        self.vx = spd * math.cos(rad)
        self.vy = spd * math.sin(rad)
        if tag:
            self.change_animation(tag)

    def stop(self):
        """Stop sprite"""
        self.vx = 0
        self.vy = 0
        self.stop_animation()

    def update_animation(self):
        """Update animation"""
        if self.anim_key not in self.anims:
            return
        if self.anim_pause:
            return
        self.anim_counter += 1
        if self.anim_counter < self.anim_interval:
            return
        self.anim_counter = 0
        self.anim_index += 1
        anim = self.anims[self.anim_key]
        if len(anim) <= self.anim_index:
            self.anim_index = 0
        self.texture = anim[self.anim_index]

    def load_animation(self, key, filename, num):
        """Load animation"""
        anim = []
        for i in range(num):
            path = filename.format(i + 1)
            anim.append(arcade.load_texture(path))
        self.anims[key] = anim

    def change_animation(self, key):
        """Change animation"""
        if key not in self.anims:
            return
        self.anim_counter = 0
        self.anim_index = 0
        self.anim_key = key
        self.texture = self.anims[key][0]
        self.start_animation()

    def start_animation(self):
        """Start animation"""
        self.anim_pause = False

    def stop_animation(self):
        """Stop animation"""
        self.anim_pause = True


class Player(BaseSprite):

    def __init__(self, filename, x, y):
        super().__init__(filename, x, y)

        # Register animations
        self.load_animation("front", "images/ninja/front_{:02d}.png", 5)
        self.load_animation("left", "images/ninja/left_{:02d}.png", 5)
        self.load_animation("right", "images/ninja/right_{:02d}.png", 5)
        self.load_animation("back", "images/ninja/back_{:02d}.png", 5)
        self.change_animation("front")


class Coin(BaseSprite):

    def __init__(self, filename, x, y):
        super().__init__(filename, x, y)

        # Register animation
        self.load_animation("coin", "images/coin/coin_{:02d}.png", 5)
        self.change_animation("coin")
Enter fullscreen mode Exit fullscreen mode
# main.py (complete code)
import arcade
import sprite
import random

class GameView(arcade.View):

    def __init__(self, window):
        super().__init__()
        self.window = window
        self.w = self.window.width
        self.h = self.window.height

        # Background color
        self.background_color = arcade.color.PAYNE_GREY

        # Background sprite
        self.backgrounds = arcade.SpriteList()
        bkg = arcade.Sprite("images/bg_temple.png")
        bkg.center_x = self.w / 2
        bkg.center_y = self.h / 2
        self.backgrounds.append(bkg)

        # Player sprite
        self.players = arcade.SpriteList()
        self.player = sprite.Player(
            "images/ninja/front_01.png",
            x=self.w / 2,
            y=self.h / 2
        )
        self.players.append(self.player)

        # Coin sprites
        self.coins = arcade.SpriteList()
        for _ in range(10):
            x = random.random() * self.w
            y = random.random() * self.h
            coin = sprite.Coin("images/coin/coin_01.png", x=x, y=y)
            self.coins.append(coin)

        # Score
        self.score = 0
        self.score_text = arcade.Text(
            f"SCORE: {self.score}",
            self.w / 2,
            self.h - 20,
            arcade.color.BLACK,
            16,
            anchor_x="center",
            anchor_y="top"
        )

        # Sound
        self.se_coin = arcade.Sound("sounds/se_coin.ogg")

    def on_key_press(self, key, modifiers):
        # Move (WASD)
        if key == arcade.key.W:
            self.player.move(90, 90, "back")   # up
        if key == arcade.key.A:
            self.player.move(90, 180, "left")  # left
        if key == arcade.key.S:
            self.player.move(90, 270, "front") # down
        if key == arcade.key.D:
            self.player.move(90, 0, "right")   # right

    def on_key_release(self, key, modifiers):
        self.player.stop()

    def on_update(self, delta_time):
        self.players.update(delta_time)
        self.coins.update(delta_time)

        # Player x coin collision
        hit_coins = arcade.check_for_collision_with_list(
            self.player,
            self.coins
        )
        for coin in hit_coins:
            coin.remove_from_sprite_lists()
            # Score
            self.score += 1
            self.score_text.text = f"SCORE: {self.score}"
            # Play sound
            arcade.play_sound(self.se_coin)

    def on_draw(self):
        self.clear()
        self.backgrounds.draw()
        self.players.draw()
        self.coins.draw()
        self.score_text.draw()


def main():
    """Main entry point"""
    window = arcade.Window(480, 320, "Hello, Arcade!!")
    game = GameView(window)
    window.show_view(game)
    arcade.run()


if __name__ == "__main__":
    main()
Enter fullscreen mode Exit fullscreen mode

The result looks like this:

Closing Thoughts

Thank you for reading!
I hope this series inspires you to start making your own games. ޱ(ఠ皿ఠ)ว👍

Top comments (0)