proxima

package module
v0.0.0-...-1143d38 Latest Latest
Warning

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

Go to latest
Published: Oct 14, 2026 License: Apache-2.0 Imports: 12 Imported by: 1

README

Fork. This is gdamore/proxima5, Apache 2.0, with three changes so it can run in a browser:

  • tcell v1 → v2. The screen that draws to WebAssembly (wscreen.go) exists only in v2. Mechanical: none of v2 breaking changes — Style no longer numeric, the mouse event changes — touch anything the game uses.
  • The game is a package, not a command. A main package cannot be imported. main.go moved to cmd/proxima5, so the standalone binary still builds and plays exactly as before.
  • Game.Init accepts a screen. It used to call tcell.NewScreen itself; NewGame(screen) hands it one instead, falling back to making its own when given nil. In a page the screen is one of several, already bound to a terminal by whatever opened the window.

Nothing else was touched — the sprites, levels, collision and generated assets are as they were. Changed spots are marked CHANGED from upstream.

ESCAPE FROM PROXIMA 5

Version 0.1

(For the in-game backstory, see story.txt.)

To build it: ./rebuild.sh

THIS GAME IS A WORK IN PROGRESS; PROBABLY OF LITTLE ACTUAL PLAYABLE VALUE OTHER THAN AS A NOVELTY.

GAME PLAY VIDEO

If you just want to see gameplay videos, check these out:

More Info

Only a single game level is implemented so far.

I built this intending to show off the capabilities of my Tcell package for Go (the library used for "terminal" graphics under the hood.)

I got kind of caught up in it, and now there is a pretty powerful game engine under the hood. There is full support for animated sprites, with collision detection, layering, etc. And I've made some pretty cool visual effects too.

It runs in a text window. You want a reasonably big window (80x25 will work, but its harder to play with smaller screens), and you'll want a fast display.

You'll also want a color terminal -- 256 color support in xterm or Terminal is highly recommended. Oh, and if you can, try to use a UTF-8 locale. The game will work in basic ASCII with black and white, and it isn't completely garbage in that mode, but its soo much better with a more capable terminal.

Oh, don't try to run this over a 300 baud modem. You won't be happy.

Local terminals work fine. 9600 baud is probably pushing it. I haven't tested anything other than local connections; there are a lot of display updates in the game, so you do want to have a reasonably fast display. You can reduce the screen size if its too slow, that may help a little.

Yes, it should run in Windows too.

There is no sound (yet!)

Much of the code here will probably get cleaned up and structured properly for reuse in nice library form. Probably sub-packages under Tcell, for both the dynamic views and probably also the sprite management code and maybe even the full game loop.

Reusing Code & Assets

If you want to reuse any of the code or assets here, feel free, per the terms of the Apache 2 license. I would however appreciate an email letting me know how you're using this stuff -- I'm really hopeful that this work will inspire new creative efforts by others and I'm anxious to see what you create!

There are no special requirements to do so, but if you do use this code, I'd appreciate a mention somewhere in your project, with a link back to this github repo.

Documentation

Overview

Level data file Generated automatically, do not edit!

Sprite data file Generated automatically, do not edit!

Sprite data file Generated automatically, do not edit!

Sprite data file Generated automatically, do not edit!

Sprite data file Generated automatically, do not edit!

Sprite data file Generated automatically, do not edit!

Sprite data file Generated automatically, do not edit!

Sprite data file Generated automatically, do not edit!

Sprite data file Generated automatically, do not edit!

Sprite data file Generated automatically, do not edit!

Sprite data file Generated automatically, do not edit!

Sprite data file Generated automatically, do not edit!

Sprite data file Generated automatically, do not edit!

Sprite data file Generated automatically, do not edit!

Sprite data file Generated automatically, do not edit!

Sprite data file Generated automatically, do not edit!

Sprite data file Generated automatically, do not edit!

Index

Constants

