Quickstart

Introduction

In this quickstart, we will be guiding you towards creating a Player character you can move with WASD on your keyboard, a secondary character that will attempt to follow the Player, and a solid object the Player can collide with and jump over.

Importing Dependencies

Let’s get the ball rolling! Before we can do anything however, we will need to import the engine and pygame-ce.

# Import the main engine
import topdownengine as tde
# The first import allows for keyboard-based movement and the second one allows for AI-based movement.
from topdownengine.mobile_object.controller import KeyboardInputController, MovementAIController
# We will need this for pre-made animations the package comes with.
from topdownengine.asset_paths import ASSETS_DIR
# pygame-ce provides us with some really helpful utilities.
import pygame as pg

The Game Class

Great! Now that we have imported everything, let’s define the first thing you will define in every project you make. The Game class mainly functions as a wrapper for updates and rendering, but it is also used by individual GameObjects for a variety of things.

# Define an instance of the Game class
game = tde.Game(
    screen_width=900, 
    screen_height=650, 
    window_title="pygame-topdownengine Basic Usage Example",
    target_scale=3 # Add scale of three to make it more visible
)

The Player

Now that we have a Game instance, the next thing we will define is the Player. This code gives the player keyboard movement and animations (using the package’s premade animations).

# Define a MobileObject to be the Player + Enable Camera Tracking
player = tde.MobileObject(
    controller=KeyboardInputController(), 
    animation_paths={
        "idle": ASSETS_DIR / "example-player" / "idle.png",
        "walk": ASSETS_DIR / "example-player" / "walk.png"
    }, frame_size=(16, 16), directional_anims=True
)
game.camera.focus_game_object = player

The Enemy

Now let’s make the character that follows you. For the purposes of this tutorial, let’s call it the “enemy”. This code makes the enemy follow the player and uses the same animations as the Player itself.

# Define a MobileObject to follow the Player
enemy = tde.MobileObject(
    controller=MovementAIController(target_mobile_obj=player), 
    animation_paths=player.animation_paths, # Use same animations as the Player
    frame_size=(16, 16), directional_anims=True
)

EnvObject

Now let’s define a box the player can collide with and jump over. Essentially, this code will make the box 32x32 in world space, give it a shadow, and set its position away from (0, 0), which is the default position for all GameObjects, which include MobileObjects (like the player and enemy) and EnvObjects (like this box).

# Define an EnvObj
env_obj = tde.EnvObject(frame_size=(32, 32), colliders=[pg.Rect(0, 0, 32, 32)])
env_obj.position = pg.Vector2(100, 100)
env_obj.obj_shadow = '32x16'

Adding Them to the Game

Now, we need to add these three to the actual game itself. In order to do that, we add each one to the Game instance’s game_object_group.

# Add them to the game object group
game.game_object_group.add(player, env_obj, enemy)

The EnvObject (again?)

Now, we have to return to the EnvObject. By default, the GameObject class generates a four frame “flashing animation.” In order have our EnvObject not flash, we will make it use only the first frame (which is solid red).

We waited to do this after setting the scale because using the set_scale method automatically reloads animations, meaning if we had done it earlier, it would have regenerated the flashing animation.

env_obj.animations['idle'] = [env_obj.animations['idle'][0]]

Subpixel vs Pixel-Perfect Rendering

pygame-topdownengine offers both pixel-perfect rendering and subpixel rendering out of the box. By default, pixel-perfect rendering is used. However, if you want subpixel rendering to make it more smooth, you can do that with this code:

tde.GameObject.SUBPIXEL = True

Execution

You made it! If you got to this point in this tutorial, you’re almost there. Before everything’s well and done, we need to actually run the game. To do that, we call the run method on the Game instance as shown below:

# Run the game
game.run()

If everything went right, you should have a character you can control with WASD (with Space for jump), another character that follows you, and a red box you can jump over and collide with! If all’s not well, check out the example code on GitHub to see what went wrong.