diff --git a/_examples/atlas/atlas.go b/_examples/atlas/atlas.go new file mode 100644 index 0000000..27eee85 --- /dev/null +++ b/_examples/atlas/atlas.go @@ -0,0 +1,64 @@ +package main + +import "github.com/firefly-zero/firefly-go/firefly" + +func init() { + firefly.Boot = boot + firefly.Render = render +} + +var ( + atlas = firefly.NewAtlas(16, 16) + + knight = atlas.Sprite(0, 0) + wall = atlas.Sprite(2, 0) + cat = atlas.Sprite(3, 0) + key = atlas.Sprite(4, 0) + door = atlas.Sprite(0, 1) +) + +var frame = 0 + +func boot() { + atlas.Load("atlas") +} + +func render() { + firefly.ClearScreen(firefly.ColorBlack) + + w := 16 + h := 16 + + // top wall + wall.Draw(firefly.P(2*w, 2*h)) + wall.Draw(firefly.P(3*w, 2*h)) + wall.Draw(firefly.P(4*w, 2*h)) + wall.Draw(firefly.P(5*w, 2*h)) + wall.Draw(firefly.P(6*w, 2*h)) + + // bottom wall + wall.Draw(firefly.P(2*w, 6*h)) + wall.Draw(firefly.P(3*w, 6*h)) + door.Draw(firefly.P(4*w, 6*h)) + wall.Draw(firefly.P(5*w, 6*h)) + wall.Draw(firefly.P(6*w, 6*h)) + + // left wall + wall.Draw(firefly.P(2*w, 2*h)) + wall.Draw(firefly.P(2*w, 3*h)) + wall.Draw(firefly.P(2*w, 4*h)) + wall.Draw(firefly.P(2*w, 5*h)) + wall.Draw(firefly.P(2*w, 6*h)) + + // right wall + wall.Draw(firefly.P(6*w, 2*h)) + wall.Draw(firefly.P(6*w, 3*h)) + wall.Draw(firefly.P(6*w, 4*h)) + wall.Draw(firefly.P(6*w, 5*h)) + wall.Draw(firefly.P(6*w, 6*h)) + + // characters and items + knight.Draw(firefly.P(3*w, 4*h)) + cat.Draw(firefly.P(5*w, 4*h)) + key.Draw(firefly.P(4*w, 5*h)) +} diff --git a/_examples/atlas/atlas.png b/_examples/atlas/atlas.png new file mode 100644 index 0000000..1e803b7 Binary files /dev/null and b/_examples/atlas/atlas.png differ diff --git a/_examples/atlas/firefly.toml b/_examples/atlas/firefly.toml new file mode 100644 index 0000000..d4a7eb5 --- /dev/null +++ b/_examples/atlas/firefly.toml @@ -0,0 +1,7 @@ +author_id = "demo" +app_id = "go-atlas" +author_name = "Demo" +app_name = "Atlas Demo (Go)" + +[files] +atlas = { path = "atlas.png" } diff --git a/_examples/atlas/go.mod b/_examples/atlas/go.mod new file mode 100644 index 0000000..cb4e0bd --- /dev/null +++ b/_examples/atlas/go.mod @@ -0,0 +1,9 @@ +module atlas + +go 1.24.0 + +replace github.com/firefly-zero/firefly-go => ../../ + +require github.com/firefly-zero/firefly-go v0.10.0 + +require github.com/orsinium-labs/tinymath v1.1.0 // indirect diff --git a/_examples/atlas/go.sum b/_examples/atlas/go.sum new file mode 100644 index 0000000..5565494 --- /dev/null +++ b/_examples/atlas/go.sum @@ -0,0 +1,4 @@ +github.com/orsinium-labs/tinymath v1.0.0 h1:Uzp3GmjWIBxMObx4MQi9ACDu4Q8WKjSRakB1OMo9Bu0= +github.com/orsinium-labs/tinymath v1.0.0/go.mod h1:WPXX6ei3KSXG7JfA03a+ekCYaY9SWN4I+JRl2p6ck+A= +github.com/orsinium-labs/tinymath v1.1.0 h1:KomdsyLHB7vE3f1nRAJF2dyf1m/gnM2HxfTeV1vS5UA= +github.com/orsinium-labs/tinymath v1.1.0/go.mod h1:WPXX6ei3KSXG7JfA03a+ekCYaY9SWN4I+JRl2p6ck+A= diff --git a/firefly/callbacks.go b/firefly/callbacks.go index e5c58a4..97bc164 100644 --- a/firefly/callbacks.go +++ b/firefly/callbacks.go @@ -27,37 +27,45 @@ var ( ) //go:export boot -func boot() { //nolint +func boot() { if Boot != nil { Boot() } } //go:export update -func update() { //nolint +func update() { if Update != nil { Update() } } //go:export render -func render() { //nolint +func render() { if Render != nil { Render() } } //go:export before_exit -func beforeExit() { //nolint +func beforeExit() { if BeforeExit != nil { BeforeExit() } } //go:export cheat -func cheat(c, v int32) int32 { //nolint +func cheat(c, v int32) int32 { if Cheat != nil { return int32(Cheat(int(c), int(v))) } return 0 } + +var ( + _ = boot + _ = update + _ = render + _ = beforeExit + _ = cheat +) diff --git a/firefly/graphics.go b/firefly/graphics.go index 03accc4..f9b1992 100644 --- a/firefly/graphics.go +++ b/firefly/graphics.go @@ -566,6 +566,46 @@ func (c Canvas) Image() Image { return Image(c) } +// Helper for working with spritesheets. +// +// Constructed by [NewAtlas]. +type Atlas struct { + img Image + spriteSize Size +} + +// Create a new [Atlas] with the given sprite dimensions. +func NewAtlas(spriteW, spriteH int) Atlas { + return Atlas{spriteSize: S(spriteW, spriteH)} +} + +// Set the underlying spritesheet image for the atlas. +// +// Should be called before any [Sprite.Draw]. +// The best is to call it once from [Boot]. +func (a *Atlas) Load(path string) { + a.img = LoadImage(path, nil) +} + +// Create a reference to a sprite within the atlas. +func (a *Atlas) Sprite(row, col int) Sprite { + pos := P(row*a.spriteSize.W, col*a.spriteSize.H) + return Sprite{atlas: a, pos: pos} +} + +type Sprite struct { + atlas *Atlas + pos Point +} + +// Render the sprite at the given position. +// +// Make sure to call [Atlas.Load] first. +func (s Sprite) Draw(p Point) { + sub := s.atlas.img.Sub(s.pos, s.atlas.spriteSize) + sub.Draw(p) +} + // Fill the whole frame with the given color. func ClearScreen(c Color) { clearScreen(int32(c))