how to load from a file

This commit is contained in:
Josh Deprez 2021-08-25 15:04:38 +10:00
parent b38aadee74
commit d10d57a3dc
17 changed files with 141 additions and 99 deletions

View file

@ -12,7 +12,7 @@ var _ Prepper = &Actor{}
var errCollision = errors.New("collision detected") var errCollision = errors.New("collision detected")
func init() { func init() {
gob.Register(Actor{}) gob.Register(&Actor{})
} }
// Thorson-style movement: // Thorson-style movement:

View file

@ -1,8 +1,14 @@
package engine package engine
import "encoding/gob"
// Ensure Anim satisfies Animer. // Ensure Anim satisfies Animer.
var _ Animer = &Anim{} var _ Animer = &Anim{}
func init() {
gob.Register(&Anim{})
}
// AnimFrame describes a frame in an animation. // AnimFrame describes a frame in an animation.
type AnimFrame struct { type AnimFrame struct {
Frame int // show this frame Frame int // show this frame

View file

@ -13,7 +13,7 @@ var (
) )
func init() { func init() {
gob.Register(AnimRef{}) gob.Register(&AnimRef{})
} }
// AnimRef manages an Anim using a premade AnimDef from the cache. // AnimRef manages an Anim using a premade AnimDef from the cache.

View file

@ -5,6 +5,7 @@ import (
"encoding/gob" "encoding/gob"
"image" "image"
"io/fs" "io/fs"
"os"
"github.com/hajimehoshi/ebiten/v2" "github.com/hajimehoshi/ebiten/v2"
) )
@ -38,6 +39,28 @@ func loadGobz(dst interface{}, assets fs.FS, path string) error {
return gob.NewDecoder(gz).Decode(dst) return gob.NewDecoder(gz).Decode(dst)
} }
// SaveGobz takes an object, gob-encodes it, gzips it, and writes to disk.
func SaveGobz(src interface{}, name string) error {
f, err := os.CreateTemp(".", name)
if err != nil {
return err
}
defer os.Remove(f.Name())
defer f.Close()
gz := gzip.NewWriter(f)
if err := gob.NewEncoder(gz).Encode(src); err != nil {
return err
}
if err := gz.Close(); err != nil {
return err
}
if err := f.Close(); err != nil {
return err
}
return os.Rename(f.Name(), name)
}
// ImageRef loads images from the AssetFS into *ebiten.Image form. // ImageRef loads images from the AssetFS into *ebiten.Image form.
// It is your responsibility to import _ "image/..." for whatever // It is your responsibility to import _ "image/..." for whatever
// format the files are in, and to load it (either return it as a // format the files are in, and to load it (either return it as a

View file

@ -17,7 +17,7 @@ var (
) )
func init() { func init() {
gob.Register(Camera{}) gob.Register(&Camera{})
} }
// Camera models a camera that is viewing a scene. // Camera models a camera that is viewing a scene.

View file

@ -24,8 +24,8 @@ var (
) )
func init() { func init() {
gob.Register(GobDumper{}) gob.Register(&GobDumper{})
gob.Register(PerfDisplay{}) gob.Register(&PerfDisplay{})
} }
// DebugToast debugprints a string for a while, then disappears. // DebugToast debugprints a string for a while, then disappears.

View file

