coldbrew

package module
v0.0.0-...-5a25bdc Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 17, 2025 License: Apache-2.0, MIT Imports: 32 Imported by: 19

README

Coldbrew

Coldbrew is the client and scene management system for the Bappa Framework. It serves as the top-level interface for game developers, providing essential functionality for game lifecycle, rendering, input processing, scene transitions, and resource management.

Previously located here prior to monorepo (archived for Git history).

Features

  • Game Loop Management: Handles update-render cycles with configurable timing
  • Scene Management: Create, activate, and transition between multiple scenes
  • Multi-Camera Support: Flexible viewport system with split-screen capabilities
  • Input Abstraction: Device-independent input system for keyboard, mouse, gamepad, and touch
  • Asset Management: Automatic loading and caching of sprites, animations, and sounds
  • System Organization: Structured approach to game logic and rendering systems

Installation

go get github.com/TheBitDrifter/coldbrew

Docs

The official docs can be found here

Examples

Examples can be found here

Technical Foundation

Coldbrew is built on the excellent Ebiten framework for Go, which provides hardware-accelerated rendering and cross-platform support. Ebiten handles the low-level graphics rendering, input detection, and platform compatibility, while Coldbrew extends these capabilities with a comprehensive entity-component system and game management features.

Coldbrew integrates with other Bappa Framework components to provide a complete game development ecosystem.

License

MIT License - see the LICENSE file for details.

Documentation

Overview

Package coldbrew provides input management functionality for various input devices.

Package coldbrew provides a game client and scene management system for the Bappa Framework.

Coldbrew handles game lifecycle, rendering, input processing, scene transitions, and resource management. It serves as the top-level interface for game developers, coordinating between the various components of the Bappa ecosystem.

Core Concepts:

  • Client: The main engine that manages game state, rendering, and input
  • Scene: Isolated game worlds with their own entities, systems, and logic
  • Camera: Viewports that render portions of scenes
  • Systems: Components that process game logic, input, and rendering
  • Receivers: Handle input from various devices (keyboard, mouse, gamepad, touch)

Basic Usage:

package main

import (
	"embed"
	"log"

	"github.com/TheBitDrifter/bappa/blueprint"
	"github.com/TheBitDrifter/bappa/coldbrew"
)

//go:embed assets/*
var assets embed.FS

func main() {
	// Create a new client with resolution 640x360
	// maxSpritesCached=100, maxSoundsCached=50, maxScenesCached=10
	client := coldbrew.NewClient(640, 360, 100, 50, 10, assets)

	// Configure the client
	client.SetTitle("My Game")
	client.SetWindowSize(1280, 720)
	client.SetResizable(true)

	// Register a scene
	err := client.RegisterScene(
		"MainScene",            // Scene name
		640, 360,               // Scene dimensions
		mainScenePlan,          // Blueprint Plan
		renderSystems,          // Render systems
		clientSystems,          // Client systems
		coreSystems,            // Core systems
	)
	if err != nil {
		log.Fatal(err)
	}

	// Register global systems
	client.RegisterGlobalRenderSystem(rendersystems.GlobalRenderer{})
	client.RegisterGlobalClientSystem(clientsystems.InputBufferSystem{})

	// Setup cameras and inputs
	client.ActivateCamera()
	receiver, _ := client.ActivateReceiver()

	// Start the game
	if err := client.Start(); err != nil {
		log.Fatal(err)
	}
}

Coldbrew organizes systems into five categories, running in this order each frame:

  1. Global Client Systems: Handle input and state across all scenes
  2. Core Systems: Process game simulation (physics, AI, collision)
  3. Scene Client Systems: Process scene-specific game logic
  4. Global Render Systems: Handle rendering across all scenes
  5. Scene Render Systems: Handle rendering specific to a scene

The framework supports multiple simultaneous active scenes, enabling features like:

  • Split-screen multiplayer
  • UI overlays
  • Level transitions
  • Mini-maps and picture-in-picture views

Coldbrew uses an input abstraction layer that separates physical inputs (keyboard, mouse, gamepad) from gameplay actions, allowing for flexible control schemes and device independence.