View Source
const (
	LayerBackdrop  = 0 // Any backdrop (will we have?)
	LayerThrust    = 1 // Ship thrust (set low to hide)
	LayerTerrain   = 2 // Foreground terrain
	LayerHazard    = 3 // Hazards that the player can hit
	LayerShot      = 4 // Player's shots
	LayerPad       = 5 // Launch pad
	LayerPlayer    = 6 // The player's ship
	LayerExplosion = 7 // Player explosion
	LayerWipe      = 8 // Blastwave
	LayerDialog    = 9 // On top of everything
)
View Source
const (
	GameObjectPropX      = "x"       // int
	GameObjectPropY      = "y"       // int
	GameObjectPropWidth  = "width"   // int
	GameObjectPropHeight = "height"  // int
	GameObjectPropVX     = "vx"      // float64
	GameObjectPropVY     = "vy"      // float64
	GameObjectFrame      = "frame"   // start frame (string)
	GameObjectSprite     = "sprite"  // sprite name (string)
	GameObjectColor1     = "color1"  // color name (string)
	GameObjectColor2     = "color2"  // color name (string)
	GameObjectColor3     = "color3"  // color name (string)
	GameObjectColor4     = "color4"  // color name (string)
	GameObjectColor5     = "color5"  // color name (string)
	GameObjectColor6     = "color6"  // color name (string)
	GameObjectColor7     = "color7"  // color name (string)
	GameObjectColor8     = "color8"  // color name (string)
	GameObjectColor9     = "color9"  // color name (string)
	GameObjectColor10    = "color10" // color name (string)
	GameObjectColor11    = "color11" // color name (string)
	GameObjectColor12    = "color12" // color name (string)
	GameObjectColor13    = "color13" // color name (string)
	GameObjectColor14    = "color14" // color name (string)
	GameObjectColor15    = "color15" // color name (string)
	GameObjectColor16    = "color16" // color name (string)
)

Variables

This section is empty.

Functions

func CollidersCollide

func CollidersCollide(a, b Collider) bool

CollidersCollide returns true if the two colliders collide.

func HandleCollision

func HandleCollision(c1, c2 Collider)

HandleCollision generates two EventCollisions, one for the each Collider, and deliveres them to the two Colliders.

func MakeGameObject

func MakeGameObject(l *Level, name string, props GameObjectProps) error

func RegisterFallbacks

func RegisterFallbacks(screen tcell.Screen)

RegisterFallbacks registers the UTF-8 runes we use in this game with reasonable (best effort) ASCII fallbacks.

func RegisterGameObjectMaker

func RegisterGameObjectMaker(name string, maker GameObjectMaker)

func RegisterLevelGobZ

func RegisterLevelGobZ(b []byte)

func RegisterSpriteGobZ

func RegisterSpriteGobZ(b []byte)

Types

type Alarm

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

Alarm represents an alarm event.

type AlarmClock

type AlarmClock map[*Alarm]struct{}

AlarmClock manages Alarms. Each Alarm is set on a clock, and a single AlarmClock can have unlimited alarms registered with it. However, the actual alarms only ring (run the handlers) when the AlarmClock's Tick method is executed; no implicit asynchronous handling is performed.

func NewAlarmClock

func NewAlarmClock() AlarmClock

NewAlarmClock creates an AlarmClock.

func (AlarmClock) Cancel

func (c AlarmClock) Cancel(a *Alarm)

Cancel cancels a previously scheduled alarm.

func (AlarmClock) Reset

func (c AlarmClock) Reset()

Reset resets the clock, clearing all alarms.

func (AlarmClock) Schedule

func (c AlarmClock) Schedule(d time.Duration, h EventHandler) *Alarm

Schedule schedules an alarm to fire after the duration has expired.

func (AlarmClock) Tick

func (c AlarmClock) Tick(now time.Time)

Tick runs through the list of alarms on this clock,, and runs the event handler for any that have expired. Any alarm that is fired is descheduled. Note that handlers all run synchornously within the caller's context.

type Collider

type Collider interface {
	// Collides returns true if the Collider would collide with an
	// object at the given coordinates.
	Collides(x, y int) bool

	// Bounds is used to report the boundary for the Collider.  We
	// make use of this to optimize our checks, so we begin looking
	// at the more tightly constrained object first.  We also are
	// able to quickly eliminate two objects that do not overlap.
	// If an object never collides with anything, it sould specify
	// the value -1 for these coordinates. Nothing collides at any -1
	// coordinate, even with other objects also at -1 coordinates.
	Bounds() (x1, y1, x2, y2 int)

	// GetLayer returns the layer that the collider exists at.
	// This is mostly useful to class collisions as a group, e.g.
	// all hazards can be set to LayerHazard.
	Layer() int

	EventHandler
}

type EventAlarm

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

EventAlarm is dispatched to the handler for an Alarm.

func (*EventAlarm) When

func (ev *EventAlarm) When() time.Time

When returns the time when the alarm fired.

type EventCollision

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

EventCollision is delivered to a Collider when a collision with another object is detected. Both Colliders will receive an event, but it will not be the same event, since they see each other's collision.

func (*EventCollision) Collider

func (ev *EventCollision) Collider() Collider

