Simple examples for beginners in PySDL3 #18
Replies: 23 comments 6 replies
-
|
Change a background color by timer Click this to collapse/fold
main.py import ctypes
import os
import time
os.environ["SDL_MAIN_USE_CALLBACKS"] = "1"
os.environ["SDL_RENDER_DRIVER"] = "opengl"
import sdl3
renderer = ctypes.POINTER(sdl3.SDL_Renderer)()
window = ctypes.POINTER(sdl3.SDL_Window)()
@sdl3.SDL_AppInit_func
def SDL_AppInit(appstate, argc, argv):
if not sdl3.SDL_Init(sdl3.SDL_INIT_VIDEO):
sdl3.SDL_Log("Couldn't initialize SDL: %s".encode() % sdl3.SDL_GetError())
return sdl3.SDL_APP_FAILURE
if not sdl3.SDL_CreateWindowAndRenderer("Background color using PySDL3".encode(), 350, 350, 0, window, renderer):
sdl3.SDL_Log("Couldn't create window/renderer: %s".encode() % sdl3.SDL_GetError())
return sdl3.SDL_APP_FAILURE
sdl3.SDL_SetRenderVSync(renderer, 1) # Turn on vertical sync
return sdl3.SDL_APP_CONTINUE
@sdl3.SDL_AppEvent_func
def SDL_AppEvent(appstate, event):
if sdl3.SDL_DEREFERENCE(event).type == sdl3.SDL_EVENT_QUIT:
return sdl3.SDL_APP_SUCCESS
return sdl3.SDL_APP_CONTINUE
@sdl3.SDL_AppIterate_func
def SDL_AppIterate(appstate):
r = 0
g = int(time.time() * 255 / 2) % 256
b = 0
sdl3.SDL_SetRenderDrawColor(renderer, r, g, b, sdl3.SDL_ALPHA_OPAQUE)
sdl3.SDL_RenderClear(renderer)
sdl3.SDL_RenderPresent(renderer)
return sdl3.SDL_APP_CONTINUE
@sdl3.SDL_AppQuit_func
def SDL_AppQuit(appstate, result):
... # SDL will clean up the window/renderer for us |
Beta Was this translation helpful? Give feedback.
-
|
Filled rectangle Click this to collapse/fold
main.py import ctypes
import os
os.environ["SDL_MAIN_USE_CALLBACKS"] = "1"
os.environ["SDL_RENDER_DRIVER"] = "opengl"
import sdl3
renderer = ctypes.POINTER(sdl3.SDL_Renderer)()
window = ctypes.POINTER(sdl3.SDL_Window)()
@sdl3.SDL_AppInit_func
def SDL_AppInit(appstate, argc, argv):
if not sdl3.SDL_Init(sdl3.SDL_INIT_VIDEO):
sdl3.SDL_Log("Couldn't initialize SDL: %s".encode() % sdl3.SDL_GetError())
return sdl3.SDL_APP_FAILURE
if not sdl3.SDL_CreateWindowAndRenderer("Rectangle".encode(), 380, 380, 0, window, renderer):
sdl3.SDL_Log("Couldn't create window/renderer: %s".encode() % sdl3.SDL_GetError())
return sdl3.SDL_APP_FAILURE
sdl3.SDL_SetRenderVSync(renderer, 1) # Turn on vertical sync
return sdl3.SDL_APP_CONTINUE
@sdl3.SDL_AppEvent_func
def SDL_AppEvent(appstate, event):
if sdl3.SDL_DEREFERENCE(event).type == sdl3.SDL_EVENT_QUIT:
return sdl3.SDL_APP_SUCCESS
return sdl3.SDL_APP_CONTINUE
@sdl3.SDL_AppIterate_func
def SDL_AppIterate(appstate):
# As you can see from this, rendering draws over whatever was drawn before it
sdl3.SDL_SetRenderDrawColor(renderer, 33, 33, 33, sdl3.SDL_ALPHA_OPAQUE)
sdl3.SDL_RenderClear(renderer) # Start with a blank canvas
# Draw a filled rectangle in the middle of the canvas
sdl3.SDL_SetRenderDrawColor(renderer, 100, 255, 100, sdl3.SDL_ALPHA_OPAQUE)
rect = sdl3.SDL_FRect()
rect.x = 50
rect.y = 200
rect.w = 280
rect.h = 30
sdl3.SDL_RenderFillRect(renderer, rect)
sdl3.SDL_RenderPresent(renderer)
return sdl3.SDL_APP_CONTINUE
@sdl3.SDL_AppQuit_func
def SDL_AppQuit(appstate, result):
... # SDL will clean up the window/renderer for us |
Beta Was this translation helpful? Give feedback.
-
|
Keyboard handler A keyboard handler for W, A, S, D key and arrow keys. It prints keyboard-handler-pysdl3-python.zip Click this to collapse/foldmain.py import ctypes
import os
os.environ["SDL_MAIN_USE_CALLBACKS"] = "1"
os.environ["SDL_RENDER_DRIVER"] = "opengl"
import sdl3
renderer = ctypes.POINTER(sdl3.SDL_Renderer)()
window = ctypes.POINTER(sdl3.SDL_Window)()
keys = { "left": False, "right": False, "up": False, "down": False }
@sdl3.SDL_AppInit_func
def SDL_AppInit(appstate, argc, argv):
if not sdl3.SDL_Init(sdl3.SDL_INIT_VIDEO):
sdl3.SDL_Log("Couldn't initialize SDL: %s".encode() % sdl3.SDL_GetError())
return sdl3.SDL_APP_FAILURE
windowTitle = "Keyboard handler using PySDL3".encode()
if not sdl3.SDL_CreateWindowAndRenderer(windowTitle, 350, 350, 0, window, renderer):
sdl3.SDL_Log("Couldn't create window/renderer: %s".encode() % sdl3.SDL_GetError())
return sdl3.SDL_APP_FAILURE
sdl3.SDL_SetRenderVSync(renderer, 1) # Turn on vertical sync
return sdl3.SDL_APP_CONTINUE
@sdl3.SDL_AppEvent_func
def SDL_AppEvent(appstate, event):
e = sdl3.SDL_DEREFERENCE(event)
sc = e.key.scancode
match e.type:
case sdl3.SDL_EVENT_QUIT:
return sdl3.SDL_APP_SUCCESS
case sdl3.SDL_EVENT_KEY_DOWN:
if sc in (sdl3.SDL_SCANCODE_A, sdl3.SDL_SCANCODE_LEFT):
keys["left"] = True
if sc in (sdl3.SDL_SCANCODE_D, sdl3.SDL_SCANCODE_RIGHT):
keys["right"] = True
if sc in (sdl3.SDL_SCANCODE_W, sdl3.SDL_SCANCODE_UP):
keys["up"] = True
if sc in (sdl3.SDL_SCANCODE_S, sdl3.SDL_SCANCODE_DOWN):
keys["down"] = True
return sdl3.SDL_APP_CONTINUE
case sdl3.SDL_EVENT_KEY_UP:
if sc in (sdl3.SDL_SCANCODE_A, sdl3.SDL_SCANCODE_LEFT):
keys["left"] = False
if sc in (sdl3.SDL_SCANCODE_D, sdl3.SDL_SCANCODE_RIGHT):
keys["right"] = False
if sc in (sdl3.SDL_SCANCODE_W, sdl3.SDL_SCANCODE_UP):
keys["up"] = False
if sc in (sdl3.SDL_SCANCODE_S, sdl3.SDL_SCANCODE_DOWN):
keys["down"] = False
return sdl3.SDL_APP_CONTINUE
return sdl3.SDL_APP_CONTINUE
def keyboard():
if keys["up"]:
print("up")
if keys["down"]:
print("down")
if keys["left"]:
print("left")
if keys["right"]:
print("right")
@sdl3.SDL_AppIterate_func
def SDL_AppIterate(appstate):
sdl3.SDL_SetRenderDrawColor(renderer, 200, 200, 220, sdl3.SDL_ALPHA_OPAQUE)
sdl3.SDL_RenderClear(renderer)
keyboard()
sdl3.SDL_RenderPresent(renderer)
return sdl3.SDL_APP_CONTINUE
@sdl3.SDL_AppQuit_func
def SDL_AppQuit(appstate, result):
... # SDL will clean up the window/renderer for us
C versionKeys statetypedef struct {
bool left;
bool right;
bool up;
bool down;
} Keys;
static Keys keys = { false, false, false, false };SDL_AppEvent callbackSDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event)
{
SDL_Event e = *event; /* equivalent to SDL_DEREFERENCE(event) */
SDL_Scancode sc = e.key.scancode;
switch (e.type)
{
case SDL_EVENT_QUIT:
return SDL_APP_SUCCESS;
case SDL_EVENT_KEY_DOWN:
if (sc == SDL_SCANCODE_A || sc == SDL_SCANCODE_LEFT)
keys.left = true;
if (sc == SDL_SCANCODE_D || sc == SDL_SCANCODE_RIGHT)
keys.right = true;
if (sc == SDL_SCANCODE_W || sc == SDL_SCANCODE_UP)
keys.up = true;
if (sc == SDL_SCANCODE_S || sc == SDL_SCANCODE_DOWN)
keys.down = true;
return SDL_APP_CONTINUE;
case SDL_EVENT_KEY_UP:
if (sc == SDL_SCANCODE_A || sc == SDL_SCANCODE_LEFT)
keys.left = false;
if (sc == SDL_SCANCODE_D || sc == SDL_SCANCODE_RIGHT)
keys.right = false;
if (sc == SDL_SCANCODE_W || sc == SDL_SCANCODE_UP)
keys.up = false;
if (sc == SDL_SCANCODE_S || sc == SDL_SCANCODE_DOWN)
keys.down = false;
return SDL_APP_CONTINUE;
}
return SDL_APP_CONTINUE;
} |
Beta Was this translation helpful? Give feedback.
-
|
NoobTuts Snake game The Snake game from the NoobTuts OpenGL/Python tutorial in PySDL3 Click this to collapse/fold
main.py import ctypes
import os
from random import randint
os.environ["SDL_MAIN_USE_CALLBACKS"] = "1"
os.environ["SDL_RENDER_DRIVER"] = "opengl"
import sdl3
renderer = ctypes.POINTER(sdl3.SDL_Renderer)()
window = ctypes.POINTER(sdl3.SDL_Window)()
windowWidth = 400
windowHeight = 400
snake = [(20, 20)] # Snake list of (x, y) positions
snakeDir = (10, 0) # Snake movement direction
interval = 0.2 # update interval in milliseconds
keyFrameTime = 0
lastTime = 0
keys = { "left": False, "right": False, "up": False, "down": False }
food = [] # Food list of type (x, y)
def vecAdd(v1, v2):
return (v1[0] + v2[0], v1[1] + v2[1])
@sdl3.SDL_AppInit_func
def SDL_AppInit(appstate, argc, argv):
global windowWidth
global windowHeight
if not sdl3.SDL_Init(sdl3.SDL_INIT_VIDEO):
sdl3.SDL_Log("Couldn't initialize SDL: %s".encode() % sdl3.SDL_GetError())
return sdl3.SDL_APP_FAILURE
if not sdl3.SDL_CreateWindowAndRenderer("Snake NoobTuts".encode(), windowWidth, windowHeight, 0, window, renderer):
sdl3.SDL_Log("Couldn't create window/renderer: %s".encode() % sdl3.SDL_GetError())
return sdl3.SDL_APP_FAILURE
sdl3.SDL_SetRenderVSync(renderer, 1) # Turn on vertical sync
return sdl3.SDL_APP_CONTINUE
@sdl3.SDL_AppEvent_func
def SDL_AppEvent(appstate, event):
if sdl3.SDL_DEREFERENCE(event).type == sdl3.SDL_EVENT_QUIT:
return sdl3.SDL_APP_SUCCESS
elif sdl3.SDL_DEREFERENCE(event).type == sdl3.SDL_EVENT_KEY_DOWN:
if sdl3.SDL_DEREFERENCE(event).key.scancode == sdl3.SDL_SCANCODE_W or sdl3.SDL_DEREFERENCE(event).button.button == sdl3.SDL_SCANCODE_UP:
keys["up"] = True
if sdl3.SDL_DEREFERENCE(event).key.scancode == sdl3.SDL_SCANCODE_S or sdl3.SDL_DEREFERENCE(event).button.button == sdl3.SDL_SCANCODE_DOWN:
keys["down"] = True
if sdl3.SDL_DEREFERENCE(event).key.scancode == sdl3.SDL_SCANCODE_A or sdl3.SDL_DEREFERENCE(event).button.button == sdl3.SDL_SCANCODE_LEFT:
keys["left"] = True
if sdl3.SDL_DEREFERENCE(event).key.scancode == sdl3.SDL_SCANCODE_D or sdl3.SDL_DEREFERENCE(event).button.button == sdl3.SDL_SCANCODE_RIGHT:
keys["right"] = True
elif sdl3.SDL_DEREFERENCE(event).type == sdl3.SDL_EVENT_KEY_UP:
if sdl3.SDL_DEREFERENCE(event).key.scancode == sdl3.SDL_SCANCODE_W or sdl3.SDL_DEREFERENCE(event).button.button == sdl3.SDL_SCANCODE_UP:
keys["up"] = False
if sdl3.SDL_DEREFERENCE(event).key.scancode == sdl3.SDL_SCANCODE_S or sdl3.SDL_DEREFERENCE(event).button.button == sdl3.SDL_SCANCODE_DOWN:
keys["down"] = False
if sdl3.SDL_DEREFERENCE(event).key.scancode == sdl3.SDL_SCANCODE_A or sdl3.SDL_DEREFERENCE(event).button.button == sdl3.SDL_SCANCODE_LEFT:
keys["left"] = False
if sdl3.SDL_DEREFERENCE(event).key.scancode == sdl3.SDL_SCANCODE_D or sdl3.SDL_DEREFERENCE(event).button.button == sdl3.SDL_SCANCODE_RIGHT:
keys["right"] = False
return sdl3.SDL_APP_CONTINUE
def keyboard():
global snakeDir # important if we want to set it to a new value
if keys["up"]:
snakeDir = (0, -10)
if keys["down"]:
snakeDir = (0, 10)
if keys["left"]:
snakeDir = (-10, 0)
if keys["right"]:
snakeDir = (10, 0)
@sdl3.SDL_AppIterate_func
def SDL_AppIterate(appstate):
global interval
global lastTime
global keyFrameTime
global snake
global snakeDir
# As you can see from this, rendering draws over whatever was drawn before it
sdl3.SDL_SetRenderDrawColor(renderer, 33, 33, 33, sdl3.SDL_ALPHA_OPAQUE)
sdl3.SDL_RenderClear(renderer) # Start with a blank canvas
keyboard();
currentTime = sdl3.SDL_GetTicks()
deltaTime = (currentTime - lastTime) / 1000
lastTime = currentTime
# Game tick
keyFrameTime += deltaTime
if keyFrameTime > interval:
# Insert new position in the beginning of the snake list
snake.insert(0, vecAdd(snake[0], snakeDir))
# Remove the last element
snake.pop()
# Spawn food
r = randint(0, 20) # Spawn food with 5% chance
if r == 0:
# Random spawn position
x = randint(0, int(windowWidth / 10)) * 10
y = randint(0, int(windowHeight / 10)) * 10
food.append((x, y))
print("spawn food:", x, y)
# Let the snake eat the food
(hx, hy) = snake[0] # Get the snake's head x and y position
for x, y in food: # Go through the food list
if hx == x and hy == y: # Is the head where the food is?
snake.append((x, y)) # Make the snake longer
food.remove((x, y)) # Remove the food
# Start a new frame
keyFrameTime = 0
rect = sdl3.SDL_FRect()
rect.w = 10
rect.h = 10
# Draw a food
sdl3.SDL_SetRenderDrawColor(renderer, 128, 128, 255, sdl3.SDL_ALPHA_OPAQUE)
for x, y in food:
rect.x = x
rect.y = y
sdl3.SDL_RenderFillRect(renderer, rect)
# Draw a snake
sdl3.SDL_SetRenderDrawColor(renderer, 255, 255, 255, sdl3.SDL_ALPHA_OPAQUE)
for x, y in snake:
rect.x = x
rect.y = y
sdl3.SDL_RenderFillRect(renderer, rect)
sdl3.SDL_RenderPresent(renderer)
return sdl3.SDL_APP_CONTINUE
@sdl3.SDL_AppQuit_func
def SDL_AppQuit(appstate, result):
... # SDL will clean up the window/renderer for ussnake-noobtuts-pysdl3.mp4 |
Beta Was this translation helpful? Give feedback.
-
|
Text drawing Click this to collapse/fold
main.py import ctypes
import os
os.environ["SDL_MAIN_USE_CALLBACKS"] = "1"
os.environ["SDL_RENDER_DRIVER"] = "opengl"
import sdl3
renderer = ctypes.POINTER(sdl3.SDL_Renderer)()
window = ctypes.POINTER(sdl3.SDL_Window)()
textTexture = None
@sdl3.SDL_AppInit_func
def SDL_AppInit(appstate, argc, argv):
global textTexture
if not sdl3.SDL_Init(sdl3.SDL_INIT_VIDEO):
sdl3.SDL_Log("Couldn't initialize SDL: %s".encode() % sdl3.SDL_GetError())
return sdl3.SDL_APP_FAILURE
# Initialize the TTF library
if not sdl3.TTF_Init():
sdl3.SDL_Log("Couldn't initialize TTF: %s".encode() % sdl3.SDL_GetError())
return sdl3.SDL_APP_FAILURE
if not sdl3.SDL_CreateWindowAndRenderer("Draw a text using PySDL3".encode(), 320, 320, 0, window, renderer):
sdl3.SDL_Log("Couldn't create window/renderer: %s".encode() % sdl3.SDL_GetError())
return sdl3.SDL_APP_FAILURE
sdl3.SDL_SetRenderVSync(renderer, 1) # Turn on vertical sync
font = sdl3.TTF_OpenFont("C:/Windows/Fonts/arial.ttf".encode(), 28)
if not font:
sdl3.SDL_Log("Error: %s".encode() % sdl3.SDL_GetError())
return sdl3.SDL_APP_FAILURE
textColor = sdl3.SDL_Color(10, 10, 10)
surface = sdl3.TTF_RenderText_Blended(font, "Hello World!".encode(), 12, textColor)
textTexture = sdl3.SDL_CreateTextureFromSurface(renderer, surface)
sdl3.SDL_DestroySurface(surface)
return sdl3.SDL_APP_CONTINUE
@sdl3.SDL_AppEvent_func
def SDL_AppEvent(appstate, event):
if sdl3.SDL_DEREFERENCE(event).type == sdl3.SDL_EVENT_QUIT:
return sdl3.SDL_APP_SUCCESS
return sdl3.SDL_APP_CONTINUE
@sdl3.SDL_AppIterate_func
def SDL_AppIterate(appstate):
sdl3.SDL_SetRenderDrawColor(renderer, 150, 200, 170, sdl3.SDL_ALPHA_OPAQUE)
sdl3.SDL_RenderClear(renderer)
width, height = ctypes.c_float(), ctypes.c_float()
sdl3.SDL_GetTextureSize(textTexture, ctypes.byref(width), ctypes.byref(height))
rect = sdl3.SDL_FRect(20.0, 20.0, width.value, height.value)
sdl3.SDL_RenderTexture(renderer, textTexture, None, rect)
sdl3.SDL_RenderPresent(renderer)
return sdl3.SDL_APP_CONTINUE
@sdl3.SDL_AppQuit_func
def SDL_AppQuit(appstate, result):
global textTexture
# SDL will clean up the window/renderer for us
sdl3.SDL_DestroyTexture(textTexture) |
Beta Was this translation helpful? Give feedback.
-
|
Mouse handler Click this to collapse/fold
main.py import ctypes
import os
os.environ["SDL_MAIN_USE_CALLBACKS"] = "1"
os.environ["SDL_RENDER_DRIVER"] = "opengl"
import sdl3
renderer = ctypes.POINTER(sdl3.SDL_Renderer)()
window = ctypes.POINTER(sdl3.SDL_Window)()
# This function runs once at startup
@sdl3.SDL_AppInit_func
def SDL_AppInit(appstate, argc, argv):
if not sdl3.SDL_Init(sdl3.SDL_INIT_VIDEO):
sdl3.SDL_Log("Couldn't initialize SDL: %s".encode() % sdl3.SDL_GetError())
return sdl3.SDL_APP_FAILURE
title = "Mouse handler, PySDL3".encode()
if not sdl3.SDL_CreateWindowAndRenderer(title, 350, 350, 0, window, renderer):
sdl3.SDL_Log("Couldn't create window/renderer: %s".encode() % sdl3.SDL_GetError())
return sdl3.SDL_APP_FAILURE
sdl3.SDL_SetRenderVSync(renderer, 1) # Turn on vertical sync
return sdl3.SDL_APP_CONTINUE
# This function runs when a new event (mouse input, keypresses, etc) occurs
@sdl3.SDL_AppEvent_func
def SDL_AppEvent(appstate, event):
if sdl3.SDL_DEREFERENCE(event).type == sdl3.SDL_EVENT_QUIT:
return sdl3.SDL_APP_SUCCESS
elif sdl3.SDL_DEREFERENCE(event).type == sdl3.SDL_EVENT_MOUSE_BUTTON_DOWN:
if sdl3.SDL_DEREFERENCE(event).button.button == sdl3.SDL_BUTTON_LEFT:
print("Left button click down")
elif sdl3.SDL_DEREFERENCE(event).button.button == sdl3.SDL_BUTTON_RIGHT:
print("Right button click down")
elif sdl3.SDL_DEREFERENCE(event).button.button == sdl3.SDL_BUTTON_MIDDLE:
print("middle button click down")
elif sdl3.SDL_DEREFERENCE(event).type == sdl3.SDL_EVENT_MOUSE_MOTION:
if sdl3.SDL_DEREFERENCE(event).button.button == sdl3.SDL_BUTTON_LEFT:
print("Motion with left button holding")
elif sdl3.SDL_DEREFERENCE(event).button.button == sdl3.SDL_BUTTON_RIGHT:
print("Motion with right button holding")
elif sdl3.SDL_DEREFERENCE(event).button.button == sdl3.SDL_BUTTON_MIDDLE:
print("Motion with middle button holding")
elif sdl3.SDL_DEREFERENCE(event).type == sdl3.SDL_EVENT_MOUSE_BUTTON_UP:
if sdl3.SDL_DEREFERENCE(event).button.button == sdl3.SDL_BUTTON_LEFT:
print("Left button click up")
elif sdl3.SDL_DEREFERENCE(event).button.button == sdl3.SDL_BUTTON_RIGHT:
print("Right button click up")
elif sdl3.SDL_DEREFERENCE(event).button.button == sdl3.SDL_BUTTON_MIDDLE:
print("middle button click up")
return sdl3.SDL_APP_CONTINUE
# This function runs once per frame, and it is the heart of the program
@sdl3.SDL_AppIterate_func
def SDL_AppIterate(appstate):
sdl3.SDL_SetRenderDrawColor(renderer, 50, 50, 50, sdl3.SDL_ALPHA_OPAQUE)
sdl3.SDL_RenderClear(renderer)
sdl3.SDL_RenderPresent(renderer)
return sdl3.SDL_APP_CONTINUE
# This function runs once at shutdown
@sdl3.SDL_AppQuit_func
def SDL_AppQuit(appstate, result):
... # SDL will clean up the window/renderer for us |
Beta Was this translation helpful? Give feedback.
-
|
Click counter It shows the Click this to collapse/foldmain.py import ctypes
import os
os.environ["SDL_MAIN_USE_CALLBACKS"] = "1"
os.environ["SDL_RENDER_DRIVER"] = "opengl"
import sdl3
renderer = ctypes.POINTER(sdl3.SDL_Renderer)()
window = ctypes.POINTER(sdl3.SDL_Window)()
font = None
textColor = sdl3.SDL_Color(255, 255, 255)
counter = 0
@sdl3.SDL_AppInit_func
def SDL_AppInit(appstate, argc, argv):
global font
if not sdl3.SDL_Init(sdl3.SDL_INIT_VIDEO):
sdl3.SDL_Log("Couldn't initialize SDL: %s".encode() % sdl3.SDL_GetError())
return sdl3.SDL_APP_FAILURE
# Initialize the TTF library
if not sdl3.TTF_Init():
sdl3.SDL_Log("Couldn't initialize TTF: %s".encode() % sdl3.SDL_GetError())
return sdl3.SDL_APP_FAILURE
if not sdl3.SDL_CreateWindowAndRenderer("Click counter using PySDL3".encode(), 320, 320, 0, window, renderer):
sdl3.SDL_Log("Couldn't create window/renderer: %s".encode() % sdl3.SDL_GetError())
return sdl3.SDL_APP_FAILURE
sdl3.SDL_SetRenderVSync(renderer, 1) # Turn on vertical sync
font = sdl3.TTF_OpenFont("C:/Windows/Fonts/arial.ttf".encode(), 28)
if not font:
sdl3.SDL_Log("Error: %s".encode() % sdl3.SDL_GetError())
return sdl3.SDL_APP_FAILURE
return sdl3.SDL_APP_CONTINUE
@sdl3.SDL_AppEvent_func
def SDL_AppEvent(appstate, event):
global counter
if sdl3.SDL_DEREFERENCE(event).type == sdl3.SDL_EVENT_QUIT:
return sdl3.SDL_APP_SUCCESS
elif sdl3.SDL_DEREFERENCE(event).type == sdl3.SDL_EVENT_MOUSE_BUTTON_DOWN:
counter += 1
return sdl3.SDL_APP_CONTINUE
@sdl3.SDL_AppIterate_func
def SDL_AppIterate(appstate):
global counter
global font
sdl3.SDL_SetRenderDrawColor(renderer, 55, 55, 55, sdl3.SDL_ALPHA_OPAQUE)
sdl3.SDL_RenderClear(renderer)
text = "Click counter = %d".encode() % counter
surface = sdl3.TTF_RenderText_Blended(font, text, len(text), textColor)
textTexture = sdl3.SDL_CreateTextureFromSurface(renderer, surface)
sdl3.SDL_DestroySurface(surface)
width, height = ctypes.c_float(), ctypes.c_float()
sdl3.SDL_GetTextureSize(textTexture, ctypes.byref(width), ctypes.byref(height))
rect = sdl3.SDL_FRect(20.0, 20.0, width.value, height.value)
sdl3.SDL_RenderTexture(renderer, textTexture, None, rect)
sdl3.SDL_RenderPresent(renderer)
sdl3.SDL_DestroyTexture(textTexture)
return sdl3.SDL_APP_CONTINUE
@sdl3.SDL_AppQuit_func
def SDL_AppQuit(appstate, result):
... # SDL will clean up the window/renderer for us
|
Beta Was this translation helpful? Give feedback.
-
|
Play a sound by click This example load this free WAV-file using SDL3_mixer: https://opengameart.org/content/picked-coin-echo-2 and play the sound by mouse click in the window. It was tested with play-sound-by-click-pysdl3.zip main.pyimport ctypes
import os
os.environ["SDL_MAIN_USE_CALLBACKS"] = "1"
os.environ["SDL_RENDER_DRIVER"] = "opengl"
import sdl3
renderer = ctypes.POINTER(sdl3.SDL_Renderer)()
window = ctypes.POINTER(sdl3.SDL_Window)()
mixer = ctypes.POINTER(sdl3.MIX_Mixer)()
audio = ctypes.POINTER(sdl3.MIX_Audio)()
@sdl3.SDL_AppInit_func
def SDL_AppInit(appstate, argc, argv):
global mixer, audio
sdl3.SDL_SetHint(b"SDL_MIXER_DISABLE_DRFLAC", b"1")
sdl3.SDL_SetHint(b"SDL_MIXER_DISABLE_DRMP3", b"1")
if not sdl3.SDL_Init(sdl3.SDL_INIT_VIDEO): # | sdl3.SDL_INIT_AUDIO
sdl3.SDL_Log("Couldn't initialize SDL: %s".encode() % sdl3.SDL_GetError())
return sdl3.SDL_APP_FAILURE
title = "Play a sound by click using PySDL3".encode()
if not sdl3.SDL_CreateWindowAndRenderer(title, 380, 380, 0, window, renderer):
sdl3.SDL_Log("Couldn't create window/renderer: %s".encode() % sdl3.SDL_GetError())
return sdl3.SDL_APP_FAILURE
sdl3.SDL_SetRenderVSync(renderer, 1) # Turn on vertical sync
# Get the compiled SDL version
compiled = sdl3.SDL_VERSION
compiled_major = sdl3.SDL_VERSIONNUM_MAJOR(compiled)
compiled_minor = sdl3.SDL_VERSIONNUM_MINOR(compiled)
compiled_micro = sdl3.SDL_VERSIONNUM_MICRO(compiled)
print(f"Compiled SDL version: {compiled_major}.{compiled_minor}.{compiled_micro}")
# Get the linked SDL version
linked = sdl3.SDL_GetVersion()
linked_major = sdl3.SDL_VERSIONNUM_MAJOR(linked)
linked_minor = sdl3.SDL_VERSIONNUM_MINOR(linked)
linked_micro = sdl3.SDL_VERSIONNUM_MICRO(linked)
print(f"Linked SDL version: {linked_major}.{linked_minor}.{linked_micro}")
# v = sdl3.MIX_Version()
# print(v) # Output: 3001000
# major = v // 1_000_000
# minor = (v // 1_000) % 1000
# micro = v % 1000
# msg = f"SDL3_mixer version {major}.{minor}.{micro}".encode("utf-8")
# sdl3.SDL_Log(msg) # Output: SDL3_mixer version 3.1.0
v = sdl3.MIX_Version()
major = sdl3.SDL_VERSIONNUM_MAJOR(v)
minor = sdl3.SDL_VERSIONNUM_MINOR(v)
micro = sdl3.SDL_VERSIONNUM_MICRO(v)
msg = f"SDL3_mixer version: {major}.{minor}.{micro}".encode("utf-8")
sdl3.SDL_Log(msg)
if not sdl3.MIX_Init():
sdl3.SDL_Log("MIX_Init failed: %s".encode() % sdl3.SDL_GetError())
return sdl3.SDL_APP_FAILURE
mixer = sdl3.MIX_CreateMixerDevice(sdl3.SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, None)
if not mixer:
err = sdl3.SDL_GetError().decode("utf-8")
sdl3.SDL_Log(f"Couldn't create mixer: {err}".encode())
return sdl3.SDL_APP_FAILURE
mixerspec = sdl3.SDL_AudioSpec()
sdl3.MIX_GetMixerFormat(mixer, ctypes.byref(mixerspec))
fmt_name = sdl3.SDL_GetAudioFormatName(mixerspec.format).decode('utf-8')
msg = f"Mixer is format {fmt_name}, {mixerspec.channels} channels, {mixerspec.freq} frequency".encode()
sdl3.SDL_Log(msg)
# --- Print available audio decoders ---
sdl3.SDL_Log(b"Available MIXER decoders:")
num_decoders = sdl3.MIX_GetNumAudioDecoders()
if num_decoders < 0:
err = sdl3.SDL_GetError().decode("utf-8")
msg = f" - [error ({err})]".encode("utf-8")
sdl3.SDL_Log(msg)
elif num_decoders == 0:
sdl3.SDL_Log(b" - [none]")
else:
for i in range(num_decoders):
decoder_name = sdl3.MIX_GetAudioDecoder(i).decode("utf-8")
msg = f" - {decoder_name}".encode("utf-8")
sdl3.SDL_Log(msg)
# --- Load audio file ---
audiofname = b"./assets/audio/picked-coin-echo-2.wav" # bytes for SDL
audio = sdl3.MIX_LoadAudio(mixer, audiofname, False)
if not audio:
err = sdl3.SDL_GetError().decode("utf-8")
msg = f"Failed to load '{audiofname.decode()}' ({err})".encode("utf-8")
sdl3.SDL_Log(msg)
else:
audiospec = sdl3.SDL_AudioSpec()
sdl3.MIX_GetAudioFormat(audio, ctypes.byref(audiospec))
fmt_name = sdl3.SDL_GetAudioFormatName(audiospec.format).decode("utf-8")
channels_text = "" if audiospec.channels == 1 else "s"
msg = f"{audiofname.decode()}: {fmt_name}, {audiospec.channels} channel{channels_text}, {audiospec.freq} freq".encode("utf-8")
sdl3.SDL_Log(msg)
return sdl3.SDL_APP_CONTINUE
@sdl3.SDL_AppEvent_func
def SDL_AppEvent(appstate, event):
if sdl3.SDL_DEREFERENCE(event).type == sdl3.SDL_EVENT_QUIT:
return sdl3.SDL_APP_SUCCESS
elif sdl3.SDL_DEREFERENCE(event).type == sdl3.SDL_EVENT_MOUSE_BUTTON_DOWN:
# Play the sound effect
if not sdl3.MIX_PlayAudio(mixer, audio):
sdl3.SDL_Log("Failed to play audio: %s".encode() % sdl3.SDL_GetError())
return sdl3.SDL_APP_CONTINUE
@sdl3.SDL_AppIterate_func
def SDL_AppIterate(appstate):
sdl3.SDL_SetRenderDrawColor(renderer, 210, 220, 210, sdl3.SDL_ALPHA_OPAQUE)
sdl3.SDL_RenderClear(renderer)
sdl3.SDL_RenderPresent(renderer)
return sdl3.SDL_APP_CONTINUE
@sdl3.SDL_AppQuit_func
def SDL_AppQuit(appstate, result):
global audio, mixer, renderer, window
if audio:
sdl3.MIX_DestroyAudio(audio)
audio = None
if mixer:
sdl3.MIX_DestroyMixer(mixer)
mixer = None
if renderer:
sdl3.SDL_DestroyRenderer(renderer)
renderer = None
if window:
sdl3.SDL_DestroyWindow(window)
window = None
sdl3.MIX_Quit()
sdl3.SDL_Quit()
C version:
|
Beta Was this translation helpful? Give feedback.
-
|
NoobTuts Pong game The Pong game from the NoobTuts OpenGL/C++ tutorial in PySDL3 Click this to collapse/fold
main.py import ctypes
import os
os.environ["SDL_MAIN_USE_CALLBACKS"] = "1"
os.environ["SDL_RENDER_DRIVER"] = "opengl"
import sdl3
renderer = ctypes.POINTER(sdl3.SDL_Renderer)()
window = ctypes.POINTER(sdl3.SDL_Window)()
leftRacketKeys = { "up": False, "down": False }
rightRacketKeys = { "up": False, "down": False }
font = None
textColor = sdl3.SDL_Color(255, 255, 255)
scoreLeft = 0
scoreRight = 0
canvasWidth = 500
canvasHeight = 200
# Rackets in general
racketWidth = 10
racketHeight = 80
racketSpeed = 190
# Left racket position
racketLeftX = 10
racketLeftY = 50
# Right racket position
racketRightX = canvasWidth - racketWidth - 10
racketRightY = 50
lastTime = 0
ballPosX = canvasWidth / 2
ballPosY = canvasHeight / 2
ballDirX = -1
ballDirY = 0
ballSize = 8
ballSpeed = 125
@sdl3.SDL_AppInit_func
def SDL_AppInit(appstate, argc, argv):
global font
global canvasWidth
global canvasHeight
if not sdl3.SDL_Init(sdl3.SDL_INIT_VIDEO):
sdl3.SDL_Log("Couldn't initialize SDL: %s".encode() % sdl3.SDL_GetError())
return sdl3.SDL_APP_FAILURE
# Initialize the TTF library
if not sdl3.TTF_Init():
sdl3.SDL_Log("Couldn't initialize TTF: %s".encode() % sdl3.SDL_GetError())
return sdl3.SDL_APP_FAILURE
if not sdl3.SDL_CreateWindowAndRenderer("Pong NoobTuts using PySDL3".encode(), canvasWidth, canvasHeight, 0, window, renderer):
sdl3.SDL_Log("Couldn't create window/renderer: %s".encode() % sdl3.SDL_GetError())
return sdl3.SDL_APP_FAILURE
sdl3.SDL_SetRenderVSync(renderer, 1) # Turn on vertical sync
font = sdl3.TTF_OpenFont("C:/Windows/Fonts/arial.ttf".encode(), 26)
if not font:
sdl3.SDL_Log("Error: %s".encode() % sdl3.SDL_GetError())
return sdl3.SDL_APP_FAILURE
return sdl3.SDL_APP_CONTINUE
@sdl3.SDL_AppEvent_func
def SDL_AppEvent(appstate, event):
if sdl3.SDL_DEREFERENCE(event).type == sdl3.SDL_EVENT_QUIT:
return sdl3.SDL_APP_SUCCESS
elif sdl3.SDL_DEREFERENCE(event).type == sdl3.SDL_EVENT_KEY_DOWN:
if sdl3.SDL_DEREFERENCE(event).key.scancode == sdl3.SDL_SCANCODE_W:
leftRacketKeys["up"] = True
if sdl3.SDL_DEREFERENCE(event).key.scancode == sdl3.SDL_SCANCODE_S:
leftRacketKeys["down"] = True
if sdl3.SDL_DEREFERENCE(event).button.button == sdl3.SDL_SCANCODE_UP:
rightRacketKeys["up"] = True
if sdl3.SDL_DEREFERENCE(event).button.button == sdl3.SDL_SCANCODE_DOWN:
rightRacketKeys["down"] = True
elif sdl3.SDL_DEREFERENCE(event).type == sdl3.SDL_EVENT_KEY_UP:
if sdl3.SDL_DEREFERENCE(event).key.scancode == sdl3.SDL_SCANCODE_W:
leftRacketKeys["up"] = False
if sdl3.SDL_DEREFERENCE(event).key.scancode == sdl3.SDL_SCANCODE_S:
leftRacketKeys["down"] = False
if sdl3.SDL_DEREFERENCE(event).button.button == sdl3.SDL_SCANCODE_UP:
rightRacketKeys["up"] = False
if sdl3.SDL_DEREFERENCE(event).button.button == sdl3.SDL_SCANCODE_DOWN:
rightRacketKeys["down"] = False
return sdl3.SDL_APP_CONTINUE
def keyboard(deltaTime):
global racketLeftY
global racketRightY
# Left racket
if leftRacketKeys["up"]:
racketLeftY -= racketSpeed * deltaTime
if leftRacketKeys["down"]:
racketLeftY += racketSpeed * deltaTime
# Right racket
if rightRacketKeys["up"]:
racketRightY -= racketSpeed * deltaTime
if rightRacketKeys["down"]:
racketRightY += racketSpeed * deltaTime
def updateBall(deltaTime):
global ballDirX
global ballDirY
global ballPosX
global ballPosY
global scoreRight
global scoreLeft
# Fly the ball a bit
ballPosX += ballDirX * ballSpeed * deltaTime
ballPosY += ballDirY * ballSpeed * deltaTime
# Hit by left racket?
if (
ballPosX < racketLeftX + racketWidth and ballPosX > racketLeftX and
ballPosY < racketLeftY + racketHeight and ballPosY > racketLeftY
):
# Set the fly direction depending on where it hit the racket
# t is 0.5 if hit at top, 0 at center, -0.5 at bottom
t = ((ballPosY - racketLeftY) / racketHeight) - 0.5
ballDirX = abs(ballDirX) # Force it to be positive
ballDirY = t
print(t)
# Hit by right racket?
if (
ballPosX < racketRightX + racketWidth and ballPosX > racketRightX and
ballPosY < racketRightY + racketHeight and ballPosY > racketRightY
):
# Set the fly direction depending on where it hit the racket
# t is 0.5 if hit at top, 0 at center, -0.5 at bottom
t = ((ballPosY - racketRightY) / racketHeight) - 0.5
ballDirX = -abs(ballDirX) # Force it to be negative
ballDirY = t
print(t)
# Hit left wall?
if ballPosX < 0:
scoreRight += 1
ballPosX = canvasWidth / 2
ballPosY = canvasHeight / 2
ballDirX = abs(ballDirX) # Force it to be positive
ballDirY = 0
# Hit right wall?
if ballPosX > canvasWidth:
scoreLeft += 1
ballPosX = canvasWidth / 2
ballPosY = canvasHeight / 2
ballDirX = -abs(ballDirX) # Force it to be negative
ballDirY = 0
# Hit top wall?
if ballPosY < 0:
ballDirY = abs(ballDirY) # Force to be positive
# Hit bottom wall?
if ballPosY > canvasHeight:
ballDirY = -abs(ballDirY) # Force bot negativef
@sdl3.SDL_AppIterate_func
def SDL_AppIterate(appstate):
global lastTime
# Delta time
currentTime = sdl3.SDL_GetTicks()
deltaTime = (currentTime - lastTime) / 1000
lastTime = currentTime
# Input handling
keyboard(deltaTime)
# Update the ball
updateBall(deltaTime)
sdl3.SDL_SetRenderDrawColor(renderer, 0, 0, 0, sdl3.SDL_ALPHA_OPAQUE)
sdl3.SDL_RenderClear(renderer)
# Draw the left racket
sdl3.SDL_SetRenderDrawColor(renderer, 255, 255, 255, sdl3.SDL_ALPHA_OPAQUE)
rect = sdl3.SDL_FRect(racketLeftX, racketLeftY, racketWidth, racketHeight)
sdl3.SDL_RenderFillRect(renderer, rect)
# Draw the right racket
sdl3.SDL_SetRenderDrawColor(renderer, 255, 255, 255, sdl3.SDL_ALPHA_OPAQUE)
rect = sdl3.SDL_FRect(racketRightX, racketRightY, racketWidth, racketHeight)
sdl3.SDL_RenderFillRect(renderer, rect)
# Draw the ball
sdl3.SDL_SetRenderDrawColor(renderer, 255, 255, 255, sdl3.SDL_ALPHA_OPAQUE)
rect = sdl3.SDL_FRect(ballPosX - ballSize / 2, ballPosY - ballSize / 2, ballSize, ballSize)
sdl3.SDL_RenderFillRect(renderer, rect)
scoreText = "%d:%d".encode() % (scoreLeft, scoreRight)
surface = sdl3.TTF_RenderText_Blended(font, scoreText, len(scoreText), textColor)
textTexture = sdl3.SDL_CreateTextureFromSurface(renderer, surface)
sdl3.SDL_DestroySurface(surface)
width, height = ctypes.c_float(), ctypes.c_float()
sdl3.SDL_GetTextureSize(textTexture, ctypes.byref(width), ctypes.byref(height))
rect = sdl3.SDL_FRect(canvasWidth / 2 - 18, 5, width.value, height.value)
sdl3.SDL_RenderTexture(renderer, textTexture, None, rect)
sdl3.SDL_RenderPresent(renderer)
sdl3.SDL_DestroyTexture(textTexture)
return sdl3.SDL_APP_CONTINUE
@sdl3.SDL_AppQuit_func
def SDL_AppQuit(appstate, result):
... # SDL will clean up the window/renderer for us |
Beta Was this translation helpful? Give feedback.
-
|
Draw an image It draws an image from the asset pack: https://opengameart.org/content/crate-5
Click this to collapse/foldmain.py import ctypes
import os
os.environ["SDL_MAIN_USE_CALLBACKS"] = "1"
os.environ["SDL_RENDER_DRIVER"] = "opengl"
import sdl3
renderer = ctypes.POINTER(sdl3.SDL_Renderer)()
window = ctypes.POINTER(sdl3.SDL_Window)()
spriteTexture = None
@sdl3.SDL_AppInit_func
def SDL_AppInit(appstate, argc, argv):
global spriteTexture
if not sdl3.SDL_Init(sdl3.SDL_INIT_VIDEO):
sdl3.SDL_Log("Couldn't initialize SDL: %s".encode() % sdl3.SDL_GetError())
return sdl3.SDL_APP_FAILURE
if not sdl3.SDL_CreateWindowAndRenderer("Draw an image using PySDL3".encode(),
350, 350, 0, window, renderer):
sdl3.SDL_Log("Couldn't create window/renderer: %s".encode() % sdl3.SDL_GetError())
return sdl3.SDL_APP_FAILURE
sdl3.SDL_SetRenderVSync(renderer, 1) # Turn on vertical sync
texturePath = "./assets/images/crate.png".encode()
spriteTexture = sdl3.IMG_LoadTexture(renderer, texturePath)
if not spriteTexture:
sdl3.SDL_Log("Error: %s".encode() % sdl3.SDL_GetError())
return sdl3.SDL_APP_FAILURE
return sdl3.SDL_APP_CONTINUE
@sdl3.SDL_AppEvent_func
def SDL_AppEvent(appstate, event):
if sdl3.SDL_DEREFERENCE(event).type == sdl3.SDL_EVENT_QUIT:
return sdl3.SDL_APP_SUCCESS
return sdl3.SDL_APP_CONTINUE
@sdl3.SDL_AppIterate_func
def SDL_AppIterate(appstate):
sdl3.SDL_SetRenderDrawColor(renderer, 200, 220, 200, sdl3.SDL_ALPHA_OPAQUE)
sdl3.SDL_RenderClear(renderer) # Start with a blank canvas
# Render a texture
srcRect = sdl3.SDL_FRect(0, 0, 256, 256)
destRect = sdl3.SDL_FRect(50, 50, 256, 256)
sdl3.SDL_RenderTexture(renderer, spriteTexture, srcRect, destRect)
sdl3.SDL_RenderPresent(renderer)
return sdl3.SDL_APP_CONTINUE
@sdl3.SDL_AppQuit_func
def SDL_AppQuit(appstate, result):
global spriteTexture
# SDL will clean up the window/renderer for us
sdl3.SDL_DestroyTexture(spriteTexture) |
Beta Was this translation helpful? Give feedback.
-
|
Sprite animation (native PNG from SDL 3.3) It plays a sprite animation from the free asset pack: https://pixelfrog-assets.itch.io/tiny-swords This example uses native SDL 3.3 (not SDL3_image): texturePath = "./assets/sprites/warrior/idle.png".encode()
surface = sdl3.SDL_LoadPNG(texturePath)
if not surface:
sdl.SDL_Log("PNG load failed: %s: %s".encode() % (texturePath, sdl3.SDL_GetError()))
return sdl3.SDL_APP_FAILURE
spriteTexture = sdl3.SDL_CreateTextureFromSurface(renderer, surface)
sdl3.SDL_DestroySurface(surface)Source code: sprite-animation-native-png-pysdl3-python.zip
Console output:
C version of the example above:
|
Beta Was this translation helpful? Give feedback.
-
|
Draw line segments It draws line segments using the SDL_RenderLine() function. Click this to collapse/fold
main.py import ctypes
import os
os.environ["SDL_MAIN_USE_CALLBACKS"] = "1"
os.environ["SDL_RENDER_DRIVER"] = "opengl"
import sdl3
renderer = ctypes.POINTER(sdl3.SDL_Renderer)()
window = ctypes.POINTER(sdl3.SDL_Window)()
@sdl3.SDL_AppInit_func
def SDL_AppInit(appstate, argc, argv):
if not sdl3.SDL_Init(sdl3.SDL_INIT_VIDEO):
sdl3.SDL_Log("Couldn't initialize SDL: %s".encode() % sdl3.SDL_GetError())
return sdl3.SDL_APP_FAILURE
if not sdl3.SDL_CreateWindowAndRenderer("Draw line segments using PySDL3".encode(),
380, 380, 0, window, renderer):
sdl3.SDL_Log("Couldn't create window/renderer: %s".encode() % sdl3.SDL_GetError())
return sdl3.SDL_APP_FAILURE
sdl3.SDL_SetRenderVSync(renderer, 1) # Turn on vertical sync
return sdl3.SDL_APP_CONTINUE
@sdl3.SDL_AppEvent_func
def SDL_AppEvent(appstate, event):
if sdl3.SDL_DEREFERENCE(event).type == sdl3.SDL_EVENT_QUIT:
return sdl3.SDL_APP_SUCCESS
return sdl3.SDL_APP_CONTINUE
@sdl3.SDL_AppIterate_func
def SDL_AppIterate(appstate):
# As you can see from this, rendering draws over whatever was drawn before it
sdl3.SDL_SetRenderDrawColor(renderer, 33, 33, 33, sdl3.SDL_ALPHA_OPAQUE)
sdl3.SDL_RenderClear(renderer) # Start with a blank canvas
# First line segment
sdl3.SDL_SetRenderDrawColor(renderer, 255, 0, 0, sdl3.SDL_ALPHA_OPAQUE)
sdl3.SDL_RenderLine(renderer, 90, 105, 285, 50)
# Second line segment
sdl3.SDL_SetRenderDrawColor(renderer, 0, 255, 0, sdl3.SDL_ALPHA_OPAQUE)
sdl3.SDL_RenderLine(renderer, 50, 170, 260, 225)
# Third line segment
sdl3.SDL_SetRenderDrawColor(renderer, 0, 0, 255, sdl3.SDL_ALPHA_OPAQUE)
sdl3.SDL_RenderLine(renderer, 65, 335, 320, 280)
sdl3.SDL_RenderPresent(renderer)
return sdl3.SDL_APP_CONTINUE
@sdl3.SDL_AppQuit_func
def SDL_AppQuit(appstate, result):
... # SDL will clean up the window/renderer for us |
Beta Was this translation helpful? Give feedback.
-
|
Draw outline rectangles It draws line segments using the SDL_RenderRect() function. Click this to collapse/fold
main.py import ctypes
import os
os.environ["SDL_MAIN_USE_CALLBACKS"] = "1"
os.environ["SDL_RENDER_DRIVER"] = "opengl"
import sdl3
renderer = ctypes.POINTER(sdl3.SDL_Renderer)()
window = ctypes.POINTER(sdl3.SDL_Window)()
@sdl3.SDL_AppInit_func
def SDL_AppInit(appstate, argc, argv):
if not sdl3.SDL_Init(sdl3.SDL_INIT_VIDEO):
sdl3.SDL_Log("Couldn't initialize SDL: %s".encode() % sdl3.SDL_GetError())
return sdl3.SDL_APP_FAILURE
if not sdl3.SDL_CreateWindowAndRenderer("Draw outline rectangles using PySDL3".encode(),
380, 380, 0, window, renderer):
sdl3.SDL_Log("Couldn't create window/renderer: %s".encode() % sdl3.SDL_GetError())
return sdl3.SDL_APP_FAILURE
sdl3.SDL_SetRenderVSync(renderer, 1) # Turn on vertical sync
return sdl3.SDL_APP_CONTINUE
@sdl3.SDL_AppEvent_func
def SDL_AppEvent(appstate, event):
if sdl3.SDL_DEREFERENCE(event).type == sdl3.SDL_EVENT_QUIT:
return sdl3.SDL_APP_SUCCESS
return sdl3.SDL_APP_CONTINUE
@sdl3.SDL_AppIterate_func
def SDL_AppIterate(appstate):
# As you can see from this, rendering draws over whatever was drawn before it
sdl3.SDL_SetRenderDrawColor(renderer, 33, 33, 33, sdl3.SDL_ALPHA_OPAQUE)
sdl3.SDL_RenderClear(renderer) # Start with a blank canvas
# First rectangle
sdl3.SDL_SetRenderDrawColor(renderer, 255, 0, 0, sdl3.SDL_ALPHA_OPAQUE)
sdl3.SDL_RenderRect(renderer, sdl3.SDL_FRect(160, 70, 160, 20))
# Second rectangle
sdl3.SDL_SetRenderDrawColor(renderer, 0, 255, 0, sdl3.SDL_ALPHA_OPAQUE)
sdl3.SDL_RenderRect(renderer, sdl3.SDL_FRect(20, 180, 160, 20))
# Third rectangle
sdl3.SDL_SetRenderDrawColor(renderer, 0, 0, 255, sdl3.SDL_ALPHA_OPAQUE)
sdl3.SDL_RenderRect(renderer, sdl3.SDL_FRect(135, 290, 200, 20))
sdl3.SDL_RenderPresent(renderer)
return sdl3.SDL_APP_CONTINUE
@sdl3.SDL_AppQuit_func
def SDL_AppQuit(appstate, result):
... # SDL will clean up the window/renderer for us |
Beta Was this translation helpful? Give feedback.
-
|
Draw rings using line segments It draws rings using the SDL_RenderLine() function. Click this to collapse/fold
main.py import math
import ctypes
import os
os.environ["SDL_MAIN_USE_CALLBACKS"] = "1"
os.environ["SDL_RENDER_DRIVER"] = "opengl"
import sdl3
renderer = ctypes.POINTER(sdl3.SDL_Renderer)()
window = ctypes.POINTER(sdl3.SDL_Window)()
@sdl3.SDL_AppInit_func
def SDL_AppInit(appstate, argc, argv):
if not sdl3.SDL_Init(sdl3.SDL_INIT_VIDEO):
sdl3.SDL_Log("Couldn't initialize SDL: %s".encode() % sdl3.SDL_GetError())
return sdl3.SDL_APP_FAILURE
windowTitle = "Draw rings using line segments, PySDL3".encode()
if not sdl3.SDL_CreateWindowAndRenderer(windowTitle,
380, 380, 0, window, renderer):
sdl3.SDL_Log("Couldn't create window/renderer: %s".encode() % sdl3.SDL_GetError())
return sdl3.SDL_APP_FAILURE
sdl3.SDL_SetRenderVSync(renderer, 1) # Turn on vertical sync
return sdl3.SDL_APP_CONTINUE
@sdl3.SDL_AppEvent_func
def SDL_AppEvent(appstate, event):
if sdl3.SDL_DEREFERENCE(event).type == sdl3.SDL_EVENT_QUIT:
return sdl3.SDL_APP_SUCCESS
return sdl3.SDL_APP_CONTINUE
def drawRing(centerX, centerY, radius, numberOfSegments=100):
angle = 0
angleStep = 360 / numberOfSegments
x = radius * math.cos(math.radians(angle))
y = radius * math.sin(math.radians(angle))
fromX = centerX + x
fromY = centerY + y
for i in range(numberOfSegments + 1):
x = radius * math.cos(math.radians(angle))
y = radius * math.sin(math.radians(angle))
toX = centerX + x
toY = centerY + y
sdl3.SDL_RenderLine(renderer, fromX, fromY, toX, toY)
angle += angleStep
fromX = toX
fromY = toY
@sdl3.SDL_AppIterate_func
def SDL_AppIterate(appstate):
# As you can see from this, rendering draws over whatever was drawn before it
sdl3.SDL_SetRenderDrawColor(renderer, 33, 33, 33, sdl3.SDL_ALPHA_OPAQUE)
sdl3.SDL_RenderClear(renderer) # Start with a blank canvas
# First ring
sdl3.SDL_SetRenderDrawColor(renderer, 255, 0, 0, sdl3.SDL_ALPHA_OPAQUE)
drawRing(95, 70, 20)
# Second ring
sdl3.SDL_SetRenderDrawColor(renderer, 0, 255, 0, sdl3.SDL_ALPHA_OPAQUE)
drawRing(190, 70, 35)
# Third ring
sdl3.SDL_SetRenderDrawColor(renderer, 0, 0, 255, sdl3.SDL_ALPHA_OPAQUE)
drawRing(285, 70, 50)
sdl3.SDL_RenderPresent(renderer)
return sdl3.SDL_APP_CONTINUE
@sdl3.SDL_AppQuit_func
def SDL_AppQuit(appstate, result):
... # SDL will clean up the window/renderer for us |
Beta Was this translation helpful? Give feedback.
-
|
Draw Box2D colliders using line segments It draws Box2D using the SDL_RenderLine() function. draw-box2d-colliders-pysdl3.zip
Click this to collapse/foldmain.py import ctypes
import math
import os
from Box2D import (b2_dynamicBody, b2BodyDef, b2CircleShape, b2FixtureDef,
b2PolygonShape, b2Vec2, b2World)
os.environ["SDL_MAIN_USE_CALLBACKS"] = "1"
os.environ["SDL_RENDER_DRIVER"] = "opengl"
import sdl3
from debug_drawer import DebugDrawer
renderer = ctypes.POINTER(sdl3.SDL_Renderer)()
window = ctypes.POINTER(sdl3.SDL_Window)()
world = b2World(gravity=b2Vec2(0, 9.8))
ppm = 30 # pixels per meter
@sdl3.SDL_AppInit_func
def SDL_AppInit(appstate, argc, argv):
if not sdl3.SDL_Init(sdl3.SDL_INIT_VIDEO):
sdl3.SDL_Log("Couldn't initialize SDL: %s".encode() % sdl3.SDL_GetError())
return sdl3.SDL_APP_FAILURE
windowTitle = "Draw Box2D colliders using line segments, PySDL3".encode()
if not sdl3.SDL_CreateWindowAndRenderer(windowTitle, 500, 300, 0, window, renderer):
sdl3.SDL_Log("Couldn't create window/renderer: %s".encode() % sdl3.SDL_GetError())
return sdl3.SDL_APP_FAILURE
sdl3.SDL_SetRenderVSync(renderer, 1) # Turn on vertical sync
debugDrawer = DebugDrawer(renderer, ppm)
debugDrawer.flags = { "drawShapes": True }
world.renderer = debugDrawer
# Create a ground body
groundBodyDef = b2BodyDef()
groundBodyDef.position = b2Vec2(250 / ppm, 270 / ppm)
groundBody = world.CreateBody(groundBodyDef)
groundShape = b2PolygonShape()
groundShape.SetAsBox(400 / 2 / ppm, 40 / 2 / ppm)
groundFixtureDef = b2FixtureDef()
groundFixtureDef.shape = groundShape
groundFixtureDef.density = 0
groundBody.CreateFixture(groundFixtureDef)
# Create a box body
boxBodyDef = b2BodyDef()
boxBodyDef.position = b2Vec2(200 / ppm, 30 / ppm)
boxBodyDef.angle = 30 * math.pi / 180
boxBodyDef.type = b2_dynamicBody
boxBody = world.CreateBody(boxBodyDef)
boxShape = b2PolygonShape()
boxShape.SetAsBox(60 / 2 / ppm, 60 / 2 / ppm)
boxFixtureDef = b2FixtureDef()
boxFixtureDef.shape = boxShape
boxFixtureDef.density = 1
boxBody.CreateFixture(boxFixtureDef)
# Create a circle body
circleBodyDef = b2BodyDef()
circleBodyDef.position = b2Vec2(300 / ppm, 50 / ppm)
circleBodyDef.type = b2_dynamicBody
circleBody = world.CreateBody(circleBodyDef)
circleShape = b2CircleShape()
circleShape.radius = 20 / ppm
circleFixtureDef = b2FixtureDef()
circleFixtureDef.shape = circleShape
circleFixtureDef.density = 1
circleFixtureDef.restitution = 0.5
circleBody.CreateFixture(circleFixtureDef)
# Create a platform body
platformBodyDef = b2BodyDef()
platformBodyDef.position = b2Vec2(320 / ppm, 200 / ppm)
platformBodyDef.angle = -20 * math.pi / 180
platformBody = world.CreateBody(platformBodyDef)
platformShape = b2PolygonShape()
platformShape.SetAsBox(100 / 2 / ppm, 10 / 2 / ppm)
platformFixtureDef = b2FixtureDef()
platformFixtureDef.shape = platformShape
platformFixtureDef.density = 0
platformBody.CreateFixture(platformFixtureDef)
return sdl3.SDL_APP_CONTINUE
@sdl3.SDL_AppEvent_func
def SDL_AppEvent(appstate, event):
if sdl3.SDL_DEREFERENCE(event).type == sdl3.SDL_EVENT_QUIT:
return sdl3.SDL_APP_SUCCESS
elif sdl3.SDL_DEREFERENCE(event).type == sdl3.SDL_EVENT_MOUSE_BUTTON_DOWN:
print("click")
return sdl3.SDL_APP_CONTINUE
@sdl3.SDL_AppIterate_func
def SDL_AppIterate(appstate):
# Set the color and clear the canvas with color
sdl3.SDL_SetRenderDrawColor(renderer, 50, 50, 50, sdl3.SDL_ALPHA_OPAQUE)
sdl3.SDL_RenderClear(renderer)
world.Step(0.016, 3, 2)
world.DrawDebugData()
sdl3.SDL_RenderPresent(renderer)
return sdl3.SDL_APP_CONTINUE
@sdl3.SDL_AppQuit_func
def SDL_AppQuit(appstate, result):
... # SDL will clean up the window/renderer for usdebug_drawer.py import math
import sdl3
from Box2D import b2Draw
class DebugDrawer(b2Draw):
def __init__(self, renderer, pixelsPerMeter, thickness=3):
super().__init__()
self.renderer = renderer
self.ppm = pixelsPerMeter
self.thickness = thickness
def DrawSolidPolygon(self, vertices, color):
r = int(color.r * 255)
g = int(color.g * 255)
b = int(color.b * 255)
sdl3.SDL_SetRenderDrawColor(self.renderer, r, g, b, sdl3.SDL_ALPHA_OPAQUE)
x0 = vertices[0][0] * self.ppm
y0 = vertices[0][1] * self.ppm
x1 = vertices[1][0] * self.ppm
y1 = vertices[1][1] * self.ppm
sdl3.SDL_RenderLine(self.renderer, x0, y0, x1, y1)
x1 = vertices[1][0] * self.ppm
y1 = vertices[1][1] * self.ppm
x2 = vertices[2][0] * self.ppm
y2 = vertices[2][1] * self.ppm
sdl3.SDL_RenderLine(self.renderer, x1, y1, x2, y2)
x2 = vertices[2][0] * self.ppm
y2 = vertices[2][1] * self.ppm
x3 = vertices[3][0] * self.ppm
y3 = vertices[3][1] * self.ppm
sdl3.SDL_RenderLine(self.renderer, x2, y2, x3, y3)
x3 = vertices[3][0] * self.ppm
y3 = vertices[3][1] * self.ppm
x0 = vertices[0][0] * self.ppm
y0 = vertices[0][1] * self.ppm
sdl3.SDL_RenderLine(self.renderer, x3, y3, x0, y0)
def DrawSolidCircle(self, center, radius, axis, color):
numberOfSegments = 100
angle = 0
angleStep = 360 / numberOfSegments
r = int(color.r * 255)
g = int(color.g * 255)
b = int(color.b * 255)
sdl3.SDL_SetRenderDrawColor(self.renderer, r, g, b, sdl3.SDL_ALPHA_OPAQUE)
centerX = center[0] * self.ppm
centerY = center[1] * self.ppm
radius *= self.ppm
x = radius * math.cos(math.radians(angle))
y = radius * math.sin(math.radians(angle))
fromX = centerX + x
fromY = centerY + y
for i in range(numberOfSegments + 1):
x = radius * math.cos(math.radians(angle))
y = radius * math.sin(math.radians(angle))
toX = centerX + x
toY = centerY + y
sdl3.SDL_RenderLine(self.renderer, fromX, fromY, toX, toY)
angle += angleStep
fromX = toX
fromY = toY
def DrawPolygon(self, vertices, color):
pass
def DrawSegment(self, p1, p2, color):
pass
def DrawPoint(self, p, size, color):
pass
def DrawCircle(self, center, radius, color, drawwidth=1):
pass
def DrawTransform(self, xf):
pass |
Beta Was this translation helpful? Give feedback.
-
|
Draw a rotated and scaled images It draws a rotated and scaled images using the SDL_RenderTextureRotated() function. Asset: https://opengameart.org/content/crate-5 draw-rotated-scaled-image-pysdl3.zip
Click this to collapse/foldmain.py import ctypes
import os
os.environ["SDL_MAIN_USE_CALLBACKS"] = "1"
os.environ["SDL_RENDER_DRIVER"] = "opengl"
import sdl3
renderer = ctypes.POINTER(sdl3.SDL_Renderer)()
window = ctypes.POINTER(sdl3.SDL_Window)()
spriteTexture = None
@sdl3.SDL_AppInit_func
def SDL_AppInit(appstate, argc, argv):
global spriteTexture
if not sdl3.SDL_Init(sdl3.SDL_INIT_VIDEO):
sdl3.SDL_Log("Couldn't initialize SDL: %s".encode() % sdl3.SDL_GetError())
return sdl3.SDL_APP_FAILURE
windowTitle = "Draw a rotated image using PySDL3".encode()
if not sdl3.SDL_CreateWindowAndRenderer(windowTitle, 380, 380, 0, window, renderer):
sdl3.SDL_Log("Couldn't create window/renderer: %s".encode() % sdl3.SDL_GetError())
return sdl3.SDL_APP_FAILURE
sdl3.SDL_SetRenderVSync(renderer, 1) # Turn on vertical sync
texturePath = "./assets/images/crate.png".encode()
spriteTexture = sdl3.IMG_LoadTexture(renderer, texturePath)
if not spriteTexture:
sdl3.SDL_Log("Error: %s".encode() % sdl3.SDL_GetError())
return sdl3.SDL_APP_FAILURE
return sdl3.SDL_APP_CONTINUE
@sdl3.SDL_AppEvent_func
def SDL_AppEvent(appstate, event):
if sdl3.SDL_DEREFERENCE(event).type == sdl3.SDL_EVENT_QUIT:
return sdl3.SDL_APP_SUCCESS
return sdl3.SDL_APP_CONTINUE
@sdl3.SDL_AppIterate_func
def SDL_AppIterate(appstate):
sdl3.SDL_SetRenderDrawColor(renderer, 200, 220, 200, sdl3.SDL_ALPHA_OPAQUE)
sdl3.SDL_RenderClear(renderer) # Start with a blank canvas
# Render a box
srcRect = sdl3.SDL_FRect(0, 0, 256, 256)
destRect = sdl3.SDL_FRect(50, 50, 128, 128)
# Rotation center (center of the rectangle)
center = sdl3.SDL_FPoint(destRect.w / 2, destRect.h / 2)
sdl3.SDL_RenderTextureRotated(renderer, spriteTexture, None,
destRect, 20, center, sdl3.SDL_FLIP_NONE)
# Render a box
srcRect = sdl3.SDL_FRect(0, 0, 256, 256)
destRect = sdl3.SDL_FRect(200, 200, 100, 100)
# Rotation center (center of the rectangle)
center = sdl3.SDL_FPoint(destRect.w / 2, destRect.h / 2)
sdl3.SDL_RenderTextureRotated(renderer, spriteTexture, None,
destRect, -20, center, sdl3.SDL_FLIP_NONE)
sdl3.SDL_RenderPresent(renderer)
return sdl3.SDL_APP_CONTINUE
@sdl3.SDL_AppQuit_func
def SDL_AppQuit(appstate, result):
global spriteTexture
# SDL will clean up the window/renderer for us
sdl3.SDL_DestroyTexture(spriteTexture) |
Beta Was this translation helpful? Give feedback.
-
|
Spawn textured boxes and circles by click It spawns a box by left mouse click and a circle by right mouse click. You can disable the drawing of colliders by commenting out this line of code: # world.DrawDebugData()spawn-angry-birds-objects-by-click-box2d-pysdl3.zip
Assets:
Click this to collapse/foldmain.py import ctypes
import math
import os
from Box2D import (b2_dynamicBody, b2BodyDef, b2CircleShape, b2FixtureDef,
b2PolygonShape, b2Vec2, b2World)
os.environ["SDL_MAIN_USE_CALLBACKS"] = "1"
os.environ["SDL_RENDER_DRIVER"] = "opengl"
import sdl3
from debug_drawer import DebugDrawer
renderer = ctypes.POINTER(sdl3.SDL_Renderer)()
window = ctypes.POINTER(sdl3.SDL_Window)()
groundTexture = None
pigTexture = None
blockTexture = None
world = b2World(gravity=b2Vec2(0, 9.8))
ppm = 30 # pixels per meter
groundPosX = 240
groundPosY = 400
groundHalfWidth = 128
groundHalfHeight = 70
boxes = []
boxHalfWidth = 32 / 2 / ppm
boxHalfHeight = 32 / 2 / ppm
circles = []
circleRadius = 27
@sdl3.SDL_AppInit_func
def SDL_AppInit(appstate, argc, argv):
global groundTexture;
global pigTexture;
global blockTexture;
if not sdl3.SDL_Init(sdl3.SDL_INIT_VIDEO):
sdl3.SDL_Log("Couldn't initialize SDL: %s".encode() % sdl3.SDL_GetError())
return sdl3.SDL_APP_FAILURE
windowTitle = "Spawn boxes and circles using PySDL3 and Box2D".encode()
if not sdl3.SDL_CreateWindowAndRenderer(windowTitle, 480, 480, 0, window, renderer):
sdl3.SDL_Log("Couldn't create window/renderer: %s".encode() % sdl3.SDL_GetError())
return sdl3.SDL_APP_FAILURE
sdl3.SDL_SetRenderVSync(renderer, 1) # Turn on vertical sync
texturePath = "./assets/sprites/ground.png".encode()
groundTexture = sdl3.IMG_LoadTexture(renderer, texturePath)
if not groundTexture:
sdl3.SDL_Log("Error: %s".encode() % sdl3.SDL_GetError())
return sdl3.SDL_APP_FAILURE
texturePath = "./assets/sprites/pig.png".encode()
pigTexture = sdl3.IMG_LoadTexture(renderer, texturePath)
if not pigTexture:
sdl3.SDL_Log("Error: %s".encode() % sdl3.SDL_GetError())
return sdl3.SDL_APP_FAILURE
texturePath = "./assets/sprites/block.png".encode()
blockTexture = sdl3.IMG_LoadTexture(renderer, texturePath)
if not blockTexture:
sdl3.SDL_Log("Error: %s".encode() % sdl3.SDL_GetError())
return sdl3.SDL_APP_FAILURE
debugDrawer = DebugDrawer(renderer, ppm)
debugDrawer.flags = { "drawShapes": True }
world.renderer = debugDrawer
# Create a ground body
groundBodyDef = b2BodyDef()
groundBodyDef.position = b2Vec2(groundPosX / ppm, groundPosY / ppm)
groundBody = world.CreateBody(groundBodyDef)
groundShape = b2PolygonShape()
groundShape.SetAsBox(groundHalfWidth / ppm, (groundHalfHeight - 12) / ppm)
groundFixtureDef = b2FixtureDef()
groundFixtureDef.shape = groundShape
groundFixtureDef.density = 0
groundBody.CreateFixture(groundFixtureDef)
return sdl3.SDL_APP_CONTINUE
def createBox(x, y):
boxBodyDef = b2BodyDef()
boxBodyDef.position = b2Vec2(x / ppm, y / ppm)
boxBodyDef.type = b2_dynamicBody
boxBody = world.CreateBody(boxBodyDef)
boxShape = b2PolygonShape()
boxShape.SetAsBox(boxHalfWidth, boxHalfHeight)
boxFixtureDef = b2FixtureDef()
boxFixtureDef.shape = boxShape
boxFixtureDef.density = 2
boxFixtureDef.restitution = 0.2
boxBody.CreateFixture(boxFixtureDef)
boxes.append(boxBody)
def createCircle(x, y):
circleBodyDef = b2BodyDef()
circleBodyDef.position = b2Vec2(x / ppm, y / ppm)
circleBodyDef.type = b2_dynamicBody
circleBody = world.CreateBody(circleBodyDef)
circleShape = b2CircleShape()
circleShape.radius = circleRadius / ppm
circleFixtureDef = b2FixtureDef()
circleFixtureDef.shape = circleShape
circleFixtureDef.density = 1
circleFixtureDef.restitution = 0.5
circleBody.CreateFixture(circleFixtureDef)
circles.append(circleBody)
@sdl3.SDL_AppEvent_func
def SDL_AppEvent(appstate, event):
if sdl3.SDL_DEREFERENCE(event).type == sdl3.SDL_EVENT_QUIT:
return sdl3.SDL_APP_SUCCESS
elif sdl3.SDL_DEREFERENCE(event).type == sdl3.SDL_EVENT_MOUSE_BUTTON_DOWN:
if sdl3.SDL_DEREFERENCE(event).button.button == sdl3.SDL_BUTTON_LEFT:
x = sdl3.SDL_DEREFERENCE(event).button.x
y = sdl3.SDL_DEREFERENCE(event).button.y
createBox(x, y)
elif sdl3.SDL_DEREFERENCE(event).button.button == sdl3.SDL_BUTTON_RIGHT:
x = sdl3.SDL_DEREFERENCE(event).button.x
y = sdl3.SDL_DEREFERENCE(event).button.y
createCircle(x, y)
return sdl3.SDL_APP_CONTINUE
@sdl3.SDL_AppIterate_func
def SDL_AppIterate(appstate):
# Set the color and clear the canvas with color
sdl3.SDL_SetRenderDrawColor(renderer, 50, 50, 50, sdl3.SDL_ALPHA_OPAQUE)
sdl3.SDL_RenderClear(renderer)
# Draw boxes
for body in boxes:
boxPosX = body.position[0] * ppm
boxPosY = body.position[1] * ppm
srcRect = sdl3.SDL_FRect(0, 0, 32, 32)
destRect = sdl3.SDL_FRect(boxPosX - 16,
boxPosY - 16, 32, 32)
# Rotation center (center of the rectangle)
center = sdl3.SDL_FPoint(destRect.w / 2, destRect.h / 2)
sdl3.SDL_RenderTextureRotated(renderer, blockTexture, None,
destRect, math.degrees(body.angle), center, sdl3.SDL_FLIP_NONE)
# Draw circles
for body in circles:
circlePosX = body.position[0] * ppm
circlePosY = body.position[1] * ppm
srcRect = sdl3.SDL_FRect(0, 0, 64, 64)
destRect = sdl3.SDL_FRect(circlePosX - 32,
circlePosY - 32, 64, 64)
center = sdl3.SDL_FPoint(destRect.w / 2, destRect.h / 2)
sdl3.SDL_RenderTextureRotated(renderer, pigTexture, None,
destRect, math.degrees(body.angle), center, sdl3.SDL_FLIP_NONE)
# Render a ground
srcRect = sdl3.SDL_FRect(0, 0, 256, 140)
destRect = sdl3.SDL_FRect(groundPosX - groundHalfWidth,
groundPosY - groundHalfHeight, 256, 140)
sdl3.SDL_RenderTexture(renderer, groundTexture, srcRect, destRect)
world.Step(0.016, 3, 2)
world.DrawDebugData()
sdl3.SDL_RenderPresent(renderer)
return sdl3.SDL_APP_CONTINUE
@sdl3.SDL_AppQuit_func
def SDL_AppQuit(appstate, result):
... # SDL will clean up the window/renderer for us
sdl3.SDL_DestroyTexture(groundTexture)
sdl3.SDL_DestroyTexture(pigTexture)
sdl3.SDL_DestroyTexture(blockTexture)debug_drawer.py import math
import sdl3
from Box2D import b2Draw
class DebugDrawer(b2Draw):
def __init__(self, renderer, pixelsPerMeter, thickness=3):
super().__init__()
self.renderer = renderer
self.ppm = pixelsPerMeter
self.thickness = thickness
def DrawSolidPolygon(self, vertices, color):
r = int(color.r * 255)
g = int(color.g * 255)
b = int(color.b * 255)
sdl3.SDL_SetRenderDrawColor(self.renderer, r, g, b, sdl3.SDL_ALPHA_OPAQUE)
x0 = vertices[0][0] * self.ppm
y0 = vertices[0][1] * self.ppm
x1 = vertices[1][0] * self.ppm
y1 = vertices[1][1] * self.ppm
sdl3.SDL_RenderLine(self.renderer, x0, y0, x1, y1)
x1 = vertices[1][0] * self.ppm
y1 = vertices[1][1] * self.ppm
x2 = vertices[2][0] * self.ppm
y2 = vertices[2][1] * self.ppm
sdl3.SDL_RenderLine(self.renderer, x1, y1, x2, y2)
x2 = vertices[2][0] * self.ppm
y2 = vertices[2][1] * self.ppm
x3 = vertices[3][0] * self.ppm
y3 = vertices[3][1] * self.ppm
sdl3.SDL_RenderLine(self.renderer, x2, y2, x3, y3)
x3 = vertices[3][0] * self.ppm
y3 = vertices[3][1] * self.ppm
x0 = vertices[0][0] * self.ppm
y0 = vertices[0][1] * self.ppm
sdl3.SDL_RenderLine(self.renderer, x3, y3, x0, y0)
def DrawSolidCircle(self, center, radius, axis, color):
numberOfSegments = 100
angle = 0
angleStep = 360 / numberOfSegments
r = int(color.r * 255)
g = int(color.g * 255)
b = int(color.b * 255)
sdl3.SDL_SetRenderDrawColor(self.renderer, r, g, b, sdl3.SDL_ALPHA_OPAQUE)
centerX = center[0] * self.ppm
centerY = center[1] * self.ppm
radius *= self.ppm
x = radius * math.cos(math.radians(angle))
y = radius * math.sin(math.radians(angle))
fromX = centerX + x
fromY = centerY + y
for i in range(numberOfSegments + 1):
x = radius * math.cos(math.radians(angle))
y = radius * math.sin(math.radians(angle))
toX = centerX + x
toY = centerY + y
sdl3.SDL_RenderLine(self.renderer, fromX, fromY, toX, toY)
angle += angleStep
fromX = toX
fromY = toY
def DrawPolygon(self, vertices, color):
pass
def DrawSegment(self, p1, p2, color):
pass
def DrawPoint(self, p, size, color):
pass
def DrawCircle(self, center, radius, color, drawwidth=1):
pass
def DrawTransform(self, xf):
pass |
Beta Was this translation helpful? Give feedback.
-
|
Move Box2D circle by keys It moves a circle by WASD or arrow keys. move-box2d-circle-by-keys-pysdl3.zip
|
Beta Was this translation helpful? Give feedback.
-
|
Collision detection using Box2D and PySDL3 It shows how to use the b2ContactListener class to detect contacts. Source code: GitHup repository pip install Box2D==2.3.10
pip install PySDL3==0.9.9b1
py main.py |
Beta Was this translation helpful? Give feedback.
-
|
FamTrinli's Snake in PySDL3 It is a port from the FamTrinli's video tutorial to PySDL3. Play in the browser: https://famtrinli-snake-in-sdl3-cpp.netlify.app/ Download sources: famtrinli's-snake-in-pysdl3.zip Click this to collapse/foldmain.py import ctypes
import os
import random
os.environ["SDL_MAIN_USE_CALLBACKS"] = "1"
os.environ["SDL_RENDER_DRIVER"] = "opengl"
import sdl3
renderer = ctypes.POINTER(sdl3.SDL_Renderer)()
window = ctypes.POINTER(sdl3.SDL_Window)()
greenSpriteTexture = None
redSpriteTexture = None
whiteSpriteTexture = None
N = 30
M = 20
size = 16
w = size * N
h = size * M
keys = { "left": False, "right": False, "up": False, "down": False }
delay = 0.1
timer = 0
lastTime = 0
snakeLength = 4
snakeMaxLength = 100
snakeDir = 0
# Snake list
s = [{ "x": 0, "y": 0 } for _ in range(snakeMaxLength)]
# Fruit list
fruit = { "x": 7, "y": 5 }
@sdl3.SDL_AppInit_func
def SDL_AppInit(appstate, argc, argv):
global greenSpriteTexture
global redSpriteTexture
global whiteSpriteTexture
if not sdl3.SDL_Init(sdl3.SDL_INIT_VIDEO):
sdl3.SDL_Log("Couldn't initialize SDL: %s".encode() % sdl3.SDL_GetError())
return sdl3.SDL_APP_FAILURE
title = "FamTrinli's Snake in PySDL3".encode()
if not sdl3.SDL_CreateWindowAndRenderer(title, w, h, 0, window, renderer):
sdl3.SDL_Log("Couldn't create window/renderer: %s".encode() % sdl3.SDL_GetError())
return sdl3.SDL_APP_FAILURE
sdl3.SDL_SetRenderVSync(renderer, 1) # Turn on vertical sync
# Green texture
texturePath = "./assets/images/green.png".encode()
greenSpriteTexture = sdl3.IMG_LoadTexture(renderer, texturePath)
if not greenSpriteTexture:
sdl3.SDL_Log("Error: %s".encode() % sdl3.SDL_GetError())
return sdl3.SDL_APP_FAILURE
sdl3.SDL_SetTextureScaleMode(greenSpriteTexture, sdl3.SDL_SCALEMODE_NEAREST)
# Red texture
texturePath = "./assets/images/red.png".encode()
redSpriteTexture = sdl3.IMG_LoadTexture(renderer, texturePath)
if not redSpriteTexture:
sdl3.SDL_Log("Error: %s".encode() % sdl3.SDL_GetError())
return sdl3.SDL_APP_FAILURE
sdl3.SDL_SetTextureScaleMode(redSpriteTexture, sdl3.SDL_SCALEMODE_NEAREST)
# White texture
texturePath = "./assets/images/white.png".encode()
whiteSpriteTexture = sdl3.IMG_LoadTexture(renderer, texturePath)
if not whiteSpriteTexture:
sdl3.SDL_Log("Error: %s".encode() % sdl3.SDL_GetError())
return sdl3.SDL_APP_FAILURE
sdl3.SDL_SetTextureScaleMode(whiteSpriteTexture, sdl3.SDL_SCALEMODE_NEAREST)
return sdl3.SDL_APP_CONTINUE
@sdl3.SDL_AppEvent_func
def SDL_AppEvent(appstate, event):
if sdl3.SDL_DEREFERENCE(event).type == sdl3.SDL_EVENT_QUIT:
return sdl3.SDL_APP_SUCCESS
elif sdl3.SDL_DEREFERENCE(event).type == sdl3.SDL_EVENT_KEY_DOWN:
if (
sdl3.SDL_DEREFERENCE(event).key.scancode == sdl3.SDL_SCANCODE_W or
sdl3.SDL_DEREFERENCE(event).button.button == sdl3.SDL_SCANCODE_UP
):
keys["up"] = True
if (
sdl3.SDL_DEREFERENCE(event).key.scancode == sdl3.SDL_SCANCODE_S or
sdl3.SDL_DEREFERENCE(event).button.button == sdl3.SDL_SCANCODE_DOWN
):
keys["down"] = True
if (
sdl3.SDL_DEREFERENCE(event).key.scancode == sdl3.SDL_SCANCODE_A or
sdl3.SDL_DEREFERENCE(event).button.button == sdl3.SDL_SCANCODE_LEFT
):
keys["left"] = True
if (
sdl3.SDL_DEREFERENCE(event).key.scancode == sdl3.SDL_SCANCODE_D or
sdl3.SDL_DEREFERENCE(event).button.button == sdl3.SDL_SCANCODE_RIGHT
):
keys["right"] = True
elif sdl3.SDL_DEREFERENCE(event).type == sdl3.SDL_EVENT_KEY_UP:
if (
sdl3.SDL_DEREFERENCE(event).key.scancode == sdl3.SDL_SCANCODE_W or
sdl3.SDL_DEREFERENCE(event).button.button == sdl3.SDL_SCANCODE_UP
):
keys["up"] = False
if (
sdl3.SDL_DEREFERENCE(event).key.scancode == sdl3.SDL_SCANCODE_S or
sdl3.SDL_DEREFERENCE(event).button.button == sdl3.SDL_SCANCODE_DOWN
):
keys["down"] = False
if (
sdl3.SDL_DEREFERENCE(event).key.scancode == sdl3.SDL_SCANCODE_A or
sdl3.SDL_DEREFERENCE(event).button.button == sdl3.SDL_SCANCODE_LEFT
):
keys["left"] = False
if (
sdl3.SDL_DEREFERENCE(event).key.scancode == sdl3.SDL_SCANCODE_D or
sdl3.SDL_DEREFERENCE(event).button.button == sdl3.SDL_SCANCODE_RIGHT
):
keys["right"] = False
return sdl3.SDL_APP_CONTINUE
def keyboard():
global snakeDir
if snakeDir != 2 and keys["left"]:
snakeDir = 1
if snakeDir != 1 and keys["right"]:
snakeDir = 2
if snakeDir != 0 and keys["up"]:
snakeDir = 3
if snakeDir != 3 and keys["down"]:
snakeDir = 0
def tick():
global snakeLength
for i in range(snakeLength, 0, -1):
s[i]["x"] = s[i - 1]["x"]
s[i]["y"] = s[i - 1]["y"]
if snakeDir == 0:
s[0]["y"] += 1 # down
if snakeDir == 1:
s[0]["x"] -= 1 # left
if snakeDir == 2:
s[0]["x"] += 1 # right
if snakeDir == 3:
s[0]["y"] -= 1 # up
if s[0]["x"] >= N:
s[0]["x"] = 0
if s[0]["x"] < 0:
s[0]["x"] = N - 1
if s[0]["y"] >= M:
s[0]["y"] = 0
if s[0]["y"] < 0:
s[0]["y"] = M - 1
if s[0]["x"] == fruit["x"] and s[0]["y"] == fruit["y"]:
snakeLength += 1
if snakeLength != snakeMaxLength:
fruit["x"] = random.randint(0, N - 1)
fruit["y"] = random.randint(0, M - 1)
else:
print("You won the game!")
fruit["x"] = -1
fruit["y"] = -1
snakeLength -= 1
for i in range(1, snakeLength):
if s[0]["x"] == s[i]["x"] and s[0]["y"] == s[i]["y"]:
snakeLength = i
@sdl3.SDL_AppIterate_func
def SDL_AppIterate(appstate):
global lastTime
global timer
global snakeLength
# Calc delta time
currentTime = sdl3.SDL_GetTicks()
deltaTime = (currentTime - lastTime) / 1000
lastTime = currentTime
timer += deltaTime
if timer > delay:
timer = 0
tick()
keyboard()
# Clear the canvas with a specific color
sdl3.SDL_SetRenderDrawColor(renderer, 168, 185, 168, sdl3.SDL_ALPHA_OPAQUE)
sdl3.SDL_RenderClear(renderer) # Start with a blank canvas
# Draw a background
for i in range(N):
for j in range(M):
srcRect = sdl3.SDL_FRect(0, 0, size, size)
destRect = sdl3.SDL_FRect(i * size, j * size, size, size)
sdl3.SDL_RenderTexture(renderer, whiteSpriteTexture, srcRect, destRect)
# Draw a snake
for i in range(snakeLength):
srcRect = sdl3.SDL_FRect(0, 0, size, size)
destRect = sdl3.SDL_FRect(s[i]["x"] * size, s[i]["y"] * size, size, size)
sdl3.SDL_RenderTexture(renderer, greenSpriteTexture, srcRect, destRect)
# Draw a fruit
srcRect = sdl3.SDL_FRect(0, 0, size, size)
destRect = sdl3.SDL_FRect(fruit["x"] * size, fruit["y"] * size, size, size)
sdl3.SDL_RenderTexture(renderer, redSpriteTexture, srcRect, destRect)
sdl3.SDL_RenderPresent(renderer)
return sdl3.SDL_APP_CONTINUE
@sdl3.SDL_AppQuit_func
def SDL_AppQuit(appstate, result):
global greenSpriteTexture
global redSpriteTexture
global whiteSpriteTexture
sdl3.SDL_DestroyTexture(greenSpriteTexture)
sdl3.SDL_DestroyTexture(redSpriteTexture)
sdl3.SDL_DestroyTexture(whiteSpriteTexture)
# SDL will clean up the window/renderer for us
|
Beta Was this translation helpful? Give feedback.
-
|
Great work! |
Beta Was this translation helpful? Give feedback.
-
|
Rotating images This rotating image example is based on my original PySDL3 structure, with the time-based rotation logic (90 degrees/sec) generated by an AI assistant powered by the Gemini Flash 2.5 model. Source code: rotating-images-pysdl3-python.zip |
Beta Was this translation helpful? Give feedback.
-
|
Print SDL3 library versions
Source code: GitHub repository Console output: |
Beta Was this translation helpful? Give feedback.






















Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Hello. There are some simple examples. There are more examples in the Need examples topic.
These examples use the PySDL3 0.9.9b1 and Box2D 2.3.10. You can install the specific versions of these packages like this:
Or try to run the examples with the latest versions for packages:
pip install PySDL3 Box2DTable of contents:
Beta Was this translation helpful? Give feedback.
All reactions