From 72442072b6e0edc54efa33e948b98d62375ca673 Mon Sep 17 00:00:00 2001 From: Shantanu Jamble Date: Mon, 11 Nov 2024 19:12:48 -0800 Subject: [PATCH] Added systems and msgs for movement component --- cardinal/component/movement.go | 6 ++--- cardinal/main.go | 4 +++ cardinal/msg/movement_player.go | 14 +++++++++++ cardinal/system/movement_system.go | 30 ++++++++++++++--------- cardinal/system/player_spawner.go | 15 ++++++++++++ cardinal/system/utils.go | 39 ++++++++++++++++++++++++++++++ 6 files changed, 93 insertions(+), 15 deletions(-) diff --git a/cardinal/component/movement.go b/cardinal/component/movement.go index 2a62415..f7488bf 100644 --- a/cardinal/component/movement.go +++ b/cardinal/component/movement.go @@ -13,13 +13,13 @@ var Directions = map[int]Direction{ } type Location struct { - X float32 - Y float32 + X float64 + Y float64 } type Movement struct { CurrentDirection Direction - Velocity float32 + Velocity float64 CurrentLocation Location } diff --git a/cardinal/main.go b/cardinal/main.go index 089b0cb..1155c5c 100644 --- a/cardinal/main.go +++ b/cardinal/main.go @@ -40,6 +40,7 @@ func MustInitWorld(w *cardinal.World) { Must( cardinal.RegisterComponent[component.Player](w), cardinal.RegisterComponent[component.Health](w), + cardinal.RegisterComponent[component.Movement](w), ) // Register messages (user action) @@ -47,6 +48,7 @@ func MustInitWorld(w *cardinal.World) { Must( cardinal.RegisterMessage[msg.CreatePlayerMsg, msg.CreatePlayerResult](w, "create-player"), cardinal.RegisterMessage[msg.AttackPlayerMsg, msg.AttackPlayerMsgReply](w, "attack-player"), + cardinal.RegisterMessage[msg.MovementPlayerMsg, msg.MovementPlayerMsgReply](w, "movement-player"), ) // Register queries @@ -63,6 +65,8 @@ func MustInitWorld(w *cardinal.World) { system.AttackSystem, system.RegenSystem, system.PlayerSpawnerSystem, + system.MovementValidationSystem, + system.MovementSystem, )) Must(cardinal.RegisterInitSystems(w, diff --git a/cardinal/msg/movement_player.go b/cardinal/msg/movement_player.go index 6cb5870..a73aaee 100644 --- a/cardinal/msg/movement_player.go +++ b/cardinal/msg/movement_player.go @@ -1 +1,15 @@ package msg + +type MovementPlayerMsg struct { + TargetNickname string `json:"target"` + Velocity int `json:"velocity"` + Direction int `json:"direction"` + LocationX float64 `json:"locationX"` + LocationY float64 `json:"locationY"` +} + +type MovementPlayerMsgReply struct { + LocationX float64 `json:"locationX"` + LocationY float64 `json:"locationY"` + IsValid bool `json:"isValid"` +} diff --git a/cardinal/system/movement_system.go b/cardinal/system/movement_system.go index a1d6e6a..50cd7a3 100644 --- a/cardinal/system/movement_system.go +++ b/cardinal/system/movement_system.go @@ -2,6 +2,7 @@ package system import ( "fmt" + "math" "pkg.world.dev/world-engine/cardinal" "pkg.world.dev/world-engine/cardinal/search/filter" "pkg.world.dev/world-engine/cardinal/types" @@ -20,8 +21,8 @@ func MovementSystem(world cardinal.WorldContext) error { } // TODO: How to get delta time? - movement.CurrentLocation.X += movement.Velocity * float32(movement.CurrentDirection.X) - movement.CurrentLocation.Y += movement.Velocity * float32(movement.CurrentDirection.Y) + movement.CurrentLocation.X += movement.Velocity * float64(movement.CurrentDirection.X) + movement.CurrentLocation.Y += movement.Velocity * float64(movement.CurrentDirection.Y) if err := cardinal.SetComponent[comp.Movement](world, id, movement); err != nil { return true @@ -31,19 +32,24 @@ func MovementSystem(world cardinal.WorldContext) error { } func MovementValidationSystem(world cardinal.WorldContext) error { - return cardinal.EachMessage[msg.AttackPlayerMsg, msg.AttackPlayerMsgReply]( + return cardinal.EachMessage[msg.MovementPlayerMsg, msg.MovementPlayerMsgReply]( world, - func(attack cardinal.TxData[msg.AttackPlayerMsg]) (msg.AttackPlayerMsgReply, error) { - playerID, playerHealth, err := queryTargetPlayer(world, attack.Msg.TargetNickname) + func(movement cardinal.TxData[msg.MovementPlayerMsg]) (msg.MovementPlayerMsgReply, error) { + playerID, playerMovementData, err := queryTargetPlayerMovementData(world, movement.Msg.TargetNickname) if err != nil { - return msg.AttackPlayerMsgReply{}, fmt.Errorf("failed to inflict damage: %w", err) + return msg.MovementPlayerMsgReply{}, fmt.Errorf("failed to update movement: %w", err) } - - playerHealth.HP -= AttackDamage - if err := cardinal.SetComponent[comp.Health](world, playerID, playerHealth); err != nil { - return msg.AttackPlayerMsgReply{}, fmt.Errorf("failed to inflict damage: %w", err) + const errorTolerance float64 = 0.001 + if math.Abs(playerMovementData.CurrentLocation.X-movement.Msg.LocationX) > errorTolerance || + math.Abs(playerMovementData.CurrentLocation.Y-movement.Msg.LocationY) > errorTolerance { + return msg.MovementPlayerMsgReply{IsValid: false, LocationX: playerMovementData.CurrentLocation.X, LocationY: playerMovementData.CurrentLocation.Y}, nil + } else { + playerMovementData.CurrentLocation.X = movement.Msg.LocationX + playerMovementData.CurrentLocation.Y = movement.Msg.LocationY + if err := cardinal.SetComponent[comp.Movement](world, playerID, playerMovementData); err != nil { + return msg.MovementPlayerMsgReply{IsValid: false, LocationX: playerMovementData.CurrentLocation.X, LocationY: playerMovementData.CurrentLocation.Y}, fmt.Errorf("failed to update movement: %w", err) + } + return msg.MovementPlayerMsgReply{IsValid: true, LocationX: playerMovementData.CurrentLocation.X, LocationY: playerMovementData.CurrentLocation.Y}, nil } - - return msg.AttackPlayerMsgReply{Damage: AttackDamage}, nil }) } diff --git a/cardinal/system/player_spawner.go b/cardinal/system/player_spawner.go index e4755a8..710afcc 100644 --- a/cardinal/system/player_spawner.go +++ b/cardinal/system/player_spawner.go @@ -13,6 +13,13 @@ const ( InitialHP = 100 ) +const ( + InitialXLocation = 0 + InitialYLocation = 0 + InitialVelocity = 0 + InitialDirection = 0 +) + // PlayerSpawnerSystem spawns players based on `CreatePlayer` transactions. // This provides an example of a system that creates a new entity. func PlayerSpawnerSystem(world cardinal.WorldContext) error { @@ -22,6 +29,14 @@ func PlayerSpawnerSystem(world cardinal.WorldContext) error { id, err := cardinal.Create(world, comp.Player{Nickname: create.Msg.Nickname}, comp.Health{HP: InitialHP}, + comp.Movement{ + CurrentLocation: comp.Location{X: InitialXLocation, Y: InitialYLocation}, + Velocity: InitialVelocity, + CurrentDirection: comp.Direction{ + comp.Directions[InitialDirection].X, + comp.Directions[InitialDirection].Y, + }, + }, ) if err != nil { return msg.CreatePlayerResult{}, fmt.Errorf("error creating player: %w", err) diff --git a/cardinal/system/utils.go b/cardinal/system/utils.go index 9ca1c72..4c9d8d1 100644 --- a/cardinal/system/utils.go +++ b/cardinal/system/utils.go @@ -49,3 +49,42 @@ func queryTargetPlayer(world cardinal.WorldContext, targetNickname string) (type return playerID, playerHealth, err } + +func queryTargetPlayerMovementData(world cardinal.WorldContext, targetNickname string) (types.EntityID, *comp.Movement, error) { + var playerID types.EntityID + var playerMovementComponent *comp.Movement + var err error + searchErr := cardinal.NewSearch().Entity( + filter.Exact(filter.Component[comp.Player](), filter.Component[comp.Movement]())).Each(world, + func(id types.EntityID) bool { + var player *comp.Player + player, err = cardinal.GetComponent[comp.Player](world, id) + if err != nil { + return false + } + + // Terminates the search if the player is found + if player.Nickname == targetNickname { + playerID = id + playerMovementComponent, err = cardinal.GetComponent[comp.Movement](world, id) + if err != nil { + return false + } + return false + } + + // Continue searching if the player is not the target player + return true + }) + if searchErr != nil { + return 0, nil, err + } + if err != nil { + return 0, nil, err + } + if playerMovementComponent == nil { + return 0, nil, fmt.Errorf("player %q does not exist", targetNickname) + } + + return playerID, playerMovementComponent, err +}