Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

all: BIG refactor by moving the Towers+Units into Lines #173

Merged
merged 1 commit into from
Mar 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ dc-serve: ## Starts the server using docker-compose
serve: wasm ## Starts the server
@go run ./cmd/server

.PHONY: client
client: ## Runs a client
@go run ./cmd/client

.PHONY: wa-build
wa-build: ## Build the wasm Game
@env GOOS=js GOARCH=wasm go build -o ./server/assets/wasm/maze-wars.wasm ./client/wasm
Expand Down
4 changes: 4 additions & 0 deletions Notes.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
## Map

A tail == 16px

The maps are in an offset of 43 tails

Each line 18t wide, 16t of those are usable and the other 2t are the left and right corners

The spawn area is 7tx16t and the end area is 3tx16t the building area is 74tx16t
Expand Down
28 changes: 14 additions & 14 deletions action/action.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package action

import (
"github.com/xescugc/maze-wars/utils"
"github.com/xescugc/maze-wars/utils/graph"
"nhooyr.io/websocket"
)

Expand Down Expand Up @@ -474,8 +475,16 @@ func NewSyncWaitingRoom(tp, s, cd int) *Action {

type SyncStatePayload struct {
Players *SyncStatePlayersPayload
Towers *SyncStateTowersPayload
Units *SyncStateUnitsPayload
Lines *SyncStateLinesPayload
}

type SyncStateLinesPayload struct {
Lines map[int]*SyncStateLinePayload
}

type SyncStateLinePayload struct {
Towers map[string]*SyncStateTowerPayload
Units map[string]*SyncStateUnitPayload
}

type SyncStatePlayersPayload struct {
Expand All @@ -494,10 +503,6 @@ type SyncStatePlayerPayload struct {
Winner bool
}

type SyncStateTowersPayload struct {
Towers map[string]*SyncStateTowerPayload
}

type SyncStateTowerPayload struct {
utils.Object

Expand All @@ -507,10 +512,6 @@ type SyncStateTowerPayload struct {
PlayerID string
}

type SyncStateUnitsPayload struct {
Units map[string]*SyncStateUnitPayload
}

type SyncStateUnitPayload struct {
utils.MovingObject

Expand All @@ -522,18 +523,17 @@ type SyncStateUnitPayload struct {

Health float64

Path []utils.Step
Path []graph.Step
HashPath string
}

// TODO: or make the action.Action separated or make the store.Player separated
func NewSyncState(players *SyncStatePlayersPayload, towers *SyncStateTowersPayload, units *SyncStateUnitsPayload) *Action {
func NewSyncState(players *SyncStatePlayersPayload, lines *SyncStateLinesPayload) *Action {
return &Action{
Type: SyncState,
SyncState: &SyncStatePayload{
Players: players,
Towers: towers,
Units: units,
Lines: lines,
},
}
}
Expand Down
15 changes: 4 additions & 11 deletions client/action.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,16 +91,9 @@ func (ac *ActionDispatcher) CameraZoom(d int) {

// PlaceTower places the tower 't' on the position X and Y of the player pid
func (ac *ActionDispatcher) PlaceTower(t, pid string, x, y int) {
units := ac.store.Units.List()
to := utils.Object{X: float64(x), Y: float64(y), H: 32, W: 32}
canPlace := true
for _, u := range units {
if u.IsColliding(to) {
canPlace = false
break
}
}
if canPlace {
// TODO: Add the LineID in the action
p := ac.store.Players.FindByID(pid)
if l := ac.store.Lines.FindByID(p.LineID); l != nil && l.Graph.CanAddTower(x, y, 32, 32) {
pta := action.NewPlaceTower(t, pid, x, y)
wsSend(pta)
}
Expand All @@ -126,7 +119,7 @@ func (ac *ActionDispatcher) SelectedTowerInvalid(i bool) {
ac.Dispatch(sta)
}

// DeelectTower cleans the current selected tower
// DeselectTower cleans the current selected tower
func (ac *ActionDispatcher) DeselectTower(t string) {
dsta := action.NewDeselectTower(t)
ac.Dispatch(dsta)
Expand Down
10 changes: 3 additions & 7 deletions client/game.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,7 @@ type Game struct {

Camera *CameraStore
HUD *HUDStore

Units *Units
Towers *Towers
Lines *Lines

Map *Map

Expand All @@ -39,8 +37,7 @@ func (g *Game) Update() error {

g.Map.Update()
g.Camera.Update()
g.Units.Update()
g.Towers.Update()
g.Lines.Update()
g.HUD.Update()

actionDispatcher.TPS()
Expand All @@ -55,6 +52,5 @@ func (g *Game) Draw(screen *ebiten.Image) {
g.Map.Draw(screen)
g.Camera.Draw(screen)
g.HUD.Draw(screen)
g.Units.Draw(screen)
g.Towers.Draw(screen)
g.Lines.Draw(screen)
}
101 changes: 11 additions & 90 deletions client/hud.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,14 +105,14 @@ func (hs *HUDStore) Update() error {
hst := hs.GetState().(HUDState)
x, y := ebiten.CursorPosition()
cp := hs.game.Store.Players.FindCurrent()
tws := hs.game.Store.Towers.List()
cl := hs.game.Store.Lines.FindByID(cp.LineID)
tws := cl.Towers
// Only send a CursorMove when the curso has actually moved
if hst.LastCursorPosition.X != float64(x) || hst.LastCursorPosition.Y != float64(y) {
actionDispatcher.CursorMove(x, y)
}
// If the Current player is dead or has no more lives there are no
// mo actions that can be done
// TODO Be able to move the camera when won or lose
if cp.Lives == 0 || cp.Winner {
return nil
}
Expand All @@ -124,32 +124,7 @@ func (hs *HUDStore) Update() error {
}

if hst.SelectedTower != nil && !hst.SelectedTower.Invalid {
// We double check that placing the tower would not block the path
utws := make([]utils.Object, 0, 0)
for _, t := range tws {
// If the tower does not belong to the current user then we can skip
// as it's outside the Players Building Zone
if t.PlayerID != cp.ID {
continue
}
utws = append(utws, t.Object)
}
var fakex, fakey float64 = hs.game.Store.Map.GetRandomSpawnCoordinatesForLineID(cp.LineID)
utws = append(utws, utils.Object{
X: hst.SelectedTower.X + cs.X,
Y: hst.SelectedTower.Y + cs.Y,
H: hst.SelectedTower.H, W: hst.SelectedTower.W,
})
steps := hs.game.Store.Units.Astar(hs.game.Store.Map, cp.LineID, utils.MovingObject{
Object: utils.Object{
X: fakex,
Y: fakey,
W: 1, H: 1,
},
}, utws)
if len(steps) != 0 {
actionDispatcher.PlaceTower(hst.SelectedTower.Type, cp.ID, int(hst.SelectedTower.X+cs.X), int(hst.SelectedTower.Y+cs.Y))
}
actionDispatcher.PlaceTower(hst.SelectedTower.Type, cp.ID, int(hst.SelectedTower.X+cs.X), int(hst.SelectedTower.Y+cs.Y))
return nil
}
for _, t := range tws {
Expand Down Expand Up @@ -200,69 +175,22 @@ func (hs *HUDStore) Update() error {
actionDispatcher.DeselectTower(hst.SelectedTower.Type)
} else {
var invalid bool
utws := make([]utils.Object, 0, 0)
// TODO: Check why the selected towers can be placed in top of other already palced towers
for _, t := range tws {
// If the tower does not belong to the current user then we can skip
// as it's outside the Players Building Zone
if t.PlayerID != cp.ID {
continue
}
utws = append(utws, t.Object)
// The t.Object has the X and Y relative to the map
// and the hst.SelectedTower has them relative to the
// screen so we need to port the t.Object to the same
// relative values
neo := t.Object
neo.X -= cs.X
neo.Y -= cs.Y
if hst.SelectedTower.IsColliding(neo) {
invalid = true
break
}
}

neo := hst.SelectedTower.Object
neo.X += cs.X
neo.Y += cs.Y
if !hs.game.Store.Map.IsInValidBuildingZone(neo, hst.SelectedTower.LineID) {
invalid = true
}

invalid = !cl.Graph.CanAddTower(int(neo.X), int(neo.Y), int(neo.W), int(neo.H))

if !invalid {
units := hs.game.Store.Units.List()
for _, u := range units {
if u.PlayerID != cp.ID {
continue
}
for _, u := range cl.Units {
if u.IsColliding(neo) {
invalid = true
break
}
}
}

// Only check if the line is blocked when is still valid position and it has not moved.
// TODO: We can improve this by storing this result (if blocking or not) so we only validate
// this once and not when the mouse is static with a selected tower
if !invalid && (hst.LastCursorPosition.X == float64(x) && hst.LastCursorPosition.Y == float64(y) && !hst.CheckedPath) {
//var fakex, fakey float64 = hs.game.Store.Map.GetRandomSpawnCoordinatesForLineID(cp.LineID)
//utws = append(utws, utils.Object{
//X: hst.SelectedTower.X + cs.X,
//Y: hst.SelectedTower.Y + cs.Y,
//H: hst.SelectedTower.H, W: hst.SelectedTower.W,
//})
//steps := hs.game.Store.Units.Astar(hs.game.Store.Map, cp.LineID, utils.MovingObject{
//Object: utils.Object{
//X: fakex,
//Y: fakey,
//W: 1, H: 1,
//},
//}, utws)
//if len(steps) == 0 {
//invalid = true
//}
//actionDispatcher.CheckedPath(true)
}
if invalid != hst.SelectedTower.Invalid {
actionDispatcher.SelectedTowerInvalid(invalid)
}
Expand Down Expand Up @@ -440,24 +368,24 @@ func (hs *HUDStore) Reduce(state, a interface{}) interface{} {
}

func fixPosition(cs CameraState, x, y float64) (float64, float64) {
//cs := hs.game.Camera.GetState().(CameraState)

absnx := x + cs.X
absny := y + cs.Y
// We find the closes multiple in case the cursor moves too fast, between FPS reloads,
// and lands in a position not 'multiple' which means the position of the SelectedTower
// is not updated and the result is the cursor far away from the Drawing of the SelectedTower
// as it has stayed on the previous position
var multiple int = 16
// If it's == 0 means it's exact but as we want to center it we remove 16 (towers are 32)
// If it's !=0 then we find what's the remaning for
if int(absnx)%multiple == 0 {
x -= 16
} else {
x = float64(closestMultiple(int(absnx), multiple)) - 16 - cs.X
x = float64(utils.ClosestMultiple(int(absnx), multiple)) - 16 - cs.X
}
if int(absny)%multiple == 0 {
y -= 16
} else {
y = float64(closestMultiple(int(absny), multiple)) - 16 - cs.Y
y = float64(utils.ClosestMultiple(int(absny), multiple)) - 16 - cs.Y
}

return x, y
Expand Down Expand Up @@ -485,13 +413,6 @@ func sortedTowers() []*tower.Tower {
return ts
}

// closestMultiple finds the coses multiple of 'b' for the number 'a'
func closestMultiple(a, b int) int {
a = a + b/2
a = a - (a % b)
return a
}

func (hs *HUDStore) buildUI() {
topRightContainer := widget.NewContainer(
widget.ContainerOpts.Layout(widget.NewAnchorLayout()),
Expand Down
Loading
Loading