Collider returns the object impacting the notified object.

func (*EventCollision) Target

func (ev *EventCollision) Target() Collider

Target returns the object that is being hit.

func (*EventCollision) When

func (ev *EventCollision) When() time.Time

When returns the time when the collision occurred.

type EventGame

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

func (*EventGame) When

func (ev *EventGame) When() time.Time

type EventGameOver

type EventGameOver struct {
	EventGame
}

type EventGravity

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

func (*EventGravity) Accel

func (ev *EventGravity) Accel() float64

func (*EventGravity) When

func (ev *EventGravity) When() time.Time

type EventHandler

type EventHandler interface {
	HandleEvent(tcell.Event) bool
}

EventHandler is anything that handles events.

type EventLevelComplete

type EventLevelComplete struct {
	EventGame
}

type EventLevelStart

type EventLevelStart struct {
	EventGame
}

type EventPlayerDeath

type EventPlayerDeath struct {
	EventGame
}

type EventSpriteAccelerate

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

EventSpriteAccelerate is delivered ot the watchers when the sprite velocity changes.

func (*EventSpriteAccelerate) Sprite

func (ev *EventSpriteAccelerate) Sprite() *Sprite

Sprite returns the sprite that accelerated.

func (*EventSpriteAccelerate) Velocity

func (ev *EventSpriteAccelerate) Velocity() (float64, float64)

Position returns the new sprite velocity (X,Y).

func (*EventSpriteAccelerate) When

func (ev *EventSpriteAccelerate) When() time.Time

When returns the time of the event.

type EventSpriteFrame

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

EventSpriteFrame is delivered to the watchers when the frame for the sprite changes. If the frame is -1, then the sprite is no longer visible.

func (*EventSpriteFrame) Frame

func (ev *EventSpriteFrame) Frame() string

Frame returns the new frame number. It will be -1 if the sprite is no longer visible. The caller is presumed to know the details of the individual frames.

func (*EventSpriteFrame) Sprite

func (ev *EventSpriteFrame) Sprite() *Sprite

Sprite returns the sprite that changed frames.

func (*EventSpriteFrame) When

func (ev *EventSpriteFrame) When() time.Time

When returns the time of the event.

type EventSpriteMove

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

EventSpriteMove is delivered ot the watchers when the sprite position changes.

func (*EventSpriteMove) Position

func (ev *EventSpriteMove) Position() (int, int)

Position returns the new sprite position (X,Y).

func (*EventSpriteMove) Sprite

func (ev *EventSpriteMove) Sprite() *Sprite

Sprite returns the sprite that moved.

func (*EventSpriteMove) When

func (ev *EventSpriteMove) When() time.Time

When returns the time of the event.

type EventTimesUp

type EventTimesUp struct {
	EventGame
}

type Game

type Game struct {
	sync.Mutex
	// contains filtered or unexported fields
}

func NewGame

func NewGame(screen tcell.Screen) *Game

NewGame returns a game that draws to screen, which must already be initialised.

ADDED for this fork. The package used to be a command, so the only way in was main; running it in a browser window means handing it a screen that something else owns.

func (*Game) Draw

func (g *Game) Draw()

func (*Game) Error

func (g *Game) Error(msg string)

func (*Game) EventPoller

func (g *Game) EventPoller()

func (*Game) HandleEvent

func (g *Game) HandleEvent(ev tcell.Event) bool

func (*Game) Init

func (g *Game) Init() error

func (*Game) Quit

func (g *Game) Quit()

func (*Game) Run

func (g *Game) Run() error

func (*Game) Updater

func (g *Game) Updater()

type GameObjectMaker

type GameObjectMaker func(l *Level, props GameObjectProps) error

ObjectMaker is a function that creates game objects as described by the properties. There may actually be multiple objects or composite objects taht result. The ObjectMaker will register any created objects with the Level.

type GameObjectProps

type GameObjectProps map[string]string

GameObjectProps is a dictionary of properties for game objects. We create our own type because we have convenience methods that provide both type conversion and default values.

func (GameObjectProps) PropBool

func (p GameObjectProps) PropBool(name string, def bool) bool

func (GameObjectProps) PropFloat64

func (p GameObjectProps) PropFloat64(name string, def float64) float64

func (GameObjectProps) PropInt

func (p GameObjectProps) PropInt(name string, def int) int

func (GameObjectProps) PropSetBool

func (p GameObjectProps) PropSetBool(name string, val bool)

func (GameObjectProps) PropSetFloat64

func (p GameObjectProps) PropSetFloat64(name string, val float64)

