From 8f12a415ab83684dc9a024dc66db2fd5b1d14e3e Mon Sep 17 00:00:00 2001 From: gram Date: Thu, 19 Feb 2026 11:12:31 +0100 Subject: [PATCH] Atlas --- _examples/atlas/atlas.go | 64 +++++++++++++++++++++++++++++++++++ _examples/atlas/atlas.png | Bin 0 -> 1257 bytes _examples/atlas/firefly.toml | 7 ++++ _examples/atlas/go.mod | 9 +++++ _examples/atlas/go.sum | 4 +++ firefly/callbacks.go | 18 +++++++--- firefly/graphics.go | 40 ++++++++++++++++++++++ 7 files changed, 137 insertions(+), 5 deletions(-) create mode 100644 _examples/atlas/atlas.go create mode 100644 _examples/atlas/atlas.png create mode 100644 _examples/atlas/firefly.toml create mode 100644 _examples/atlas/go.mod create mode 100644 _examples/atlas/go.sum 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 0000000000000000000000000000000000000000..1e803b7c9e7ea3c17ef840288a88dc3dda325e7a GIT binary patch literal 1257 zcmV=P)gk}H$H2e!Gq3PAaf&C2IVs0Cke4LU&VMc&%D3z%58n8)ws}FA z18V(qly8CV_Oy*$H9N2j7 z1iY4;=sqtuh2tw{bW|M^DBRmWn*l!Ae$GWlCV=eaiWs&Jd<=@R8;9E+%!6YM7hlH zqFJD0P?4i-z#$GG%TIn;C~NDre*iGwmax4S6y*RQUAZ8X1DakPgHP)KfLh_TvHu$Y zuzoqPUMI}E4j|5ma>}AGaR7;E0Qfxm$h1w3K4AK#5owBU9ppq3;+9KHwDH#jY14li zGDoD%L5_(AyX6wRio4JkGR+~TFg=gR%QP1dCt=dA;w1^wIzon|&Lfy49CUj^ji=j6 zl|wD#o35SxcEIp;X4>lM8317T?W>tWF=(4KCjJvNjsT zNV?x`^F`PTZk&$0uPy|MhPvg_=zw%VvTw2Rya8jkwn~8fiI`rHw~Rh3b3lz8^9w zEiXKWZ>RaP_t!B#@R|d3PM2uNl5<+HdU_^}W?jV9dlgi16yoUj`YU2Oa&v-816^(aZ>)3EM*TvcUYs z1&J`7NCO~sf-Iq`_&nm&0kq7xTX_U`&&vKe0MeIidUfId0qGhgY4A?aHNJ>X5Vr{9 zqnw@rq8yM{8S=5SqkLEzoDdqrW)ZdfK4ZkzW)aXmdp6}OAWFnc9iY3_Omh}p2Z+uS zhUF3yxh~@E|HR?*?@w31y!;4ffNU^);T0FAyM(5E({;QFpBS1rBC-%8ARBEhLC2um zL&N_v^Pt`$qBi0(qyQ5SMQwud;Me6D-+=G8gK?Z2@clFX?EFa%@G7pOdlOOLj6WOS zdL`^tT*u^`cwT(n`zFnw+g3ydJy_q4j+=~<;_KcwX})p>n96}Emht(S1T7hq5@ad| zrdY=3Ta_T2NNRPIt%5SdLSl#VNv)2SZ55QKJLpP;>_68setdqm8J7}%h6Uk2VN&%H T*f$!#00000NkvXXu0mjfG*wtl literal 0 HcmV?d00001 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))