New SoundBuffer Python type enables procedural audio generation: - Tone synthesis (sine, square, saw, triangle, noise) with ADSR envelopes - sfxr retro sound effect engine (7 presets, 24 params, mutation, seeding) - DSP effects chain: pitch_shift, low/high pass, echo, reverb, distortion, bit_crush, normalize, reverse, slice - Composition: concat (with crossfade overlap) and mix - Sound() now accepts SoundBuffer or filename string - Sound gains pitch property and play_varied() method - Platform stubs for HeadlessTypes and SDL2Types (loadFromSamples, pitch) - Interactive demo: sfxr clone UI + Animalese speech synthesizer - 62 unit tests across 6 test files (all passing) Refs #251 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1413 lines
42 KiB
Python
1413 lines
42 KiB
Python
"""Type stubs for McRogueFace Python API.
|
|
|
|
Core game engine interface for creating roguelike games with Python.
|
|
"""
|
|
|
|
from typing import Any, List, Dict, Tuple, Optional, Callable, Union, overload
|
|
|
|
# Type aliases - Color tuples are accepted anywhere a Color is expected
|
|
ColorLike = Union['Color', Tuple[int, int, int], Tuple[int, int, int, int]]
|
|
UIElement = Union['Frame', 'Caption', 'Sprite', 'Grid', 'Line', 'Circle', 'Arc']
|
|
Transition = Union[str, None]
|
|
|
|
# Enums
|
|
|
|
class Key:
|
|
"""Keyboard key codes enum.
|
|
|
|
All standard keyboard keys are available as class attributes:
|
|
A-Z, Num0-Num9, F1-F15, Arrow keys, modifiers, etc.
|
|
"""
|
|
A: 'Key'
|
|
B: 'Key'
|
|
C: 'Key'
|
|
D: 'Key'
|
|
E: 'Key'
|
|
F: 'Key'
|
|
G: 'Key'
|
|
H: 'Key'
|
|
I: 'Key'
|
|
J: 'Key'
|
|
K: 'Key'
|
|
L: 'Key'
|
|
M: 'Key'
|
|
N: 'Key'
|
|
O: 'Key'
|
|
P: 'Key'
|
|
Q: 'Key'
|
|
R: 'Key'
|
|
S: 'Key'
|
|
T: 'Key'
|
|
U: 'Key'
|
|
V: 'Key'
|
|
W: 'Key'
|
|
X: 'Key'
|
|
Y: 'Key'
|
|
Z: 'Key'
|
|
Num0: 'Key'
|
|
Num1: 'Key'
|
|
Num2: 'Key'
|
|
Num3: 'Key'
|
|
Num4: 'Key'
|
|
Num5: 'Key'
|
|
Num6: 'Key'
|
|
Num7: 'Key'
|
|
Num8: 'Key'
|
|
Num9: 'Key'
|
|
ESCAPE: 'Key'
|
|
ENTER: 'Key'
|
|
SPACE: 'Key'
|
|
TAB: 'Key'
|
|
BACKSPACE: 'Key'
|
|
DELETE: 'Key'
|
|
UP: 'Key'
|
|
DOWN: 'Key'
|
|
LEFT: 'Key'
|
|
RIGHT: 'Key'
|
|
LSHIFT: 'Key'
|
|
RSHIFT: 'Key'
|
|
LCTRL: 'Key'
|
|
RCTRL: 'Key'
|
|
LALT: 'Key'
|
|
RALT: 'Key'
|
|
F1: 'Key'
|
|
F2: 'Key'
|
|
F3: 'Key'
|
|
F4: 'Key'
|
|
F5: 'Key'
|
|
F6: 'Key'
|
|
F7: 'Key'
|
|
F8: 'Key'
|
|
F9: 'Key'
|
|
F10: 'Key'
|
|
F11: 'Key'
|
|
F12: 'Key'
|
|
F13: 'Key'
|
|
F14: 'Key'
|
|
F15: 'Key'
|
|
HOME: 'Key'
|
|
END: 'Key'
|
|
PAGEUP: 'Key'
|
|
PAGEDOWN: 'Key'
|
|
INSERT: 'Key'
|
|
PAUSE: 'Key'
|
|
TILDE: 'Key'
|
|
MINUS: 'Key'
|
|
EQUAL: 'Key'
|
|
LBRACKET: 'Key'
|
|
RBRACKET: 'Key'
|
|
BACKSLASH: 'Key'
|
|
SEMICOLON: 'Key'
|
|
QUOTE: 'Key'
|
|
COMMA: 'Key'
|
|
PERIOD: 'Key'
|
|
SLASH: 'Key'
|
|
# NUM_ aliases for Num keys
|
|
NUM_0: 'Key'
|
|
NUM_1: 'Key'
|
|
NUM_2: 'Key'
|
|
NUM_3: 'Key'
|
|
NUM_4: 'Key'
|
|
NUM_5: 'Key'
|
|
NUM_6: 'Key'
|
|
NUM_7: 'Key'
|
|
NUM_8: 'Key'
|
|
NUM_9: 'Key'
|
|
NUMPAD0: 'Key'
|
|
NUMPAD1: 'Key'
|
|
NUMPAD2: 'Key'
|
|
NUMPAD3: 'Key'
|
|
NUMPAD4: 'Key'
|
|
NUMPAD5: 'Key'
|
|
NUMPAD6: 'Key'
|
|
NUMPAD7: 'Key'
|
|
NUMPAD8: 'Key'
|
|
NUMPAD9: 'Key'
|
|
|
|
class MouseButton:
|
|
"""Mouse button enum for click callbacks."""
|
|
LEFT: 'MouseButton'
|
|
RIGHT: 'MouseButton'
|
|
MIDDLE: 'MouseButton'
|
|
|
|
class InputState:
|
|
"""Input action state enum for callbacks."""
|
|
PRESSED: 'InputState'
|
|
RELEASED: 'InputState'
|
|
|
|
class Easing:
|
|
"""Animation easing function enum.
|
|
|
|
Available easing functions for smooth animations.
|
|
"""
|
|
LINEAR: 'Easing'
|
|
EASE_IN: 'Easing'
|
|
EASE_OUT: 'Easing'
|
|
EASE_IN_OUT: 'Easing'
|
|
EASE_IN_QUAD: 'Easing'
|
|
EASE_OUT_QUAD: 'Easing'
|
|
EASE_IN_OUT_QUAD: 'Easing'
|
|
EASE_IN_CUBIC: 'Easing'
|
|
EASE_OUT_CUBIC: 'Easing'
|
|
EASE_IN_OUT_CUBIC: 'Easing'
|
|
EASE_IN_QUART: 'Easing'
|
|
EASE_OUT_QUART: 'Easing'
|
|
EASE_IN_OUT_QUART: 'Easing'
|
|
EASE_IN_SINE: 'Easing'
|
|
EASE_OUT_SINE: 'Easing'
|
|
EASE_IN_OUT_SINE: 'Easing'
|
|
EASE_IN_EXPO: 'Easing'
|
|
EASE_OUT_EXPO: 'Easing'
|
|
EASE_IN_OUT_EXPO: 'Easing'
|
|
EASE_IN_CIRC: 'Easing'
|
|
EASE_OUT_CIRC: 'Easing'
|
|
EASE_IN_OUT_CIRC: 'Easing'
|
|
EASE_IN_ELASTIC: 'Easing'
|
|
EASE_OUT_ELASTIC: 'Easing'
|
|
EASE_IN_OUT_ELASTIC: 'Easing'
|
|
EASE_IN_BACK: 'Easing'
|
|
EASE_OUT_BACK: 'Easing'
|
|
EASE_IN_OUT_BACK: 'Easing'
|
|
EASE_IN_BOUNCE: 'Easing'
|
|
EASE_OUT_BOUNCE: 'Easing'
|
|
EASE_IN_OUT_BOUNCE: 'Easing'
|
|
|
|
# Classes
|
|
|
|
class Color:
|
|
"""SFML Color Object for RGBA colors."""
|
|
|
|
r: int
|
|
g: int
|
|
b: int
|
|
a: int
|
|
|
|
@overload
|
|
def __init__(self) -> None: ...
|
|
@overload
|
|
def __init__(self, r: int, g: int, b: int, a: int = 255) -> None: ...
|
|
|
|
def from_hex(self, hex_string: str) -> 'Color':
|
|
"""Create color from hex string (e.g., '#FF0000' or 'FF0000')."""
|
|
...
|
|
|
|
def to_hex(self) -> str:
|
|
"""Convert color to hex string format."""
|
|
...
|
|
|
|
def lerp(self, other: 'Color', t: float) -> 'Color':
|
|
"""Linear interpolation between two colors."""
|
|
...
|
|
|
|
class Vector:
|
|
"""SFML Vector Object for 2D coordinates."""
|
|
|
|
x: float
|
|
y: float
|
|
|
|
@overload
|
|
def __init__(self) -> None: ...
|
|
@overload
|
|
def __init__(self, x: float, y: float) -> None: ...
|
|
|
|
def add(self, other: 'Vector') -> 'Vector': ...
|
|
def subtract(self, other: 'Vector') -> 'Vector': ...
|
|
def multiply(self, scalar: float) -> 'Vector': ...
|
|
def divide(self, scalar: float) -> 'Vector': ...
|
|
def distance(self, other: 'Vector') -> float: ...
|
|
def normalize(self) -> 'Vector': ...
|
|
def dot(self, other: 'Vector') -> float: ...
|
|
|
|
class Texture:
|
|
"""SFML Texture Object for sprite sheet images."""
|
|
|
|
def __init__(self, filename: str, sprite_width: int = 0, sprite_height: int = 0) -> None: ...
|
|
|
|
filename: str
|
|
width: int
|
|
height: int
|
|
sprite_count: int
|
|
|
|
@classmethod
|
|
def from_bytes(cls, data: bytes, width: int, height: int,
|
|
sprite_width: int, sprite_height: int,
|
|
name: str = "<generated>") -> 'Texture':
|
|
"""Create texture from raw RGBA bytes."""
|
|
...
|
|
|
|
@classmethod
|
|
def composite(cls, textures: List['Texture'],
|
|
sprite_width: int, sprite_height: int,
|
|
name: str = "<composite>") -> 'Texture':
|
|
"""Composite multiple textures into one by layering sprites."""
|
|
...
|
|
|
|
def hsl_shift(self, hue_shift: float, sat_shift: float = 0.0,
|
|
lit_shift: float = 0.0) -> 'Texture':
|
|
"""Return a new texture with HSL color shift applied."""
|
|
...
|
|
|
|
class Font:
|
|
"""SFML Font Object for text rendering."""
|
|
|
|
def __init__(self, filename: str) -> None: ...
|
|
|
|
filename: str
|
|
family: str
|
|
|
|
class SoundBuffer:
|
|
"""In-memory audio buffer for procedural audio generation and DSP effects.
|
|
|
|
Supports tone synthesis, sfxr-style retro sound effects, DSP processing,
|
|
and composition. Effects return new SoundBuffer instances (copy-modify pattern).
|
|
"""
|
|
|
|
def __init__(self, filename: str) -> None:
|
|
"""Load audio from a file into memory."""
|
|
...
|
|
|
|
@property
|
|
def duration(self) -> float:
|
|
"""Duration in seconds (read-only)."""
|
|
...
|
|
|
|
@property
|
|
def sample_count(self) -> int:
|
|
"""Number of samples (read-only)."""
|
|
...
|
|
|
|
@property
|
|
def sample_rate(self) -> int:
|
|
"""Sample rate in Hz (read-only)."""
|
|
...
|
|
|
|
@property
|
|
def channels(self) -> int:
|
|
"""Number of audio channels (read-only)."""
|
|
...
|
|
|
|
@property
|
|
def sfxr_params(self) -> Optional[Dict[str, Any]]:
|
|
"""sfxr synthesis parameters, or None if not sfxr-generated (read-only)."""
|
|
...
|
|
|
|
# --- Factory class methods ---
|
|
|
|
@classmethod
|
|
def from_samples(cls, data: bytes, channels: int, sample_rate: int) -> 'SoundBuffer':
|
|
"""Create SoundBuffer from raw int16 PCM sample data."""
|
|
...
|
|
|
|
@overload
|
|
@classmethod
|
|
def tone(cls, frequency: float, duration: float, waveform: str) -> 'SoundBuffer': ...
|
|
|
|
@overload
|
|
@classmethod
|
|
def tone(cls, frequency: float, duration: float, waveform: str, *,
|
|
attack: float = ..., decay: float = ...,
|
|
sustain: float = ..., release: float = ...,
|
|
sample_rate: int = ...) -> 'SoundBuffer': ...
|
|
|
|
@classmethod
|
|
def tone(cls, frequency: float, duration: float, waveform: str, **kwargs: Any) -> 'SoundBuffer':
|
|
"""Generate a tone with specified waveform and optional ADSR envelope.
|
|
|
|
Args:
|
|
frequency: Frequency in Hz.
|
|
duration: Duration in seconds.
|
|
waveform: One of "sine", "square", "saw", "triangle", "noise".
|
|
attack: ADSR attack time in seconds.
|
|
decay: ADSR decay time in seconds.
|
|
sustain: ADSR sustain level (0.0-1.0).
|
|
release: ADSR release time in seconds.
|
|
sample_rate: Sample rate (default 44100).
|
|
"""
|
|
...
|
|
|
|
@overload
|
|
@classmethod
|
|
def sfxr(cls, preset: str, *, seed: Optional[int] = ...) -> 'SoundBuffer': ...
|
|
|
|
@overload
|
|
@classmethod
|
|
def sfxr(cls, *, wave_type: int = ..., base_freq: float = ...,
|
|
freq_limit: float = ..., freq_ramp: float = ...,
|
|
freq_dramp: float = ..., duty: float = ...,
|
|
duty_ramp: float = ..., vib_strength: float = ...,
|
|
vib_speed: float = ..., env_attack: float = ...,
|
|
env_sustain: float = ..., env_decay: float = ...,
|
|
env_punch: float = ..., lpf_freq: float = ...,
|
|
lpf_ramp: float = ..., lpf_resonance: float = ...,
|
|
hpf_freq: float = ..., hpf_ramp: float = ...,
|
|
pha_offset: float = ..., pha_ramp: float = ...,
|
|
repeat_speed: float = ..., arp_speed: float = ...,
|
|
arp_mod: float = ..., seed: Optional[int] = ...) -> 'SoundBuffer': ...
|
|
|
|
@classmethod
|
|
def sfxr(cls, *args: Any, **kwargs: Any) -> 'SoundBuffer':
|
|
"""Generate sfxr-style retro sound effect.
|
|
|
|
Can be called with a preset name ("coin", "laser", "explosion",
|
|
"powerup", "hurt", "jump", "blip") or with custom sfxr parameters.
|
|
|
|
Args:
|
|
preset: Name of sfxr preset.
|
|
seed: Random seed for deterministic generation.
|
|
**kwargs: Individual sfxr parameters (wave_type, base_freq, etc.)
|
|
"""
|
|
...
|
|
|
|
@classmethod
|
|
def concat(cls, buffers: List['SoundBuffer'], overlap: float = 0.0) -> 'SoundBuffer':
|
|
"""Concatenate multiple SoundBuffers with optional crossfade overlap."""
|
|
...
|
|
|
|
@classmethod
|
|
def mix(cls, buffers: List['SoundBuffer']) -> 'SoundBuffer':
|
|
"""Mix (add) multiple SoundBuffers together, padding to longest."""
|
|
...
|
|
|
|
# --- DSP effects (each returns a new SoundBuffer) ---
|
|
|
|
def pitch_shift(self, factor: float) -> 'SoundBuffer':
|
|
"""Resample to shift pitch. Factor > 1.0 = higher pitch, shorter duration."""
|
|
...
|
|
|
|
def low_pass(self, cutoff_hz: float) -> 'SoundBuffer':
|
|
"""Apply single-pole IIR low-pass filter."""
|
|
...
|
|
|
|
def high_pass(self, cutoff_hz: float) -> 'SoundBuffer':
|
|
"""Apply high-pass filter (complement of low-pass)."""
|
|
...
|
|
|
|
def echo(self, delay_ms: float, feedback: float, wet: float) -> 'SoundBuffer':
|
|
"""Apply echo effect with delay, feedback, and wet/dry mix."""
|
|
...
|
|
|
|
def reverb(self, room_size: float, damping: float, wet: float) -> 'SoundBuffer':
|
|
"""Apply simplified Freeverb-style reverb."""
|
|
...
|
|
|
|
def distortion(self, drive: float) -> 'SoundBuffer':
|
|
"""Apply tanh soft-clipping distortion."""
|
|
...
|
|
|
|
def bit_crush(self, bits: int, rate_divisor: int) -> 'SoundBuffer':
|
|
"""Apply bit depth reduction and sample rate crushing."""
|
|
...
|
|
|
|
def normalize(self) -> 'SoundBuffer':
|
|
"""Scale samples to 95% of maximum amplitude."""
|
|
...
|
|
|
|
def reverse(self) -> 'SoundBuffer':
|
|
"""Reverse sample order."""
|
|
...
|
|
|
|
def slice(self, start: float, end: float) -> 'SoundBuffer':
|
|
"""Extract a time range (in seconds) as a new SoundBuffer."""
|
|
...
|
|
|
|
def sfxr_mutate(self, amount: float, seed: Optional[int] = None) -> 'SoundBuffer':
|
|
"""Jitter sfxr parameters by +/- amount and re-synthesize. Only works on sfxr-generated buffers."""
|
|
...
|
|
|
|
|
|
class Sound:
|
|
"""Sound effect object for short audio clips.
|
|
|
|
Can be created from a filename string or a SoundBuffer object.
|
|
"""
|
|
|
|
@overload
|
|
def __init__(self, filename: str) -> None: ...
|
|
@overload
|
|
def __init__(self, buffer: SoundBuffer) -> None: ...
|
|
def __init__(self, source: Union[str, SoundBuffer]) -> None: ...
|
|
|
|
volume: float
|
|
loop: bool
|
|
playing: bool # Read-only
|
|
duration: float # Read-only
|
|
source: str # Read-only
|
|
pitch: float
|
|
|
|
@property
|
|
def buffer(self) -> Optional[SoundBuffer]:
|
|
"""The SoundBuffer, or None for file-loaded sounds (read-only)."""
|
|
...
|
|
|
|
def play(self) -> None:
|
|
"""Play the sound effect."""
|
|
...
|
|
|
|
def pause(self) -> None:
|
|
"""Pause playback."""
|
|
...
|
|
|
|
def stop(self) -> None:
|
|
"""Stop playback."""
|
|
...
|
|
|
|
def play_varied(self, *, pitch_range: float = 0.1, volume_range: float = 3.0) -> None:
|
|
"""Play with randomized pitch and volume variation."""
|
|
...
|
|
|
|
class Music:
|
|
"""Streaming music object for longer audio tracks."""
|
|
|
|
def __init__(self, filename: str) -> None: ...
|
|
|
|
volume: float
|
|
loop: bool
|
|
playing: bool # Read-only
|
|
duration: float # Read-only
|
|
position: float # Playback position in seconds
|
|
source: str # Read-only
|
|
|
|
def play(self) -> None:
|
|
"""Play the music."""
|
|
...
|
|
|
|
def pause(self) -> None:
|
|
"""Pause playback."""
|
|
...
|
|
|
|
def stop(self) -> None:
|
|
"""Stop playback."""
|
|
...
|
|
|
|
class Drawable:
|
|
"""Base class for all drawable UI elements."""
|
|
|
|
x: float
|
|
y: float
|
|
visible: bool
|
|
z_index: int
|
|
name: str
|
|
pos: Vector
|
|
opacity: float
|
|
|
|
# Mouse event callbacks (#140, #141, #230)
|
|
# on_click receives (pos: Vector, button: MouseButton, action: InputState)
|
|
on_click: Optional[Callable[['Vector', 'MouseButton', 'InputState'], None]]
|
|
# Hover callbacks receive only position per #230
|
|
on_enter: Optional[Callable[['Vector'], None]]
|
|
on_exit: Optional[Callable[['Vector'], None]]
|
|
on_move: Optional[Callable[['Vector'], None]]
|
|
|
|
# Read-only hover state (#140)
|
|
hovered: bool
|
|
|
|
def get_bounds(self) -> Tuple[float, float, float, float]:
|
|
"""Get bounding box as (x, y, width, height)."""
|
|
...
|
|
|
|
def move(self, dx: float, dy: float) -> None:
|
|
"""Move by relative offset (dx, dy)."""
|
|
...
|
|
|
|
def resize(self, width: float, height: float) -> None:
|
|
"""Resize to new dimensions (width, height)."""
|
|
...
|
|
|
|
def animate(self, property: str, end_value: Any, duration: float,
|
|
easing: Union[str, 'Easing'] = 'linear',
|
|
callback: Optional[Callable[[Any, str, Any], None]] = None) -> None:
|
|
"""Animate a property to a target value over duration seconds."""
|
|
...
|
|
|
|
class Frame(Drawable):
|
|
"""Frame(x=0, y=0, w=0, h=0, fill_color=None, outline_color=None, outline=0, on_click=None, children=None)
|
|
|
|
A rectangular frame UI element that can contain other drawable elements.
|
|
"""
|
|
|
|
@overload
|
|
def __init__(self) -> None: ...
|
|
@overload
|
|
def __init__(self, x: float = 0, y: float = 0, w: float = 0, h: float = 0,
|
|
fill_color: Optional[ColorLike] = None, outline_color: Optional[ColorLike] = None,
|
|
outline: float = 0, on_click: Optional[Callable] = None,
|
|
children: Optional[List[UIElement]] = None) -> None: ...
|
|
@overload
|
|
def __init__(self, pos: Tuple[float, float], size: Tuple[float, float],
|
|
fill_color: Optional[ColorLike] = None, outline_color: Optional[ColorLike] = None,
|
|
outline: float = 0, on_click: Optional[Callable] = None,
|
|
children: Optional[List[UIElement]] = None) -> None: ...
|
|
|
|
w: float
|
|
h: float
|
|
fill_color: ColorLike
|
|
outline_color: ColorLike
|
|
outline: float
|
|
children: 'UICollection'
|
|
clip_children: bool
|
|
|
|
class Caption(Drawable):
|
|
"""Caption(pos=None, font=None, text='', fill_color=None, ...)
|
|
|
|
A text display UI element with customizable font and styling.
|
|
Positional args: pos, font, text. Everything else is keyword-only.
|
|
"""
|
|
|
|
@overload
|
|
def __init__(self) -> None: ...
|
|
@overload
|
|
def __init__(self, pos: Optional[Tuple[float, float]] = None,
|
|
font: Optional[Font] = None, text: str = '',
|
|
fill_color: Optional[ColorLike] = None,
|
|
outline_color: Optional[ColorLike] = None, outline: float = 0,
|
|
font_size: float = 16.0, on_click: Optional[Callable] = None,
|
|
visible: bool = True, opacity: float = 1.0,
|
|
z_index: int = 0, name: str = '',
|
|
x: float = 0, y: float = 0) -> None: ...
|
|
|
|
text: str
|
|
font: Font
|
|
fill_color: ColorLike
|
|
outline_color: ColorLike
|
|
outline: float
|
|
font_size: float
|
|
w: float # Read-only, computed from text
|
|
h: float # Read-only, computed from text
|
|
|
|
class Sprite(Drawable):
|
|
"""Sprite(pos=None, texture=None, sprite_index=0, scale=1.0, on_click=None)
|
|
|
|
A sprite UI element that displays a texture or portion of a texture atlas.
|
|
Positional args: pos, texture, sprite_index. Everything else is keyword-only.
|
|
"""
|
|
|
|
@overload
|
|
def __init__(self) -> None: ...
|
|
@overload
|
|
def __init__(self, pos: Optional[Tuple[float, float]] = None,
|
|
texture: Optional[Texture] = None,
|
|
sprite_index: int = 0, scale: float = 1.0,
|
|
on_click: Optional[Callable] = None,
|
|
visible: bool = True, opacity: float = 1.0,
|
|
z_index: int = 0, name: str = '',
|
|
x: float = 0, y: float = 0) -> None: ...
|
|
|
|
texture: Texture
|
|
sprite_index: int
|
|
sprite_number: int # Deprecated alias for sprite_index
|
|
scale: float
|
|
w: float # Read-only, computed from texture
|
|
h: float # Read-only, computed from texture
|
|
|
|
class Grid(Drawable):
|
|
"""Grid(pos=(0,0), size=(0,0), grid_size=(2,2), texture=None, ...)
|
|
|
|
A grid-based tilemap UI element for rendering tile-based levels and game worlds.
|
|
Supports layers, FOV, pathfinding, and entity management.
|
|
"""
|
|
|
|
@overload
|
|
def __init__(self) -> None: ...
|
|
@overload
|
|
def __init__(self, pos: Tuple[float, float] = (0, 0),
|
|
size: Tuple[float, float] = (0, 0),
|
|
grid_size: Tuple[int, int] = (2, 2),
|
|
texture: Optional[Texture] = None,
|
|
fill_color: Optional[ColorLike] = None,
|
|
on_click: Optional[Callable] = None,
|
|
center_x: float = 0, center_y: float = 0, zoom: float = 1.0,
|
|
visible: bool = True, opacity: float = 1.0,
|
|
z_index: int = 0, name: str = '',
|
|
layers: Optional[List[Union['ColorLayer', 'TileLayer']]] = None) -> None: ...
|
|
|
|
# Dimensions
|
|
grid_size: Vector # Read-only - has .x (width) and .y (height)
|
|
grid_w: int # Read-only
|
|
grid_h: int # Read-only
|
|
|
|
# Position and size
|
|
position: Tuple[float, float]
|
|
size: Vector
|
|
w: float
|
|
h: float
|
|
|
|
# Camera/viewport
|
|
center: Union[Vector, Tuple[float, float]] # Viewport center point (pixel coordinates)
|
|
center_x: float
|
|
center_y: float
|
|
zoom: float # Scale factor for rendering
|
|
|
|
# Collections
|
|
entities: 'EntityCollection' # Entities on this grid
|
|
children: 'UICollection' # UI overlays (speech bubbles, effects)
|
|
layers: Tuple[Union['ColorLayer', 'TileLayer'], ...] # Grid layers sorted by z_index
|
|
|
|
# Appearance
|
|
texture: Texture # Read-only
|
|
fill_color: ColorLike # Background fill color
|
|
|
|
# Perspective/FOV
|
|
perspective: Optional['Entity'] # Entity for FOV rendering (None = omniscient)
|
|
perspective_enabled: bool # Whether to use perspective-based FOV
|
|
fov: 'FOV' # FOV algorithm enum
|
|
fov_radius: int # Default FOV radius
|
|
|
|
# Cell-level mouse events (#230)
|
|
on_cell_click: Optional[Callable[['Vector', 'MouseButton', 'InputState'], None]]
|
|
on_cell_enter: Optional[Callable[['Vector'], None]]
|
|
on_cell_exit: Optional[Callable[['Vector'], None]]
|
|
hovered_cell: Optional[Tuple[int, int]] # Read-only
|
|
|
|
def at(self, x: int, y: int) -> 'GridPoint':
|
|
"""Get grid point at tile coordinates."""
|
|
...
|
|
|
|
def center_camera(self, pos: Optional[Tuple[float, float]] = None) -> None:
|
|
"""Center the camera on a tile coordinate."""
|
|
...
|
|
|
|
# FOV methods
|
|
def compute_fov(self, pos: Tuple[int, int], radius: int = 0,
|
|
light_walls: bool = True, algorithm: Optional['FOV'] = None) -> None:
|
|
"""Compute field of view from a position."""
|
|
...
|
|
|
|
def is_in_fov(self, pos: Tuple[int, int]) -> bool:
|
|
"""Check if a cell is in the field of view."""
|
|
...
|
|
|
|
# Pathfinding methods
|
|
def find_path(self, start: Union[Tuple[int, int], 'Vector', 'Entity'],
|
|
end: Union[Tuple[int, int], 'Vector', 'Entity'],
|
|
diagonal_cost: float = 1.41) -> Optional['AStarPath']:
|
|
"""Compute A* path between two points."""
|
|
...
|
|
|
|
def get_dijkstra_map(self, root: Union[Tuple[int, int], 'Vector', 'Entity'],
|
|
diagonal_cost: float = 1.41) -> 'DijkstraMap':
|
|
"""Get or create a Dijkstra distance map for a root position."""
|
|
...
|
|
|
|
def clear_dijkstra_maps(self) -> None:
|
|
"""Clear all cached Dijkstra maps."""
|
|
...
|
|
|
|
# Layer methods
|
|
def add_layer(self, layer: Union['ColorLayer', 'TileLayer']) -> None:
|
|
"""Add a pre-constructed layer to the grid."""
|
|
...
|
|
|
|
def remove_layer(self, layer: Union['ColorLayer', 'TileLayer']) -> None:
|
|
"""Remove a layer from the grid."""
|
|
...
|
|
|
|
def layer(self, name: str) -> Optional[Union['ColorLayer', 'TileLayer']]:
|
|
"""Get layer by name."""
|
|
...
|
|
|
|
# Spatial queries
|
|
def entities_in_radius(self, pos: Union[Tuple[float, float], 'Vector'],
|
|
radius: float) -> List['Entity']:
|
|
"""Query entities within radius using spatial hash."""
|
|
...
|
|
|
|
# HeightMap application
|
|
def apply_threshold(self, source: 'HeightMap', range: Tuple[float, float],
|
|
walkable: Optional[bool] = None,
|
|
transparent: Optional[bool] = None) -> 'Grid':
|
|
"""Apply walkable/transparent properties where heightmap values are in range."""
|
|
...
|
|
|
|
def apply_ranges(self, source: 'HeightMap',
|
|
ranges: List[Tuple[Tuple[float, float], Dict[str, bool]]]) -> 'Grid':
|
|
"""Apply multiple thresholds in a single pass."""
|
|
...
|
|
|
|
class Line(Drawable):
|
|
"""Line(start=None, end=None, thickness=1.0, color=None, on_click=None, **kwargs)
|
|
|
|
A line UI element for drawing straight lines between two points.
|
|
"""
|
|
|
|
@overload
|
|
def __init__(self) -> None: ...
|
|
@overload
|
|
def __init__(self, start: Optional[Tuple[float, float]] = None,
|
|
end: Optional[Tuple[float, float]] = None,
|
|
thickness: float = 1.0, color: Optional[ColorLike] = None,
|
|
on_click: Optional[Callable] = None) -> None: ...
|
|
|
|
start: Vector
|
|
end: Vector
|
|
thickness: float
|
|
color: ColorLike
|
|
|
|
class Circle(Drawable):
|
|
"""Circle(radius=0, center=None, fill_color=None, outline_color=None, outline=0, on_click=None, **kwargs)
|
|
|
|
A circle UI element for drawing filled or outlined circles.
|
|
"""
|
|
|
|
@overload
|
|
def __init__(self) -> None: ...
|
|
@overload
|
|
def __init__(self, radius: float = 0, center: Optional[Tuple[float, float]] = None,
|
|
fill_color: Optional[ColorLike] = None, outline_color: Optional[ColorLike] = None,
|
|
outline: float = 0, on_click: Optional[Callable] = None) -> None: ...
|
|
|
|
radius: float
|
|
center: Vector
|
|
fill_color: ColorLike
|
|
outline_color: ColorLike
|
|
outline: float
|
|
|
|
class Arc(Drawable):
|
|
"""Arc(center=None, radius=0, start_angle=0, end_angle=90, color=None, thickness=1, on_click=None, **kwargs)
|
|
|
|
An arc UI element for drawing curved line segments.
|
|
"""
|
|
|
|
@overload
|
|
def __init__(self) -> None: ...
|
|
@overload
|
|
def __init__(self, center: Optional[Tuple[float, float]] = None, radius: float = 0,
|
|
start_angle: float = 0, end_angle: float = 90,
|
|
color: Optional[ColorLike] = None, thickness: float = 1.0,
|
|
on_click: Optional[Callable] = None) -> None: ...
|
|
|
|
center: Vector
|
|
radius: float
|
|
start_angle: float
|
|
end_angle: float
|
|
color: ColorLike
|
|
thickness: float
|
|
|
|
class GridPoint:
|
|
"""Grid point representing a single tile's properties.
|
|
|
|
Accessed via Grid.at(x, y). Controls walkability and transparency
|
|
for pathfinding and FOV calculations.
|
|
"""
|
|
|
|
walkable: bool # Whether entities can walk through this cell
|
|
transparent: bool # Whether light/sight passes through this cell
|
|
tilesprite: int # Tile sprite index (legacy property, not in dir())
|
|
entities: List['Entity'] # Read-only list of entities at this cell
|
|
grid_pos: Tuple[int, int] # Read-only (x, y) position in grid
|
|
|
|
class GridPointState:
|
|
"""Per-entity visibility state for a grid cell.
|
|
|
|
Tracks what an entity has seen/discovered. Accessed via entity perspective system.
|
|
"""
|
|
|
|
visible: bool # Currently visible in FOV
|
|
discovered: bool # Has been seen at least once
|
|
point: Optional['GridPoint'] # The GridPoint at this position (None if not discovered)
|
|
|
|
class ColorLayer:
|
|
"""A color overlay layer for Grid.
|
|
|
|
Provides per-cell color values for tinting, fog of war, etc.
|
|
Construct independently, then add to a Grid via grid.add_layer().
|
|
"""
|
|
|
|
def __init__(self, z_index: int = -1, name: Optional[str] = None,
|
|
grid_size: Optional[Tuple[int, int]] = None) -> None: ...
|
|
|
|
z_index: int
|
|
name: str # Read-only
|
|
visible: bool
|
|
grid_size: Vector # Read-only
|
|
grid: Optional['Grid']
|
|
|
|
def fill(self, color: ColorLike) -> None:
|
|
"""Fill entire layer with a single color."""
|
|
...
|
|
|
|
def set(self, pos: Tuple[int, int], color: ColorLike) -> None:
|
|
"""Set color at a specific cell."""
|
|
...
|
|
|
|
def get(self, pos: Tuple[int, int]) -> Color:
|
|
"""Get color at a specific cell."""
|
|
...
|
|
|
|
class TileLayer:
|
|
"""A tile sprite layer for Grid.
|
|
|
|
Provides per-cell tile indices for multi-layer tile rendering.
|
|
Construct independently, then add to a Grid via grid.add_layer().
|
|
"""
|
|
|
|
def __init__(self, z_index: int = -1, name: Optional[str] = None,
|
|
texture: Optional[Texture] = None,
|
|
grid_size: Optional[Tuple[int, int]] = None) -> None: ...
|
|
|
|
z_index: int
|
|
name: str # Read-only
|
|
visible: bool
|
|
texture: Optional[Texture]
|
|
grid_size: Vector # Read-only
|
|
grid: Optional['Grid']
|
|
|
|
def fill(self, tile_index: int) -> None:
|
|
"""Fill entire layer with a single tile index."""
|
|
...
|
|
|
|
def set(self, pos: Tuple[int, int], tile_index: int) -> None:
|
|
"""Set tile index at a specific cell. Use -1 for transparent."""
|
|
...
|
|
|
|
def get(self, pos: Tuple[int, int]) -> int:
|
|
"""Get tile index at a specific cell."""
|
|
...
|
|
|
|
class FOV:
|
|
"""Field of view algorithm enum.
|
|
|
|
Available algorithms:
|
|
- FOV.BASIC: Simple raycasting
|
|
- FOV.DIAMOND: Diamond-shaped FOV
|
|
- FOV.SHADOW: Shadow casting (recommended)
|
|
- FOV.PERMISSIVE_0 through FOV.PERMISSIVE_8: Permissive algorithms
|
|
- FOV.RESTRICTIVE: Restrictive precise angle shadowcasting
|
|
"""
|
|
|
|
BASIC: 'FOV'
|
|
DIAMOND: 'FOV'
|
|
SHADOW: 'FOV'
|
|
PERMISSIVE_0: 'FOV'
|
|
PERMISSIVE_1: 'FOV'
|
|
PERMISSIVE_2: 'FOV'
|
|
PERMISSIVE_3: 'FOV'
|
|
PERMISSIVE_4: 'FOV'
|
|
PERMISSIVE_5: 'FOV'
|
|
PERMISSIVE_6: 'FOV'
|
|
PERMISSIVE_7: 'FOV'
|
|
PERMISSIVE_8: 'FOV'
|
|
RESTRICTIVE: 'FOV'
|
|
|
|
class AStarPath:
|
|
"""A* pathfinding result.
|
|
|
|
Returned by Grid.find_path(). Can be iterated or walked step-by-step.
|
|
"""
|
|
|
|
def __iter__(self) -> Any: ...
|
|
def __len__(self) -> int: ...
|
|
|
|
def walk(self) -> Optional[Tuple[int, int]]:
|
|
"""Get next step in path, or None if complete."""
|
|
...
|
|
|
|
def reverse(self) -> 'AStarPath':
|
|
"""Return a reversed copy of the path."""
|
|
...
|
|
|
|
class DijkstraMap:
|
|
"""Dijkstra distance map for pathfinding.
|
|
|
|
Created by Grid.get_dijkstra_map(). Provides distance queries
|
|
and path finding from the root position.
|
|
"""
|
|
|
|
root: Tuple[int, int] # Read-only root position
|
|
|
|
def get_distance(self, pos: Tuple[int, int]) -> float:
|
|
"""Get distance from root to position (-1 if unreachable)."""
|
|
...
|
|
|
|
def get_path(self, pos: Tuple[int, int]) -> Optional[List[Tuple[int, int]]]:
|
|
"""Get path from position to root."""
|
|
...
|
|
|
|
class HeightMap:
|
|
"""2D height field for terrain generation.
|
|
|
|
Used for procedural generation and applying terrain to grids.
|
|
"""
|
|
|
|
width: int # Read-only
|
|
height: int # Read-only
|
|
|
|
def __init__(self, width: int, height: int) -> None: ...
|
|
|
|
def get(self, x: int, y: int) -> float:
|
|
"""Get height value at position."""
|
|
...
|
|
|
|
def set(self, x: int, y: int, value: float) -> None:
|
|
"""Set height value at position."""
|
|
...
|
|
|
|
def fill(self, value: float) -> 'HeightMap':
|
|
"""Fill entire heightmap with a value."""
|
|
...
|
|
|
|
def clear(self) -> 'HeightMap':
|
|
"""Clear heightmap to 0."""
|
|
...
|
|
|
|
def normalize(self, min_val: float = 0.0, max_val: float = 1.0) -> 'HeightMap':
|
|
"""Normalize values to range."""
|
|
...
|
|
|
|
def add_hill(self, center: Tuple[float, float], radius: float, height: float) -> 'HeightMap':
|
|
"""Add a hill at position."""
|
|
...
|
|
|
|
def add_fbm(self, noise: 'NoiseSource', mulx: float = 1.0, muly: float = 1.0,
|
|
addx: float = 0.0, addy: float = 0.0, octaves: int = 4,
|
|
delta: float = 1.0, scale: float = 1.0) -> 'HeightMap':
|
|
"""Add fractal Brownian motion noise."""
|
|
...
|
|
|
|
def scale(self, factor: float) -> 'HeightMap':
|
|
"""Scale all values by factor."""
|
|
...
|
|
|
|
def clamp(self, min_val: float, max_val: float) -> 'HeightMap':
|
|
"""Clamp values to range."""
|
|
...
|
|
|
|
class NoiseSource:
|
|
"""Coherent noise generator for procedural generation.
|
|
|
|
Supports various noise types: PERLIN, SIMPLEX, WAVELET, etc.
|
|
"""
|
|
|
|
def __init__(self, type: str = 'SIMPLEX', seed: Optional[int] = None) -> None: ...
|
|
|
|
def get(self, x: float, y: float, z: float = 0.0) -> float:
|
|
"""Get noise value at position."""
|
|
...
|
|
|
|
class BSP:
|
|
"""Binary space partitioning for dungeon generation.
|
|
|
|
Recursively subdivides a rectangle into rooms.
|
|
"""
|
|
|
|
x: int
|
|
y: int
|
|
width: int
|
|
height: int
|
|
level: int
|
|
horizontal: bool
|
|
position: int
|
|
|
|
def __init__(self, x: int, y: int, width: int, height: int) -> None: ...
|
|
|
|
def split_recursive(self, randomizer: Optional[Any] = None, nb: int = 8,
|
|
minHSize: int = 4, minVSize: int = 4,
|
|
maxHRatio: float = 1.5, maxVRatio: float = 1.5) -> None:
|
|
"""Recursively split the BSP tree."""
|
|
...
|
|
|
|
def traverse(self, callback: Callable[['BSP'], bool],
|
|
order: str = 'PRE_ORDER') -> None:
|
|
"""Traverse BSP tree calling callback for each node."""
|
|
...
|
|
|
|
def is_leaf(self) -> bool:
|
|
"""Check if this is a leaf node (no children)."""
|
|
...
|
|
|
|
def contains(self, x: int, y: int) -> bool:
|
|
"""Check if point is within this node's bounds."""
|
|
...
|
|
|
|
def get_left(self) -> Optional['BSP']:
|
|
"""Get left child node."""
|
|
...
|
|
|
|
def get_right(self) -> Optional['BSP']:
|
|
"""Get right child node."""
|
|
...
|
|
|
|
class Entity(Drawable):
|
|
"""Entity(grid_x=0, grid_y=0, texture=None, sprite_index=0, name='')
|
|
|
|
Game entity that lives within a Grid.
|
|
"""
|
|
|
|
@overload
|
|
def __init__(self) -> None: ...
|
|
@overload
|
|
def __init__(self, grid_x: float = 0, grid_y: float = 0, texture: Optional[Texture] = None,
|
|
sprite_index: int = 0, name: str = '') -> None: ...
|
|
|
|
grid_x: float
|
|
grid_y: float
|
|
texture: Texture
|
|
sprite_index: int
|
|
sprite_number: int # Deprecated alias for sprite_index
|
|
grid: Optional[Grid]
|
|
|
|
def at(self, grid_x: float, grid_y: float) -> None:
|
|
"""Move entity to grid position."""
|
|
...
|
|
|
|
def die(self) -> None:
|
|
"""Remove entity from its grid."""
|
|
...
|
|
|
|
def index(self) -> int:
|
|
"""Get index in parent grid's entity collection."""
|
|
...
|
|
|
|
class UICollection:
|
|
"""Collection of UI drawable elements (Frame, Caption, Sprite, Grid, Line, Circle, Arc)."""
|
|
|
|
def __len__(self) -> int: ...
|
|
def __getitem__(self, index: int) -> UIElement: ...
|
|
def __setitem__(self, index: int, value: UIElement) -> None: ...
|
|
def __delitem__(self, index: int) -> None: ...
|
|
def __contains__(self, item: UIElement) -> bool: ...
|
|
def __iter__(self) -> Any: ...
|
|
def __add__(self, other: 'UICollection') -> 'UICollection': ...
|
|
def __iadd__(self, other: 'UICollection') -> 'UICollection': ...
|
|
|
|
def append(self, item: UIElement) -> None: ...
|
|
def extend(self, items: List[UIElement]) -> None: ...
|
|
def pop(self, index: int = -1) -> UIElement: ...
|
|
def remove(self, item: UIElement) -> None: ...
|
|
def index(self, item: UIElement) -> int: ...
|
|
def count(self, item: UIElement) -> int: ...
|
|
|
|
class EntityCollection:
|
|
"""Collection of Entity objects."""
|
|
|
|
def __len__(self) -> int: ...
|
|
def __getitem__(self, index: int) -> Entity: ...
|
|
def __setitem__(self, index: int, value: Entity) -> None: ...
|
|
def __delitem__(self, index: int) -> None: ...
|
|
def __contains__(self, item: Entity) -> bool: ...
|
|
def __iter__(self) -> Any: ...
|
|
def __add__(self, other: 'EntityCollection') -> 'EntityCollection': ...
|
|
def __iadd__(self, other: 'EntityCollection') -> 'EntityCollection': ...
|
|
|
|
def append(self, item: Entity) -> None: ...
|
|
def extend(self, items: List[Entity]) -> None: ...
|
|
def pop(self, index: int = -1) -> Entity: ...
|
|
def remove(self, item: Entity) -> None: ...
|
|
def index(self, item: Entity) -> int: ...
|
|
def count(self, item: Entity) -> int: ...
|
|
|
|
class Scene:
|
|
"""Base class for object-oriented scenes."""
|
|
|
|
name: str
|
|
children: UICollection # UI elements collection (read-only alias for get_ui())
|
|
# Keyboard handler receives (key: Key, action: InputState) per #184
|
|
on_key: Optional[Callable[['Key', 'InputState'], None]]
|
|
|
|
def __init__(self, name: str) -> None: ...
|
|
|
|
def activate(self) -> None:
|
|
"""Called when scene becomes active."""
|
|
...
|
|
|
|
def deactivate(self) -> None:
|
|
"""Called when scene becomes inactive."""
|
|
...
|
|
|
|
def get_ui(self) -> UICollection:
|
|
"""Get UI elements collection."""
|
|
...
|
|
|
|
def on_keypress(self, key: str, pressed: bool) -> None:
|
|
"""Handle keyboard events (override in subclass)."""
|
|
...
|
|
|
|
def on_click(self, x: float, y: float, button: int) -> None:
|
|
"""Handle mouse clicks (override in subclass)."""
|
|
...
|
|
|
|
def on_enter(self) -> None:
|
|
"""Called when entering the scene (override in subclass)."""
|
|
...
|
|
|
|
def on_exit(self) -> None:
|
|
"""Called when leaving the scene (override in subclass)."""
|
|
...
|
|
|
|
def on_resize(self, width: int, height: int) -> None:
|
|
"""Handle window resize events (override in subclass)."""
|
|
...
|
|
|
|
def update(self, dt: float) -> None:
|
|
"""Update scene logic (override in subclass)."""
|
|
...
|
|
|
|
class Timer:
|
|
"""Timer object for scheduled callbacks.
|
|
|
|
Callback receives (timer_object, runtime_ms).
|
|
"""
|
|
|
|
name: str
|
|
interval: int
|
|
callback: Callable[['Timer', float], None]
|
|
active: bool
|
|
paused: bool
|
|
stopped: bool
|
|
remaining: int
|
|
once: bool
|
|
|
|
def __init__(self, name: str, callback: Callable[['Timer', float], None],
|
|
interval: int, once: bool = False, start: bool = True) -> None: ...
|
|
|
|
def stop(self) -> None:
|
|
"""Stop the timer."""
|
|
...
|
|
|
|
def pause(self) -> None:
|
|
"""Pause the timer."""
|
|
...
|
|
|
|
def resume(self) -> None:
|
|
"""Resume the timer."""
|
|
...
|
|
|
|
def restart(self) -> None:
|
|
"""Restart the timer."""
|
|
...
|
|
|
|
def cancel(self) -> None:
|
|
"""Cancel and remove the timer."""
|
|
...
|
|
|
|
class Window:
|
|
"""Window singleton for managing the game window."""
|
|
|
|
resolution: Tuple[int, int]
|
|
fullscreen: bool
|
|
vsync: bool
|
|
title: str
|
|
fps_limit: int
|
|
game_resolution: Tuple[int, int]
|
|
scaling_mode: str
|
|
|
|
@staticmethod
|
|
def get() -> 'Window':
|
|
"""Get the window singleton instance."""
|
|
...
|
|
|
|
class Animation:
|
|
"""Animation object for animating UI properties.
|
|
|
|
Note: The preferred way to create animations is via the .animate() method
|
|
on drawable objects:
|
|
frame.animate("x", 500.0, 2.0, mcrfpy.Easing.EASE_IN_OUT)
|
|
|
|
Animation callbacks (#229) receive (target, property, final_value):
|
|
def on_complete(target, prop, value):
|
|
print(f"{type(target).__name__}.{prop} = {value}")
|
|
"""
|
|
|
|
property: str
|
|
duration: float
|
|
easing: 'Easing'
|
|
callback: Optional[Callable[[Any, str, Any], None]]
|
|
|
|
def __init__(self, property: str, end_value: Any, duration: float,
|
|
easing: Union[str, 'Easing'] = 'linear',
|
|
callback: Optional[Callable[[Any, str, Any], None]] = None) -> None: ...
|
|
|
|
def start(self, target: Any) -> None:
|
|
"""Start the animation on a target object."""
|
|
...
|
|
|
|
def get_current_value(self) -> Any:
|
|
"""Get the current interpolated value."""
|
|
...
|
|
|
|
# Module-level properties
|
|
|
|
current_scene: Scene # Get or set the active scene
|
|
|
|
# Module functions
|
|
|
|
def createSoundBuffer(filename: str) -> int:
|
|
"""Load a sound effect from a file and return its buffer ID."""
|
|
...
|
|
|
|
def loadMusic(filename: str) -> None:
|
|
"""Load and immediately play background music from a file."""
|
|
...
|
|
|
|
def setMusicVolume(volume: int) -> None:
|
|
"""Set the global music volume (0-100)."""
|
|
...
|
|
|
|
def setSoundVolume(volume: int) -> None:
|
|
"""Set the global sound effects volume (0-100)."""
|
|
...
|
|
|
|
def playSound(buffer_id: int) -> None:
|
|
"""Play a sound effect using a previously loaded buffer."""
|
|
...
|
|
|
|
def getMusicVolume() -> int:
|
|
"""Get the current music volume level (0-100)."""
|
|
...
|
|
|
|
def getSoundVolume() -> int:
|
|
"""Get the current sound effects volume level (0-100)."""
|
|
...
|
|
|
|
def sceneUI(scene: Optional[str] = None) -> UICollection:
|
|
"""Get all UI elements for a scene."""
|
|
...
|
|
|
|
def currentScene() -> str:
|
|
"""Get the name of the currently active scene."""
|
|
...
|
|
|
|
def setScene(scene: str, transition: Optional[str] = None, duration: float = 0.0) -> None:
|
|
"""Switch to a different scene with optional transition effect."""
|
|
...
|
|
|
|
def createScene(name: str) -> None:
|
|
"""Create a new empty scene."""
|
|
...
|
|
|
|
def keypressScene(handler: Callable[[str, bool], None]) -> None:
|
|
"""Set the keyboard event handler for the current scene.
|
|
|
|
DEPRECATED: Use scene.on_key = handler instead.
|
|
The new handler receives (key: Key, action: InputState) enums.
|
|
"""
|
|
...
|
|
|
|
def setTimer(name: str, handler: Callable[[float], None], interval: int) -> None:
|
|
"""Create or update a recurring timer.
|
|
|
|
DEPRECATED: Use Timer(name, callback, interval) object instead.
|
|
"""
|
|
...
|
|
|
|
def delTimer(name: str) -> None:
|
|
"""Stop and remove a timer.
|
|
|
|
DEPRECATED: Use timer.cancel() method instead.
|
|
"""
|
|
...
|
|
|
|
def exit() -> None:
|
|
"""Cleanly shut down the game engine and exit the application."""
|
|
...
|
|
|
|
def setScale(multiplier: float) -> None:
|
|
"""Scale the game window size (deprecated - use Window.resolution)."""
|
|
...
|
|
|
|
def find(name: str, scene: Optional[str] = None) -> Optional[UIElement]:
|
|
"""Find the first UI element with the specified name."""
|
|
...
|
|
|
|
def findAll(pattern: str, scene: Optional[str] = None) -> List[UIElement]:
|
|
"""Find all UI elements matching a name pattern (supports * wildcards)."""
|
|
...
|
|
|
|
def getMetrics() -> Dict[str, Union[int, float]]:
|
|
"""Get current performance metrics."""
|
|
...
|
|
|
|
def step(dt: float) -> None:
|
|
"""Advance the game loop by dt seconds (headless mode only)."""
|
|
...
|
|
|
|
def start_benchmark() -> None:
|
|
"""Start performance benchmarking."""
|
|
...
|
|
|
|
def end_benchmark() -> None:
|
|
"""End performance benchmarking."""
|
|
...
|
|
|
|
def log_benchmark(message: str) -> None:
|
|
"""Log a benchmark measurement."""
|
|
...
|
|
|
|
# Submodule
|
|
class automation:
|
|
"""Automation API for testing and scripting."""
|
|
|
|
@staticmethod
|
|
def screenshot(filename: str) -> bool:
|
|
"""Save a screenshot to the specified file."""
|
|
...
|
|
|
|
@staticmethod
|
|
def position() -> Tuple[int, int]:
|
|
"""Get current mouse position as (x, y) tuple."""
|
|
...
|
|
|
|
@staticmethod
|
|
def size() -> Tuple[int, int]:
|
|
"""Get screen size as (width, height) tuple."""
|
|
...
|
|
|
|
@staticmethod
|
|
def onScreen(x: int, y: int) -> bool:
|
|
"""Check if coordinates are within screen bounds."""
|
|
...
|
|
|
|
@staticmethod
|
|
def moveTo(x: int, y: int, duration: float = 0.0) -> None:
|
|
"""Move mouse to absolute position."""
|
|
...
|
|
|
|
@staticmethod
|
|
def moveRel(xOffset: int, yOffset: int, duration: float = 0.0) -> None:
|
|
"""Move mouse relative to current position."""
|
|
...
|
|
|
|
@staticmethod
|
|
def dragTo(x: int, y: int, duration: float = 0.0, button: str = 'left') -> None:
|
|
"""Drag mouse to position."""
|
|
...
|
|
|
|
@staticmethod
|
|
def dragRel(xOffset: int, yOffset: int, duration: float = 0.0, button: str = 'left') -> None:
|
|
"""Drag mouse relative to current position."""
|
|
...
|
|
|
|
@staticmethod
|
|
def click(x: Optional[int] = None, y: Optional[int] = None, clicks: int = 1,
|
|
interval: float = 0.0, button: str = 'left') -> None:
|
|
"""Click mouse at position."""
|
|
...
|
|
|
|
@staticmethod
|
|
def mouseDown(x: Optional[int] = None, y: Optional[int] = None, button: str = 'left') -> None:
|
|
"""Press mouse button down."""
|
|
...
|
|
|
|
@staticmethod
|
|
def mouseUp(x: Optional[int] = None, y: Optional[int] = None, button: str = 'left') -> None:
|
|
"""Release mouse button."""
|
|
...
|
|
|
|
@staticmethod
|
|
def keyDown(key: str) -> None:
|
|
"""Press key down."""
|
|
...
|
|
|
|
@staticmethod
|
|
def keyUp(key: str) -> None:
|
|
"""Release key."""
|
|
...
|
|
|
|
@staticmethod
|
|
def press(key: str) -> None:
|
|
"""Press and release a key."""
|
|
...
|
|
|
|
@staticmethod
|
|
def typewrite(text: str, interval: float = 0.0) -> None:
|
|
"""Type text with optional interval between characters."""
|
|
...
|