DEV Community

Kajiru
Kajiru

Posted on

Getting Started with 2D Games Using Pyxel (Part 6): Moving Characters

Moving Characters

Now it’s time to finally move the sprite we created in the previous chapter.
In this chapter, we will give sprites a concept of velocity and build a simple movement system.

The complete code is shown at the end of this article.

1. Improving the Sprite Class

First, we enhance the common base class BaseSprite.
In its constructor, we add two new member variables: vx and vy.

These variables are added to the sprite’s coordinates x and y during the update() step.

By doing this, the character’s position changes little by little,
which makes it appear to move on the game screen.

We also add a new method called move().
As the name suggests, this method starts the movement.

It takes speed and angle as arguments:

  • The horizontal component (X direction) is calculated with math.cos() and assigned to vx
  • The vertical component (Y direction) is calculated with math.sin() and assigned to vy

(You don’t need to fully understand the math behind this yet—it’s totally fine!)

# sprite.py (excerpt)

class BaseSprite:

    def __init__(self, x, y, w=8, h=8):
        """ Constructor """
        self.x = x
        self.y = y
        self.w = w
        self.h = h
        self.vx = 0  # Velocity (X direction)
        self.vy = 0  # Velocity (Y direction)

    def update(self):
        """ Update logic """
        self.x += self.vx  # Move in X direction
        self.y += self.vy  # Move in Y direction

    def draw(self):
        """ Drawing logic (implemented in subclasses) """
        pass

    def move(self, spd, deg):
        """ Start movement """
        rad = deg * math.pi / 180
        self.vx = spd * math.cos(rad)  # X velocity
        self.vy = spd * math.sin(rad)  # Y velocity
Enter fullscreen mode Exit fullscreen mode

2. Defining Constants

Next, add a constant to main.py that represents the player’s movement speed.
Defining values as constants makes them much easier to adjust later.

# main.py (add constants)

SHIP_SPD = 1.4  # Player speed
Enter fullscreen mode Exit fullscreen mode

3. Testing Sprite Movement

Now let’s check whether the sprite actually moves.
Inside the constructor of the Game class, we give the player a movement command for testing.

# main.py (added to the Game class constructor)

# Test movement (toward the upper-left)
self.ship.move(SHIP_SPD, 220)
Enter fullscreen mode Exit fullscreen mode

Try changing the angle value and confirm that the movement direction changes as well.

Complete Code

Below is the complete code with all features implemented so far.

# sprite.py

import pyxel
import math
import random

class BaseSprite:

    def __init__(self, x, y, w=8, h=8):
        """ Constructor """
        self.x = x
        self.y = y
        self.w = w
        self.h = h
        self.vx = 0  # Velocity (X direction)
        self.vy = 0  # Velocity (Y direction)

    def update(self):
        """ Update logic """
        self.x += self.vx  # Move in X direction
        self.y += self.vy  # Move in Y direction

    def draw(self):
        """ Drawing logic (implemented in subclasses) """
        pass

    def move(self, spd, deg):
        """ Start movement """
        rad = deg * math.pi / 180
        self.vx = spd * math.cos(rad)  # X velocity
        self.vy = spd * math.sin(rad)  # Y velocity

class ShipSprite(BaseSprite):

    def __init__(self, x, y):
        """ Constructor """
        super().__init__(x, y)

    def draw(self):
        """ Drawing logic """
        pyxel.blt(
            self.x, self.y, 0,
            0, 0,
            self.w, self.h, 0
        )  # Ship
Enter fullscreen mode Exit fullscreen mode
# main.py

import pyxel
import math
import random
import sprite

W, H = 160, 120
SHIP_SPD = 1.4  # Player speed

# Game
class Game:
    def __init__(self):
        """ Constructor """

        # Initialize score
        self.score = 0

        # Initialize player
        self.ship = sprite.ShipSprite(W / 2, H - 40)

        # Test movement (toward the upper-left)
        self.ship.move(SHIP_SPD, 220)

        # Start Pyxel
        pyxel.init(W, H, title="Hello, Pyxel!!")
        pyxel.load("shooter.pyxres")
        pyxel.run(self.update, self.draw)

    def update(self):
        """ Update logic """

        # Update player
        self.ship.update()

    def draw(self):
        """ Drawing logic """
        pyxel.cls(0)

        # Draw score
        pyxel.text(
            10, 10,
            "SCORE:{:04}".format(self.score),
            12
        )

        # Draw player
        self.ship.draw()

def main():
    """ Main entry point """
    Game()

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

When you run this program, the result will look like this:

Coming Up Next...

Thank you for reading this chapter.
The next title is “Controlling the Character.”

See you next time!!

Top comments (0)