diff --git a/action/action.go b/action/action.go index 09cd6eb..46d5705 100644 --- a/action/action.go +++ b/action/action.go @@ -26,7 +26,6 @@ type Action struct { NavigateTo *NavigateToPayload `json:"navigate_to, omitempty"` StartGame *StartGamePayload `json:"start_game, omitempty"` GoHome *GoHomePayload `json:"go_home, omitempty"` - CheckedPath *CheckedPathPayload `json:"checked_path,omitempty"` ToggleStats *ToggleStatsPayload `json:"toggle_stats,omitempty"` OpenTowerMenu *OpenTowerMenuPayload `json:"open_tower_menu, omitempty"` @@ -351,19 +350,6 @@ func NewGoHome() *Action { } } -type CheckedPathPayload struct { - Checked bool -} - -func NewCheckedPath(cp bool) *Action { - return &Action{ - Type: CheckedPath, - CheckedPath: &CheckedPathPayload{ - Checked: cp, - }, - } -} - type ToggleStatsPayload struct { } diff --git a/action/type.go b/action/type.go index f5e8e59..3a8c5f5 100644 --- a/action/type.go +++ b/action/type.go @@ -26,7 +26,6 @@ const ( OpenTowerMenu CloseTowerMenu GoHome - CheckedPath ChangeUnitLine SignUpError UserSignUp diff --git a/action/type_string.go b/action/type_string.go index 0c4d0aa..571535d 100644 --- a/action/type_string.go +++ b/action/type_string.go @@ -8,11 +8,11 @@ import ( "strings" ) -const _TypeName = "cursor_movecamera_zoomsummon_unittpsremove_unitsteal_liveplace_towerremove_towerselect_towerselected_towerselected_tower_invaliddeselect_towerincome_ticktower_attackunit_killedwindow_resizingnavigate_tostart_gameopen_tower_menuclose_tower_menugo_homechecked_pathchange_unit_linesign_up_erroruser_sign_upuser_sign_inuser_sign_outjoin_waiting_roomexit_waiting_roomtoggle_statsadd_playerremove_playersync_statesync_userswait_room_countdown_ticksync_waiting_room" +const _TypeName = "cursor_movecamera_zoomsummon_unittpsremove_unitsteal_liveplace_towerremove_towerselect_towerselected_towerselected_tower_invaliddeselect_towerincome_ticktower_attackunit_killedwindow_resizingnavigate_tostart_gameopen_tower_menuclose_tower_menugo_homechange_unit_linesign_up_erroruser_sign_upuser_sign_inuser_sign_outjoin_waiting_roomexit_waiting_roomtoggle_statsadd_playerremove_playersync_statesync_userswait_room_countdown_ticksync_waiting_room" -var _TypeIndex = [...]uint16{0, 11, 22, 33, 36, 47, 57, 68, 80, 92, 106, 128, 142, 153, 165, 176, 191, 202, 212, 227, 243, 250, 262, 278, 291, 303, 315, 328, 345, 362, 374, 384, 397, 407, 417, 441, 458} +var _TypeIndex = [...]uint16{0, 11, 22, 33, 36, 47, 57, 68, 80, 92, 106, 128, 142, 153, 165, 176, 191, 202, 212, 227, 243, 250, 266, 279, 291, 303, 316, 333, 350, 362, 372, 385, 395, 405, 429, 446} -const _TypeLowerName = "cursor_movecamera_zoomsummon_unittpsremove_unitsteal_liveplace_towerremove_towerselect_towerselected_towerselected_tower_invaliddeselect_towerincome_ticktower_attackunit_killedwindow_resizingnavigate_tostart_gameopen_tower_menuclose_tower_menugo_homechecked_pathchange_unit_linesign_up_erroruser_sign_upuser_sign_inuser_sign_outjoin_waiting_roomexit_waiting_roomtoggle_statsadd_playerremove_playersync_statesync_userswait_room_countdown_ticksync_waiting_room" +const _TypeLowerName = "cursor_movecamera_zoomsummon_unittpsremove_unitsteal_liveplace_towerremove_towerselect_towerselected_towerselected_tower_invaliddeselect_towerincome_ticktower_attackunit_killedwindow_resizingnavigate_tostart_gameopen_tower_menuclose_tower_menugo_homechange_unit_linesign_up_erroruser_sign_upuser_sign_inuser_sign_outjoin_waiting_roomexit_waiting_roomtoggle_statsadd_playerremove_playersync_statesync_userswait_room_countdown_ticksync_waiting_room" func (i Type) String() string { if i < 0 || i >= Type(len(_TypeIndex)-1) { @@ -46,24 +46,23 @@ func _TypeNoOp() { _ = x[OpenTowerMenu-(18)] _ = x[CloseTowerMenu-(19)] _ = x[GoHome-(20)] - _ = x[CheckedPath-(21)] - _ = x[ChangeUnitLine-(22)] - _ = x[SignUpError-(23)] - _ = x[UserSignUp-(24)] - _ = x[UserSignIn-(25)] - _ = x[UserSignOut-(26)] - _ = x[JoinWaitingRoom-(27)] - _ = x[ExitWaitingRoom-(28)] - _ = x[ToggleStats-(29)] - _ = x[AddPlayer-(30)] - _ = x[RemovePlayer-(31)] - _ = x[SyncState-(32)] - _ = x[SyncUsers-(33)] - _ = x[WaitRoomCountdownTick-(34)] - _ = x[SyncWaitingRoom-(35)] + _ = x[ChangeUnitLine-(21)] + _ = x[SignUpError-(22)] + _ = x[UserSignUp-(23)] + _ = x[UserSignIn-(24)] + _ = x[UserSignOut-(25)] + _ = x[JoinWaitingRoom-(26)] + _ = x[ExitWaitingRoom-(27)] + _ = x[ToggleStats-(28)] + _ = x[AddPlayer-(29)] + _ = x[RemovePlayer-(30)] + _ = x[SyncState-(31)] + _ = x[SyncUsers-(32)] + _ = x[WaitRoomCountdownTick-(33)] + _ = x[SyncWaitingRoom-(34)] } -var _TypeValues = []Type{CursorMove, CameraZoom, SummonUnit, TPS, RemoveUnit, StealLive, PlaceTower, RemoveTower, SelectTower, SelectedTower, SelectedTowerInvalid, DeselectTower, IncomeTick, TowerAttack, UnitKilled, WindowResizing, NavigateTo, StartGame, OpenTowerMenu, CloseTowerMenu, GoHome, CheckedPath, ChangeUnitLine, SignUpError, UserSignUp, UserSignIn, UserSignOut, JoinWaitingRoom, ExitWaitingRoom, ToggleStats, AddPlayer, RemovePlayer, SyncState, SyncUsers, WaitRoomCountdownTick, SyncWaitingRoom} +var _TypeValues = []Type{CursorMove, CameraZoom, SummonUnit, TPS, RemoveUnit, StealLive, PlaceTower, RemoveTower, SelectTower, SelectedTower, SelectedTowerInvalid, DeselectTower, IncomeTick, TowerAttack, UnitKilled, WindowResizing, NavigateTo, StartGame, OpenTowerMenu, CloseTowerMenu, GoHome, ChangeUnitLine, SignUpError, UserSignUp, UserSignIn, UserSignOut, JoinWaitingRoom, ExitWaitingRoom, ToggleStats, AddPlayer, RemovePlayer, SyncState, SyncUsers, WaitRoomCountdownTick, SyncWaitingRoom} var _TypeNameToValueMap = map[string]Type{ _TypeName[0:11]: CursorMove, @@ -108,36 +107,34 @@ var _TypeNameToValueMap = map[string]Type{ _TypeLowerName[227:243]: CloseTowerMenu, _TypeName[243:250]: GoHome, _TypeLowerName[243:250]: GoHome, - _TypeName[250:262]: CheckedPath, - _TypeLowerName[250:262]: CheckedPath, - _TypeName[262:278]: ChangeUnitLine, - _TypeLowerName[262:278]: ChangeUnitLine, - _TypeName[278:291]: SignUpError, - _TypeLowerName[278:291]: SignUpError, - _TypeName[291:303]: UserSignUp, - _TypeLowerName[291:303]: UserSignUp, - _TypeName[303:315]: UserSignIn, - _TypeLowerName[303:315]: UserSignIn, - _TypeName[315:328]: UserSignOut, - _TypeLowerName[315:328]: UserSignOut, - _TypeName[328:345]: JoinWaitingRoom, - _TypeLowerName[328:345]: JoinWaitingRoom, - _TypeName[345:362]: ExitWaitingRoom, - _TypeLowerName[345:362]: ExitWaitingRoom, - _TypeName[362:374]: ToggleStats, - _TypeLowerName[362:374]: ToggleStats, - _TypeName[374:384]: AddPlayer, - _TypeLowerName[374:384]: AddPlayer, - _TypeName[384:397]: RemovePlayer, - _TypeLowerName[384:397]: RemovePlayer, - _TypeName[397:407]: SyncState, - _TypeLowerName[397:407]: SyncState, - _TypeName[407:417]: SyncUsers, - _TypeLowerName[407:417]: SyncUsers, - _TypeName[417:441]: WaitRoomCountdownTick, - _TypeLowerName[417:441]: WaitRoomCountdownTick, - _TypeName[441:458]: SyncWaitingRoom, - _TypeLowerName[441:458]: SyncWaitingRoom, + _TypeName[250:266]: ChangeUnitLine, + _TypeLowerName[250:266]: ChangeUnitLine, + _TypeName[266:279]: SignUpError, + _TypeLowerName[266:279]: SignUpError, + _TypeName[279:291]: UserSignUp, + _TypeLowerName[279:291]: UserSignUp, + _TypeName[291:303]: UserSignIn, + _TypeLowerName[291:303]: UserSignIn, + _TypeName[303:316]: UserSignOut, + _TypeLowerName[303:316]: UserSignOut, + _TypeName[316:333]: JoinWaitingRoom, + _TypeLowerName[316:333]: JoinWaitingRoom, + _TypeName[333:350]: ExitWaitingRoom, + _TypeLowerName[333:350]: ExitWaitingRoom, + _TypeName[350:362]: ToggleStats, + _TypeLowerName[350:362]: ToggleStats, + _TypeName[362:372]: AddPlayer, + _TypeLowerName[362:372]: AddPlayer, + _TypeName[372:385]: RemovePlayer, + _TypeLowerName[372:385]: RemovePlayer, + _TypeName[385:395]: SyncState, + _TypeLowerName[385:395]: SyncState, + _TypeName[395:405]: SyncUsers, + _TypeLowerName[395:405]: SyncUsers, + _TypeName[405:429]: WaitRoomCountdownTick, + _TypeLowerName[405:429]: WaitRoomCountdownTick, + _TypeName[429:446]: SyncWaitingRoom, + _TypeLowerName[429:446]: SyncWaitingRoom, } var _TypeNames = []string{ @@ -162,21 +159,20 @@ var _TypeNames = []string{ _TypeName[212:227], _TypeName[227:243], _TypeName[243:250], - _TypeName[250:262], - _TypeName[262:278], - _TypeName[278:291], + _TypeName[250:266], + _TypeName[266:279], + _TypeName[279:291], _TypeName[291:303], - _TypeName[303:315], - _TypeName[315:328], - _TypeName[328:345], - _TypeName[345:362], - _TypeName[362:374], - _TypeName[374:384], - _TypeName[384:397], - _TypeName[397:407], - _TypeName[407:417], - _TypeName[417:441], - _TypeName[441:458], + _TypeName[303:316], + _TypeName[316:333], + _TypeName[333:350], + _TypeName[350:362], + _TypeName[362:372], + _TypeName[372:385], + _TypeName[385:395], + _TypeName[395:405], + _TypeName[405:429], + _TypeName[429:446], } // TypeString retrieves an enum value from the enum constants string name. diff --git a/client/action.go b/client/action.go index cb7cbee..ff7a643 100644 --- a/client/action.go +++ b/client/action.go @@ -12,6 +12,7 @@ import ( "github.com/xescugc/go-flux" "github.com/xescugc/maze-wars/action" + cutils "github.com/xescugc/maze-wars/client/utils" "github.com/xescugc/maze-wars/store" "github.com/xescugc/maze-wars/utils" "nhooyr.io/websocket" @@ -47,111 +48,6 @@ func (ac *ActionDispatcher) Dispatch(a *action.Action) { ac.dispatcher.Dispatch(a) } -// CursorMove dispatches an action of moving the Cursor -// to the new x,y coordinates -func (ac *ActionDispatcher) CursorMove(x, y int) { - cma := action.NewCursorMove(x, y) - ac.Dispatch(cma) -} - -// SummonUnit summons the 'unit' from the player id 'pid' to the line -// 'plid' and with the current line id 'clid' -func (ac *ActionDispatcher) SummonUnit(unit, pid string, plid, clid int) { - sua := action.NewSummonUnit(unit, pid, plid, clid) - wsSend(sua) - //ac.Dispatch(sua) -} - -// TPS is the call for every TPS event -func (ac *ActionDispatcher) TPS() { - tpsa := action.NewTPS() - ac.Dispatch(tpsa) -} - -// RemoveUnit removes the unit with the id 'uid' -func (ac *ActionDispatcher) RemoveUnit(uid string) { - rua := action.NewRemoveUnit(uid) - wsSend(rua) - ac.Dispatch(rua) -} - -// StealLive removes one live from the player with id 'fpid' and -// adds it to the player with id 'tpid' -func (ac *ActionDispatcher) StealLive(fpid, tpid string) { - sla := action.NewStealLive(fpid, tpid) - wsSend(sla) - ac.Dispatch(sla) -} - -// CameraZoom zooms the camera the direction 'd' -func (ac *ActionDispatcher) CameraZoom(d int) { - cza := action.NewCameraZoom(d) - ac.Dispatch(cza) -} - -// 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) { - // 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) - } - //ac.Dispatch(pta) -} - -// RemoveTower removes the tower tid -func (ac *ActionDispatcher) RemoveTower(pid, tid, tt string) { - rta := action.NewRemoveTower(pid, tid, tt) - wsSend(rta) - //ac.Dispatch(rta) -} - -// SelectTower selects the tower 't' on the position x, y -func (ac *ActionDispatcher) SelectTower(t string, x, y int) { - sta := action.NewSelectTower(t, x, y) - ac.Dispatch(sta) -} - -// SelectTower selects the tower 't' on the position x, y -func (ac *ActionDispatcher) SelectedTowerInvalid(i bool) { - sta := action.NewSelectedTowerInvalid(i) - ac.Dispatch(sta) -} - -// DeselectTower cleans the current selected tower -func (ac *ActionDispatcher) DeselectTower(t string) { - dsta := action.NewDeselectTower(t) - ac.Dispatch(dsta) -} - -// IncomeTick a new tick for the income -func (ac *ActionDispatcher) IncomeTick() { - it := action.NewIncomeTick() - ac.Dispatch(it) -} - -// TowerAttack issues a attack to the Unit with uid -func (ac *ActionDispatcher) TowerAttack(uid, tt string) { - ta := action.NewTowerAttack(uid, tt) - wsSend(ta) - ac.Dispatch(ta) -} - -// UnitKilled adds gold to the user -func (ac *ActionDispatcher) UnitKilled(pid, ut string) { - uk := action.NewUnitKilled(pid, ut) - wsSend(uk) - ac.Dispatch(uk) -} - -func (ac *ActionDispatcher) RemovePlayer(pid string) { - rpa := action.NewRemovePlayer(pid) - wsSend(rpa) - ac.Dispatch(rpa) - ac.Dispatch(action.NewNavigateTo(LobbyRoute)) -} - // WindowResizing new sizes of the window func (ac *ActionDispatcher) WindowResizing(w, h int) { wr := action.NewWindowResizing(w, h) @@ -164,38 +60,6 @@ func (ac *ActionDispatcher) NavigateTo(route string) { ac.Dispatch(nt) } -// OpenTowerMenu when a tower is clicked and the menu of -// the tower is displayed -func (ac *ActionDispatcher) OpenTowerMenu(tid string) { - otm := action.NewOpenTowerMenu(tid) - ac.Dispatch(otm) -} - -// CloseTowerMenu when a tower menu needs to be closed -func (ac *ActionDispatcher) CloseTowerMenu() { - ctm := action.NewCloseTowerMenu() - ac.Dispatch(ctm) -} - -// GoHome will move the camera to the current player home line -func (ac *ActionDispatcher) GoHome() { - gha := action.NewGoHome() - ac.Dispatch(gha) -} - -// CheckedPath will set the value of the path checked -func (ac *ActionDispatcher) CheckedPath(cp bool) { - cpa := action.NewCheckedPath(cp) - ac.Dispatch(cpa) -} - -// ChangeUnitLine will move the unit to the next line -func (ac *ActionDispatcher) ChangeUnitLine(uid string) { - cula := action.NewChangeUnitLine(uid) - wsSend(cula) - ac.Dispatch(cula) -} - func (ac *ActionDispatcher) SignUpSubmit(un string) { httpu, _ := url.Parse(ac.opt.HostURL) httpu.Path = "/users" @@ -247,25 +111,25 @@ func (ac *ActionDispatcher) SignUpSubmit(un string) { go wsHandler(ctx) - ac.Dispatch(action.NewNavigateTo(LobbyRoute)) + ac.Dispatch(action.NewNavigateTo(cutils.LobbyRoute)) +} + +// GoHome will move the camera to the current player home line +func (ac *ActionDispatcher) GoHome() { + gha := action.NewGoHome() + ac.Dispatch(gha) } func (ac *ActionDispatcher) JoinWaitingRoom(un string) { jwra := action.NewJoinWaitingRoom(un) wsSend(jwra) - ac.Dispatch(action.NewNavigateTo(WaitingRoomRoute)) + ac.Dispatch(action.NewNavigateTo(cutils.WaitingRoomRoute)) } func (ac *ActionDispatcher) ExitWaitingRoom(un string) { ewra := action.NewExitWaitingRoom(un) wsSend(ewra) - ac.Dispatch(action.NewNavigateTo(LobbyRoute)) -} - -func (ac *ActionDispatcher) ToggleStats() { - tsa := action.NewToggleStats() - - ac.Dispatch(tsa) + ac.Dispatch(action.NewNavigateTo(cutils.LobbyRoute)) } diff --git a/client/colors.go b/client/colors.go deleted file mode 100644 index 33a1714..0000000 --- a/client/colors.go +++ /dev/null @@ -1,8 +0,0 @@ -package client - -import "image/color" - -var ( - green = color.RGBA{0x00, 0x80, 0x00, 0xff} - red = color.RGBA{0x80, 0x00, 0x00, 0xff} -) diff --git a/client/game.go b/client/game.go index a178a6e..8b80b2e 100644 --- a/client/game.go +++ b/client/game.go @@ -5,6 +5,8 @@ import ( "time" "github.com/hajimehoshi/ebiten/v2" + "github.com/xescugc/go-flux" + "github.com/xescugc/maze-wars/client/game" "github.com/xescugc/maze-wars/store" "github.com/xescugc/maze-wars/utils" ) @@ -13,20 +15,15 @@ import ( // of the main loop. // It holds all the other Stores and the Map type Game struct { - Store *store.Store - - Camera *CameraStore - HUD *HUDStore - Lines *Lines - - Map *Map + Game *game.Game Logger *slog.Logger } -func NewGame(s *store.Store, l *slog.Logger) *Game { +func NewGame(s *store.Store, d *flux.Dispatcher, l *slog.Logger) *Game { + gl := l.WithGroup("game") return &Game{ - Store: s, + Game: game.New(s, game.NewActionDispatcher(d, s, wsSend, gl), gl), Logger: l, } } @@ -35,12 +32,7 @@ func (g *Game) Update() error { b := time.Now() defer utils.LogTime(g.Logger, b, "game update") - g.Map.Update() - g.Camera.Update() - g.Lines.Update() - g.HUD.Update() - - actionDispatcher.TPS() + g.Game.Update() return nil } @@ -49,8 +41,5 @@ func (g *Game) Draw(screen *ebiten.Image) { b := time.Now() defer utils.LogTime(g.Logger, b, "game draw") - g.Map.Draw(screen) - g.Camera.Draw(screen) - g.HUD.Draw(screen) - g.Lines.Draw(screen) + g.Game.Draw(screen) } diff --git a/client/game/action.go b/client/game/action.go new file mode 100644 index 0000000..51fefb2 --- /dev/null +++ b/client/game/action.go @@ -0,0 +1,179 @@ +package game + +import ( + "log/slog" + "time" + + "github.com/xescugc/go-flux" + "github.com/xescugc/maze-wars/action" + cutils "github.com/xescugc/maze-wars/client/utils" + "github.com/xescugc/maze-wars/store" + "github.com/xescugc/maze-wars/utils" +) + +// ActionDispatcher is in charge of dispatching actions to the +// application dispatcher +type ActionDispatcher struct { + dispatcher *flux.Dispatcher + store *store.Store + logger *slog.Logger + + wsSend func(a *action.Action) +} + +// NewActionDispatcher initializes the action dispatcher +// with the give dispatcher +func NewActionDispatcher(d *flux.Dispatcher, s *store.Store, wsSendFn func(a *action.Action), l *slog.Logger) *ActionDispatcher { + return &ActionDispatcher{ + dispatcher: d, + store: s, + logger: l, + wsSend: wsSendFn, + } +} + +// Dispatch is a helper to access to the internal dispatch directly with an action. +// This should only be used from the WS Handler to forward server actions directly +func (ac *ActionDispatcher) Dispatch(a *action.Action) { + b := time.Now() + defer utils.LogTime(ac.logger, b, "action dispatched", "action", a.Type) + + ac.dispatcher.Dispatch(a) +} + +// CursorMove dispatches an action of moving the Cursor +// to the new x,y coordinates +func (ac *ActionDispatcher) CursorMove(x, y int) { + cma := action.NewCursorMove(x, y) + ac.Dispatch(cma) +} + +// SummonUnit summons the 'unit' from the player id 'pid' to the line +// 'plid' and with the current line id 'clid' +func (ac *ActionDispatcher) SummonUnit(unit, pid string, plid, clid int) { + sua := action.NewSummonUnit(unit, pid, plid, clid) + ac.wsSend(sua) + //ac.Dispatch(sua) +} + +// TPS is the call for every TPS event +func (ac *ActionDispatcher) TPS() { + tpsa := action.NewTPS() + ac.Dispatch(tpsa) +} + +// RemoveUnit removes the unit with the id 'uid' +func (ac *ActionDispatcher) RemoveUnit(uid string) { + rua := action.NewRemoveUnit(uid) + ac.wsSend(rua) + ac.Dispatch(rua) +} + +// StealLive removes one live from the player with id 'fpid' and +// adds it to the player with id 'tpid' +func (ac *ActionDispatcher) StealLive(fpid, tpid string) { + sla := action.NewStealLive(fpid, tpid) + ac.wsSend(sla) + ac.Dispatch(sla) +} + +// CameraZoom zooms the camera the direction 'd' +func (ac *ActionDispatcher) CameraZoom(d int) { + cza := action.NewCameraZoom(d) + ac.Dispatch(cza) +} + +// 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) { + // 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) + ac.wsSend(pta) + } + //ac.Dispatch(pta) +} + +// RemoveTower removes the tower tid +func (ac *ActionDispatcher) RemoveTower(pid, tid, tt string) { + rta := action.NewRemoveTower(pid, tid, tt) + ac.wsSend(rta) + //ac.Dispatch(rta) +} + +// SelectTower selects the tower 't' on the position x, y +func (ac *ActionDispatcher) SelectTower(t string, x, y int) { + sta := action.NewSelectTower(t, x, y) + ac.Dispatch(sta) +} + +// SelectTower selects the tower 't' on the position x, y +func (ac *ActionDispatcher) SelectedTowerInvalid(i bool) { + sta := action.NewSelectedTowerInvalid(i) + ac.Dispatch(sta) +} + +// DeselectTower cleans the current selected tower +func (ac *ActionDispatcher) DeselectTower(t string) { + dsta := action.NewDeselectTower(t) + ac.Dispatch(dsta) +} + +// IncomeTick a new tick for the income +func (ac *ActionDispatcher) IncomeTick() { + it := action.NewIncomeTick() + ac.Dispatch(it) +} + +// TowerAttack issues a attack to the Unit with uid +func (ac *ActionDispatcher) TowerAttack(uid, tt string) { + ta := action.NewTowerAttack(uid, tt) + ac.wsSend(ta) + ac.Dispatch(ta) +} + +// UnitKilled adds gold to the user +func (ac *ActionDispatcher) UnitKilled(pid, ut string) { + uk := action.NewUnitKilled(pid, ut) + ac.wsSend(uk) + ac.Dispatch(uk) +} + +func (ac *ActionDispatcher) RemovePlayer(pid string) { + rpa := action.NewRemovePlayer(pid) + ac.wsSend(rpa) + ac.Dispatch(rpa) + ac.Dispatch(action.NewNavigateTo(cutils.LobbyRoute)) +} + +// OpenTowerMenu when a tower is clicked and the menu of +// the tower is displayed +func (ac *ActionDispatcher) OpenTowerMenu(tid string) { + otm := action.NewOpenTowerMenu(tid) + ac.Dispatch(otm) +} + +// CloseTowerMenu when a tower menu needs to be closed +func (ac *ActionDispatcher) CloseTowerMenu() { + ctm := action.NewCloseTowerMenu() + ac.Dispatch(ctm) +} + +// ChangeUnitLine will move the unit to the next line +func (ac *ActionDispatcher) ChangeUnitLine(uid string) { + cula := action.NewChangeUnitLine(uid) + ac.wsSend(cula) + ac.Dispatch(cula) +} + +func (ac *ActionDispatcher) ToggleStats() { + tsa := action.NewToggleStats() + + ac.Dispatch(tsa) +} + +// GoHome will move the camera to the current player home line +func (ac *ActionDispatcher) GoHome() { + gha := action.NewGoHome() + ac.Dispatch(gha) +} diff --git a/client/camera.go b/client/game/camera.go similarity index 99% rename from client/camera.go rename to client/game/camera.go index d3b4a19..f980d73 100644 --- a/client/camera.go +++ b/client/game/camera.go @@ -1,4 +1,4 @@ -package client +package game import ( "log/slog" diff --git a/client/game/game.go b/client/game/game.go new file mode 100644 index 0000000..8e5e07a --- /dev/null +++ b/client/game/game.go @@ -0,0 +1,60 @@ +package game + +import ( + "log/slog" + "time" + + "github.com/hajimehoshi/ebiten/v2" + "github.com/xescugc/maze-wars/store" + "github.com/xescugc/maze-wars/utils" +) + +var ( + // actionDispatcher is the main dispatcher of the application + // all the actions have to be registered to it + actionDispatcher *ActionDispatcher +) + +type Game struct { + Store *store.Store + + Camera *CameraStore + HUD *HUDStore + Lines *Lines + + Map *Map + + Logger *slog.Logger +} + +func New(s *store.Store, ad *ActionDispatcher, l *slog.Logger) *Game { + actionDispatcher = ad + return &Game{ + Store: s, + Logger: l, + } +} + +func (g *Game) Update() error { + b := time.Now() + defer utils.LogTime(g.Logger, b, "game update") + + g.Map.Update() + g.Camera.Update() + g.Lines.Update() + g.HUD.Update() + + actionDispatcher.TPS() + + return nil +} + +func (g *Game) Draw(screen *ebiten.Image) { + b := time.Now() + defer utils.LogTime(g.Logger, b, "game draw") + + g.Map.Draw(screen) + g.Camera.Draw(screen) + g.HUD.Draw(screen) + g.Lines.Draw(screen) +} diff --git a/client/hud.go b/client/game/hud.go similarity index 95% rename from client/hud.go rename to client/game/hud.go index 4ebe054..5666506 100644 --- a/client/hud.go +++ b/client/game/hud.go @@ -1,4 +1,4 @@ -package client +package game import ( "fmt" @@ -16,6 +16,7 @@ import ( "github.com/hajimehoshi/ebiten/v2/inpututil" "github.com/xescugc/go-flux" "github.com/xescugc/maze-wars/action" + cutils "github.com/xescugc/maze-wars/client/utils" "github.com/xescugc/maze-wars/store" "github.com/xescugc/maze-wars/tower" "github.com/xescugc/maze-wars/unit" @@ -44,7 +45,6 @@ type HUDState struct { TowerOpenMenuID string LastCursorPosition utils.Object - CheckedPath bool ShowStats bool } @@ -346,9 +346,6 @@ func (hs *HUDStore) Reduce(state, a interface{}) interface{} { hstate.SelectedTower.X, hstate.SelectedTower.Y = fixPosition(cs, nx, ny) } - // If it has moved we set the CheckedPath as not checked as it's only checked - // when the Cursor has not moved - hstate.CheckedPath = false case action.PlaceTower, action.DeselectTower: hstate.SelectedTower = nil case action.SelectedTowerInvalid: @@ -359,8 +356,6 @@ func (hs *HUDStore) Reduce(state, a interface{}) interface{} { hstate.TowerOpenMenuID = act.OpenTowerMenu.TowerID case action.CloseTowerMenu: hstate.TowerOpenMenuID = "" - case action.CheckedPath: - hstate.CheckedPath = act.CheckedPath.Checked case action.ToggleStats: hstate.ShowStats = !hstate.ShowStats default: @@ -457,9 +452,9 @@ func (hs *HUDStore) buildUI() { ) homeBtnW := widget.NewButton( - widget.ButtonOpts.Image(buttonImage), + widget.ButtonOpts.Image(cutils.ButtonImage), - widget.ButtonOpts.Text("HOME(F1)", smallFont, &widget.ButtonTextColor{ + widget.ButtonOpts.Text("HOME(F1)", cutils.SmallFont, &widget.ButtonTextColor{ Idle: color.NRGBA{0xdf, 0xf4, 0xff, 0xff}, }), @@ -477,9 +472,9 @@ func (hs *HUDStore) buildUI() { ) statsBtnW := widget.NewButton( - widget.ButtonOpts.Image(buttonImage), + widget.ButtonOpts.Image(cutils.ButtonImage), - widget.ButtonOpts.Text("STATS", smallFont, &widget.ButtonTextColor{ + widget.ButtonOpts.Text("STATS", cutils.SmallFont, &widget.ButtonTextColor{ Idle: color.NRGBA{0xdf, 0xf4, 0xff, 0xff}, }), @@ -524,7 +519,7 @@ func (hs *HUDStore) buildUI() { widget.SliderOpts.Images(&widget.SliderTrackImage{ Idle: image.NewNineSliceColor(color.NRGBA{100, 100, 100, 255}), Hover: image.NewNineSliceColor(color.NRGBA{100, 100, 100, 255}), - }, buttonImage), + }, cutils.ButtonImage), widget.SliderOpts.MinHandleSize(5), // Set how wide the track should be widget.SliderOpts.TrackPadding(widget.NewInsetsSimple(2)), @@ -533,7 +528,7 @@ func (hs *HUDStore) buildUI() { widget.ListOpts.HideHorizontalSlider(), widget.ListOpts.HideVerticalSlider(), // Set the font for the list options - widget.ListOpts.EntryFontFace(smallFont), + widget.ListOpts.EntryFontFace(cutils.SmallFont), // Set the colors for the list widget.ListOpts.EntryColor(&widget.ListEntryColor{ Selected: color.NRGBA{0, 255, 0, 255}, // Foreground color for the unfocused selected entry @@ -561,7 +556,7 @@ func (hs *HUDStore) buildUI() { ) incomeTextW := widget.NewText( - widget.TextOpts.Text("Gold: 40 Income Timer: 15s", smallFont, color.White), + widget.TextOpts.Text("Gold: 40 Income Timer: 15s", cutils.SmallFont, color.White), widget.TextOpts.Position(widget.TextPositionCenter, widget.TextPositionCenter), widget.TextOpts.WidgetOpts( widget.WidgetOpts.LayoutData(widget.RowLayoutData{ @@ -604,7 +599,7 @@ func (hs *HUDStore) buildUI() { toolTxt := widget.NewText( widget.TextOpts.Position(widget.TextPositionCenter, widget.TextPositionCenter), - widget.TextOpts.Text(fmt.Sprintf("Gold: %d\nHP: %.0f\nIncome: %d\nKeybind: %s", u.Gold, u.Health, u.Income, u.Keybind), smallFont, color.White), + widget.TextOpts.Text(fmt.Sprintf("Gold: %d\nHP: %.0f\nIncome: %d\nKeybind: %s", u.Gold, u.Health, u.Income, u.Keybind), cutils.SmallFont, color.White), widget.TextOpts.WidgetOpts(widget.WidgetOpts.MinSize(100, 0)), ) tooltipContainer.AddChild(toolTxt) @@ -631,7 +626,7 @@ func (hs *HUDStore) buildUI() { ), // specify the images to sue - widget.ButtonOpts.Image(buttonImageFromImage(imagesCache.Get(u.FacesetKey()))), + widget.ButtonOpts.Image(cutils.ButtonImageFromImage(imagesCache.Get(u.FacesetKey()))), // add a handler that reacts to clicking the button widget.ButtonOpts.ClickedHandler(func(u *unit.Unit) func(args *widget.ButtonClickedEventArgs) { @@ -673,7 +668,7 @@ func (hs *HUDStore) buildUI() { toolTxt := widget.NewText( widget.TextOpts.Position(widget.TextPositionCenter, widget.TextPositionCenter), - widget.TextOpts.Text(fmt.Sprintf("Gold: %d\nRange: %.0f\nDamage: %.0f\nKeybind: %s", t.Gold, t.Range, t.Damage, t.Keybind), smallFont, color.White), + widget.TextOpts.Text(fmt.Sprintf("Gold: %d\nRange: %.0f\nDamage: %.0f\nKeybind: %s", t.Gold, t.Range, t.Damage, t.Keybind), cutils.SmallFont, color.White), widget.TextOpts.WidgetOpts(widget.WidgetOpts.MinSize(100, 0)), ) tooltipContainer.AddChild(toolTxt) @@ -699,7 +694,7 @@ func (hs *HUDStore) buildUI() { ), // specify the images to sue - widget.ButtonOpts.Image(buttonImageFromImage(imagesCache.Get(t.FacesetKey()))), + widget.ButtonOpts.Image(cutils.ButtonImageFromImage(imagesCache.Get(t.FacesetKey()))), // add a handler that reacts to clicking the button widget.ButtonOpts.ClickedHandler(func(t *tower.Tower) func(args *widget.ButtonClickedEventArgs) { @@ -715,8 +710,8 @@ func (hs *HUDStore) buildUI() { tabTowers.AddChild(towersC) tabBook := widget.NewTabBook( - widget.TabBookOpts.TabButtonImage(buttonImage), - widget.TabBookOpts.TabButtonText(smallFont, &widget.ButtonTextColor{Idle: color.White, Disabled: color.White}), + widget.TabBookOpts.TabButtonImage(cutils.ButtonImage), + widget.TabBookOpts.TabButtonText(cutils.SmallFont, &widget.ButtonTextColor{Idle: color.White, Disabled: color.White}), widget.TabBookOpts.TabButtonSpacing(0), widget.TabBookOpts.ContainerOpts( widget.ContainerOpts.WidgetOpts(widget.WidgetOpts.LayoutData(widget.AnchorLayoutData{ @@ -757,9 +752,9 @@ func (hs *HUDStore) buildUI() { }), ), - widget.ButtonOpts.Image(buttonImage), + widget.ButtonOpts.Image(cutils.ButtonImage), - widget.ButtonOpts.Text("LEAVE", smallFont, &widget.ButtonTextColor{ + widget.ButtonOpts.Text("LEAVE", cutils.SmallFont, &widget.ButtonTextColor{ Idle: color.NRGBA{0xdf, 0xf4, 0xff, 0xff}, }), @@ -782,7 +777,7 @@ func (hs *HUDStore) buildUI() { ) winLoseTextW := widget.NewText( - widget.TextOpts.Text("", smallFont, color.White), + widget.TextOpts.Text("", cutils.SmallFont, color.White), widget.TextOpts.Position(widget.TextPositionCenter, widget.TextPositionCenter), widget.TextOpts.WidgetOpts( widget.WidgetOpts.LayoutData(widget.AnchorLayoutData{ diff --git a/client/images.go b/client/game/images.go similarity index 98% rename from client/images.go rename to client/game/images.go index a876b89..e501a58 100644 --- a/client/images.go +++ b/client/game/images.go @@ -1,4 +1,4 @@ -package client +package game import ( "fmt" diff --git a/client/lines.go b/client/game/lines.go similarity index 99% rename from client/lines.go rename to client/game/lines.go index 1dce523..f84be6f 100644 --- a/client/lines.go +++ b/client/game/lines.go @@ -1,4 +1,4 @@ -package client +package game import ( "bytes" diff --git a/client/map.go b/client/game/map.go similarity index 66% rename from client/map.go rename to client/game/map.go index 93de94c..8c32f00 100644 --- a/client/map.go +++ b/client/game/map.go @@ -1,10 +1,11 @@ -package client +package game import ( "image" "time" "github.com/hajimehoshi/ebiten/v2" + cutils "github.com/xescugc/maze-wars/client/utils" "github.com/xescugc/maze-wars/utils" ) @@ -49,23 +50,23 @@ func (m *Map) Draw(screen *ebiten.Image) { for i := x - 4; i <= x+(18*16)+3; i++ { // We draw 3 lines so it's kind of **bold** // and it's easier to see - screen.Set(int(i-cs.X), int(y-cs.Y-4), green) - screen.Set(int(i-cs.X), int(y-cs.Y-3), green) - screen.Set(int(i-cs.X), int(y-cs.Y-2), green) + screen.Set(int(i-cs.X), int(y-cs.Y-4), cutils.Green) + screen.Set(int(i-cs.X), int(y-cs.Y-3), cutils.Green) + screen.Set(int(i-cs.X), int(y-cs.Y-2), cutils.Green) - screen.Set(int(i-cs.X), int((y+86*16)-cs.Y+3), green) - screen.Set(int(i-cs.X), int((y+86*16)-cs.Y+2), green) - screen.Set(int(i-cs.X), int((y+86*16)-cs.Y+1), green) + screen.Set(int(i-cs.X), int((y+86*16)-cs.Y+3), cutils.Green) + screen.Set(int(i-cs.X), int((y+86*16)-cs.Y+2), cutils.Green) + screen.Set(int(i-cs.X), int((y+86*16)-cs.Y+1), cutils.Green) } // Color Left and Right for i := y - 1; i <= y+(86*16); i++ { - screen.Set(int(x-cs.X-4), int(i-cs.Y), green) - screen.Set(int(x-cs.X-3), int(i-cs.Y), green) - screen.Set(int(x-cs.X-2), int(i-cs.Y), green) + screen.Set(int(x-cs.X-4), int(i-cs.Y), cutils.Green) + screen.Set(int(x-cs.X-3), int(i-cs.Y), cutils.Green) + screen.Set(int(x-cs.X-2), int(i-cs.Y), cutils.Green) - screen.Set(int((x+18*16)-cs.X+3), int(i-cs.Y), green) - screen.Set(int((x+18*16)-cs.X+2), int(i-cs.Y), green) - screen.Set(int((x+18*16)-cs.X+1), int(i-cs.Y), green) + screen.Set(int((x+18*16)-cs.X+3), int(i-cs.Y), cutils.Green) + screen.Set(int((x+18*16)-cs.X+2), int(i-cs.Y), cutils.Green) + screen.Set(int((x+18*16)-cs.X+1), int(i-cs.Y), cutils.Green) } } diff --git a/client/lobby.go b/client/lobby.go index 5294467..1b4cd49 100644 --- a/client/lobby.go +++ b/client/lobby.go @@ -12,6 +12,7 @@ import ( "github.com/hajimehoshi/ebiten/v2" "github.com/xescugc/go-flux" "github.com/xescugc/maze-wars/action" + cutils "github.com/xescugc/maze-wars/client/utils" "github.com/xescugc/maze-wars/utils" ) @@ -107,7 +108,7 @@ func (ls *LobbyStore) buildUI() { } titleW := widget.NewText( - widget.TextOpts.Text("Maze Wars", normalFont, color.White), + widget.TextOpts.Text("Maze Wars", cutils.NormalFont, color.White), widget.TextOpts.Position(widget.TextPositionCenter, widget.TextPositionCenter), widget.TextOpts.WidgetOpts( widget.WidgetOpts.LayoutData(widget.RowLayoutData{ @@ -119,7 +120,7 @@ func (ls *LobbyStore) buildUI() { ) textPlayersW := widget.NewText( - widget.TextOpts.Text("", smallFont, color.White), + widget.TextOpts.Text("", cutils.SmallFont, color.White), widget.TextOpts.Position(widget.TextPositionCenter, widget.TextPositionCenter), widget.TextOpts.WidgetOpts( widget.WidgetOpts.LayoutData(widget.RowLayoutData{ @@ -142,7 +143,7 @@ func (ls *LobbyStore) buildUI() { widget.ButtonOpts.Image(buttonImageL), // specify the button's text, the font face, and the color - widget.ButtonOpts.Text("Play", smallFont, &widget.ButtonTextColor{ + widget.ButtonOpts.Text("Play", cutils.SmallFont, &widget.ButtonTextColor{ Idle: color.NRGBA{0xdf, 0xf4, 0xff, 0xff}, }), diff --git a/client/new.go b/client/new.go index f7a2016..314daba 100644 --- a/client/new.go +++ b/client/new.go @@ -9,9 +9,6 @@ import ( "github.com/hajimehoshi/ebiten/v2" "github.com/xescugc/maze-wars/action" - "github.com/xescugc/maze-wars/assets" - "golang.org/x/image/font" - "golang.org/x/image/font/opentype" "nhooyr.io/websocket" "nhooyr.io/websocket/wsjson" ) @@ -22,35 +19,11 @@ var ( actionDispatcher *ActionDispatcher wsc *websocket.Conn - - normalFont font.Face - smallFont font.Face ) func init() { rand.Seed(time.Now().UnixNano()) - // Initialize Font - tt, err := opentype.Parse(assets.Kongtext_ttf) - if err != nil { - log.Fatal(err) - } - - const dpi = 72 - normalFont, err = opentype.NewFace(tt, &opentype.FaceOptions{ - Size: 24, - DPI: dpi, - Hinting: font.HintingFull, - }) - smallFont, err = opentype.NewFace(tt, &opentype.FaceOptions{ - Size: 16, - DPI: dpi, - Hinting: font.HintingFull, - }) - if err != nil { - log.Fatal(err) - } - } func New(ctx context.Context, ad *ActionDispatcher, rs *RouterStore, opt Options) error { diff --git a/client/router.go b/client/router.go index 754f930..4a960c7 100644 --- a/client/router.go +++ b/client/router.go @@ -7,16 +7,11 @@ import ( "github.com/hajimehoshi/ebiten/v2" "github.com/xescugc/go-flux" "github.com/xescugc/maze-wars/action" + "github.com/xescugc/maze-wars/client/game" + cutils "github.com/xescugc/maze-wars/client/utils" "github.com/xescugc/maze-wars/utils" ) -const ( - SignUpRoute = "sign_up" - LobbyRoute = "lobby" - GameRoute = "game" - WaitingRoomRoute = "waiting_room" -) - type RouterStore struct { *flux.ReduceStore @@ -41,7 +36,7 @@ func NewRouterStore(d *flux.Dispatcher, su *SignUpStore, ls *LobbyStore, wr *Wai } rs.ReduceStore = flux.NewReduceStore(d, rs.Reduce, RouterState{ - Route: SignUpRoute, + Route: cutils.SignUpRoute, //Route: GameRoute, }) @@ -54,13 +49,13 @@ func (rs *RouterStore) Update() error { rstate := rs.GetState().(RouterState) switch rstate.Route { - case SignUpRoute: + case cutils.SignUpRoute: rs.signUp.Update() - case LobbyRoute: + case cutils.LobbyRoute: rs.lobby.Update() - case WaitingRoomRoute: + case cutils.WaitingRoomRoute: rs.waitingRoom.Update() - case GameRoute: + case cutils.GameRoute: rs.game.Update() } return nil @@ -72,19 +67,19 @@ func (rs *RouterStore) Draw(screen *ebiten.Image) { rstate := rs.GetState().(RouterState) switch rstate.Route { - case SignUpRoute: + case cutils.SignUpRoute: rs.signUp.Draw(screen) - case LobbyRoute: + case cutils.LobbyRoute: rs.lobby.Draw(screen) - case WaitingRoomRoute: + case cutils.WaitingRoomRoute: rs.waitingRoom.Draw(screen) - case GameRoute: + case cutils.GameRoute: rs.game.Draw(screen) } } func (rs *RouterStore) Layout(outsideWidth, outsideHeight int) (screenWidth, screenHeight int) { - cs := rs.game.Camera.GetState().(CameraState) + cs := rs.game.Game.Camera.GetState().(game.CameraState) if cs.W != float64(outsideWidth) || cs.H != float64(outsideHeight) { actionDispatcher.WindowResizing(outsideWidth, outsideHeight) } @@ -106,7 +101,7 @@ func (rs *RouterStore) Reduce(state, a interface{}) interface{} { case action.NavigateTo: rstate.Route = act.NavigateTo.Route case action.StartGame: - rstate.Route = GameRoute + rstate.Route = cutils.GameRoute } return rstate diff --git a/client/sign_up.go b/client/sign_up.go index dfa0cd2..522a9f4 100644 --- a/client/sign_up.go +++ b/client/sign_up.go @@ -10,25 +10,19 @@ import ( "github.com/ebitenui/ebitenui/widget" "github.com/hajimehoshi/ebiten/v2" - "github.com/hajimehoshi/ebiten/v2/colorm" "github.com/xescugc/go-flux" "github.com/xescugc/maze-wars/action" + cutils "github.com/xescugc/maze-wars/client/utils" "github.com/xescugc/maze-wars/store" "github.com/xescugc/maze-wars/utils" ) -var ( - buttonImage, _ = loadButtonImage() -) - type SignUpStore struct { *flux.ReduceStore Store *store.Store Logger *slog.Logger - Camera *CameraStore - ui *ebitenui.UI inputErrorW *widget.Text } @@ -114,7 +108,7 @@ func (su *SignUpStore) buildUI() { } titleW := widget.NewText( - widget.TextOpts.Text("Maze Wars", normalFont, color.White), + widget.TextOpts.Text("Maze Wars", cutils.NormalFont, color.White), widget.TextOpts.Position(widget.TextPositionCenter, widget.TextPositionCenter), widget.TextOpts.WidgetOpts( widget.WidgetOpts.LayoutData(widget.RowLayoutData{ @@ -146,7 +140,7 @@ func (su *SignUpStore) buildUI() { }), //Set the font face and size for the widget - widget.TextInputOpts.Face(smallFont), + widget.TextInputOpts.Face(cutils.SmallFont), //Set the colors for the text and caret widget.TextInputOpts.Color(&widget.TextInputColor{ @@ -161,7 +155,7 @@ func (su *SignUpStore) buildUI() { //Set the font and width of the caret widget.TextInputOpts.CaretOpts( - widget.CaretOpts.Size(smallFont, 2), + widget.CaretOpts.Size(cutils.SmallFont, 2), ), //This text is displayed if the input is empty @@ -175,7 +169,7 @@ func (su *SignUpStore) buildUI() { ) inputErrorW := widget.NewText( - widget.TextOpts.Text(su.GetState().(SignUpState).Error, normalFont, red), + widget.TextOpts.Text(su.GetState().(SignUpState).Error, cutils.NormalFont, cutils.Red), widget.TextOpts.Position(widget.TextPositionCenter, widget.TextPositionCenter), widget.TextOpts.WidgetOpts( widget.WidgetOpts.LayoutData(widget.RowLayoutData{ @@ -195,10 +189,10 @@ func (su *SignUpStore) buildUI() { ), // specify the images to sue - widget.ButtonOpts.Image(buttonImage), + widget.ButtonOpts.Image(cutils.ButtonImage), // specify the button's text, the font face, and the color - widget.ButtonOpts.Text("Enter", smallFont, &widget.ButtonTextColor{ + widget.ButtonOpts.Text("Enter", cutils.SmallFont, &widget.ButtonTextColor{ Idle: color.NRGBA{0xdf, 0xf4, 0xff, 0xff}, }), @@ -228,34 +222,3 @@ func (su *SignUpStore) buildUI() { rootContainer.AddChild(titleInputC) } - -func loadButtonImage() (*widget.ButtonImage, error) { - idle := euiimage.NewNineSliceColor(color.NRGBA{R: 170, G: 170, B: 180, A: 255}) - - hover := euiimage.NewNineSliceColor(color.NRGBA{R: 130, G: 130, B: 150, A: 255}) - - pressed := euiimage.NewNineSliceColor(color.NRGBA{R: 100, G: 100, B: 120, A: 255}) - - return &widget.ButtonImage{ - Idle: idle, - Hover: hover, - Pressed: pressed, - }, nil -} - -func buttonImageFromImage(i *ebiten.Image) *widget.ButtonImage { - nsi := euiimage.NewNineSliceSimple(i, i.Bounds().Dx(), i.Bounds().Dy()) - - cm := colorm.ColorM{} - cm.Scale(2, 0.5, 0.5, 0.9) - - ni := ebiten.NewImage(i.Bounds().Dx(), i.Bounds().Dy()) - colorm.DrawImage(ni, i, cm, nil) - dsi := euiimage.NewNineSliceSimple(ni, ni.Bounds().Dx(), ni.Bounds().Dy()) - return &widget.ButtonImage{ - Idle: nsi, - Hover: nsi, - Pressed: nsi, - Disabled: dsi, - } -} diff --git a/client/utils/button.go b/client/utils/button.go new file mode 100644 index 0000000..d7b2d76 --- /dev/null +++ b/client/utils/button.go @@ -0,0 +1,45 @@ +package utils + +import ( + "image/color" + + euiimage "github.com/ebitenui/ebitenui/image" + "github.com/ebitenui/ebitenui/widget" + "github.com/hajimehoshi/ebiten/v2" + "github.com/hajimehoshi/ebiten/v2/colorm" +) + +var ( + ButtonImage = loadButtonImage() +) + +func loadButtonImage() *widget.ButtonImage { + idle := euiimage.NewNineSliceColor(color.NRGBA{R: 170, G: 170, B: 180, A: 255}) + + hover := euiimage.NewNineSliceColor(color.NRGBA{R: 130, G: 130, B: 150, A: 255}) + + pressed := euiimage.NewNineSliceColor(color.NRGBA{R: 100, G: 100, B: 120, A: 255}) + + return &widget.ButtonImage{ + Idle: idle, + Hover: hover, + Pressed: pressed, + } +} + +func ButtonImageFromImage(i *ebiten.Image) *widget.ButtonImage { + nsi := euiimage.NewNineSliceSimple(i, i.Bounds().Dx(), i.Bounds().Dy()) + + cm := colorm.ColorM{} + cm.Scale(2, 0.5, 0.5, 0.9) + + ni := ebiten.NewImage(i.Bounds().Dx(), i.Bounds().Dy()) + colorm.DrawImage(ni, i, cm, nil) + dsi := euiimage.NewNineSliceSimple(ni, ni.Bounds().Dx(), ni.Bounds().Dy()) + return &widget.ButtonImage{ + Idle: nsi, + Hover: nsi, + Pressed: nsi, + Disabled: dsi, + } +} diff --git a/client/utils/colors.go b/client/utils/colors.go new file mode 100644 index 0000000..8101d43 --- /dev/null +++ b/client/utils/colors.go @@ -0,0 +1,8 @@ +package utils + +import "image/color" + +var ( + Green = color.RGBA{0x00, 0x80, 0x00, 0xff} + Red = color.RGBA{0x80, 0x00, 0x00, 0xff} +) diff --git a/client/utils/font.go b/client/utils/font.go new file mode 100644 index 0000000..90d4790 --- /dev/null +++ b/client/utils/font.go @@ -0,0 +1,38 @@ +package utils + +import ( + "log" + + "github.com/xescugc/maze-wars/assets" + "golang.org/x/image/font" + "golang.org/x/image/font/opentype" +) + +var ( + NormalFont font.Face + SmallFont font.Face +) + +func init() { + // Initialize Font + tt, err := opentype.Parse(assets.Kongtext_ttf) + if err != nil { + log.Fatal(err) + } + + const dpi = 72 + NormalFont, err = opentype.NewFace(tt, &opentype.FaceOptions{ + Size: 24, + DPI: dpi, + Hinting: font.HintingFull, + }) + SmallFont, err = opentype.NewFace(tt, &opentype.FaceOptions{ + Size: 16, + DPI: dpi, + Hinting: font.HintingFull, + }) + if err != nil { + log.Fatal(err) + } + +} diff --git a/client/utils/routes.go b/client/utils/routes.go new file mode 100644 index 0000000..451960c --- /dev/null +++ b/client/utils/routes.go @@ -0,0 +1,8 @@ +package utils + +const ( + SignUpRoute = "sign_up" + LobbyRoute = "lobby" + GameRoute = "game" + WaitingRoomRoute = "waiting_room" +) diff --git a/client/waiting_room.go b/client/waiting_room.go index 5eb03c3..b319757 100644 --- a/client/waiting_room.go +++ b/client/waiting_room.go @@ -11,6 +11,7 @@ import ( "github.com/hajimehoshi/ebiten/v2" "github.com/xescugc/go-flux" "github.com/xescugc/maze-wars/action" + cutils "github.com/xescugc/maze-wars/client/utils" "github.com/xescugc/maze-wars/utils" ) @@ -108,7 +109,7 @@ func (wr *WaitingRoomStore) buildUI() { } titleW := widget.NewText( - widget.TextOpts.Text("Waiting for players to join", normalFont, color.White), + widget.TextOpts.Text("Waiting for players to join", cutils.NormalFont, color.White), widget.TextOpts.Position(widget.TextPositionCenter, widget.TextPositionCenter), widget.TextOpts.WidgetOpts( widget.WidgetOpts.LayoutData(widget.RowLayoutData{ @@ -120,7 +121,7 @@ func (wr *WaitingRoomStore) buildUI() { ) textPlayersW := widget.NewText( - widget.TextOpts.Text("", smallFont, color.White), + widget.TextOpts.Text("", cutils.SmallFont, color.White), widget.TextOpts.Position(widget.TextPositionCenter, widget.TextPositionCenter), widget.TextOpts.WidgetOpts( widget.WidgetOpts.LayoutData(widget.RowLayoutData{ @@ -131,7 +132,7 @@ func (wr *WaitingRoomStore) buildUI() { ) textColdownW := widget.NewText( - widget.TextOpts.Text("", smallFont, color.White), + widget.TextOpts.Text("", cutils.SmallFont, color.White), widget.TextOpts.Position(widget.TextPositionCenter, widget.TextPositionCenter), widget.TextOpts.WidgetOpts( widget.WidgetOpts.LayoutData(widget.RowLayoutData{ @@ -151,10 +152,10 @@ func (wr *WaitingRoomStore) buildUI() { ), // specify the images to sue - widget.ButtonOpts.Image(buttonImage), + widget.ButtonOpts.Image(cutils.ButtonImage), // specify the button's text, the font face, and the color - widget.ButtonOpts.Text("EXIT", smallFont, &widget.ButtonTextColor{ + widget.ButtonOpts.Text("EXIT", cutils.SmallFont, &widget.ButtonTextColor{ Idle: color.NRGBA{0xdf, 0xf4, 0xff, 0xff}, }), diff --git a/client/wasm/main.go b/client/wasm/main.go index 34dc149..c5307bf 100644 --- a/client/wasm/main.go +++ b/client/wasm/main.go @@ -12,6 +12,7 @@ import ( "github.com/xescugc/go-flux" "github.com/xescugc/maze-wars/client" + "github.com/xescugc/maze-wars/client/game" "github.com/xescugc/maze-wars/store" ) @@ -44,22 +45,21 @@ func NewClient() js.Func { ad := client.NewActionDispatcher(d, s, l, opt) - g := client.NewGame(s, l) + g := client.NewGame(s, d, l) - // TODO: Change this to pass the specific store needed instead of all the game object - cs := client.NewCameraStore(d, s, l, screenW, screenH) - g.Camera = cs - g.Lines, err = client.NewLines(g) + cs := game.NewCameraStore(d, s, l, screenW, screenH) + g.Game.Camera = cs + g.Game.Lines, err = game.NewLines(g.Game) if err != nil { return fmt.Errorf("failed to initialize Lines: %w", err) } - g.HUD, err = client.NewHUDStore(d, g) + g.Game.HUD, err = game.NewHUDStore(d, g.Game) if err != nil { return fmt.Errorf("failed to initialize HUDStore: %w", err) } - g.Map = client.NewMap(g) + g.Game.Map = game.NewMap(g.Game) us := client.NewUserStore(d) cls := client.NewStore(s, us) diff --git a/cmd/client/main.go b/cmd/client/main.go index 3c59c57..a7359a1 100644 --- a/cmd/client/main.go +++ b/cmd/client/main.go @@ -11,6 +11,7 @@ import ( "github.com/spf13/cobra" "github.com/xescugc/go-flux" "github.com/xescugc/maze-wars/client" + "github.com/xescugc/maze-wars/client/game" "github.com/xescugc/maze-wars/store" ) @@ -57,21 +58,21 @@ var ( s := store.NewStore(d, l) ad := client.NewActionDispatcher(d, s, l, opt) - g := client.NewGame(s, l) + g := client.NewGame(s, d, l) - cs := client.NewCameraStore(d, s, l, screenW, screenH) - g.Camera = cs - g.Lines, err = client.NewLines(g) + cs := game.NewCameraStore(d, s, l, screenW, screenH) + g.Game.Camera = cs + g.Game.Lines, err = game.NewLines(g.Game) if err != nil { return fmt.Errorf("failed to initialize Lines: %w", err) } - g.HUD, err = client.NewHUDStore(d, g) + g.Game.HUD, err = game.NewHUDStore(d, g.Game) if err != nil { return fmt.Errorf("failed to initialize HUDStore: %w", err) } - g.Map = client.NewMap(g) + g.Game.Map = game.NewMap(g.Game) us := client.NewUserStore(d) cls := client.NewStore(s, us) diff --git a/server/assets/wasm/maze-wars.wasm b/server/assets/wasm/maze-wars.wasm index a2a3fc8..c2ba13b 100755 Binary files a/server/assets/wasm/maze-wars.wasm and b/server/assets/wasm/maze-wars.wasm differ diff --git a/store/reduce_test.go b/store/reduce_test.go index 9955a0c..cee3401 100644 --- a/store/reduce_test.go +++ b/store/reduce_test.go @@ -54,7 +54,6 @@ var ( actionsTested = map[string]struct{}{ // This are all the actions not involved on the Store action.CameraZoom.String(): {}, - action.CheckedPath.String(): {}, action.CloseTowerMenu.String(): {}, action.CursorMove.String(): {}, action.DeselectTower.String(): {},