Skip to main content

Moteur de jeu 2D sur Pygame

Project description

Tiavina.engine

Moteur de jeu 2D pixel art, construit sur Pygame.
Fonctionne avec un écran virtuel (résolution logique) mis à l'échelle entière vers la fenêtre d'affichage.

Installation

pip install Tiavina.engine
from Engine import engine as e

e.init(200, 200, "Mon Jeu", fps=60, display_scale=4)

def update():
    if e.btn(e.KEY_ESCAPE):
        e.quit()

def draw():
    e.cls((30, 30, 40))
    e.rect(10, 10, 20, 20, (255, 0, 0))

e.run(update, draw)

Table des matières


Architecture

Engine/
├── __init__.py        ← réexporte l'API
├── engine.py          ← le moteur (tout-en-un)
└── fonts/
    └── PressStart2P.ttf   ← police pixel embarquée

Le moteur expose une API globale : on importe from Engine import engine as e et on appelle e.init(), e.cls(), e.btn(), etc.

Sous le capot :

  • App — classe principale qui gère la fenêtre Pygame, l'horloge FPS, le virtual_screen (Surface logique), et la boucle d'événements.
  • Graphics — dessin sur l'écran virtuel avec support de caméra, clipping, et alpha.
  • Input — gestion clavier, souris, joystick.
  • Resources — chargement d'images, sons, musiques.
  • Audio — lecture son/musique via les canaux Pygame.

Initialisation

e.init(width, height, title="T.engine", fps=30, display_scale=1)

Crée la fenêtre et initialise tous les sous-systèmes.

Paramètre Type Description
width int Largeur logique de l'écran virtuel (ex: 200)
height int Hauteur logique (ex: 200)
title str Titre de la fenêtre
fps int Images par seconde cibles
display_scale int Facteur d'échelle entier (ex: 5 → fenêtre 1000×1000 pour 200×200)

L'écran virtuel fait width × height pixels. Chaque frame, il est scaled par display_scale et affiché dans la fenêtre système.

e.init(200, 200, "Mon Jeu", 60, 5)

e.run(update, draw)

Lance la boucle de jeu. update() est appelée à chaque frame pour la logique, draw() pour le rendu.

def update():
    pass

def draw():
    e.cls((0, 0, 0))

e.run(update, draw)

e.quit()

Ferme Pygame et termine le processus.

e.width(), e.height()

Retourne la largeur/hauteur logique définies dans init().

e.frame_count()

Retourne le nombre de frames écoulées depuis init().


Graphismes — Graphics

Toutes les fonctions de dessin sont affectées par la caméra (sauf si camera() est réinitialisée).
Les coordonnées sont en pixels logiques.

Primitives de dessin

Fonction Description
cls(color) Remplit tout l'écran virtuel avec une couleur
pset(x, y, color) Dessine un pixel
pget(x, y) → Color Lit la couleur d'un pixel
line(x1, y1, x2, y2, color) Ligne
rect(x, y, w, h, color) Rectangle plein
rectb(x, y, w, h, color) Rectangle vide (1px de bord)
circ(x, y, r, color) Cercle plein
circb(x, y, r, color) Cercle vide (1px de bord)
elli(x, y, w, h, color) Ellipse pleine
ellib(x, y, w, h, color) Ellipse vide (1px de bord)
tri(x1, y1, x2, y2, x3, y3, color) Triangle plein
trib(x1, y1, x2, y2, x3, y3, color) Triangle vide (1px de bord)

Couleurs avec alpha (RGBA)

Toutes les primitives sauf text() et pget() acceptent des couleurs RGBA (4 valeurs).
L'alpha est géré via un blending additif sur une surface temporaire.

# Rectangle semi-transparent
e.rect(10, 10, 50, 50, (255, 0, 0, 128))

Blit d'image

