Skip to content

Repository files navigation

Frame — GoEngine

A modular 2D game engine written in Go, built on Ebitengine. Designed for small platform games with a data-driven, component-based architecture and a Lua scripting layer for game logic.

Features

  • Component system — Unity-style GameObjects with pluggable components (Transform, Spritesheet, Animator, PhysicsBody, Script, IntentBuffer, Block, Ball)
  • Data-driven scenes — worlds are defined in YAML; no code changes required to add objects or tweak layouts
  • Lua scripting — pure-Go Lua 5.1 VM (gopher-lua); write game logic in .lua files, no recompile needed
  • Physics — Box2D integration via box2d-go (kinematic, dynamic, and static bodies)
  • Event bus — type-safe synchronous event bus for decoupled communication between systems
  • Input bindings — configurable keyboard bindings; input actions emit intent events consumed by scripts
  • Asset loading — sprites, spritesheets, fonts, and audio (WAV) loaded from the game root directory
  • Flexible config — all engine settings (window, physics, input, assets) live in a single config.yaml

Demo

Two example games exercise the engine:

  • games/demo1 — a Knight platformer (Lua scripts): Move A/D, Dash Shift, Attack J/K, Debug overlay F3
  • games/metalslug_demo — a Metal Slug-style run-and-gun demo (Python scripts), the actively developed one and the default game main.go runs: Move A/D, Jump Space, Shoot J, Debug overlay F3

Getting Started

Prerequisites: Go 1.24+

git clone https://github.com/diego3/frame.git
cd frame
go run .                          # runs games/metalslug_demo (the default)
go run . games/demo1/config.yaml  # or pick a specific game's config

Project Structure

The engine (frameengine/) and the application layer (main.go, games/) are split into separate trees, in preparation for eventually extracting frameengine/ into its own importable Go module (see docs/frame_engine_migration_plan.md). frameengine/ has no knowledge of any specific game; each game under games/ depends on it, never the reverse.

frame/
├── main.go                              # Entry point (defaults to games/metalslug_demo)
├── main_wasm.go                         # WASM entry point (demo1 only)
├── frameengine/                         # The engine
│   ├── application/
│   │   ├── config/                      # Config loader (YAML)
│   │   ├── data/                        # Scene YAML loader + component builders
│   │   ├── engine/                      # Engine bootstrap (window, signal handling)
│   │   └── game/                        # Game orchestrator (scene manager, input, loop)
│   ├── object/                          # GameObject and all components
│   ├── physics/                         # Physics interfaces + Box2D implementation
│   ├── script/                          # Scripting backends (Lua via gopher-lua, Python via gpython)
│   ├── event/ + events/                 # Type-safe event bus + event type definitions
│   ├── ports/                           # Core interfaces (Scene, AssetLoader, UIRoot)
│   ├── process/                         # Process manager (timed behavior)
│   ├── resource/                        # Asset loader (images, fonts, audio)
│   └── view/
│       ├── input/                       # Keyboard input → intent events
│       ├── scene/                       # The generic WorldScene scene type + PhysicsSystem
│       ├── camera/                      # Follow-camera
│       └── ui/                          # UI widgets (Button, Container)
└── games/                                # Application layer: each game is a frameengine consumer
    ├── demo1/                            # Demo game (Lua scripts)
    │   ├── config.yaml                   # Window, physics, input, asset config
    │   ├── scenes/main_menu.yaml         # Data-driven scene definition
    │   └── scripts/                      # Lua game logic scripts
    └── metalslug_demo/                   # Metal Slug demo (Python scripts)
        ├── config.yaml
        ├── scene.go                       # Embeds *scene.WorldScene, adds this demo's own rules
        └── scripts/python/                # Python game logic scripts

Data-Driven Scenes

Scenes are defined in YAML. Each object lists its components:

objects:
  - name: knight
    components:
      - type: transform
        x: 100
        y: 200
      - type: script
        path: "scripts/knight_controller.lua"
      - type: physics_body
        body_type: kinematic
        width: 50
        height: 80
      - type: spritesheet
        name: idle
        image: "assets/knight/_Idle.png"
        frame_width: 120
        frame_height: 80
        cols: 10
        fps: 8
      - type: animator
        current: idle

Scripting

Scripts are Lua files attached to GameObjects via the script component. The engine calls update(dt) every frame and delivers input events via on_event(name, payload).

-- Entity API (self)
self.set_velocity(vx, vy)
self.play_animation("run")
self.current_animation()    -- -> string
self.animation_finished()   -- -> bool
self.get_intent("move_x")   -- -> number

-- Engine API
engine.play_sound("assets/click.wav")
engine.switch_scene("main_menu")
engine.quit()
engine.emit("DashRequested", { speed = 10 })

Input actions can be wired to script events in config.yaml:

script_events:
  dash: "DashRequested"
  attack: "AttackRequested"

Configuration

window:
  width: 800
  height: 600
  title: "My Game"
  resizable: true

physics:
  gravity_y: 800
  pixel_scale: 64   # pixels per meter

input:
  move_left: A
  move_right: D
  dash: [ShiftLeft, ShiftRight]

assets:
  font_path: "assets/font.ttf"
  scene_path: "scenes/main_menu.yaml"

Architecture Decisions

Design decisions are documented as ADRs in docs/adr/:

  • ADR-005 — Scripting: pure-Go Lua VM (gopher-lua), no CGo
  • ADR-006 — Coding standards
  • ADR-008 — Testing approaches

Dependencies

Package Purpose
ebitengine/ebiten 2D rendering, window, audio
yuin/gopher-lua Pure-Go Lua 5.1 VM (legacy scripting backend)
go-python/gpython Pure-Go Python 3.4 VM (scripting backend for new games)
oliverbestmann/box2d-go Box2D physics
gopkg.in/yaml.v3 YAML config parsing

License

See LICENSE.

About

Frame is my custom game engine side project

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages