diff --git a/assets/assets.go b/assets/assets.go index 5952b76..52e32e4 100644 --- a/assets/assets.go +++ b/assets/assets.go @@ -5,9 +5,70 @@ import ( _ "image/png" ) -//go:embed cyclope/Faceset.png +// UNITS + +//go:embed units/cyclope/Faceset.png var CyclopeFaceset_png []byte +//go:embed units/cyclope/Cyclopes.png +var Cyclope_png []byte + +//go:embed units/cyclope2/Faceset.png +var Cyclope2Faceset_png []byte + +//go:embed units/cyclope2/SpriteSheet.png +var Cyclope2_png []byte + +//go:embed units/flam/Faceset19.png +var FlamFaceset_png []byte + +//go:embed units/flam/Flam.png +var Flam_png []byte + +//go:embed units/flam2/Faceset14.png +var Flam2Faceset_png []byte + +//go:embed units/flam2/Flam2.png +var Flam2_png []byte + +//go:embed units/gold_racoon/Faceset23.png +var GoldRacoonFaceset_png []byte + +//go:embed units/gold_racoon/Tanuki2.png +var GoldRacoon_png []byte + +//go:embed units/octopus/Faceset21.png +var OctopusFaceset_png []byte + +//go:embed units/octopus/Octopus.png +var Octopus_png []byte + +//go:embed units/octopus2/Faceset16.png +var Octopus2Faceset_png []byte + +//go:embed units/octopus2/Octopus2.png +var Octopus2_png []byte + +//go:embed units/racoon/Faceset18.png +var RacoonFaceset_png []byte + +//go:embed units/racoon/Tanuki.png +var Racoon_png []byte + +//go:embed units/spirit/Faceset20.png +var SpiritFaceset_png []byte + +//go:embed units/spirit/Spirit.png +var Spirit_png []byte + +//go:embed units/spirit2/Faceset15.png +var Spirit2Faceset_png []byte + +//go:embed units/spirit2/Spirit2.png +var Spirit2_png []byte + +// END UNITS + //go:embed TilesetHouse.png var TilesetHouse_png []byte @@ -17,9 +78,6 @@ var TilesetLogic_png []byte //go:embed TilesetElement.png var TilesetElement_png []byte -//go:embed cyclope/Cyclopes.png -var Cyclopes_png []byte - //go:embed maps/2.png var Map_2_png []byte diff --git a/assets/units.json b/assets/units.json index 5887930..6c7007f 100644 --- a/assets/units.json +++ b/assets/units.json @@ -1,7 +1,52 @@ { - "cyclope": { - "health": 100, - "income": 1, - "gold": 10 - } + "spirit":{ + "health": 100, + "income": 1, + "gold": 10 + }, + "spirit2":{ + "health": 200, + "income": 2, + "gold": 20 + }, + "flam2":{ + "health": 300, + "income": 3, + "gold": 30 + }, + "flam":{ + "health": 400, + "income": 4, + "gold": 40 + }, + "octopus":{ + "health": 500, + "income": 5, + "gold": 50 + }, + "octopus2":{ + "health": 600, + "income": 6, + "gold": 60 + }, + "raccon":{ + "health": 700, + "income": 7, + "gold": 70 + }, + "gold_racoon":{ + "health": 800, + "income": 8, + "gold": 80 + }, + "cyclope2":{ + "health": 900, + "income": 9, + "gold": 90 + }, + "cyclope":{ + "health": 1000, + "income":10, + "gold": 100 + } } diff --git a/assets/cyclope/Cyclopes.png b/assets/units/cyclope/Cyclopes.png similarity index 100% rename from assets/cyclope/Cyclopes.png rename to assets/units/cyclope/Cyclopes.png diff --git a/assets/cyclope/Faceset.png b/assets/units/cyclope/Faceset.png similarity index 100% rename from assets/cyclope/Faceset.png rename to assets/units/cyclope/Faceset.png diff --git a/assets/units/cyclope2/Faceset.png b/assets/units/cyclope2/Faceset.png new file mode 100644 index 0000000..971b820 Binary files /dev/null and b/assets/units/cyclope2/Faceset.png differ diff --git a/assets/units/cyclope2/SpriteSheet.png b/assets/units/cyclope2/SpriteSheet.png new file mode 100644 index 0000000..8f9a431 Binary files /dev/null and b/assets/units/cyclope2/SpriteSheet.png differ diff --git a/assets/units/flam/Faceset19.png b/assets/units/flam/Faceset19.png new file mode 100644 index 0000000..b70771f Binary files /dev/null and b/assets/units/flam/Faceset19.png differ diff --git a/assets/units/flam/Flam.png b/assets/units/flam/Flam.png new file mode 100644 index 0000000..673ce62 Binary files /dev/null and b/assets/units/flam/Flam.png differ diff --git a/assets/units/flam2/Faceset14.png b/assets/units/flam2/Faceset14.png new file mode 100644 index 0000000..3921689 Binary files /dev/null and b/assets/units/flam2/Faceset14.png differ diff --git a/assets/units/flam2/Flam2.png b/assets/units/flam2/Flam2.png new file mode 100644 index 0000000..0cddf57 Binary files /dev/null and b/assets/units/flam2/Flam2.png differ diff --git a/assets/units/gold_racoon/Faceset23.png b/assets/units/gold_racoon/Faceset23.png new file mode 100644 index 0000000..a11cf34 Binary files /dev/null and b/assets/units/gold_racoon/Faceset23.png differ diff --git a/assets/units/gold_racoon/Tanuki2.png b/assets/units/gold_racoon/Tanuki2.png new file mode 100644 index 0000000..4cd98a9 Binary files /dev/null and b/assets/units/gold_racoon/Tanuki2.png differ diff --git a/assets/units/octopus/Faceset21.png b/assets/units/octopus/Faceset21.png new file mode 100644 index 0000000..0fc0cbc Binary files /dev/null and b/assets/units/octopus/Faceset21.png differ diff --git a/assets/units/octopus/Octopus.png b/assets/units/octopus/Octopus.png new file mode 100644 index 0000000..197e3c2 Binary files /dev/null and b/assets/units/octopus/Octopus.png differ diff --git a/assets/units/octopus2/Faceset16.png b/assets/units/octopus2/Faceset16.png new file mode 100644 index 0000000..8cdf6d1 Binary files /dev/null and b/assets/units/octopus2/Faceset16.png differ diff --git a/assets/units/octopus2/Octopus2.png b/assets/units/octopus2/Octopus2.png new file mode 100644 index 0000000..688dd44 Binary files /dev/null and b/assets/units/octopus2/Octopus2.png differ diff --git a/assets/units/racoon/Faceset18.png b/assets/units/racoon/Faceset18.png new file mode 100644 index 0000000..6bea301 Binary files /dev/null and b/assets/units/racoon/Faceset18.png differ diff --git a/assets/units/racoon/Tanuki.png b/assets/units/racoon/Tanuki.png new file mode 100644 index 0000000..b1cf2b1 Binary files /dev/null and b/assets/units/racoon/Tanuki.png differ diff --git a/assets/units/spirit/Faceset20.png b/assets/units/spirit/Faceset20.png new file mode 100644 index 0000000..88ff611 Binary files /dev/null and b/assets/units/spirit/Faceset20.png differ diff --git a/assets/units/spirit/Spirit.png b/assets/units/spirit/Spirit.png new file mode 100644 index 0000000..113b1ae Binary files /dev/null and b/assets/units/spirit/Spirit.png differ diff --git a/assets/units/spirit2/Faceset15.png b/assets/units/spirit2/Faceset15.png new file mode 100644 index 0000000..9393d28 Binary files /dev/null and b/assets/units/spirit2/Faceset15.png differ diff --git a/assets/units/spirit2/Spirit2.png b/assets/units/spirit2/Spirit2.png new file mode 100644 index 0000000..dcc5763 Binary files /dev/null and b/assets/units/spirit2/Spirit2.png differ diff --git a/client/hud.go b/client/hud.go index 358994b..c009aca 100644 --- a/client/hud.go +++ b/client/hud.go @@ -36,6 +36,8 @@ type HUDStore struct { // HUDState stores the HUD state type HUDState struct { + Facesets []facesetButton + CyclopeButton utils.Object SoldierButton utils.Object HouseButton utils.Object @@ -47,6 +49,11 @@ type HUDState struct { CheckedPath bool } +type facesetButton struct { + Unit *unit.Unit + Object utils.Object +} + type SelectedTower struct { store.Tower @@ -55,9 +62,32 @@ type SelectedTower struct { // NewHUDStore creates a new HUDStore with the Dispatcher d and the Game g func NewHUDStore(d *flux.Dispatcher, i inputer.Inputer, g *Game) (*HUDStore, error) { - fi, _, err := image.Decode(bytes.NewReader(assets.CyclopeFaceset_png)) - if err != nil { - return nil, err + us := make([]*unit.Unit, 0, 0) + for _, u := range unit.Units { + us = append(us, u) + } + sort.Slice(us, func(i, j int) bool { + return us[i].Gold < us[j].Gold + }) + + cs := g.Camera.GetState().(CameraState) + // We want to create rows of 5 + fs := make([]facesetButton, 0, 0) + nrows := len(us) / 5 + + // As all the Faceset are equal squares + // we just need to take one + fhw := float64(us[0].Faceset.Bounds().Dx()) + for i, u := range us { + fs = append(fs, facesetButton{ + Unit: u, + Object: utils.Object{ + X: cs.W - (fhw * float64(5-(i%5))), + Y: cs.H - (fhw * float64(nrows-(i/5))), + W: fhw, + H: fhw, + }, + }) } thi, _, err := image.Decode(bytes.NewReader(assets.TilesetHouse_png)) @@ -73,20 +103,13 @@ func NewHUDStore(d *flux.Dispatcher, i inputer.Inputer, g *Game) (*HUDStore, err hs := &HUDStore{ game: g, - cyclopeFacesetImage: ebiten.NewImageFromImage(fi), - tilesetHouseImage: ebiten.NewImageFromImage(thi).SubImage(image.Rect(5*16, 17*16, 5*16+16*2, 17*16+16*2)), - houseIcon: ebiten.NewImageFromImage(hi).SubImage(image.Rect(12*16, 0*16, 12*16+16, 0*16+16)), + tilesetHouseImage: ebiten.NewImageFromImage(thi).SubImage(image.Rect(5*16, 17*16, 5*16+16*2, 17*16+16*2)), + houseIcon: ebiten.NewImageFromImage(hi).SubImage(image.Rect(12*16, 0*16, 12*16+16, 0*16+16)), input: i, } - cs := g.Camera.GetState().(CameraState) hs.ReduceStore = flux.NewReduceStore(d, hs.Reduce, HUDState{ - CyclopeButton: utils.Object{ - X: float64(cs.W - float64(hs.cyclopeFacesetImage.Bounds().Dx())), - Y: float64(cs.H - float64(hs.cyclopeFacesetImage.Bounds().Dy())), - W: float64(hs.cyclopeFacesetImage.Bounds().Dx()), - H: float64(hs.cyclopeFacesetImage.Bounds().Dy()), - }, + Facesets: fs, SoldierButton: utils.Object{ X: 0, Y: float64(cs.H - 16*2), @@ -132,9 +155,11 @@ func (hs *HUDStore) Update() error { W: 1, H: 1, } // Check what the user has just clicked - if cp.Gold >= unit.Units[unit.Cyclope.String()].Gold && hst.CyclopeButton.IsColliding(click) { - actionDispatcher.SummonUnit(unit.Cyclope.String(), cp.ID, cp.LineID, hs.game.Store.Map.GetNextLineID(cp.LineID)) - return nil + for _, f := range hst.Facesets { + if cp.Gold >= f.Unit.Gold && f.Object.IsColliding(click) { + actionDispatcher.SummonUnit(f.Unit.Type.String(), cp.ID, cp.LineID, hs.game.Store.Map.GetNextLineID(cp.LineID)) + return nil + } } if cp.Gold >= tower.Towers[tower.Soldier.String()].Gold && hst.SoldierButton.IsColliding(click) { actionDispatcher.SelectTower(tower.Soldier.String(), x, y) @@ -282,14 +307,16 @@ func (hs *HUDStore) Draw(screen *ebiten.Image) { text.Draw(screen, "YOU WON!", smallFont, int(cs.W/2), int(cs.H/2), color.White) } - op := &ebiten.DrawImageOptions{} - op.GeoM.Translate(hst.CyclopeButton.X, hst.CyclopeButton.Y) - if cp.Gold < unit.Units[unit.Cyclope.String()].Gold { - op.ColorM.Scale(2, 0.5, 0.5, 0.9) + for _, f := range hst.Facesets { + op := &ebiten.DrawImageOptions{} + op.GeoM.Translate(f.Object.X, f.Object.Y) + if cp.Gold < f.Unit.Gold { + op.ColorM.Scale(2, 0.5, 0.5, 0.9) + } + screen.DrawImage(f.Unit.Faceset.(*ebiten.Image), op) } - screen.DrawImage(hs.cyclopeFacesetImage.(*ebiten.Image), op) - op = &ebiten.DrawImageOptions{} + op := &ebiten.DrawImageOptions{} op.GeoM.Translate(hst.SoldierButton.X, hst.SoldierButton.Y) if cp.Gold < tower.Towers[tower.Soldier.String()].Gold { op.ColorM.Scale(2, 0.5, 0.5, 0.9) @@ -345,12 +372,34 @@ func (hs *HUDStore) Reduce(state, a interface{}) interface{} { case action.WindowResizing: hs.GetDispatcher().WaitFor(hs.game.Camera.GetDispatcherToken()) cs := hs.game.Camera.GetState().(CameraState) - hstate.CyclopeButton = utils.Object{ - X: float64(cs.W - float64(hs.cyclopeFacesetImage.Bounds().Dx())), - Y: float64(cs.H - float64(hs.cyclopeFacesetImage.Bounds().Dy())), - W: float64(hs.cyclopeFacesetImage.Bounds().Dx()), - H: float64(hs.cyclopeFacesetImage.Bounds().Dy()), + + us := make([]*unit.Unit, 0, 0) + for _, u := range unit.Units { + us = append(us, u) + } + sort.Slice(us, func(i, j int) bool { + return us[i].Gold < us[j].Gold + }) + + // We want to create rows of 5 + fs := make([]facesetButton, 0, 0) + nrows := len(us) / 5 + + // As all the Faceset are equal squares + // we just need to take one + fhw := float64(us[0].Faceset.Bounds().Dx()) + for i, u := range us { + fs = append(fs, facesetButton{ + Unit: u, + Object: utils.Object{ + X: cs.W - (fhw * float64(5-(i%5))), + Y: cs.H - (fhw * float64(nrows-(i/5))), + W: fhw, + H: fhw, + }, + }) } + hstate.Facesets = fs hstate.SoldierButton = utils.Object{ X: 0, Y: float64(cs.H - 16*2), diff --git a/client/units.go b/client/units.go index 6d3ccf5..0de4415 100644 --- a/client/units.go +++ b/client/units.go @@ -100,7 +100,7 @@ func (us *Units) DrawUnit(screen *ebiten.Image, c *CameraStore, u *store.Unit) { sx := facingToTile[u.Facing] * int(u.W) i := (u.MovingCount / 5) % 4 sy := i * int(u.H) - screen.DrawImage(u.Image().(*ebiten.Image).SubImage(image.Rect(sx, sy, sx+int(u.W), sy+int(u.H))).(*ebiten.Image), op) + screen.DrawImage(u.Sprite().(*ebiten.Image).SubImage(image.Rect(sx, sy, sx+int(u.W), sy+int(u.H))).(*ebiten.Image), op) // Only draw the Health bar if the unit has been hit h := unit.Units[u.Type].Health diff --git a/store/units.go b/store/units.go index 3bb5cfb..ab64de7 100644 --- a/store/units.go +++ b/store/units.go @@ -40,8 +40,12 @@ type Unit struct { Path []utils.Step } -func (u *Unit) Image() image.Image { - return unit.Units[u.Type].Image +func (u *Unit) Faceset() image.Image { + return unit.Units[u.Type].Faceset +} + +func (u *Unit) Sprite() image.Image { + return unit.Units[u.Type].Sprite } func NewUnits(d *flux.Dispatcher, s *Store) *Units { diff --git a/unit/type.go b/unit/type.go index 227697a..3aad9a2 100644 --- a/unit/type.go +++ b/unit/type.go @@ -1,9 +1,18 @@ package unit -//go:generate enumer -type=Type -transform=lower -output=type_string.go +//go:generate enumer -type=Type -transform=lower -transform=snake -output=type_string.go type Type int const ( - Cyclope Type = iota + Spirit Type = iota + Spirit2 + Flam + Flam2 + Octopus + Octopus2 + Raccon + GoldRacoon + Cyclope + Cyclope2 ) diff --git a/unit/type_string.go b/unit/type_string.go index 79e224f..12f011a 100644 --- a/unit/type_string.go +++ b/unit/type_string.go @@ -1,4 +1,4 @@ -// Code generated by "enumer -type=Type -transform=lower -output=type_string.go"; DO NOT EDIT. +// Code generated by "enumer -type=Type -transform=lower -transform=snake -output=type_string.go"; DO NOT EDIT. package unit @@ -7,11 +7,11 @@ import ( "strings" ) -const _TypeName = "cyclope" +const _TypeName = "spiritspirit2flamflam2octopusoctopus2raccongold_racooncyclopecyclope2" -var _TypeIndex = [...]uint8{0, 7} +var _TypeIndex = [...]uint8{0, 6, 13, 17, 22, 29, 37, 43, 54, 61, 69} -const _TypeLowerName = "cyclope" +const _TypeLowerName = "spiritspirit2flamflam2octopusoctopus2raccongold_racooncyclopecyclope2" func (i Type) String() string { if i < 0 || i >= Type(len(_TypeIndex)-1) { @@ -24,18 +24,54 @@ func (i Type) String() string { // Re-run the stringer command to generate them again. func _TypeNoOp() { var x [1]struct{} - _ = x[Cyclope-(0)] + _ = x[Spirit-(0)] + _ = x[Spirit2-(1)] + _ = x[Flam-(2)] + _ = x[Flam2-(3)] + _ = x[Octopus-(4)] + _ = x[Octopus2-(5)] + _ = x[Raccon-(6)] + _ = x[GoldRacoon-(7)] + _ = x[Cyclope-(8)] + _ = x[Cyclope2-(9)] } -var _TypeValues = []Type{Cyclope} +var _TypeValues = []Type{Spirit, Spirit2, Flam, Flam2, Octopus, Octopus2, Raccon, GoldRacoon, Cyclope, Cyclope2} var _TypeNameToValueMap = map[string]Type{ - _TypeName[0:7]: Cyclope, - _TypeLowerName[0:7]: Cyclope, + _TypeName[0:6]: Spirit, + _TypeLowerName[0:6]: Spirit, + _TypeName[6:13]: Spirit2, + _TypeLowerName[6:13]: Spirit2, + _TypeName[13:17]: Flam, + _TypeLowerName[13:17]: Flam, + _TypeName[17:22]: Flam2, + _TypeLowerName[17:22]: Flam2, + _TypeName[22:29]: Octopus, + _TypeLowerName[22:29]: Octopus, + _TypeName[29:37]: Octopus2, + _TypeLowerName[29:37]: Octopus2, + _TypeName[37:43]: Raccon, + _TypeLowerName[37:43]: Raccon, + _TypeName[43:54]: GoldRacoon, + _TypeLowerName[43:54]: GoldRacoon, + _TypeName[54:61]: Cyclope, + _TypeLowerName[54:61]: Cyclope, + _TypeName[61:69]: Cyclope2, + _TypeLowerName[61:69]: Cyclope2, } var _TypeNames = []string{ - _TypeName[0:7], + _TypeName[0:6], + _TypeName[6:13], + _TypeName[13:17], + _TypeName[17:22], + _TypeName[22:29], + _TypeName[29:37], + _TypeName[37:43], + _TypeName[43:54], + _TypeName[54:61], + _TypeName[61:69], } // TypeString retrieves an enum value from the enum constants string name. diff --git a/unit/unit.go b/unit/unit.go index 17e0865..061dd9f 100644 --- a/unit/unit.go +++ b/unit/unit.go @@ -11,15 +11,44 @@ import ( ) type Unit struct { + Type Type + Health float64 `json:"health"` Income int `json:"income"` Gold int `json:"gold"` - Image image.Image + Faceset image.Image + Sprite image.Image } var ( Units map[string]*Unit + + sprites = map[Type][]byte{ + Spirit: assets.Spirit_png, + Spirit2: assets.Spirit2_png, + Flam2: assets.Flam2_png, + Flam: assets.Flam_png, + Octopus: assets.Octopus_png, + Octopus2: assets.Octopus2_png, + Raccon: assets.Racoon_png, + GoldRacoon: assets.GoldRacoon_png, + Cyclope2: assets.Cyclope2_png, + Cyclope: assets.Cyclope_png, + } + + facesets = map[Type][]byte{ + Spirit: assets.SpiritFaceset_png, + Spirit2: assets.Spirit2Faceset_png, + Flam2: assets.Flam2Faceset_png, + Flam: assets.FlamFaceset_png, + Octopus: assets.OctopusFaceset_png, + Octopus2: assets.Octopus2Faceset_png, + Raccon: assets.RacoonFaceset_png, + GoldRacoon: assets.GoldRacoonFaceset_png, + Cyclope2: assets.Cyclope2Faceset_png, + Cyclope: assets.CyclopeFaceset_png, + } ) func init() { @@ -33,16 +62,27 @@ func init() { if err != nil { log.Fatal(err) } - switch ty { - case Cyclope: - i, _, err := image.Decode(bytes.NewReader(assets.Cyclopes_png)) - if err != nil { - log.Fatal(err) - } - - u.Image = ebiten.NewImageFromImage(i) - default: - log.Fatalf("failed to load unit %q\n", t) + + fb, ok := facesets[ty] + if !ok { + log.Fatalf("Type %s does not have an faceset assigned", ty) } + fi, _, err := image.Decode(bytes.NewReader(fb)) + if err != nil { + log.Fatal(err) + } + + sb, ok := sprites[ty] + if !ok { + log.Fatalf("Type %s does not have an sprite assigned", ty) + } + si, _, err := image.Decode(bytes.NewReader(sb)) + if err != nil { + log.Fatal(err) + } + + u.Sprite = ebiten.NewImageFromImage(si) + u.Faceset = ebiten.NewImageFromImage(fi) + u.Type = ty } }