Coldbrew is built on top of the Ebiten game engine (https://github.com/hajimehoshi/ebiten), which provides the low-level graphics rendering, input detection, and cross-platform functionality. Coldbrew extends Ebiten with a comprehensive entity-component system and game management features while integrating the other components of the Bappa Framework: Blueprint, Warehouse, Tteokbokki, and Mask.

Index

Constants

View Source
const MaxSplit = client.MaxSplit

TODO: This whole setup is subpar and odd Would like to refactor the coldbrew config eventually

MaxSplit is the maximum number of splits allowed by the blueprint client

Variables

View Source
var ClientConfig = func() *config {
	defConfig := config{
		configWrite: configWrite{
			Title:       "Bappa!",
			DebugVisual: true,
		},
		minimumLoadTime:    0,
		enforceMinOnActive: true,
		tps:                60,
		debugKey:           ebiten.Key0,
		cameraBorderSize:   0,
		resolution: struct{ x, y int }{
			x: 640,
			y: 360,
		},
		windowSize: struct{ x, y int }{
			x: 1920,
			y: 1080,
		},
		localAssetPath: "assets/",
	}

	defConfig.maxSpritesCached.Store(200)
	defConfig.maxSoundsCached.Store(200)
	return &defConfig
}()

Functions

func ForceSetTick

func ForceSetTick(i int)

func NewSoundLoader

func NewSoundLoader(embeddedFS fs.FS) *soundLoader

NewSoundLoader creates a sound loader with 44.1kHz sample rate

func NewSpriteLoader

func NewSpriteLoader(embeddedFS fs.FS) *spriteLoader

NewSpriteLoader creates a sprite loader with the provided filesystem

Types

type CacheBustError

type CacheBustError struct{}

func (*CacheBustError) Error

func (*CacheBustError) Error() string

type CacheResolveErrorHandler

type CacheResolveErrorHandler func(error)

CacheResolveErrorHandler is a function type for handling cache resolution errors

func GetCacheResolveErrorHandler

func GetCacheResolveErrorHandler() CacheResolveErrorHandler

GetCacheResolveErrorHandler safely retrieves the current error handler

func SetCacheResolveErrorHandler

func SetCacheResolveErrorHandler(handler CacheResolveErrorHandler) CacheResolveErrorHandler

SetCacheResolveErrorHandler allows changing the error handler, returns the previous handler

type Camera

type Camera interface {
	// Ready checks if the camera is ready for rendering based on client state
	Ready(Client) bool
	// Active returns whether the camera is currently active
	Active() bool
	// Activate enables the camera
	Activate()
	// Deactivate clears the surface and disables the camera
	Deactivate()
	// Surface returns the camera's rendering surface
	Surface() *ebiten.Image
	// Localize transforms global scene coordinates to camera-local coordinates
	Localize(pos vector.Two) vector.Two
	// DrawImage renders an image at the specified scene position, localized to the camera
	DrawImage(img *ebiten.Image, opts *ebiten.DrawImageOptions, pos vector.Two)
	// DrawImageStatic renders an image at an absolute position without transformation (on the camera)
	DrawImageStatic(img *ebiten.Image, opts *ebiten.DrawImageOptions, pos vector.Two)
	// DrawTextBasic renders basic text at the specified scene position, localized to the camera
	DrawTextBasic(text string, opts *text.DrawOptions, fontFace *text.GoXFace, pos vector.Two)
	// DrawText renders text at the specified scene position, localized to the camera
	DrawText(text string, opts *text.DrawOptions, fontFace *text.GoTextFace, pos vector.Two)
	// DrawTextBasicStatic renders basic text at an absolute position (on the camera)
	DrawTextBasicStatic(text string, opts *text.DrawOptions, fontFace *text.GoXFace, pos vector.Two)
	// DrawTextStatic renders text at an absolute position (on the camera)
	DrawTextStatic(text string, opts *text.DrawOptions, fontFace *text.GoTextFace, pos vector.Two)
	// PresentToScreen renders the camera's contents to the provided screen
	PresentToScreen(screen Screen, borderSize int)
	// SetDimensions updates the camera's width and height
	SetDimensions(width, height int)
	// Dimensions returns the camera's current width and height
	Dimensions() (width, height int)
	// Positions returns the camera's global (screen) and local (scene/world) positions
	Positions() (screen, scene *vector.Two)
	// Index returns the camera's rendering priority
	Index() int
	// contains filtered or unexported methods
}

Camera manages viewport rendering and coordinate transformation between screen space and scene space

type CameraManager

type CameraManager interface {
	// CameraSceneTracker returns the tracker for camera scene transitions
	CameraSceneTracker() CameraSceneTracker

	// Cameras returns the array of available cameras
	Cameras() [MaxSplit]Camera

	// ActivateCamera attempts to activate a camera and returns it if successful
	ActivateCamera() (Camera, error)
}

CameraManager handles the creation and management of camera objects and provides access to scene tracking capabilities

type CameraSceneRecord

type CameraSceneRecord struct {
	Scene Scene
	Tick  int
}

CameraSceneRecord stores information about a camera's current scene and tick

type CameraSceneTracker

type CameraSceneTracker map[Camera]CameraSceneRecord

CameraSceneTracker tracks which scene each camera is rendering and when it changed

type Client

type Client interface {
	LocalClient
	SceneManager
	CameraManager
	PreExecAllPlans() error
	PreExecSceneByName(string) error
}

Client manages game state, rendering, and input

func NewClient

func NewClient(baseResX, baseResY, maxSpritesCached, maxSoundsCached, maxScenesCached int, embeddedFS fs.FS) Client

NewClient creates a new client with specified resolution and cache settings

func NewTestClient

func NewTestClient(baseResX, baseResY, maxSpritesCached, maxSoundsCached, maxScenesCached int) Client

NewTestClient creates a client specifically for testing purposes with mock asset loaders that don't require real files

type ClientSystem

type ClientSystem interface {
	Run(LocalClient, Scene) error
}

ClientSystem runs in the update loop at the scene level Processes local sound effects and input handling without access to other scenes

type ConfigManager

type ConfigManager interface {
	SetTitle(string)
	SetWindowSize(x, y int)
	SetResolution(x, y int)
	SetResizable(bool)
	SetFullScreen(bool)
	SetMinimumLoadTime(ticks int)
	SetEnforceMinOnActive(bool)
	SetTPS(int)
	BindDebugKey(ebiten.Key)
	SetDebugMode(bool)
	SetCameraBorderSize(int)
	SetLocalAssetPath(path string)
}

ConfigManager defines the interface for managing game configuration settings

type GlobalClientSystem

type GlobalClientSystem interface {
	Run(Client) error
}

GlobalClientSystem runs in the update loop with access to all scenes via client Typically handles sound processing and transforms raw inputs into a usable state for core simulation systems Can run before or after blueprint.CoreSystems depending on registration type

type GlobalRenderSystem

type GlobalRenderSystem interface {
	Render(Client, Screen)
}

GlobalRenderSystem handles rendering at the global/client level with access to all scenes

type InputCapturer

type InputCapturer interface {
	Capture()
}

Captures 'raw' client inputs, and passes them to the client 'receiver' for mapping/tracking

type InputManager

type InputManager interface {
	ActivateReceiver() (Receiver, error)
	Receiver(index int) Receiver
}

InputManager defines the interface for managing input receivers.

type KeyLayout

type KeyLayout interface {
	RegisterKey(ebiten.Key, input.Action)
	RegisterReleasedKey(ebiten.Key, input.Action)
	RegisterJustPressedKey(ebiten.Key, input.Action)
}

KeyLayout maps keyboard keys to game actions

type LocalClientSceneManager

type LocalClientSceneManager interface {
	ActivateSceneByName(string, ...warehouse.Entity) (uint32, error)
	ActivateSceneByIndex(int, ...warehouse.Entity) error

	ChangeSceneByName(string, ...warehouse.Entity) (uint32, error)
	ChangeSceneByIndex(int, ...warehouse.Entity) error
}

type MockSoundLoader

type MockSoundLoader struct {
}

MockSoundLoader implements the sound loading functionality for tests

func NewMockSoundLoader

func NewMockSoundLoader() *MockSoundLoader

NewMockSoundLoader creates a new MockSoundLoader

func (*MockSoundLoader) Load

func (m *MockSoundLoader) Load(soundBundle *client.SoundBundle, cache warehouse.Cache[Sound]) error

Load implements the sound loading for tests

func (*MockSoundLoader) PreLoad

func (m *MockSoundLoader) PreLoad(bundle client.PreLoadAssetBundle, cache warehouse.Cache[Sound]) error

type MockSpriteLoader

type MockSpriteLoader struct{}

MockSpriteLoader implements the sprite loading functionality for tests

func NewMockSpriteLoader

func NewMockSpriteLoader() *MockSpriteLoader

NewMockSpriteLoader creates a new MockSpriteLoader

func (*MockSpriteLoader) Load

func (m *MockSpriteLoader) Load(spriteBundle *client.SpriteBundle, cache warehouse.Cache[Sprite]) error

Load implements the sprite loading for tests

func (*MockSpriteLoader) PreLoad

type MouseLayout

type MouseLayout interface {
	RegisterMouseButton(ebiten.MouseButton, input.Action)
}

MouseLayout maps mouse buttons to game actions

type NetworkClient

type NetworkClient interface {
	Client

	// Connect establishes a connection to a drip server.
	Connect(address string) error

	// Disconnect closes the connection to the server.
	Disconnect() error

	// Send transmits data to the server.
	Send(data []byte) error

	// IsConnected returns true if the client is currently connected.
	IsConnected() bool

	SetDeserCallback(func(NetworkClient, []byte) error)

	AssociatedEntityID() (int, bool)
}

NetworkClient extends the base Client interface with networking capabilities.

func NewNetworkClient

func NewNetworkClient(baseResX, baseResY, maxSpritesCached, maxSoundsCached, maxScenesCached int, embeddedFS fs.FS) NetworkClient

NewNetworkClient creates a new network-enabled client.

type PadLayout

type PadLayout interface {
	RegisterPad(padID int)
	RegisterGamepadButton(ebiten.GamepadButton, input.Action)

	RegisterGamepadJustPressedButton(ebiten.GamepadButton, input.Action)
	RegisterGamepadReleasedButton(ebiten.GamepadButton, input.Action)

	RegisterGamepadAxes(left bool, input input.Action)

	PadActive() bool

	ResetPadButtonMapping()
}

PadLayout manages gamepad input mapping configuration

type Receiver

type Receiver interface {
	RegisterPad(padID int)
	Active() bool
	PopActions() []input.StampedAction
	PadLayout
	KeyLayout
	MouseLayout
	TouchLayout
}

Receiver combines multiple input layouts and manages input state It handles keyboard, gamepad, mouse, and touch inputs

type RenderSystem

type RenderSystem interface {
	Render(Scene, Screen, LocalClient)
}

RenderSystem handles rendering at the scene level and runs after global render systems when its parent scene is active

type RenderUtility

type RenderUtility interface {
	// ActiveCamerasFor returns all active cameras assigned to the given scene
	ActiveCamerasFor(Scene) []Camera

	// Ready determines if a camera is ready to be used based on timing constraints
	Ready(Camera) bool
}

type Scene

type Scene interface {
	// Core information
	Name() string
	Height() int
	Width() int
	CurrentTick() int
	LastSelectedTick() int
	SetSelectedTick()
	LastActivatedTick() int
	SetActivatedTick()
	TicksSinceActivated() int
	TicksSinceSelected() int
	// Storage and queries
	Storage() warehouse.Storage
	NewCursor(warehouse.QueryNode) *warehouse.Cursor
	// Loading state
	IsLoaded() bool
	SetLoaded(bool)
	IsLoading() bool
	SetLoading(bool)
	TryStartLoading() bool
	Ready() bool
	// Systems and execution
	CoreSystems() []blueprint.CoreSystem
	Renderers() []RenderSystem
	ClientSystems() []ClientSystem
	ExecutePlan() (alreadyExecuted bool, err error)
	Reset() error
	PreloadAssetBundle() client.PreLoadAssetBundle
}

Scene manages game scene state and systems It handles loading, storage, world dimensions, and local game systems

type SceneManager

type SceneManager interface {

	// IsActive checks if the given scene is currently active
	IsActive(Scene) bool
	// LoadingScenes returns all scenes currently being loaded
	LoadingScenes() []Scene
	// Cache returns the scene cache
	Cache() warehouse.Cache[Scene]

	ActiveScenes() iter.Seq[Scene]
	ActiveScene(int) Scene
	SceneCount() int
	// RegisterScene creates and registers a new scene with the provided configuration
	RegisterScene(string, int, int, blueprint.Plan, []RenderSystem, []ClientSystem, []blueprint.CoreSystem, ...client.PreLoadAssetBlueprint) error
	// ChangeScene transitions to a target scene, transferring specified entities
	ChangeScene(target Scene, entities ...warehouse.Entity) error
	// ActivateScene activates a target scene while keeping the origin scene active
	ActivateScene(target Scene, entities ...warehouse.Entity) error
	// DeactivateScene removes a scene from the active scenes list
	DeactivateScene(target Scene)
}

SceneManager handles scene lifecycle, transitions, and state management

type Screen

type Screen struct {
	// contains filtered or unexported fields
}

func (*Screen) Draw

func (s *Screen) Draw(target *ebiten.Image, opts *ebiten.DrawImageOptions)

func (*Screen) GetFrame

func (s *Screen) GetFrame(rowIndex, frameIndex, frameWidth, frameHeight int) *ebiten.Image

GetFrame retrieves a frame from the sprite sheet, using the cache if available

func (*Screen) GetTile

func (s *Screen) GetTile(tileX, tileY, tileWidth, tileHeight int) *ebiten.Image

GetTile retrieves a tile from the tileset, using the cache if available

func (*Screen) Image

func (s *Screen) Image() *ebiten.Image

func (*Screen) Name

func (s *Screen) Name() string

type Sound

type Sound struct {
	// contains filtered or unexported fields
}

Sound represents an audio resource that can be played multiple times simultaneously

func MaterializeSound

func MaterializeSound(soundBundle *client.SoundBundle, sc client.SoundConfig) (Sound, error)

MaterializeSound finds and returns a specific Sound object from a bundle based on the provided SoundConfig Returns an error if the sound is not found

func MaterializeSounds

func MaterializeSounds(soundBundle *client.SoundBundle) []Sound

MaterializeSounds converts a collection of sound blueprints into concrete Sound objects It skips any blueprint with an empty location key

func (Sound) GetAny

func (s Sound) GetAny() *audio.Player

GetAnyAvailable returns an available player that is not currently playing, or the first player if all are in use

func (Sound) GetAnyAvailable

func (s Sound) GetAnyAvailable() (*audio.Player, error)

GetAnyAvailable returns an available player that is not currently playing,

func (Sound) GetPlayer

func (s Sound) GetPlayer(i int) *audio.Player

GetPlayer returns the audio player at the specified index

type SoundLoader

type SoundLoader interface {
	Load(bundle *client.SoundBundle, cache warehouse.Cache[Sound]) error

	PreLoad(bundle client.PreLoadAssetBundle, cache warehouse.Cache[Sound]) error
}

type Sprite

type Sprite interface {
	// Name returns the sprite's identifier
	Name() string
	// Image returns the underlying ebiten.Image
	Image() *ebiten.Image
	// Draw renders the sprite to the target image with the provided options
	Draw(*ebiten.Image, *ebiten.DrawImageOptions)
	// GetFrame retrieves a specific frame from a sprite sheet
	GetFrame(rowIndex, frameIndex, frameWidth, frameHeight int) *ebiten.Image
	// GetTile retrieves a specific tile from a tileset
	GetTile(tileX, tileY, tileWidth, tileHeight int) *ebiten.Image
}

Sprite manages image state and rendering properties It contains a reference to the drawable *ebiten.Image

func MaterializeSprite

func MaterializeSprite(spriteBundle *client.SpriteBundle, index int) (Sprite, error)

MaterializeSprites converts a bundle of sprite blueprints into concrete Sprite objects It skips any blueprint with an empty location key

func MaterializeSprites

func MaterializeSprites(spriteBundle *client.SpriteBundle) []Sprite

MaterializeSprites converts a bundle of sprite blueprints into concrete Sprite objects It skips any blueprint with an empty location key

func NewSprite

func NewSprite(name string, image *ebiten.Image) Sprite

NewSprite creates a new sprite instance with frame and tile caching capability

type SpriteLoader

type SpriteLoader interface {
	Load(spriteBundle *client.SpriteBundle, cache warehouse.Cache[Sprite]) error
	PreLoad(bundle client.PreLoadAssetBundle, cache warehouse.Cache[Sprite]) error
}

type SystemManager

type SystemManager interface {
	RegisterGlobalRenderSystem(...GlobalRenderSystem)
	RegisterGlobalClientSystem(...GlobalClientSystem)
}

SystemManager manages registration of various system types

type TickManager

type TickManager interface {
	CurrentTick() int
	ebiten.Game
}

TickManager provides game tick counting functionality and implements ebiten.Game

type TouchLayout

type TouchLayout interface {
	RegisterTouch(input.Action)
}

TouchLayout maps touch input to game actions

Directories

Path Synopsis
examples
animation command
cache_bust command
gamepad command
keyboard command
mouse command
music command
parallax command
physicangular command
physiclinear command
scene_transfer command
splitscreen command
sprite command
touch command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL