better and easier to understand asset loading
This commit is contained in:
parent
95469ab3c7
commit
cb3ccb323c
@ -6,6 +6,7 @@ import (
|
||||
"encoding/json"
|
||||
"image"
|
||||
_ "image/png"
|
||||
"io/fs"
|
||||
"log"
|
||||
"log/slog"
|
||||
"path"
|
||||
@ -17,6 +18,11 @@ import (
|
||||
// Maps image name to image data
|
||||
type AssetRegistry map[string]*ebiten.Image
|
||||
|
||||
// A helper to pass the registry easier around
|
||||
type assetData struct {
|
||||
Registry AssetRegistry
|
||||
}
|
||||
|
||||
type AnimationGeo struct {
|
||||
X int `json:"x"`
|
||||
Y int `json:"y"`
|
||||
@ -52,13 +58,15 @@ type AnimationRegistry map[string]AnimationSet
|
||||
//go:embed sprites/*.png fonts/*.ttf levels/*.ldtk shaders/*.kg sprites/*.json
|
||||
var assetfs embed.FS
|
||||
|
||||
// Called at build time, creates the global asset and animation registries
|
||||
var Assets, Animations = LoadImages()
|
||||
|
||||
// load pngs and json files
|
||||
func LoadImages() (AssetRegistry, AnimationRegistry) {
|
||||
dir := "sprites"
|
||||
images := AssetRegistry{}
|
||||
imagedata := &assetData{}
|
||||
imagedata.Registry = AssetRegistry{}
|
||||
rawanimations := []AnimationJSON{}
|
||||
animations := AnimationRegistry{}
|
||||
|
||||
// we use embed.FS to iterate over all files in ./assets/
|
||||
entries, err := assetfs.ReadDir(dir)
|
||||
@ -69,14 +77,32 @@ func LoadImages() (AssetRegistry, AnimationRegistry) {
|
||||
for _, imagefile := range entries {
|
||||
path := path.Join(dir, imagefile.Name())
|
||||
|
||||
switch {
|
||||
case strings.HasSuffix(path, ".png"):
|
||||
fd, err := assetfs.Open(path)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to open image file %s: %s", imagefile.Name(), err)
|
||||
log.Fatalf("failed to open file %s: %s", imagefile.Name(), err)
|
||||
}
|
||||
defer fd.Close()
|
||||
|
||||
switch {
|
||||
case strings.HasSuffix(path, ".png"):
|
||||
name, image := ReadImage(imagefile, fd)
|
||||
imagedata.Registry[name] = image
|
||||
|
||||
case strings.HasSuffix(path, ".json"):
|
||||
animationjson := ReadJson(imagefile, fd)
|
||||
rawanimations = append(rawanimations, animationjson)
|
||||
}
|
||||
|
||||
slog.Debug("loaded asset", "path", path)
|
||||
}
|
||||
|
||||
// preprocess animation sprites
|
||||
animations := ProcessAnimations(rawanimations, imagedata)
|
||||
|
||||
return imagedata.Registry, animations
|
||||
}
|
||||
|
||||
func ReadImage(imagefile fs.DirEntry, fd fs.File) (string, *ebiten.Image) {
|
||||
name := strings.TrimSuffix(imagefile.Name(), ".png")
|
||||
|
||||
img, _, err := image.Decode(fd)
|
||||
@ -84,38 +110,42 @@ func LoadImages() (AssetRegistry, AnimationRegistry) {
|
||||
log.Fatalf("failed to decode image %s: %s", imagefile.Name(), err)
|
||||
}
|
||||
|
||||
images[name] = ebiten.NewImageFromImage(img)
|
||||
image := ebiten.NewImageFromImage(img)
|
||||
|
||||
slog.Debug("loaded asset", "path", path)
|
||||
case strings.HasSuffix(path, ".json"):
|
||||
fd, err := assetfs.Open(path)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to open json file %s: %s", imagefile.Name(), err)
|
||||
return name, image
|
||||
}
|
||||
defer fd.Close()
|
||||
|
||||
func ReadJson(imagefile fs.DirEntry, fd fs.File) AnimationJSON {
|
||||
buf := new(bytes.Buffer)
|
||||
buf.ReadFrom(fd)
|
||||
|
||||
animationjson := AnimationJSON{}
|
||||
|
||||
err = json.Unmarshal(buf.Bytes(), &animationjson)
|
||||
err := json.Unmarshal(buf.Bytes(), &animationjson)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to parse JSON: %s", err)
|
||||
}
|
||||
|
||||
rawanimations = append(rawanimations, animationjson)
|
||||
}
|
||||
return animationjson
|
||||
}
|
||||
|
||||
// preprocess animation sprites
|
||||
// turn a raw JSON from Asesprite into something we can use better
|
||||
// internally we also load all the sprites of an animation by using
|
||||
// image.SubImage() on the spriteset matching the animation name.
|
||||
// so, if the animation JSON is called "player-idle.json", then we
|
||||
// expect to receive the spriteset in a file "player-idle.png", which
|
||||
// has of course already been loaded at this stage. These spritesets
|
||||
// must contain a row of sprites. We get the measurements from the JSON.
|
||||
func ProcessAnimations(rawanimations []AnimationJSON, imagedata *assetData) AnimationRegistry {
|
||||
animations := AnimationRegistry{}
|
||||
|
||||
for _, animation := range rawanimations {
|
||||
animationset := AnimationSet{}
|
||||
|
||||
animationset.File = strings.TrimSuffix(animation.Meta.Name, ".png")
|
||||
|
||||
for _, frame := range animation.Frames {
|
||||
sprite := images[animationset.File].SubImage(
|
||||
sprite := imagedata.Registry[animationset.File].SubImage(
|
||||
image.Rect(
|
||||
frame.Position.X,
|
||||
frame.Position.Y,
|
||||
@ -132,5 +162,5 @@ func LoadImages() (AssetRegistry, AnimationRegistry) {
|
||||
animations[animationset.File] = animationset
|
||||
}
|
||||
|
||||
return images, animations
|
||||
return animations
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user