Noah Petherbridge
3c185528f9
Starts the implementation of the chunk-based pixel storage system for levels and drawings. Previously the levels had a Pixels structure which was just an array of X,Y and palette index triplets. The new chunk system divides the map up into square chunks, and lets each chunk manage its own memory layout. The "MapAccessor" layout is implemented first which is a map of X,Y coordinates to their Swatches (pointer to an index of the palette). When serialized the MapAccessor maps the "X,Y": "index" similarly to the old Pixels array. The object hierarchy for the chunk system is like: * Chunker: the manager of the chunks who keeps track of the ChunkSize and a map of "chunk coordinates" to the chunk in charge of it. * Chunk: a part of the drawing ChunkSize length square. A chunk has a Type (of how it stores its data, 0 being a map[Point]Swatch and 1 being a [][]Swatch 2D array), and the chunk has an Accessor which implements the underlying type. * Accessor: an interface for a Chunk to provide access to its pixels. * MapAccessor: a "sparse map" of coordinates to their Swatches. * GridAccessor: TBD, will be a "dense" 2D grid of Swatches. The JSON files are loaded in two passes: 1. The chunks only load their swatch indexes from disk. 2. With the palette also loaded, the chunks are "inflated" and linked to their swatch pointers. Misc changes: * The `level.Canvas` UI widget switches from the old Grid data type to being able to directly use a `level.Chunker` * The Chunker is a shared data type between the on-disk level format and the actual renderer (level.Canvas), so saving the level is easy because you can just pull the Chunker out from the canvas. * ChunkSize is stored inside the level file and the default value is at balance/numbers.go: 1000
149 lines
2.9 KiB
Go
149 lines
2.9 KiB
Go
package doodle
|
|
|
|
import (
|
|
"git.kirsle.net/apps/doodle/doodads"
|
|
"git.kirsle.net/apps/doodle/events"
|
|
"git.kirsle.net/apps/doodle/level"
|
|
"git.kirsle.net/apps/doodle/render"
|
|
)
|
|
|
|
// PlayScene manages the "Edit Level" game mode.
|
|
type PlayScene struct {
|
|
// Configuration attributes.
|
|
Filename string
|
|
Canvas *level.Grid
|
|
|
|
// Private variables.
|
|
canvas *level.Grid
|
|
|
|
// Canvas size
|
|
width int32
|
|
height int32
|
|
|
|
// Player character
|
|
Player doodads.Doodad
|
|
}
|
|
|
|
// Name of the scene.
|
|
func (s *PlayScene) Name() string {
|
|
return "Play"
|
|
}
|
|
|
|
// Setup the play scene.
|
|
func (s *PlayScene) Setup(d *Doodle) error {
|
|
// Given a filename or map data to play?
|
|
if s.Canvas != nil {
|
|
log.Debug("PlayScene.Setup: loading map from given canvas")
|
|
s.canvas = s.Canvas
|
|
|
|
} else if s.Filename != "" {
|
|
log.Debug("PlayScene.Setup: loading map from file %s", s.Filename)
|
|
s.LoadLevel(s.Filename)
|
|
s.Filename = ""
|
|
}
|
|
|
|
s.Player = doodads.NewPlayer()
|
|
|
|
if s.canvas == nil {
|
|
log.Debug("PlayScene.Setup: no grid given, initializing empty grid")
|
|
s.canvas = &level.Grid{}
|
|
}
|
|
|
|
s.width = d.width // TODO: canvas width = copy the window size
|
|
s.height = d.height
|
|
|
|
d.Flash("Entered Play Mode. Press 'E' to edit this map.")
|
|
|
|
return nil
|
|
}
|
|
|
|
// Loop the editor scene.
|
|
func (s *PlayScene) Loop(d *Doodle, ev *events.State) error {
|
|
// Switching to Edit Mode?
|
|
if ev.KeyName.Read() == "e" {
|
|
log.Info("Edit Mode, Go!")
|
|
d.Goto(&EditorScene{
|
|
// Canvas: s.canvas,
|
|
})
|
|
return nil
|
|
}
|
|
|
|
s.movePlayer(ev)
|
|
return nil
|
|
}
|
|
|
|
// Draw the pixels on this frame.
|
|
func (s *PlayScene) Draw(d *Doodle) error {
|
|
// Clear the canvas and fill it with white.
|
|
d.Engine.Clear(render.White)
|
|
|
|
s.canvas.Draw(d.Engine)
|
|
|
|
// Draw our hero.
|
|
s.Player.Draw(d.Engine)
|
|
|
|
// Draw out bounding boxes.
|
|
d.DrawCollisionBox(s.Player)
|
|
|
|
return nil
|
|
}
|
|
|
|
// movePlayer updates the player's X,Y coordinate based on key pressed.
|
|
func (s *PlayScene) movePlayer(ev *events.State) {
|
|
delta := s.Player.Position()
|
|
var playerSpeed int32 = 8
|
|
var gravity int32 = 2
|
|
|
|
if ev.Down.Now {
|
|
delta.Y += playerSpeed
|
|
}
|
|
if ev.Left.Now {
|
|
delta.X -= playerSpeed
|
|
}
|
|
if ev.Right.Now {
|
|
delta.X += playerSpeed
|
|
}
|
|
if ev.Up.Now {
|
|
delta.Y -= playerSpeed
|
|
}
|
|
|
|
// Apply gravity.
|
|
// var onFloor bool
|
|
|
|
info, ok := doodads.CollidesWithGrid(s.Player, s.canvas, delta)
|
|
if ok {
|
|
// Collision happened with world.
|
|
}
|
|
delta = info.MoveTo
|
|
|
|
// Apply gravity if not grounded.
|
|
if !s.Player.Grounded() {
|
|
// Gravity has to pipe through the collision checker, too, so it
|
|
// can't give us a cheated downward boost.
|
|
delta.Y += gravity
|
|
}
|
|
|
|
s.Player.MoveTo(delta)
|
|
}
|
|
|
|
// LoadLevel loads a level from disk.
|
|
func (s *PlayScene) LoadLevel(filename string) error {
|
|
s.canvas = &level.Grid{}
|
|
|
|
// m, err := level.LoadJSON(filename)
|
|
// if err != nil {
|
|
// return err
|
|
// }
|
|
|
|
// for _, pixel := range m.Pixels {
|
|
// // *s.canvas[pixel] = nil
|
|
// }
|
|
|
|
return nil
|
|
}
|
|
|
|
// Destroy the scene.
|
|
func (s *PlayScene) Destroy() error {
|
|
return nil
|
|
}
|