A reference and guide to retroPy's API
Written by retrocat
15 minute read
[updated for retroPy beta 0.1 with RP2040]
While the core game engine is written in c and handled at the machine level to ensure a refresh rate of 50fps, we have exposed some key functions in micro-python as a library for user control and access.
To use the library, we’ll need to import it and ensure we have the minimum basic setup as shown.
from RetroPy.retroPy import rpy, kb, draw, gameObj, LoadSpriteStr, LoadSprite, sprite
def Update(dt):
pass
def Draw(dt):
pass
#==================================
rpy.run(Update, Draw)
By default, retroPy uses PICO-8’s 16 colour palette. Every number (0-15) represents a colour.
draw
class membersClears the screen with an optional colour. By default, the value is 0 which is black.
Example:
def Draw():
draw.clear()
Alternatively:
def Draw():
draw.clear(1) #fill the background with dark blue
Write text to screen at position x,y with an optional specified colour
def Draw():
draw.text("Hello World",50,50,7)
By default, retroPy uses a monospace 8x8 font size. Position x,y is the top left starting position.
Get/Set current palette colour for use in draw methods
def Draw():
draw.clear(0)
draw.currColor = 7
draw.text("Hello",50,50)
draw.text("World",50,60)
While drawing primitives is more costly and slower than drawing a sprite, they have their uses. retroPy supports the following primitive draw functions.
Draw a pixel at position x, y with an optional specified colour
def Draw():
draw.clear(0)
draw.currColor = 7
draw.pixel(10,10)
Draw an outline circle or filled circle given the center-point and radius, with an optional specified colour
Draw a line given the starting and ending x,y position, with an optional specified colour
Draw a horizontal/ vertical line given the starting x,y position and length of the line, with an optional specified colour
Draw an outline or filled rectangle, with an optional specified colour
*Draw a sprite image with the starting index, located at the provided pointer at position x,y with an optional flip value. Used for drawing images that do not require the functionality of that of a game object. *
ptr_chicken=(LoadSpriteStr(Bird.chicken))
def Draw():
draw.clear(0)
draw.sprite(0,ptr_chicken,120,120)
Refer to segment on loading sprites for more info.
retroPy supports 2 methods of storing and loading sprites.
In the Assets
folder, you will notice 2 types of sprites assets.
retroPy’s own 4-bit retroSprite files. Images are stored in a 4-bit colour format.
Sprites and animation frames are stored in strings of numbers (representing palette colours).
To load rs4 sprites, provide the file path to the rs4 file.
from RetroPy.retroPy import rpy, LoadSprite
p_fire = LoadSprite("Assets/fire1.rs4") #<< rs4 file
To load sprites stored in python Sprite String files, import the .py file as a library.
from RetroPy.retroPy import rpy, LoadSpriteStr
from RetroPy.Sprites import heart
p_player = LoadSpriteStr(heart.heart) #<< python string file
Where Sprites
is the folder name, and heart is the python file name (heart.py
), followed by the variable named heart
.
retroPy comes with standard assets for you to quickly get started.
Game Objects are objects that have native support for what we consider essential in a game.
retroPy natively supports game objects with the following:
retroPy is sprite-centric. All sprites are treated as a game object. This includes the characters, items, special effects and game terrains.
To create a game object, we’ll make use of the gameObj
class like so.
player = gameObj(p_player, pos_x, pos_y, flip_duration, speed_x, speed_y)
The gameObj
class requires a few things.
p_player
- pointer to where the sprite ispos_x
, pos_y
- starting x, y coordinates of the game objectflip_duration
- (if sprite is an animation) how long(ms) to show each frame before showing the next (leave as 0 if static image)speed_x
, speed_y
- how fast (pixels per second) to move the sprite along the x and y axisThe main concept to using the game object is a simple 3 steps.
- Load sprite
- Create game object
- Use in Update/Draw Loop
As an example, let’s create a cat character and get it to appear in the bottom-left of the screen.
cat = gameObj(p_cat, 10, 220, 200, 0, 0)
We’ll place that line into the basic setup like so.
from RetroPy.retroPy import rpy, gameObj LoadSpriteStr
from RetroPy.Sprites import cat
#1. Load sprite image into memory
p_cat = LoadSpriteStr(cat.idle)
#2. Create game object
cat = gameObj(p_cat, 10, 220, 200, 0, 0)
#3. Use in update/draw loop
def Update(dt):
cat.update(dt) #update required for animation. (not needed for static images eg. terrain.)
pass
def Draw(dt):
rpy.clear()
cat.draw()
pass
#====================================================
rpy.run(Update, Draw)
You should see the cat on the screen with an idle animation like so.
Get/ Set the (top left) position of the game object
Example:
#set the player position to coordinates (0,0)
player.pos(0,0)
alternatively,
player.pos_x = 0
player.pos_y = 0
Get/Set the middle (center point) or bottom (bottom right) position of the game object
Example:
player.mid_x = 7
player.mid_y = 7
player.bot_x = 15
player.bot_y = 15
Get/Set the speed (pixels per second) of the game object along the x and y axis
Example:
#move the player to the right at a speed of 20
player.speed(20,0)
Alternatively,
player.speed_x = 20
player.speed_y = 0
Get/Set the acceleration of the game object along the x and y axis
Example:
#set an upward acceleration of 10
player.acc(0,-10)
Alternatively,
player.acc_x = 0
player.acc_y = -10
Get distance in pixels from another game object
Example:
cat.dist(food)
Move game object to a given coordinate at a given speed.
Example:
def Update(dt):
cat.moveTowards(food.pos_x, food.pos_y, 20, dt)
pass
Set movement boundaries of game object. Game objects will not move past these boundaries.
The following game object members are specific to the sprites used in the game object.
These are especially useful for changing sprite properties on the fly.
Set pointer to sprite to be used.
Example:
if kb.A_down:
cat.sprite(p_cat_attack, 200)
Set current index of sprite to be used. Pick index frame from animation.
Example use: Ending off a moving sprite animation to a final static image.
Flip sprite horizontally and/or vertically
Flip Options:
Example use: Changing player walking direction, without needing separate sprites for each direction.
if kb.right_down:
cat.sprite(p_cat_run,200)
cat.speed_x = 30
cat.flip(0) #no flip. cat sprite is already facing right
if kb.left_down:
cat.sprite(p_cat_run,200)
cat.speed_x = -30
cat.flip(1) #flip sprite horizontally. In this case, from right to left
Sprite animation display mode
Mode Options:
Set how long(ms) to show each frame before showing the next frame in the animation (leave as 0 if sprite is static)
Colliders are useful for troubleshooting during the development process of the game, and for checking if the game objects have collided into other game objects like walls/ enemies/ items. Colliders are part of game objects.
Draws a rectangle in a given colour to represent the collider. By default, the collider is the size of the sprite.
Example:
def Draw(dt):
draw.clear()
cat.draw()
cat.drawCollider(3)
pass
Returns True if the game object collided with another game object.
Example:
def Update(dt):
food.update(dt)
cat.moveTowards(food.pos_x, food.pos_y, 20, dt)
if cat.collider(food):
print("Collide!")
Similar to collider with extra info
Check if a point is inside the gameObj collider
Resize the gameObj collider.
Example use: AOE damage
Check if gameObj collides with another gameObj at position x,y
kb
MembersThe retroPy game engine natively supports the handheld game console’s 8 button inputs.
Obtaining the 2 states of a button press - Down & Up (release) is easy.
Example:
def Update(dt):
if kb.right_down:
cat.sprite(p_cat_run,200)
cat.speed_x = 30
cat.flip(0) #no flip. cat sprite is already facing right
if kb.left_down:
cat.sprite(p_cat_run,200)
cat.speed_x = -30
cat.flip(1) #flip sprite horizontally. In this case, from right to left
if kb.left_up or kb.right_up:
cat.sprite(p_cat,200) #set back to idle animation
cat.speed_x = 0
Full list below.
To get the button Down (pressed) or Up (released) state, check the corresponding buttons in the update loop.
Directional Buttons:
Action Buttons:
Shoulder Trigger Buttons:
rpy
core membersQuits the run loop
Pauses the run loop
Resumes the run loop after a pause
Pauses game timer
Resumes game timer
If you find any bugs or problems with the documentation, please open an issue over on Github.
GithubFeel free to drop us a tweet if you have suggestions for retroPy. Or if you just want to say hi.
Twitter