@ -1,6 +1,7 @@
package engine package engine
import ( import (
"encoding/gob"
"image/color" "image/color"
"github.com/hajimehoshi/ebiten/v2" "github.com/hajimehoshi/ebiten/v2"
@ -9,6 +10,12 @@ import (
// Ensure Fill satisfies Drawer. // Ensure Fill satisfies Drawer.
var _ Drawer = &Fill{} var _ Drawer = &Fill{}
func init() {
gob.Register(Fill{})
gob.Register(color.Gray{})
gob.Register(color.RGBA{})
}
// Fill fills the screen with a colour. // Fill fills the screen with a colour.
type Fill struct { type Fill struct {
ID ID

View file

@ -8,7 +8,7 @@ import (
) )
func init() { func init() {
gob.Register(Game{}) gob.Register(&Game{})
} }
// Game implements the ebiten methods using a collection of components. // Game implements the ebiten methods using a collection of components.

View file

@ -17,7 +17,7 @@ var (
) )
func init() { func init() {
gob.Register(Image{}) gob.Register(&Image{})
} }
// Image draws an image at a position. // Image draws an image at a position.

View file

@ -12,7 +12,7 @@ import (
var _ Scener = &Scene{} var _ Scener = &Scene{}
func init() { func init() {
gob.Register(Scene{}) gob.Register(&Scene{})
} }
// Scene manages drawing and updating a bunch of components. // Scene manages drawing and updating a bunch of components.

View file

@ -24,7 +24,7 @@ func init() {
// //
// var sc = &Scene{ // var sc = &Scene{
// Components: []interface{}{ // Components: []interface{}{
// SceneRef{Path: "assets/foo.gob.gz"} // inflated at Load time // &SceneRef{Path: "assets/foo.gob.gz"} // inflated at Load time
// }, // },
// } // }
type SceneRef struct { type SceneRef struct {

View file

@ -8,7 +8,7 @@ import (
var _ Collider = SolidRect{} var _ Collider = SolidRect{}
func init() { func init() {
gob.Register(SolidRect{}) gob.Register(&SolidRect{})
} }
type SolidRect struct { type SolidRect struct {

View file

@ -17,7 +17,7 @@ var (
) )
func init() { func init() {
gob.Register(Sprite{}) gob.Register(&Sprite{})
} }
// Sprite combines an Actor with the ability to Draw from a single spritesheet. // Sprite combines an Actor with the ability to Draw from a single spritesheet.

View file

@ -19,9 +19,9 @@ var (
) )
func init() { func init() {
gob.Register(AnimatedTile{}) gob.Register(&AnimatedTile{})
gob.Register(StaticTile(0)) gob.Register(StaticTile(0))
gob.Register(Tilemap{}) gob.Register(&Tilemap{})
} }
// Tilemap renders a grid of tiles. // Tilemap renders a grid of tiles.

BIN
game/assets/level1.gobz Normal file

Binary file not shown.

View file

@ -11,7 +11,7 @@ import (
) )
func init() { func init() {
gob.Register(Awakeman{}) gob.Register(&Awakeman{})
} }
type Awakeman struct { type Awakeman struct {

176
main.go
View file

@ -16,95 +16,101 @@ func main() {
ebiten.SetWindowSize(640, 480) ebiten.SetWindowSize(640, 480)
ebiten.SetWindowTitle("TODO") ebiten.SetWindowTitle("TODO")
redTileAnim := &engine.Anim{Frames: []engine.AnimFrame{ if false {
{Frame: 3, Duration: 12}, redTileAnim := &engine.Anim{Frames: []engine.AnimFrame{
{Frame: 4, Duration: 12}, {Frame: 3, Duration: 12},
{Frame: 5, Duration: 12}, {Frame: 4, Duration: 12},
{Frame: 6, Duration: 12}, {Frame: 5, Duration: 12},
}} {Frame: 6, Duration: 12},
greenTileAnim := &engine.Anim{Frames: []engine.AnimFrame{ }}
{Frame: 0, Duration: 16}, greenTileAnim := &engine.Anim{Frames: []engine.AnimFrame{
{Frame: 1, Duration: 16}, {Frame: 0, Duration: 16},
{Frame: 2, Duration: 16}, {Frame: 1, Duration: 16},
}} {Frame: 2, Duration: 16},
denseTiles := [][]engine.Tile{ }}
{engine.StaticTile(9), nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, engine.StaticTile(9)}, denseTiles := [][]engine.Tile{
{nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, engine.AnimatedTile{Animer: redTileAnim.Copy()}, nil, nil, nil, nil, nil, nil, nil, nil, nil}, {engine.StaticTile(9), nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, engine.StaticTile(9)},
{nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, engine.AnimatedTile{Animer: redTileAnim.Copy()}, nil, nil, nil}, {nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, engine.AnimatedTile{Animer: redTileAnim.Copy()}, nil, nil, nil, nil, nil, nil, nil, nil, nil},
{nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil}, {nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, engine.AnimatedTile{Animer: redTileAnim.Copy()}, nil, nil, nil},
{nil, nil, engine.AnimatedTile{Animer: greenTileAnim.Copy()}, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil}, {nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil},
{nil, nil, nil, nil, nil, engine.AnimatedTile{Animer: redTileAnim.Copy()}, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil}, {nil, nil, engine.AnimatedTile{Animer: greenTileAnim.Copy()}, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil},
{nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, engine.AnimatedTile{Animer: greenTileAnim.Copy()}, nil, nil, nil, nil, nil, nil}, {nil, nil, nil, nil, nil, engine.AnimatedTile{Animer: redTileAnim.Copy()}, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil},
{nil, nil, nil, nil, engine.AnimatedTile{Animer: greenTileAnim.Copy()}, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil}, {nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, engine.AnimatedTile{Animer: greenTileAnim.Copy()}, nil, nil, nil, nil, nil, nil},
{nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, engine.AnimatedTile{Animer: greenTileAnim.Copy()}, nil, nil, nil, nil, nil, nil, nil, nil, nil}, {nil, nil, nil, nil, engine.AnimatedTile{Animer: greenTileAnim.Copy()}, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil},
{nil, engine.AnimatedTile{Animer: redTileAnim.Copy()}, nil, nil, nil, nil, nil, nil, engine.StaticTile(9), nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil}, {nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, engine.AnimatedTile{Animer: greenTileAnim.Copy()}, nil, nil, nil, nil, nil, nil, nil, nil, nil},
{nil, nil, nil, nil, nil, engine.StaticTile(9), nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, engine.StaticTile(9), nil, nil, nil}, {nil, engine.AnimatedTile{Animer: redTileAnim.Copy()}, nil, nil, nil, nil, nil, nil, engine.StaticTile(9), nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil},
{nil, nil, nil, nil, engine.StaticTile(9), engine.StaticTile(9), engine.StaticTile(9), nil, nil, nil, engine.StaticTile(9), nil, nil, nil, nil, nil, nil, nil, nil, nil}, {nil, nil, nil, nil, nil, engine.StaticTile(9), nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, engine.StaticTile(9), nil, nil, nil},
{engine.StaticTile(8), engine.StaticTile(8), engine.StaticTile(8), engine.StaticTile(8), engine.StaticTile(8), engine.StaticTile(8), engine.StaticTile(8), engine.StaticTile(8), engine.StaticTile(8), engine.StaticTile(8), engine.AnimatedTile{Animer: redTileAnim.Copy()}, engine.StaticTile(8), engine.StaticTile(8), engine.StaticTile(8), engine.StaticTile(8), engine.StaticTile(8), engine.StaticTile(8), engine.StaticTile(8), engine.StaticTile(8), engine.StaticTile(8)}, {nil, nil, nil, nil, engine.StaticTile(9), engine.StaticTile(9), engine.StaticTile(9), nil, nil, nil, engine.StaticTile(9), nil, nil, nil, nil, nil, nil, nil, nil, nil},
{engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.AnimatedTile{Animer: redTileAnim.Copy()}, engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.AnimatedTile{Animer: greenTileAnim.Copy()}, engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7)}, {engine.StaticTile(8), engine.StaticTile(8), engine.StaticTile(8), engine.StaticTile(8), engine.StaticTile(8), engine.StaticTile(8), engine.StaticTile(8), engine.StaticTile(8), engine.StaticTile(8), engine.StaticTile(8), engine.AnimatedTile{Animer: redTileAnim.Copy()}, engine.StaticTile(8), engine.StaticTile(8), engine.StaticTile(8), engine.StaticTile(8), engine.StaticTile(8), engine.StaticTile(8), engine.StaticTile(8), engine.StaticTile(8), engine.StaticTile(8)},
{engine.StaticTile(9), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(9)}, {engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.AnimatedTile{Animer: redTileAnim.Copy()}, engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.AnimatedTile{Animer: greenTileAnim.Copy()}, engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7)},
} {engine.StaticTile(9), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(9)},
tiles := make(map[image.Point]engine.Tile) }
for j, row := range denseTiles { tiles := make(map[image.Point]engine.Tile)
for i, tile := range row { for j, row := range denseTiles {
if tile == nil { for i, tile := range row {
continue if tile == nil {
} continue
tiles[image.Pt(i, j)] = tile }
tiles[image.Pt(i, j)] = tile
}
} }
}
level1 := &engine.Scene{ level1 := &engine.Scene{
ID: "level_1", ID: "level_1",
Bounds: engine.Bounds(image.Rect(-32, -32, 320+32, 240+32)), Bounds: engine.Bounds(image.Rect(-32, -32, 320+32, 240+32)),
Components: []interface{}{ Components: []interface{}{
&engine.Fill{ &engine.Fill{
Color: color.Gray{100}, Color: color.Gray{100},
ZOrder: 0, ZOrder: 0,
}, },
&engine.Image{ &engine.Image{
ID: "bg_image", ID: "bg_image",
Parallax: 0.5, Parallax: 0.5,
ZOrder: 1, ZOrder: 1,
Pos: image.Pt(-160, -120), Pos: image.Pt(-160, -120),
Src: engine.ImageRef{Path: "assets/space.png"}, Src: engine.ImageRef{Path: "assets/space.png"},
}, },
&engine.Tilemap{ &engine.Tilemap{
ID: "terrain", ID: "terrain",
ZOrder: 2, ZOrder: 2,
Map: tiles, Map: tiles,
Src: engine.ImageRef{Path: "assets/boxes.png"}, Src: engine.ImageRef{Path: "assets/boxes.png"},
TileSize: 16, TileSize: 16,
}, },
&engine.SolidRect{ &engine.SolidRect{
ID: "ceiling", ID: "ceiling",
Bounds: engine.Bounds(image.Rect(0, -1, 320, 0)), Bounds: engine.Bounds(image.Rect(0, -1, 320, 0)),
}, },
&engine.SolidRect{ &engine.SolidRect{
ID: "left_wall", ID: "left_wall",
Bounds: engine.Bounds(image.Rect(-1, 0, 0, 240)), Bounds: engine.Bounds(image.Rect(-1, 0, 0, 240)),
}, },
&engine.SolidRect{ &engine.SolidRect{
ID: "right_wall", ID: "right_wall",
Bounds: engine.Bounds(image.Rect(320, 0, 321, 240)), Bounds: engine.Bounds(image.Rect(320, 0, 321, 240)),
}, },
&game.Awakeman{ &game.Awakeman{
CameraID: "game_camera", CameraID: "game_camera",
ToastID: "toast", ToastID: "toast",
Sprite: engine.Sprite{ Sprite: engine.Sprite{
ID: "awakeman", ID: "awakeman",
Actor: engine.Actor{ Actor: engine.Actor{
CollisionDomain: "level_1", CollisionDomain: "level_1",
Pos: image.Pt(100, 100), Pos: image.Pt(100, 100),
Size: image.Pt(8, 16), Size: image.Pt(8, 16),
},
ZOrder: 3,
FrameOffset: image.Pt(-1, 0),
FrameSize: image.Pt(10, 16),
Src: engine.ImageRef{Path: "assets/aw.png"},
}, },
ZOrder: 3,
FrameOffset: image.Pt(-1, 0),
FrameSize: image.Pt(10, 16),
Src: engine.ImageRef{Path: "assets/aw.png"},
}, },
}, },
}, }
if err := engine.SaveGobz(level1, "level1.gobz"); err != nil {
log.Fatalf("Couldn't save level1.gobz: %v", err)
}
} }
g := &engine.Game{ g := &engine.Game{
@ -118,7 +124,7 @@ func main() {
}, },
&engine.Camera{ &engine.Camera{
ID: "game_camera", ID: "game_camera",
Scene: level1, Scene: &engine.SceneRef{Path: "assets/level1.gobz"},
}, },
&engine.DebugToast{ &engine.DebugToast{
ID: "toast", ID: "toast",