func (GameObjectProps) PropSetInt

func (p GameObjectProps) PropSetInt(name string, val int)

func (GameObjectProps) PropSetString

func (p GameObjectProps) PropSetString(name string, val string)

func (GameObjectProps) PropString

func (p GameObjectProps) PropString(name string, def string) string

type Level

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

func GetLevel

func GetLevel(name string) *Level

func NewLevelFromData

func NewLevelFromData(d *LevelData) *Level

func (*Level) AddAlarm

func (l *Level) AddAlarm(d time.Duration, h EventHandler) *Alarm

func (*Level) AddSprite

func (l *Level) AddSprite(sprite *Sprite)

func (*Level) Center

func (l *Level) Center(x, y int)

func (*Level) Draw

func (l *Level) Draw(v *views.ViewPort)

func (*Level) GetTimer

func (l *Level) GetTimer() time.Duration

func (*Level) HandleEvent

func (l *Level) HandleEvent(ev tcell.Event) bool

func (*Level) Layer

func (l *Level) Layer() int

func (*Level) MakeVisible

func (l *Level) MakeVisible(x, y int)

func (*Level) Name

func (l *Level) Name() string

func (*Level) RemoveAlarm

func (l *Level) RemoveAlarm(a *Alarm)

func (*Level) RemoveSprite

func (l *Level) RemoveSprite(sprite *Sprite)

func (*Level) Reset

func (l *Level) Reset()

func (*Level) SetGame

func (l *Level) SetGame(g *Game)

func (*Level) SetView

func (l *Level) SetView(v *views.ViewPort)

func (*Level) ShowComplete

func (l *Level) ShowComplete()

func (*Level) ShowPress

func (l *Level) ShowPress()

func (*Level) Size

func (l *Level) Size() (int, int)

func (*Level) Start

func (l *Level) Start()

func (*Level) Title

func (l *Level) Title() string

func (*Level) Update

func (l *Level) Update(now time.Time)

type LevelData

type LevelData struct {
	Name       string
	Properties GameObjectProps
	Objects    map[string]GameObjectProps
}

LevelData describes the set up for the level.

In order to keep this as flexible as possible, we use dictionaries of name value pairs. The level has some initial properties that are global to the level itself, and then a series of objects to create. One of those objects must be a player object.

Here are the properties we known about for the level (the Properties member of the LevelData):

title       Printable title for level
terrain     Name of terrain sprite.  The terrain sprite is expected
            to have a starting frame called "TERRAIN".  This is
            likely the only frame in the terrain sprite.
player      Name of player object (found in Objects array)
time        Timer in seconds for completion of the level.  Use
            0 to create a non-expiring level.
gravity     (cells/sec*sec) This value is added to Y velocity.

Each game object may have the following standard properties. Different classes of objects may have others. These are used for the Objects member.

label       Label for the instance.  This string value is set implictly
            to the key of map, and it is not overridable.
class       Name of the object class (string).  This is used to obtain
            an instance of the object, with MakeGameObject().
            Note that the detailed list of class-specific bheaviors
            and properties, as well as any requirements, are part
            of each class.  For example, many classes require that
            the sprites with which they are used meet certain
            requirements.
sprite      Name of the sprite to use (string).  Each class provides
            a default value here, but a different sprite can be
            chosen with this.  (Not all classes support changing
            the sprite.)
