Skip to main content

Tiny scene-based game loop core for small arcade games.

Project description

mini-arcade-core 🎮

Tiny Python game core for building simple scene-based arcade games
(Pong, Breakout, Space Invaders, etc.).

Minimal, opinionated abstractions: Game, Scene, and Entity – nothing else.


Features

  • 🎯 Tiny API surface

    • GameConfig – basic window & FPS configuration
    • Game – abstract game core to plug your own backend (e.g. pygame)
    • Scene – base class for screens/states (menus, gameplay, pause)
    • Entity / SpriteEntity – simple game object primitives
    • run_game() – convenience helper once a concrete Game backend is wired
  • 🧩 Backend-agnostic

    • The core doesn’t depend on any specific rendering/input library.
    • You can build backends using pygame, pyglet, or something custom.
  • 🕹️ Perfect for small arcade projects

    • Pong, Breakout, Snake, Asteroids-likes, runners, flappy-likes, etc.
    • Great for learning, experiments, and portfolio-friendly mini games.

Installation

Note: Adjust this once it’s on PyPI.

# From a local checkout
pip install -e .

Or, once published:

pip install mini-arcade-core

Requires Python 3.9–3.11.


Core Concepts

GameConfig

Basic configuration for your game:

from mini_arcade_core import GameConfig

config = GameConfig(
    width=800,
    height=600,
    title="My Mini Arcade Game",
    fps=60,
    background_color=(0, 0, 0),  # RGB
)

Game

Abstract base class that owns:

  • the main loop
  • the active Scene
  • high-level control like run() and change_scene()

You subclass Game to plug in your rendering/input backend.

Scene

Represents one state of your game (menu, gameplay, pause, etc.):

from mini_arcade_core import Scene, Game

class MyScene(Scene):
    def on_enter(self) -> None:
        print("Scene entered")

    def on_exit(self) -> None:
        print("Scene exited")

    def handle_event(self, event: object) -> None:
        # Handle input / events from your backend
        pass

    def update(self, dt: float) -> None:
        # Game logic
        pass

    def draw(self, surface: object) -> None:
        # Rendering via your backend
        pass

Entity & SpriteEntity

Lightweight game object primitives:

from mini_arcade_core import Entity, SpriteEntity

class Ball(Entity):
    def __init__(self) -> None:
        self.x = 100.0
        self.y = 100.0
        self.vx = 200.0
        self.vy = 150.0

    def update(self, dt: float) -> None:
        self.x += self.vx * dt
        self.y += self.vy * dt

    def draw(self, surface: object) -> None:
        # Use your backend to draw the ball on `surface`
        pass

paddle = SpriteEntity(x=50.0, y=300.0, width=80, height=16)

Example: Minimal pygame Backend

mini-arcade-core doesn’t force any backend. Here’s a minimal example using pygame as a backend:

# example_pygame_game.py

import pygame
from mini_arcade_core import Game, GameConfig, Scene


class PygameGame(Game):
    def __init__(self, config: GameConfig) -> None:
        super().__init__(config)
        pygame.init()
        self._screen = pygame.display.set_mode(
            (config.width, config.height)
        )
        pygame.display.set_caption(config.title)
        self._clock = pygame.time.Clock()

    def change_scene(self, scene: Scene) -> None:
        if self._current_scene is not None:
            self._current_scene.on_exit()
        self._current_scene = scene
        self._current_scene.on_enter()

    def run(self, initial_scene: Scene) -> None:
        self.change_scene(initial_scene)
        self._running = True

        while self._running:
            dt = self._clock.tick(self.config.fps) / 1000.0

            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    self._running = False
                elif self._current_scene is not None:
                    self._current_scene.handle_event(event)

            if self._current_scene is not None:
                self._current_scene.update(dt)
                self._screen.fill(self.config.background_color)
                self._current_scene.draw(self._screen)
                pygame.display.flip()

        pygame.quit()


class PongScene(Scene):
    def __init__(self, game: Game) -> None:
        super().__init__(game)
        self.x = 100.0
        self.y = 100.0
        self.vx = 200.0
        self.vy = 150.0
        self.radius = 10

    def on_enter(self) -> None:
        print("Pong started")

    def on_exit(self) -> None:
        print("Pong finished")

    def handle_event(self, event: object) -> None:
        # no input yet
        pass

    def update(self, dt: float) -> None:
        self.x += self.vx * dt
        self.y += self.vy * dt

        width = self.game.config.width
        height = self.game.config.height

        if self.x < self.radius or self.x > width - self.radius:
            self.vx *= -1
        if self.y < self.radius or self.y > height - self.radius:
            self.vy *= -1

    def draw(self, surface: pygame.Surface) -> None:  # type: ignore[override]
        pygame.draw.circle(
            surface, (255, 255, 255), (int(self.x), int(self.y)), self.radius
        )


if __name__ == "__main__":
    cfg = GameConfig(width=640, height=360, title="Mini Arcade - Pong")
    game = PygameGame(cfg)
    scene = PongScene(game)
    game.run(scene)

Once you have a shared backend like PygameGame in its own package (or inside your game repo), you can also wire run_game() to use it instead of the abstract Game.


Testing

This project uses pytest for tests.

pip install -e ".[dev]"
pytest

Roadmap

[ ] First concrete backend (e.g. mini-arcade-pygame) [ ] Example games: Pong, Breakout, Snake, Asteroids-lite, Endless Runner [ ] Packaging the example games as separate repos using this core

License

License: MIT License — feel free to use this as a learning tool, or as a base for your own mini arcade projects.

Project details


Download files

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

Source Distribution

mini_arcade_core-0.7.3.tar.gz (8.3 kB view details)

Uploaded Source

Built Distribution

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

mini_arcade_core-0.7.3-py3-none-any.whl (10.7 kB view details)

Uploaded Python 3

File details

Details for the file mini_arcade_core-0.7.3.tar.gz.

File metadata

  • Download URL: mini_arcade_core-0.7.3.tar.gz
  • Upload date:
  • Size: 8.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for mini_arcade_core-0.7.3.tar.gz
Algorithm Hash digest
SHA256 f2c03fa18c3c73a6947394b3c749ed89ed8dfb3c7e67d6bdfe55759f00ae97dd
MD5 ab2f3bda61737b0718bb978d336d523a
BLAKE2b-256 d73ebedc94517cf1f0653607f61233ea4b0f74c905fd6131bab8217ec53404be

See more details on using hashes here.

File details

Details for the file mini_arcade_core-0.7.3-py3-none-any.whl.

File metadata

File hashes

Hashes for mini_arcade_core-0.7.3-py3-none-any.whl
Algorithm Hash digest
SHA256 b3b08fa9e220033011a0d36a0f14a7fea53d74f6eccabc86ee94c185a6734d7f
MD5 5a1c274bd2d7538a5d2fa4ca7b2b69df
BLAKE2b-256 a1699de4d39344b18e002f24c6ed0e2f126b77197e4462cc1b0e4ff228412fa1

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