Posts
Search
Contact
Cookies
About
RSS

Python and raylib - great for beginners

Added 21 Sep 2020, 7:10 a.m. edited 18 Jun 2023, 1:12 a.m.

When I was looking around for an environment to teach programming, I thought wouldn't it be great if I could teach with raylib, however as much as I like C for all sorts of reasons, it can be a little daunting at first, especially if for example you've only coded with scratch before. Enter python which I kind of think as the modern successor to BASIC, add in a comprehensive wrapper for raylib and you have a powerful environment. Installing the wrapper is often easiest accomplished with pip. When looking at the code with this post I recommend using Thonny which is a great IDE for developing with python....

Linux setup

You are quite likely to have python3 and even pip installed already if not check your package manager. Open a terminal and type

pip install raylib

grab a text editor and you're ready to go!

Windows setup

Not surprisingly setup on windows is a little more complex, first grab python 3 I used the executable installer, do ensure the option add python to path is selected... (why it doesn't do this be default who knows!)

Once installed open a command prompt, first you need to upgrade pip

pip install --upgrade pip

once upgraded we can install the raylib module

pip install raylib

From there you can load scripts into the python IDLE editor and run them by pressing the F5 key. You might want to look for a more comfortable editor once you're all set up and working.

Lets look at some code

Phew! after all the setup its about time we looked at some code! here's my take on showing a window with some text on it, lets take a look so we can get a handle on how we need to use raylib.

from raylib.static import rl, ffi
from raylib.colors import *

# Initialization
rl.SetConfigFlags(rl.FLAG_MSAA_4X_HINT)  # Enable Multi Sampling Anti Aliasing 4x (if available)
rl.SetTargetFPS(60)
rl.InitWindow(800, 450, b"A window")

# Main game loop
while not rl.WindowShouldClose():  # Detect window close button or ESC key
    # Update
    # TODO: Update your variables here

    # Draw
    rl.BeginDrawing()
    rl.ClearBackground(BLACK)
    rl.DrawText(b'A window!', 20, 20, 42, WHITE)
    rl.EndDrawing()

The first thing to remember about python is that it is strict about indenting, it uses the indent (what column the text starts) in order to determine where a block of code begins and ends. For example the main loop is a while loop, notice that all the code in the loop is indented. The fact that python is strict about using indenting, has a interesting effect on your coding, it forces you to be tidy and makes the code easier to follow, add in a good habit of adding comments where you can and your code should be easy to follow, even if you haven't looked at it for some time.

from raylib.static import rl, ffi
from raylib.colors import *

The first two lines of the above example, tells python to include the raylib wrapper into our project. Accessing the library is via the namespace rl, we also import ffi which allows low level access to C structures (don't worry about this for now - we'll see more later) The second line simply imports all of the raylib colour values.

# Initialization
rl.SetConfigFlags(rl.FLAG_MSAA_4X_HINT)  # Enable Multi Sampling Anti Aliasing 4x (if available)
rl.SetTargetFPS(60)
rl.InitWindow(800, 450, b"A window")

next we have some simple initialisation, we can set hints for raylib to tell it the sort of window we want available flags are

typedef enum {
    FLAG_RESERVED           = 1,    // Reserved
    FLAG_FULLSCREEN_MODE    = 2,    // Set to run program in fullscreen
    FLAG_WINDOW_RESIZABLE   = 4,    // Set to allow resizable window
    FLAG_WINDOW_UNDECORATED = 8,    // Set to disable window decoration (frame and buttons)
    FLAG_WINDOW_TRANSPARENT = 16,   // Set to allow transparent window
    FLAG_WINDOW_HIDDEN      = 128,  // Set to create the window initially hidden
    FLAG_WINDOW_ALWAYS_RUN  = 256,  // Set to allow windows running while minimized
    FLAG_MSAA_4X_HINT       = 32,   // Set to try enabling MSAA 4X
    FLAG_VSYNC_HINT         = 64    // Set to try enabling V-Sync on GPU
} ConfigFlag;

Note that this is taken directly from raylib.h probably your best reference to the functions available in raylib next to the cheat sheet. Yes that's a LOT of functions! but don't worry, you don't need to know them all...

So now we have our new window its time for the main loop

# Main game loop
while not rl.WindowShouldClose():  # Detect window close button or ESC key
    # Update
    # TODO: Update your variables here

    # Draw
    rl.BeginDrawing()
    rl.ClearBackground(BLACK)
    rl.DrawText(b'A window!', 20, 20, 42, WHITE)
    rl.EndDrawing()

raylib kindly does a whole bunch of housekeeping for us in the background and looks after our window for us, in return we need to keep an eye on if the window is closing. while the window isn't (not) closing we need our game loop to be running. The first task in your game loop should be to update your variables, for example check key presses and move a character appropriately. Next is the fun bit drawing, all drawing with raylib need to be done in between these two function calls

    BeginDrawing()
    EndDrawing()

BeginDrawing() set everything ready to draw, where as EndDrawing() finalises the render instructions you've supplied and sends them off to the GPU (Graphics Processing Unit - the video card)

So in the case of our very simple example we are just left with two command one to clear the back buffer we're about to draw to and another command to draw the text

    rl.ClearBackground(BLACK)
    rl.DrawText(b'A window!', 20, 20, 42, WHITE)

Here's the C protoype from raylib.h so we can see what the parameters are called.

RLAPI void DrawText(const char *text, int posX, int posY, int fontSize, Color color);
       // Draw text (using default font)

So the DrawText function unsurprisingly needs some text as its first parameter, notice the little b before the string, that's just needed because we want to send a C string to the wrapper, so don't forget it. next two parameters are x & y position to render the text, followed by the font size and colour.

Okay running a simple window is just a handful of lines of code, but there have been some technicalities to bare in mind. That said we have a start!

Printing variables is probably the first thing you'll want to play with, there is a slight complication here and that's the aforementioned binary strings. If we want to take advantage of pythons new "f" strings we'll need to convert it after the string is built, take a look at this...

rl.DrawText(f"Frame: {int(frame)}".encode('UTF-8') , 10, 28, 20, MAROON)

and a more "raylib" version

rl.DrawText(rl.TextFormat(b"level: %i",ffi.cast("int", level)), 10, 216, 20, WHITE)

Take a look at the format string on its own (first example)

f"Frame: {int(frame)}".encode('UTF-8') 

we can embed the variable in the string, after this is done, the strings encode method allows us to present it to raylib as a binary string.

So to take stock we have opened a simple window and presented some text, we can also display variable values. On the face of it not much but it hasn't taken very many lines of code, and this gives a template for our forthcoming experiments. Check back for the next episode soon where we'll display some actual graphics....