blt(x, y, img, u, v, w, h, colkey=None, rotate=0)
Paramètre Type Description
x, y int Position de destination (coin supérieur gauche)
img pygame.Surface Image source
u, v int Coordonnées source (coin supérieur gauche dans l'image)
w, h int Dimensions de la région source
colkey Color ou None Couleur de transparence (optionnelle)
rotate float Rotation en degrés horaire (pivot au centre)
e.blt(100, 100, img, 0, 0, 16, 16)          # blit simple
e.blt(100, 100, img, 0, 0, 16, 16, rotate=45)  # rotation

Texte

text(x, y, s, color, font=None)
Paramètre Type Description
x, y int Position
s str Texte à afficher
color tuple Couleur RGB (pas de support alpha)
font pygame.Font ou None Police personnalisée (None = police pixel par défaut)

La police par défaut est PressStart2P.ttf taille 6px, rendu sans anti-aliasing pour un aspect pixel art.

e.text(5, 5, "Score: 42", (255, 255, 255))

# Avec une police différente
big = e.default_font(16)
e.text(5, 20, "Titre", (255, 200, 0), font=big)

Caméra

camera(dx, dy)    # Applique un décalage à tout le dessin suivant
camera()          # Réinitialise le décalage à (0, 0)

La caméra est cumulative : tous les appels camera() s'ajoutent.
Pour un système plus avancé, voir la classe Camera.

e.camera(-player.x + 100, -player.y + 100)   # suit le joueur

Clipping

clip(x, y, w, h)    # Active un rectangle de clipping
clip()              # Désactive le clipping

Le clipping est appliqué après la caméra.


Caméra intelligente — Camera

cam = e.Camera(target, screen_width, screen_height,
               mouse_influence=0.2, mouse_limit=10)

Classe réutilisable avec suivi de cible, offset souris, tremblement et flash.

Paramètres du constructeur

Paramètre Défaut Description
target Objet suivi (doit avoir .x, .y)
screen_width Largeur de l'écran logique
screen_height Hauteur de l'écran logique
mouse_influence 0.2 Sensibilité du regard vers la souris (0.0–1.0)
mouse_limit 10 Décalage maximal dû à la souris (en pixels logiques)

Méthodes

Méthode Description
update() Calcule la nouvelle position de la caméra (target + souris + shake)
apply() Applique le décalage au moteur graphique (e.camera(cam.cam_x, cam.cam_y))
shake(duration, intensity) Déclenche un tremblement d'écran
flash(color, alpha, duration) Déclenche un flash d'écran

Attributs

Attribut Description
cam_x, cam_y Position calculée de la caméra (en pixels logiques)
flash_color Couleur du flash actif
flash_alpha Opacité courante du flash
shake_intensity Intensité du tremblement actuel

Le flash doit être dessiné manuellement dans draw() :

if cam.flash_alpha > 0:
    surf = pygame.Surface((e.width(), e.height()), pygame.SRCALPHA)
    surf.fill((*cam.flash_color, cam.flash_alpha))
    e.graphics.screen.blit(surf, (0, 0))

Entrées — Input

Clavier

btn(key)        # → True si la touche est maintenue
btnp(key)       # → True le frame où la touche est pressée (pas de répétition)
btnr(key)       # → True le frame où la touche est relâchée
if e.btn(e.KEY_SPACE):
    player.jump()
if e.btnp(e.KEY_E):
    player.interact()

Souris

mouse_x(), mouse_y()     # → Position logique (divisée par display_scale)
mouse_btn(button)        # → True si le bouton est maintenu
mouse_btnp(button)       # → True le frame du clic
mouse_btnr(button)       # → True le frame du relâchement
mouse(visible=True)      # → Affiche ou cache le curseur système

Boutons : MOUSE_BUTTON_LEFT (1), MOUSE_BUTTON_MIDDLE (2), MOUSE_BUTTON_RIGHT (3)

if e.mouse_btnp(e.MOUSE_BUTTON_LEFT):
    print(f"Clic à ({e.mouse_x()}, {e.mouse_y()})")

Joystick

joy(joy_id, button)       # → True si le bouton du joystick est pressé
joy_axis(joy_id, axis)    # → Valeur de l'axe (-1.0 à 1.0)

Les joysticks sont détectés et initialisés automatiquement au lancement.


Ressources — Resources

resources.image(bank, path, colkey=None)   # → pygame.Surface ou None
resources.sound(bank, path)                # → pygame.mixer.Sound ou None
resources.music(bank, path)                # → None (enregistre le chemin)
resources.tilemap(bank)                    # → None (non implémenté)
resources.load(filename)                   # → lève NotImplementedError

Images

image() charge une image dans resources.images[bank].

  • bank : index numérique (int)
  • path : chemin relatif ou absolu
  • colkey : couleur de transparence optionnelle (ex: (255, 0, 255))
e.resources.image(0, "./sprites/player.png")
e.resources.image(1, "./sprites/tiles.png", (255, 0, 255))

# Utilisation
img = e.resources.images[1]

Sons

e.resources.sound(0, "./sfx/jump.wav")
e.audio.play(0, 0)         # joue sur le canal 0

Audio — Audio

8 canaux (0–7) pour les effets sonores, 1 flux pour la musique.

audio.play(channel, sound_key, loop=False)       # joue un son
audio.playm(music_key, loop=False)               # joue une musique
audio.stop(channel=None)                         # stop (tout si channel=None)
audio.play_pos(channel)                          # → True si le canal est actif
e.audio.play(2, 0)                 # son index 0 sur canal 2
e.audio.playm("boss_music")        # musique
e.audio.stop()                     # coupe tout

Police pixel — default_font

default_font(size=6)  pygame.Font

Charge et met en cache la police PressStart2P.ttf.
Si le fichier TTF est introuvable, tombe sur pygame.font.Font(None, size).

La police est stockée dans un cache global _pixel_font_cache : chaque taille n'est chargée qu'une fois.

petite = e.default_font(6)
moyenne = e.default_font(8)
grande  = e.default_font(16)

Constantes

Touches clavier

KEY_AKEY_Z, KEY_0KEY_9, KEY_SPACE, KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT, KEY_ESCAPE, KEY_RETURN, KEY_TAB, KEY_BACKSPACE, KEY_LSHIFT, KEY_RSHIFT, KEY_LCTRL, KEY_RCTRL, KEY_LALT, KEY_RALT

Toutes sont des constantes Pygame (pygame.K_*) réexportées par le module.

Boutons souris

Constante Valeur
MOUSE_BUTTON_LEFT 1
MOUSE_BUTTON_MIDDLE 2
MOUSE_BUTTON_RIGHT 3

Fonctions globales

Le module engine expose des fonctions globales qui délèguent aux sous-systèmes internes :

Fonction Délègue à
cls(c) graphics.cls(c)
pset(x,y,c) graphics.pset(x,y,c)
pget(x,y) graphics.pget(x,y)
line(x1,y1,x2,y2,c) graphics.line(...)
rect(x,y,w,h,c) graphics.rect(...)
rectb(x,y,w,h,c) graphics.rectb(...)
circ(x,y,r,c) graphics.circ(...)
circb(x,y,r,c) graphics.circb(...)
elli(x,y,w,h,c) graphics.elli(...)
ellib(x,y,w,h,c) graphics.ellib(...)
tri(x1,y1,x2,y2,x3,y3,c) graphics.tri(...)
trib(x1,y1,x2,y2,x3,y3,c) graphics.trib(...)
text(x,y,s,c,font) graphics.text(...)
blt(x,y,img,u,v,w,h,...) graphics.blt(...)
bltm(x,y,tm,u,v,w,h,...) graphics.bltm(...)
clip(x,y,w,h) graphics.clip(...)
camera(x,y) graphics.camera(...)
pal(c1,c2) graphics.pal(...) (stub)
dither(a) graphics.dither(...) (stub)
mouse_btn(b) input.mouse_btn(b)
mouse_btnp(b) input.mouse_btnp(b)
mouse_btnr(b) input.mouse_btnr(b)
btn(k) input.btn(k)
btnp(k) input.btnp(k)
btnr(k) input.btnr(k)

Exemple complet

import pygame
from Engine import engine as e
from random import randint

# ── Initialisation ─────────────────────────────────────
e.init(200, 200, "Aventurier", fps=60, display_scale=5)

# ── Ressources ─────────────────────────────────────────
e.resources.image(0, "./sprites/player.png")
e.resources.image(1, "./sprites/tiles.png")

# ── Joueur ─────────────────────────────────────────────
class Player:
    def __init__(self):
        self.x = 100
        self.y = 100
        self.w = 8
        self.h = 8
        self.vie = 100

player = Player()

# ── Caméra ─────────────────────────────────────────────
cam = e.Camera(player, e.width(), e.height(),
               mouse_influence=0.3, mouse_limit=12)

# ── Boucle ─────────────────────────────────────────────
def update():
    # Déplacements
    if e.btn(e.KEY_LEFT):  player.x -= 1
    if e.btn(e.KEY_RIGHT): player.x += 1
    if e.btn(e.KEY_UP):    player.y -= 1
    if e.btn(e.KEY_DOWN):  player.y += 1
    if e.btn(e.KEY_ESCAPE): e.quit()

    # Clic pour shake
    if e.mouse_btnp(e.MOUSE_BUTTON_LEFT):
        cam.shake(10, 6)
        cam.flash((255, 255, 200), 60, 4)

    cam.update()
    cam.apply()

def draw():
    e.cls((30, 30, 40))

    # Sol (en coordonnées monde)
    for i in range(-2, 30):
        for j in range(-2, 20):
            e.rect(i * 8, j * 8, 8, 8, (40, 45, 55))

    # Joueur
    e.rect(player.x, player.y, player.w, player.h,
           (100, 200, 255) if player.vie > 0 else (255, 50, 50))

    # Flash overlay (dessiné avant la réinitialisation caméra)
    if cam.flash_alpha > 0:
        surf = pygame.Surface((e.width(), e.height()), pygame.SRCALPHA)
        surf.fill((*cam.flash_color, cam.flash_alpha))
        e.graphics.screen.blit(surf, (0, 0))

    # ── HUD (coordonnées écran) ──
    e.camera()  # ← réinitialise la caméra

    e.text(4, 4, f"Vie: {player.vie}", (255, 255, 255))
    e.text(4, 12, f"Pos: {player.x},{player.y}", (200, 200, 200))

    # Curseur
    e.circb(e.mouse_x(), e.mouse_y(), 3, (255, 255, 255, 80))

e.run(update, draw)

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

tiavina_engine-0.2.0-py3-none-any.whl (44.9 kB view details)

Uploaded Python 3

File details

Details for the file tiavina_engine-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: tiavina_engine-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 44.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for tiavina_engine-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 80123091be82be491f8ff33fbda5145ed38245a5eadb3bb4ea67e38c67174483
MD5 8c1f12f1f6c968598faa29e132c22e17
BLAKE2b-256 a4efc0b58873a98e0c420e7defc587259c359227f6b1f133a32295c9ebd6ed20

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page