krampus19/cmd/krampus19/sprite.go
Sander Schobers b85ac17d8a Added sprites & tried out splash animation.
Moveds fonts to separate directory & added corresponding license texts.
Moved console & fps to separte gut (game utility) package.
Added console (view only).
2019-12-20 21:05:23 +01:00

127 lines
2.7 KiB
Go

package main
import (
"errors"
"io"
"strconv"
"strings"
"opslag.de/schobers/geom"
)
type sprite struct {
texture string
parts []spritePart
}
type spritePart struct {
name string
sub geom.Rectangle
anchor geom.Point
}
func loadSpriteAsset(r io.Reader) (sprite, error) {
var l sprite
ctx := spriteContext{&l, nil}
err := parseLines(r, ctx.parse)
if err != nil {
return sprite{}, err
}
return l, nil
}
type spriteContext struct {
sprite *sprite
part *spritePart
}
func (c *spriteContext) parse(p *lineParser) parseLineFn {
if p.skipSpaceEOF() {
return nil
}
line := p.peek()
switch {
case strings.HasPrefix(line, "sprite:"):
p.next()
return c.parseContent
default:
return nil
}
}
func (c *spriteContext) parseContent(p *lineParser) parseLineFn {
const partTag = "part:"
const textureTag = "texture:"
const spriteEndTag = ":sprite"
if p.skipSpaceEOF() {
return p.emitErr(errUnexpectedEnd)
}
line := p.peek()
switch {
case strings.HasPrefix(line, textureTag):
c.sprite.texture = strings.TrimSpace(line[len(textureTag):])
p.next()
return c.parseContent
case line == partTag:
p.next()
c.part = &spritePart{}
return c.parsePart
case line == spriteEndTag:
return nil
}
return p.emitErr(errors.New("unexpected content of sprite"))
}
func (c *spriteContext) parsePart(p *lineParser) parseLineFn {
mustAtois := func(s ...string) []int {
res := make([]int, len(s))
var err error
for i, s := range s {
res[i], err = strconv.Atoi(s)
if err != nil {
panic("string does not represent an integer")
}
}
return res
}
mustCoords := func(s string) []int {
coords := strings.Split(strings.TrimSpace(s), ",")
return mustAtois(coords...)
}
const nameTag = "name:"
const subTextureTag = "sub_texture:"
const anchorTag = "anchor:"
const partEndTag = ":part"
if p.skipSpaceEOF() {
return p.emitErr(errUnexpectedEnd)
}
line := p.peek()
switch {
case strings.HasPrefix(line, nameTag):
c.part.name = strings.TrimSpace(line[len(nameTag):])
p.next()
return c.parsePart
case strings.HasPrefix(line, subTextureTag):
var coords = mustCoords(line[len(subTextureTag):])
if len(coords) != 4 {
panic("expected four coordinates (min x, min y, size x, size y)")
}
c.part.sub = geom.Rect(coords[0], coords[1], coords[0]+coords[2], coords[1]+coords[3])
p.next()
return c.parsePart
case strings.HasPrefix(line, anchorTag):
var coords = mustCoords(line[len(anchorTag):])
if len(coords) != 2 {
panic("expected two coordinates (min x, min y)")
}
c.part.anchor = geom.Pt(coords[0], coords[1])
p.next()
return c.parsePart
case line == partEndTag:
c.sprite.parts = append(c.sprite.parts, *c.part)
p.next()
return c.parseContent
}
return p.emitErr(errors.New("unexpected content of part"))
}