A retro game engine for Python
MIT License
[ English | | Deutsch | Espaol | Franais | Italiano | | | Portugus | | Trke | ]
Pyxel is a retro game engine for Python.
Thanks to its simple specifications inspired by retro gaming consoles, such as only 16 colors can be displayed and only 4 sounds can be played back at the same time, you can feel free to enjoy making pixel art style games.
The motivation for the development of Pyxel is the feedback from users. Please give Pyxel a star on GitHub!
Pyxel's specifications and APIs are inspired by PICO-8 and TIC-80.
Pyxel is open source under the MIT license and free to use. Let's start making a retro game with Pyxel!
After installing Python3 (version 3.8 or higher), run the following command:
pip install -U pyxel
If you install Python using the official installer, please check the Add Python 3.x to PATH
checkbox to enable pyxel
command.
After installing Homebrew, run the following commands:
brew install pipx
pipx ensurepath
pipx install pyxel
To update the version after installing Pyxel, run pipx upgrade pyxel
.
After installing the SDL2 package (libsdl2-dev
for Ubuntu), Python3 (version 3.8 or higher), and python3-pip
, run the following command:
sudo pip3 install -U pyxel
If the above doesn't work, try self-building according to the instructions in Makefile.
The web version of Pyxel does not require Python or Pyxel installation and runs on PCs as well as smartphones and tablets with supported web browsers.
For specific instructions, please refer to this page.
After installing Pyxel, the examples of Pyxel will be copied to the current directory with the following command:
pyxel copy_examples
The examples to be copied are as follows:
An examples can be executed with the following commands:
cd pyxel_examples
pyxel run 01_hello_pyxel.py
pyxel play 30sec_of_daylight.pyxapp
After importing the Pyxel module in your python script, specify the window size with init
function first, then starts the Pyxel application with run
function.
import pyxel
pyxel.init(160, 120)
def update():
if pyxel.btnp(pyxel.KEY_Q):
pyxel.quit()
def draw():
pyxel.cls(0)
pyxel.rect(10, 10, 20, 20, 11)
pyxel.run(update, draw)
The arguments of run
function are update
function to update each frame and draw
function to draw screen when necessary.
In an actual application, it is recommended to wrap pyxel code in a class as below:
import pyxel
class App:
def __init__(self):
pyxel.init(160, 120)
self.x = 0
pyxel.run(self.update, self.draw)
def update(self):
self.x = (self.x + 1) % pyxel.width
def draw(self):
pyxel.cls(0)
pyxel.rect(self.x, 0, 8, 8, 9)
App()
When creating simple graphics without animation, show
function can be used to make the code more concise.
import pyxel
pyxel.init(120, 120)
pyxel.cls(1)
pyxel.circb(60, 60, 40, 7)
pyxel.show()
A created Python script can be executed using the python
command:
python PYTHON_SCRIPT_FILE
It can also be run with the pyxel run
command:
pyxel run PYTHON_SCRIPT_FILE
Additionally, the pyxel watch
command enables monitoring of changes in a specified directory, automatically re-running the program when changes are detected:
pyxel watch WATCH_DIR PYTHON_SCRIPT_FILE
Directory monitoring can be stopped by pressing Ctrl(Command)+C
.
The following special controls can be performed while a Pyxel application is running:
Esc
Alt(Option)+1
Alt(Option)+2
Alt(Option)+3
Alt(Option)+9
Alt(Option)+0
Alt(Option)+Enter
Shift+Alt(Option)+1/2/3
Shift+Alt(Option)+0
Pyxel Editor can create images and sounds used in a Pyxel application.
It starts with the following command:
pyxel edit PYXEL_RESOURCE_FILE
If the specified Pyxel resource file (.pyxres) exists, the file is loaded, and if it does not exist, a new file is created with the specified name. If the resource file is omitted, the name is my_resource.pyxres
.
After starting Pyxel Editor, the file can be switched by dragging and dropping another resource file.
The created resource file can be loaded with load
function.
Pyxel Editor has the following edit modes.
Image Editor
The mode to edit the image banks.
Drag and drop an image file (PNG/GIF/JPEG) onto the Image Editor to load the image into the currently selected image bank.
Tilemap Editor
The mode to edit tilemaps in which images of the image banks are arranged in a tile pattern.
Drag and drop a TMX file (Tiled Map File) onto the Tilemap Editor to load its layer in the drawing order that corresponds to the currently selected tilemap number.
Sound Editor
The mode to edit sounds.
Music Editor
The mode to edit musics in which the sounds are arranged in order of playback.
Pyxel images and tilemaps can also be created by the following methods:
Image.set
function or Tilemap.set
functionImage.load
functionPyxel sounds can also be created in the following method:
Sound.set
function or Music.set
functionPlease refer to the API reference for usage of these functions.
Pyxel supports a dedicated application distribution file format (Pyxel application file) that works across platforms.
Create the Pyxel application file (.pyxapp) with the pyxel package
command:
pyxel package APP_DIR STARTUP_SCRIPT_FILE
If the application should include resources or additional modules, place them in the application directory.
Metadata can be displayed at runtime by specifying it in the following format within the startup script. Fields other than title
and author
can be omitted.
# title: Pyxel Platformer
# author: Takashi Kitao
# desc: A Pyxel platformer example
# site: https://github.com/kitao/pyxel
# license: MIT
# version: 1.0
The created application file can be executed with the pyxel play
command:
pyxel play PYXEL_APP_FILE
Pyxel application file also can be converted to an executable or an HTML file with the pyxel app2exe
or pyxel app2html
commands.
width
, height
The width and height of the screen
frame_count
The number of the elapsed frames
init(width, height, [title], [fps], [quit_key], [display_scale], [capture_scale], [capture_sec])
Initialize the Pyxel application with screen size (width
, height
). The following can be specified as options: the window title with title
, the frame rate with fps
, the key to quit the application with quit_key
, the scale of the display with display_scale
, the scale of the screen capture with capture_scale
, and the maximum recording time of the screen capture video with capture_sec
.
e.g. pyxel.init(160, 120, title="My Pyxel App", fps=60, quit_key=pyxel.KEY_NONE, capture_scale=3, capture_sec=0)
run(update, draw)
Start the Pyxel application and call update
function for frame update and draw
function for drawing.
show()
Show the screen and wait until the Esc
key is pressed.
flip()
Refresh the screen by one frame. The application exits when the Esc
key is pressed. This function does not work in the web version.
quit()
Quit the Pyxel application.
load(filename, [excl_images], [excl_tilemaps], [excl_sounds], [excl_musics])
True
, the resource will not be loaded. If a palette file (.pyxpal) of the same name exists in the same location as the resource file, the palette display color will also be changed. The palette file is a hexadecimal entry of the display colors (e.g. 1100FF
), separated by newlines. The palette file can also be used to change the colors displayed in Pyxel Editor.mouse_x
, mouse_y
The current position of the mouse cursor
mouse_wheel
The current value of the mouse wheel
btn(key)
Return True
if key
is pressed, otherwise return False
. (Key definition list)
btnp(key, [hold], [repeat])
Return True
if key
is pressed at that frame, otherwise return False
. When hold
and repeat
are specified, True
will be returned at the repeat
frame interval when the key
is held down for more than hold
frames.
btnr(key)
Return True
if key
is released at that frame, otherwise return False
.
mouse(visible)
If visible
is True
, show the mouse cursor. If False
, hide it. Even if the mouse cursor is not displayed, its position is updated.
colors
List of the palette display colors. The display color is specified by a 24-bit numerical value. Use colors.from_list
and colors.to_list
to directly assign and retrieve Python lists.
e.g. old_colors = pyxel.colors.to_list(); pyxel.colors.from_list([0x111111, 0x222222, 0x333333]); pyxel.colors[15] = 0x112233
images
List of the image banks (0-2). (See the Image class)
e.g. pyxel.images[0].load(0, 0, "title.png")
tilemaps
List of the tilemaps (0-7). (See the Tilemap class)
clip(x, y, w, h)
Set the drawing area of the screen from (x
, y
) to width w
and height h
. Reset the drawing area to full screen with clip()
.
camera(x, y)
Change the upper left corner coordinates of the screen to (x
, y
). Reset the upper left corner coordinates to (0
, 0
) with camera()
.
pal(col1, col2)
Replace color col1
with col2
at drawing. pal()
to reset to the initial palette.
dither(alpha)
Applies dithering (pseudo-transparency) at drawing. Set alpha
in the range 0.0-1.0, where 0.0 is transparent and 1.0 is opaque.
cls(col)
Clear screen with color col
.
pget(x, y)
Get the color of the pixel at (x
, y
).
pset(x, y, col)
Draw a pixel of color col
at (x
, y
).
line(x1, y1, x2, y2, col)
Draw a line of color col
from (x1
, y1
) to (x2
, y2
).
rect(x, y, w, h, col)
Draw a rectangle of width w
, height h
and color col
from (x
, y
).
rectb(x, y, w, h, col)
Draw the outline of a rectangle of width w
, height h
and color col
from (x
, y
).
circ(x, y, r, col)
Draw a circle of radius r
and color col
at (x
, y
).
circb(x, y, r, col)
Draw the outline of a circle of radius r
and color col
at (x
, y
).
elli(x, y, w, h, col)
Draw an ellipse of width w
, height h
and color col
from (x
, y
).
ellib(x, y, w, h, col)
Draw the outline of an ellipse of width w
, height h
and color col
from (x
, y
).
tri(x1, y1, x2, y2, x3, y3, col)
Draw a triangle with vertices (x1
, y1
), (x2
, y2
), (x3
, y3
) and color col
.
trib(x1, y1, x2, y2, x3, y3, col)
Draw the outline of a triangle with vertices (x1
, y1
), (x2
, y2
), (x3
, y3
) and color col
.
fill(x, y, col)
Fill the area connected with the same color as (x
, y
) with color col
.
blt(x, y, img, u, v, w, h, [colkey], [rotate], [scale])
Copy the region of size (w
, h
) from (u
, v
) of the image bank img
(0-2) to (x
, y
). If negative value is set for w
and/or h
, it will reverse horizontally and/or vertically. If colkey
is specified, treated as transparent color. If rotate
(in degrees), scale
(1.0 = 100%), or both are specified, the corresponding transformation will be applied.
bltm(x, y, tm, u, v, w, h, [colkey], [rotate], [scale])
w
, h
) from (u
, v
) of the tilemap tm
(0-7) to (x
, y
). If negative value is set for w
and/or h
, it will reverse horizontally and/or vertically. If colkey
is specified, treated as transparent color. If rotate
(in degrees), scale
(1.0 = 100%), or both are specified, the corresponding transformation will be applied. The size of a tile is 8x8 pixels and is stored in a tilemap as a tuple of (tile_x, tile_y)
.text(x, y, s, col)
s
of color col
at (x
, y
).sounds
List of the sounds (0-63). (See the Sound class)
e.g. pyxel.sounds[0].speed = 60
musics
List of the musics (0-7). (See the Music class)
play(ch, snd, [tick], [loop], [resume])
Play the sound snd
(0-63) on channel ch
(0-3). If snd
is a list, it will be played in order. The playback start position can be specified by tick
(1 tick = 1/120 seconds). If True
is specified for loop
, loop playback is performed. To resume the previous sound after playback ends, set resume
to True
.
playm(msc, [tick], [loop])
Play the music msc
(0-7). The playback start position can be specified by tick
(1 tick = 1/120 seconds). If True
is specified for loop
, loop playback is performed.
stop([ch])
Stops playback of the specified channel ch
(0-3). stop()
to stop playing all channels.
play_pos(ch)
Get the sound playback position of channel ch
(0-3) as a tuple of (sound no, note no)
. Returns None
when playback is stopped.
ceil(x)
Returns the smallest integer greater than or equal to x
.
floor(x)
Returns the largest integer less than or equal to x
.
sgn(x)
Returns 1 when x
is positive, 0 when it is zero, and -1 when it is negative.
sqrt(x)
Returns the square root of x
.
sin(deg)
Returns the sine of deg
degrees.
cos(deg)
Returns the cosine of deg
degrees.
atan2(y, x)
Returns the arctangent of y
/x
in degrees.
rseed(seed)
Sets the seed of the random number generator.
rndi(a, b)
Returns an random integer greater than or equal to a
and less than or equal to b
.
rndf(a, b)
Returns a random decimal greater than or equal to a
and less than or equal to b
.
nseed(seed)
Sets the seed of Perlin noise.
noise(x, [y], [z])
Returns the Perlin noise value for the specified coordinates.
width
, height
The width and height of the image
set(x, y, data)
Set the image at (x
, y
) by a list of strings.
e.g. pyxel.images[0].set(10, 10, ["0123", "4567", "89ab", "cdef"])
load(x, y, filename)
Load the image file (PNG/GIF/JPEG) at (x
, y
).
pget(x, y)
Get the pixel color at (x
, y
).
pset(x, y, col)
Draw a pixel of color col
at (x
, y
).
width
, height
The width and height of the tilemap
imgsrc
The image bank (0-2) referenced by the tilemap
set(x, y, data)
Set the tilemap at (x
, y
) by a list of strings.
e.g. pyxel.tilemap(0).set(0, 0, ["0000 0100 a0b0", "0001 0101 a1b1"])
load(x, y, filename, layer)
Load the layer in the drawing order layer
(0-) from the TMX file (Tiled Map File) at (x
, y
).
pget(x, y)
Get the tile at (x
, y
). A tile is a tuple of (tile_x, tile_y)
.
pset(x, y, tile)
Draw a tile
at (x
, y
). A tile is a tuple of (tile_x, tile_y)
.
notes
List of notes (0-127). The higher the number, the higher the pitch, and at 33 it becomes 'A2'(440Hz). The rest is -1.
tones
List of tones (0:Triangle / 1:Square / 2:Pulse / 3:Noise)
volumes
List of volumes (0-7)
effects
List of effects (0:None / 1:Slide / 2:Vibrato / 3:FadeOut / 4:Half-FadeOut / 5:Quarter-FadeOut)
speed
Playback speed. 1 is the fastest, and the larger the number, the slower the playback speed. At 120, the length of one note becomes 1 second.
set(notes, tones, volumes, effects, speed)
Set notes, tones, volumes, and effects with a string. If the tones, volumes, and effects length are shorter than the notes, it is repeated from the beginning.
set_notes(notes)
Set the notes with a string made of 'CDEFGAB'+'#-'+'01234' or 'R'. Case-insensitive and whitespace is ignored.
e.g. pyxel.sounds[0].set_notes("G2B-2D3R RF3F3F3")
set_tones(tones)
Set the tones with a string made of 'TSPN'. Case-insensitive and whitespace is ignored.
e.g. pyxel.sounds[0].set_tones("TTSS PPPN")
set_volumes(volumes)
Set the volumes with a string made of '01234567'. Case-insensitive and whitespace is ignored.
e.g. pyxel.sounds[0].set_volumes("7777 7531")
set_effects(effects)
Set the effects with a string made of 'NSVFHQ'. Case-insensitive and whitespace is ignored.
e.g. pyxel.sounds[0].set_effects("NFNF NVVS")
seqs
Two-dimensional list of sounds (0-63) with the number of channels
set(seq0, seq1, seq2, ...)
Set the lists of sound (0-63) of channels. If an empty list is specified, that channel is not used for playback.
e.g. pyxel.musics[0].set([0, 1], [], [3])
Pyxel has "advanced APIs" that are not mentioned in this reference because they "may confuse users" or "need specialized knowledge to use".
If you are familiar with your skills, try to create amazing works with this as a clue!
Use the Issue Tracker to submit bug reports and feature/enhancement requests. Before submitting a new issue, ensure that there is no similar open issue.
Anyone manually testing the code and reporting bugs or suggestions for enhancements in the Issue Tracker are very welcome!
Patches/fixes are accepted in form of pull requests (PRs). Make sure the issue the pull request addresses is open in the Issue Tracker.
Submitted pull request is deemed to have agreed to publish under MIT License.
Pyxel is under MIT License. It can be reused within proprietary software, provided that all copies of the software or its substantial portions include a copy of the terms of the MIT License and also a copyright notice.
Pyxel is looking for sponsors on GitHub Sponsors. Consider sponsoring Pyxel for continued maintenance and feature additions. Sponsors can consult about Pyxel as a benefit. Please see here for details.