Arcade Game Development Library
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Comprehensive texture loading, caching, atlas management, procedural texture generation, and sprite sheet handling for efficient graphics resource management and optimal rendering performance.
Base texture classes for managing image data and rendering properties.
class Texture:
"""
Main texture class for managing image data, rendering properties, and GPU resources.
Textures can be loaded from files, created programmatically, or extracted from sprite sheets.
"""
def __init__(self, image: PIL.Image.Image, name: str = None, hit_box_algorithm: str = "Simple",
hit_box_detail: float = 4.5, hit_box_points: list[tuple[float, float]] = None):
"""
Create a texture from a PIL Image.
Args:
image: PIL Image object containing texture data
name: Optional name for the texture (used for caching/debugging)
hit_box_algorithm: Algorithm for calculating hit box ("Simple", "Detailed", or "None")
hit_box_detail: Detail level for "Detailed" hit box algorithm
hit_box_points: Pre-calculated hit box points
"""
# Properties
name: str
width: int
height: int
image: PIL.Image.Image
hit_box_points: list[tuple[float, float]]
# Atlas properties
atlas: arcade.TextureAtlasBase
atlas_name: str
def create_empty(name: str, size: tuple[int, int], color: tuple[int, int, int, int] = (0, 0, 0, 0)) -> arcade.Texture:
"""
Create an empty texture with specified size and color.
Args:
name: Name for the texture
size: (width, height) in pixels
color: RGBA color tuple (0-255)
Returns:
New Texture instance
"""
def create_filled(name: str, size: tuple[int, int], color: tuple[int, int, int, int]) -> arcade.Texture:
"""
Create a texture filled with a solid color.
Args:
name: Name for the texture
size: (width, height) in pixels
color: RGBA color tuple (0-255)
Returns:
New Texture instance
"""
def flip_horizontally(self) -> arcade.Texture:
"""
Create a horizontally flipped version of this texture.
Returns:
New Texture instance with flipped image
"""
def flip_vertically(self) -> arcade.Texture:
"""
Create a vertically flipped version of this texture.
Returns:
New Texture instance with flipped image
"""
def flip_diagonally(self) -> arcade.Texture:
"""
Create a diagonally flipped version of this texture.
Returns:
New Texture instance with flipped image
"""
def rotate_90(self) -> arcade.Texture:
"""
Create a texture rotated 90 degrees clockwise.
Returns:
New Texture instance with rotated image
"""
def crop(self, x: int, y: int, width: int, height: int) -> arcade.Texture:
"""
Create a cropped version of this texture.
Args:
x: Left coordinate of crop area
y: Bottom coordinate of crop area
width: Width of crop area
height: Height of crop area
Returns:
New Texture instance with cropped image
"""
def resize(self, new_size: tuple[int, int], resample: int = PIL.Image.LANCZOS) -> arcade.Texture:
"""
Create a resized version of this texture.
Args:
new_size: (width, height) for resized texture
resample: PIL resampling algorithm
Returns:
New Texture instance with resized image
"""
class TextureCacheManager:
"""
Manages texture caching and memory usage to prevent duplicate texture loading
and optimize GPU memory usage.
"""
def __init__(self):
"""Create a texture cache manager."""
def get_texture_by_name(self, name: str) -> arcade.Texture:
"""
Get a cached texture by name.
Args:
name: Name of the texture to retrieve
Returns:
Cached Texture instance or None if not found
"""
def put_texture(self, name: str, texture: arcade.Texture) -> None:
"""
Store a texture in the cache.
Args:
name: Cache key for the texture
texture: Texture instance to cache
"""
def clear_cache(self) -> None:
"""Clear all cached textures from memory."""
def get_cache_size(self) -> int:
"""
Get the number of textures currently cached.
Returns:
Number of cached textures
"""Functions for loading textures from files and resources with various options and transformations.
def load_texture(file_path: str, x: int = 0, y: int = 0, width: int = 0, height: int = 0,
flipped_horizontally: bool = False, flipped_vertically: bool = False,
flipped_diagonally: bool = False, can_cache: bool = True,
hit_box_algorithm: str = "Simple", hit_box_detail: float = 4.5) -> arcade.Texture:
"""
Load a texture from a file with optional transformations and cropping.
Args:
file_path: Path to image file or resource handle (e.g., ":resources:images/...")
x: X offset for cropping (pixels from left)
y: Y offset for cropping (pixels from bottom)
width: Width of crop area (0 = full width)
height: Height of crop area (0 = full height)
flipped_horizontally: Mirror texture horizontally
flipped_vertically: Mirror texture vertically
flipped_diagonally: Mirror texture diagonally
can_cache: Whether this texture can be cached
hit_box_algorithm: Hit box calculation method
hit_box_detail: Detail level for detailed hit boxes
Returns:
Loaded Texture instance
"""
def load_image(file_path: str) -> PIL.Image.Image:
"""
Load an image file as a PIL Image object.
Args:
file_path: Path to image file
Returns:
PIL Image object
"""
def load_spritesheet(file_path: str, sprite_width: int, sprite_height: int,
columns: int, count: int, margin: int = 0, spacing: int = 0) -> list[arcade.Texture]:
"""
Load a sprite sheet and return individual sprites as textures.
Args:
file_path: Path to sprite sheet image
sprite_width: Width of each sprite in pixels
sprite_height: Height of each sprite in pixels
columns: Number of columns in the sprite sheet
count: Total number of sprites to load
margin: Margin around the entire sprite sheet
spacing: Spacing between individual sprites
Returns:
List of Texture instances, one for each sprite
"""
def get_default_texture() -> arcade.Texture:
"""
Get the default fallback texture (used when texture loading fails).
Returns:
Default Texture instance (usually a colored square)
"""
def get_default_image() -> PIL.Image.Image:
"""
Get the default fallback image.
Returns:
Default PIL Image object
"""Functions for creating textures programmatically with various shapes, patterns, and effects.
def make_circle_texture(diameter: int, color: arcade.types.Color, name: str = "circle") -> arcade.Texture:
"""
Generate a circular texture with solid color.
Args:
diameter: Diameter of the circle in pixels
color: Circle color as RGB or RGBA tuple (0-255)
name: Name for the generated texture
Returns:
Generated Texture instance
"""
def make_soft_circle_texture(diameter: int, color: arcade.types.Color,
center_alpha: int = 255, outer_alpha: int = 0,
name: str = "soft_circle") -> arcade.Texture:
"""
Generate a circular texture with soft, gradient edges.
Args:
diameter: Diameter of the circle in pixels
color: Base color as RGB tuple (0-255)
center_alpha: Alpha value at circle center (0-255)
outer_alpha: Alpha value at circle edge (0-255)
name: Name for the generated texture
Returns:
Generated Texture instance with gradient alpha
"""
def make_soft_square_texture(size: int, color: arcade.types.Color,
center_alpha: int = 255, outer_alpha: int = 0,
name: str = "soft_square") -> arcade.Texture:
"""
Generate a square texture with soft, gradient edges.
Args:
size: Size of the square in pixels
color: Base color as RGB tuple (0-255)
center_alpha: Alpha value at square center (0-255)
outer_alpha: Alpha value at square edges (0-255)
name: Name for the generated texture
Returns:
Generated Texture instance with gradient alpha
"""Classes and functions for working with sprite sheets and texture atlases.
class SpriteSheet:
"""
Manages sprite sheets for extracting individual sprites and optimizing texture usage.
"""
def __init__(self, file_path: str, sprite_width: int, sprite_height: int,
columns: int = None, rows: int = None, margin: int = 0, spacing: int = 0):
"""
Create a sprite sheet manager.
Args:
file_path: Path to sprite sheet image file
sprite_width: Width of each individual sprite
sprite_height: Height of each individual sprite
columns: Number of columns (auto-calculated if None)
rows: Number of rows (auto-calculated if None)
margin: Margin around the entire sheet
spacing: Spacing between individual sprites
"""
# Properties
file_path: str
sprite_width: int
sprite_height: int
columns: int
rows: int
margin: int
spacing: int
def get_texture(self, column: int, row: int) -> arcade.Texture:
"""
Extract a single sprite texture from the sheet.
Args:
column: Column index (0-based)
row: Row index (0-based)
Returns:
Texture for the sprite at the specified position
"""
def get_textures(self, start_column: int = 0, start_row: int = 0,
end_column: int = None, end_row: int = None) -> list[arcade.Texture]:
"""
Extract multiple sprite textures from a range.
Args:
start_column: Starting column (inclusive)
start_row: Starting row (inclusive)
end_column: Ending column (inclusive, None = last column)
end_row: Ending row (inclusive, None = last row)
Returns:
List of Texture instances for the specified range
"""
def get_texture_list(self) -> list[arcade.Texture]:
"""
Get all sprites from the sheet as a list.
Returns:
List of all Texture instances in the sheet
"""Advanced texture management for optimizing GPU memory and rendering performance.
class DefaultTextureAtlas:
"""
Default texture atlas implementation for batching textures into a single GPU texture
to improve rendering performance and reduce GPU memory usage.
"""
def __init__(self, size: tuple[int, int] = (2048, 2048), auto_resize: bool = True,
ctx: arcade.ArcadeContext = None):
"""
Create a texture atlas.
Args:
size: (width, height) of the atlas texture in pixels
auto_resize: Whether to automatically resize when full
ctx: OpenGL context (uses current context if None)
"""
# Properties
size: tuple[int, int]
auto_resize: bool
ctx: arcade.ArcadeContext
def add(self, texture: arcade.Texture) -> bool:
"""
Add a texture to the atlas.
Args:
texture: Texture to add
Returns:
True if successfully added, False if atlas is full
"""
def remove(self, texture: arcade.Texture) -> bool:
"""
Remove a texture from the atlas.
Args:
texture: Texture to remove
Returns:
True if successfully removed, False if not found
"""
def clear(self) -> None:
"""Remove all textures from the atlas."""
def resize(self, new_size: tuple[int, int]) -> None:
"""
Resize the atlas texture.
Args:
new_size: New (width, height) for the atlas
"""
def get_texture_count(self) -> int:
"""
Get the number of textures currently in the atlas.
Returns:
Number of textures in the atlas
"""
def get_usage_percent(self) -> float:
"""
Get the percentage of atlas space currently used.
Returns:
Usage percentage (0.0 to 100.0)
"""
class TextureAtlasBase:
"""
Base class for texture atlas implementations.
"""
def __init__(self):
"""Create base texture atlas."""
def add(self, texture: arcade.Texture) -> bool:
"""Add a texture to the atlas."""
def remove(self, texture: arcade.Texture) -> bool:
"""Remove a texture from the atlas."""
def clear(self) -> None:
"""Clear all textures from the atlas."""
class AtlasRegion:
"""
Represents a region within a texture atlas containing a specific texture.
"""
def __init__(self, atlas: arcade.TextureAtlasBase, x: int, y: int, width: int, height: int):
"""
Create an atlas region.
Args:
atlas: The texture atlas containing this region
x: X coordinate within the atlas
y: Y coordinate within the atlas
width: Width of the region
height: Height of the region
"""
atlas: arcade.TextureAtlasBase
x: int
y: int
width: int
height: intimport arcade
class TextureExample(arcade.Window):
def __init__(self):
super().__init__(800, 600, "Texture Example")
self.texture_list = []
self.sprite_list = arcade.SpriteList()
def setup(self):
# Load individual textures
player_texture = arcade.load_texture(":resources:images/animated_characters/female_adventurer/femaleAdventurer_idle.png")
# Load with transformations
flipped_texture = arcade.load_texture(
":resources:images/animated_characters/female_adventurer/femaleAdventurer_idle.png",
flipped_horizontally=True
)
# Load cropped portion
cropped_texture = arcade.load_texture(
":resources:images/tiles/grassMid.png",
x=0, y=0, width=32, height=32
)
# Create sprites using loaded textures
player = arcade.Sprite(texture=player_texture, scale=0.5)
player.center_x = 200
player.center_y = 300
self.sprite_list.append(player)
flipped_player = arcade.Sprite(texture=flipped_texture, scale=0.5)
flipped_player.center_x = 400
flipped_player.center_y = 300
self.sprite_list.append(flipped_player)
# Generate procedural textures
circle_texture = arcade.make_circle_texture(50, arcade.color.RED)
circle_sprite = arcade.Sprite(texture=circle_texture)
circle_sprite.center_x = 600
circle_sprite.center_y = 300
self.sprite_list.append(circle_sprite)
# Soft circle with gradient
soft_texture = arcade.make_soft_circle_texture(80, arcade.color.BLUE, 255, 50)
soft_sprite = arcade.Sprite(texture=soft_texture)
soft_sprite.center_x = 200
soft_sprite.center_y = 150
self.sprite_list.append(soft_sprite)
def on_draw(self):
self.clear()
self.sprite_list.draw()
def main():
game = TextureExample()
game.setup()
arcade.run()
if __name__ == "__main__":
main()import arcade
class AnimationExample(arcade.Window):
def __init__(self):
super().__init__(800, 600, "Sprite Sheet Animation")
self.player_list = arcade.SpriteList()
self.walk_textures = []
def setup(self):
# Load walking animation frames from sprite sheet
self.walk_textures = arcade.load_spritesheet(
":resources:images/animated_characters/female_adventurer/femaleAdventurer_walk.png",
sprite_width=128,
sprite_height=128,
columns=8,
count=8
)
# Alternative: Load individual frames
# self.walk_textures = []
# for i in range(8):
# texture = arcade.load_texture(f":resources:images/animated_characters/female_adventurer/femaleAdventurer_walk{i}.png")
# self.walk_textures.append(texture)
# Create animated player
self.player = arcade.Sprite()
self.player.center_x = 400
self.player.center_y = 300
self.player.scale = 0.5
# Set initial texture
self.player.texture = self.walk_textures[0]
self.player_list.append(self.player)
# Animation state
self.current_frame = 0
self.frame_timer = 0
self.frame_duration = 0.1 # seconds per frame
def on_draw(self):
self.clear()
self.player_list.draw()
# Draw frame counter
arcade.draw_text(f"Frame: {self.current_frame}", 10, 550, arcade.color.WHITE, 16)
def on_update(self, delta_time):
# Update animation
self.frame_timer += delta_time
if self.frame_timer >= self.frame_duration:
self.frame_timer = 0
self.current_frame = (self.current_frame + 1) % len(self.walk_textures)
self.player.texture = self.walk_textures[self.current_frame]
def main():
game = AnimationExample()
game.setup()
arcade.run()
if __name__ == "__main__":
main()import arcade
class AtlasExample(arcade.Window):
def __init__(self):
super().__init__(800, 600, "Texture Atlas Example")
self.sprite_list = arcade.SpriteList(use_spatial_hash=True)
self.atlas = None
def setup(self):
# Create texture atlas for optimal rendering
self.atlas = arcade.DefaultTextureAtlas(size=(1024, 1024))
# Load various textures
textures = [
arcade.load_texture(":resources:images/animated_characters/female_adventurer/femaleAdventurer_idle.png"),
arcade.load_texture(":resources:images/animated_characters/male_adventurer/maleAdventurer_idle.png"),
arcade.load_texture(":resources:images/enemies/bee.png"),
arcade.load_texture(":resources:images/items/coinGold.png"),
]
# Add textures to atlas
for texture in textures:
success = self.atlas.add(texture)
print(f"Added texture '{texture.name}' to atlas: {success}")
# Create sprites using atlas textures
for i, texture in enumerate(textures):
for j in range(10):
sprite = arcade.Sprite(texture=texture, scale=0.3)
sprite.center_x = 100 + (i * 150) + (j * 15)
sprite.center_y = 300
self.sprite_list.append(sprite)
# Print atlas statistics
print(f"Atlas usage: {self.atlas.get_usage_percent():.1f}%")
print(f"Textures in atlas: {self.atlas.get_texture_count()}")
def on_draw(self):
self.clear()
self.sprite_list.draw()
# Draw atlas info
if self.atlas:
usage = self.atlas.get_usage_percent()
texture_count = self.atlas.get_texture_count()
arcade.draw_text(f"Atlas Usage: {usage:.1f}%", 10, 550, arcade.color.WHITE, 16)
arcade.draw_text(f"Textures: {texture_count}", 10, 525, arcade.color.WHITE, 16)
def main():
game = AtlasExample()
game.setup()
arcade.run()
if __name__ == "__main__":
main()Install with Tessl CLI
npx tessl i tessl/pypi-arcade