x           X position (int) (using the sprite's X origin)
y           Y position (int) (using the sprite's Y origin)
vx          X velocity (float64), cells/sec.  Negative values are
            motion to the left.
vy          Y velocity (float64), cells/sec.  Negative values are
            motion up.
width       Width of sprite in cells (int) if adjustable.
height      Height of sprite in cells (int) if adjustable.
colorX      Name of color (string) to substitute for given color
            in the sprite's color map.

type Sprite

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

func GetSprite

func GetSprite(name string) *Sprite

func NewSprite

func NewSprite(w, h int) *Sprite

func (*Sprite) AddFrame

func (s *Sprite) AddFrame(name string, runes []rune, styles []tcell.Style)

AddFrame adds a frame, and return the frame number.

func (*Sprite) Bounds

func (s *Sprite) Bounds() (x1, y1, x2, y2 int)

Bounds returns the bounds of the sprite, for collision detection purposes (See Collider interface)

func (*Sprite) Collides

func (s *Sprite) Collides(x, y int) bool

Collides checks if a collision at the given coordinates occurs.

func (*Sprite) Draw

func (s *Sprite) Draw(view views.View)

func (*Sprite) Frame

func (s *Sprite) Frame() string

func (*Sprite) HandleEvent

func (s *Sprite) HandleEvent(ev tcell.Event) bool

func (*Sprite) Hide

func (s *Sprite) Hide()

func (*Sprite) Layer

func (s *Sprite) Layer() int

Layer returns the layer at which the sprite exists.

func (*Sprite) Position

func (s *Sprite) Position() (int, int)

func (*Sprite) Resize

func (s *Sprite) Resize(w, h int)

Resize resizes a sprite. If the sprite shrinks then the cells are clipped from the end. If the sprite grows, then new cells are added by copying to the last to the end.

func (*Sprite) ScheduleFrame

func (s *Sprite) ScheduleFrame(frame string, when time.Time)

ScheduleFrame arranges to change the frame to the named frame at some point near the given time. The purpose is to allow deferring the initial display of a sprite. Only a single frame change may be scheduled this way.

func (*Sprite) SetFrame

func (s *Sprite) SetFrame(frame string)

func (*Sprite) SetLayer

func (s *Sprite) SetLayer(layer int)

SetLayer sets the layer. This determines when the object is drawn, higher layers are drawn after lower ones. This is also reported via Layer() and may be used in collision event handlers.

func (*Sprite) SetNextFrame

func (s *Sprite) SetNextFrame(name string, d time.Duration, next string)

SetNextFrame is used to arrange for automatic frame transitions. At the specified duration after this frame is made active, the frame will advance to the frame specified by next. If next is -1, then the sprite will be made invisible. If the duration is is zero, then no automatic transition will occur.

func (*Sprite) SetOrigin

func (s *Sprite) SetOrigin(x, y int)

func (*Sprite) SetPosition

func (s *Sprite) SetPosition(x, y int)

func (*Sprite) SetVelocity

func (s *Sprite) SetVelocity(velx, vely float64)

Set the velocity of the sprite. The units are cells per second. This cancels any previous but uncalculated motion, so don't call this unless the values are actually different, otherwise the motion may appear choppier than it should.

func (*Sprite) UnscheduleFrame

func (s *Sprite) UnscheduleFrame()

UnscheduleFrame cancels the scheduled change.

func (*Sprite) Unwatch

func (s *Sprite) Unwatch(h EventHandler)

Unwatch removes the handler from the notify list for sprite events.

func (*Sprite) Update

func (s *Sprite) Update(now time.Time)

func (*Sprite) Velocity

func (s *Sprite) Velocity() (float64, float64)

Velocity returns the velocity of the sprite in cells per second.

func (*Sprite) Visible

func (s *Sprite) Visible() bool

func (*Sprite) Watch

func (s *Sprite) Watch(h EventHandler)

Watch adds the handler to the list that will be notified for sprite events. Note that handlers may be called in any order. However, a handler that returns true will consume the event, and no other handlers will receive it afterwards. For most events, it probably is best to return false, so that other game consumers can see the event as well.

type SpriteData

type SpriteData struct {
	Name    string
	Width   int
	Height  int
	OriginX int
	OriginY int
	Layer   int
	Glyphs  map[string]SpriteGlyph
	Palette map[string]string
	Frames  []SpriteFrameData
}

type SpriteFrameData

type SpriteFrameData struct {
	Names []string // names for frame
	Next  string   // Next Frame number, or "" for none
	Time  int      // time in msec to display frame
	Data  []string // lines of frame data (ASCII)
}

type SpriteGlyph

type SpriteGlyph struct {
	Display    string // What is displayed, can be Unicode
	Foreground string // See colors.go for color names
	Background string
}

type SpriteManager

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

func NewSpriteManager

func NewSpriteManager(width, height int) *SpriteManager

func (*SpriteManager) AddSprite

func (m *SpriteManager) AddSprite(s *Sprite)

func (*SpriteManager) Draw

func (m *SpriteManager) Draw(v views.View)

func (*SpriteManager) HandleEvent

func (m *SpriteManager) HandleEvent(ev tcell.Event) bool

func (*SpriteManager) RemoveSprite

func (m *SpriteManager) RemoveSprite(s *Sprite)

func (*SpriteManager) Reset

func (m *SpriteManager) Reset()

func (*SpriteManager) SetView

func (m *SpriteManager) SetView(v *views.ViewPort)

func (*SpriteManager) Size

func (m *SpriteManager) Size() (int, int)

func (*SpriteManager) Update

func (m *SpriteManager) Update(now time.Time)

Directories

Path Synopsis
cmd
proxima5 command
internal

Jump to

Keyboard shortcuts

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