Add AI and Patrol components, update related resources and presenters
This commit is contained in:
@@ -1,7 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using CryptonymThunder.Code.Extensions;
|
||||
using CryptonymThunder.Code.Resources;
|
||||
using GameCore.AI;
|
||||
using GameCore.Attributes;
|
||||
using GameCore.Combat;
|
||||
using GameCore.Combat.Interfaces;
|
||||
@@ -46,6 +48,8 @@ public class ComponentFactory
|
||||
Register<WorldIdComponentResource>(res => new WorldIdComponent(res.WorldId));
|
||||
Register<ButtonComponentResource>(CreateButtonComponent);
|
||||
Register<LogicSequenceComponentResource>(CreateLogicSequenceComponent);
|
||||
Register<AIComponentResource>(CreateAIComponent);
|
||||
Register<PatrolComponentResource>(CreatePatrolComponent);
|
||||
}
|
||||
|
||||
public IComponent Create(Resource resource)
|
||||
@@ -187,4 +191,25 @@ public class ComponentFactory
|
||||
|
||||
return component;
|
||||
}
|
||||
|
||||
private AIComponent CreateAIComponent(AIComponentResource resource)
|
||||
{
|
||||
return new AIComponent
|
||||
{
|
||||
CurrentState = resource.InitialState,
|
||||
SightRange = resource.SightRange,
|
||||
FieldOfView = resource.FieldOfView,
|
||||
AttackRange = resource.AttackRange,
|
||||
ChaseGiveUpTime = resource.ChaseGiveUpTime,
|
||||
ReactionTime = resource.ReactionTime,
|
||||
};
|
||||
}
|
||||
|
||||
private PatrolComponent CreatePatrolComponent(PatrolComponentResource resource)
|
||||
{
|
||||
return new PatrolComponent
|
||||
{
|
||||
IsLooping = resource.IsLooping,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,8 @@ namespace CryptonymThunder.Code.Presenters;
|
||||
[GlobalClass]
|
||||
public partial class CharacterBody3DPresenter : CharacterBody3D, IEntityPresenter, IPresenterComponent
|
||||
{
|
||||
[Export] private Node3D _muzzleNode;
|
||||
|
||||
private World _world;
|
||||
private VelocityComponent _velocity;
|
||||
private PositionComponent _position;
|
||||
@@ -30,7 +32,7 @@ public partial class CharacterBody3DPresenter : CharacterBody3D, IEntityPresente
|
||||
_rotation = _world.GetComponent<RotationComponent>(CoreEntity);
|
||||
_inputState = _world.GetComponent<InputStateComponent>(CoreEntity);
|
||||
_characterState = _world.GetComponent<CharacterStateComponent>(CoreEntity);
|
||||
_camera = GetNode<Camera3D>("CameraPivot/Camera3D");
|
||||
_camera = GetNodeOrNull<Camera3D>("CameraPivot/Camera3D");
|
||||
}
|
||||
|
||||
public void SyncToPresentation(float delta)
|
||||
@@ -40,8 +42,12 @@ public partial class CharacterBody3DPresenter : CharacterBody3D, IEntityPresente
|
||||
var coreRotation = _rotation.Rotation;
|
||||
Rotation = new Vector3(Rotation.X, coreRotation.Y, Rotation.Z);
|
||||
}
|
||||
|
||||
if (_velocity == null) return;
|
||||
|
||||
if (_velocity == null)
|
||||
{
|
||||
_world.Logger.Warn("No VelocityComponent found for CharacterBody3DPresenter.");
|
||||
return;
|
||||
}
|
||||
|
||||
var godotVelocity = Velocity;
|
||||
godotVelocity.X = _velocity.DesiredVelocity.X;
|
||||
@@ -57,10 +63,24 @@ public partial class CharacterBody3DPresenter : CharacterBody3D, IEntityPresente
|
||||
if (_position != null) _position.Position = GlobalPosition.ToGameCore();
|
||||
if (_velocity != null) _velocity.ActualVelocity = Velocity.ToGameCore();
|
||||
if (_characterState != null) _characterState.IsOnFloor = IsOnFloor();
|
||||
if (_inputState != null && _camera != null)
|
||||
if (_inputState != null)
|
||||
{
|
||||
_inputState.MuzzlePosition = _camera.GlobalPosition.ToGameCore();
|
||||
_inputState.MuzzleDirection = (-_camera.GlobalTransform.Basis.Z).ToGameCore();
|
||||
if (_camera != null)
|
||||
{
|
||||
_inputState.MuzzlePosition = _camera.GlobalPosition.ToGameCore();
|
||||
_inputState.MuzzleDirection = (-_camera.GlobalTransform.Basis.Z).ToGameCore();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_muzzleNode != null)
|
||||
{
|
||||
_inputState.MuzzlePosition = _muzzleNode.GlobalPosition.ToGameCore();
|
||||
}
|
||||
else
|
||||
{
|
||||
_inputState.MuzzlePosition = GlobalPosition.ToGameCore();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ using CryptonymThunder.Code.Autoloads;
|
||||
using CryptonymThunder.Code.Factories;
|
||||
using CryptonymThunder.Code.Resources;
|
||||
using CryptonymThunder.Code.Services;
|
||||
using GameCore.AI;
|
||||
using GameCore.Attributes;
|
||||
using GameCore.Combat;
|
||||
using GameCore.Config;
|
||||
@@ -101,6 +102,11 @@ public partial class GamePresenter : Node
|
||||
|
||||
_world.RegisterSystem(new HealingSystem(_world));
|
||||
_world.RegisterSystem(new DamageSystem(_world));
|
||||
|
||||
_world.RegisterSystem(new AIPerceptionSystem());
|
||||
_world.RegisterSystem(new AIPathfindingSystem());
|
||||
_world.RegisterSystem(new AIAimSystem());
|
||||
|
||||
_world.RegisterSystem(new ProjectileCleanupSystem());
|
||||
_world.RegisterSystem(new DestructionSystem());
|
||||
|
||||
@@ -112,6 +118,8 @@ public partial class GamePresenter : Node
|
||||
var playerData = _presenterFactory.CreateEntityFromArchetype(PlayerArchetype);
|
||||
_presenters.Add(playerData.Entity.Id, playerData.Presenter);
|
||||
_presenterComponents.Add(playerData.Entity.Id, playerData.Components);
|
||||
|
||||
_world.GameState.SetStatus(GameStatus.InGame);
|
||||
}
|
||||
|
||||
public override void _Input(InputEvent @event)
|
||||
|
||||
38
Code/Presenters/PatrolComponentPresenter.cs
Normal file
38
Code/Presenters/PatrolComponentPresenter.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
using CryptonymThunder.Code.Extensions;
|
||||
using GameCore.AI;
|
||||
using GameCore.ECS;
|
||||
using GameCore.ECS.Interfaces;
|
||||
using Godot;
|
||||
using Godot.Collections;
|
||||
|
||||
namespace CryptonymThunder.Code.Presenters;
|
||||
|
||||
[GlobalClass]
|
||||
public partial class PatrolComponentPresenter : Node, IPresenterComponent
|
||||
{
|
||||
[Export] public Array<Marker3D> PatrolPoints { get; set; }= [];
|
||||
|
||||
public void Initialize(Entity coreEntity, World world)
|
||||
{
|
||||
var patrolComponent = world.GetComponent<PatrolComponent>(coreEntity);
|
||||
if (patrolComponent == null)
|
||||
{
|
||||
world.Logger.Warn($"Entity '{coreEntity.Id}' does not have a PatrolComponent.");
|
||||
return;
|
||||
}
|
||||
|
||||
patrolComponent.PatrolPoints.Clear();
|
||||
foreach (var marker in PatrolPoints)
|
||||
{
|
||||
patrolComponent.PatrolPoints.Add(marker.GlobalPosition.ToGameCore());
|
||||
}
|
||||
}
|
||||
|
||||
public void SyncToPresentation(float delta)
|
||||
{
|
||||
}
|
||||
|
||||
public void SyncToCore(float delta)
|
||||
{
|
||||
}
|
||||
}
|
||||
1
Code/Presenters/PatrolComponentPresenter.cs.uid
Normal file
1
Code/Presenters/PatrolComponentPresenter.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://b583iynr5p62n
|
||||
17
Code/Resources/AIComponentResource.cs
Normal file
17
Code/Resources/AIComponentResource.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using GameCore.AI;
|
||||
using Godot;
|
||||
|
||||
namespace CryptonymThunder.Code.Resources;
|
||||
|
||||
[GlobalClass]
|
||||
public partial class AIComponentResource : Resource
|
||||
{
|
||||
[Export] public AIState InitialState { get; set; } = AIState.Idle;
|
||||
|
||||
[ExportGroup("Personality")]
|
||||
[Export(PropertyHint.Range, "1.0, 100.0, 0.1")] public float SightRange { get; set; } = 20f;
|
||||
[Export(PropertyHint.Range, "1.0, 180.0, 0.1")] public float FieldOfView { get; set; } = 90f; // In degrees
|
||||
[Export(PropertyHint.Range, "0.1, 100.0, 0.1")] public float AttackRange { get; set; } = 10f;
|
||||
[Export(PropertyHint.Range, "0.0, 30.0, 0.1")] public float ChaseGiveUpTime { get; set; } = 5.0f; // Time to chase after losing sight
|
||||
[Export(PropertyHint.Range, "0.0, 5.0, 0.05")] public float ReactionTime { get; set; } = 0.5f; // Delay before seeing player
|
||||
}
|
||||
1
Code/Resources/AIComponentResource.cs.uid
Normal file
1
Code/Resources/AIComponentResource.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://cq6c0en5gw7ia
|
||||
10
Code/Resources/PatrolComponentResource.cs
Normal file
10
Code/Resources/PatrolComponentResource.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using Godot;
|
||||
using Godot.Collections;
|
||||
|
||||
namespace CryptonymThunder.Code.Resources;
|
||||
|
||||
[GlobalClass]
|
||||
public partial class PatrolComponentResource : Resource
|
||||
{
|
||||
[Export] public bool IsLooping { get; set; } = false;
|
||||
}
|
||||
1
Code/Resources/PatrolComponentResource.cs.uid
Normal file
1
Code/Resources/PatrolComponentResource.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://dknbh3vlew4v5
|
||||
1
Code/Services/GodotAudioService.cs.uid
Normal file
1
Code/Services/GodotAudioService.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://brwkqiox7aijm
|
||||
1
Code/Services/GodotParticleService.cs.uid
Normal file
1
Code/Services/GodotParticleService.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://dyyu7jl3gfjpg
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using CryptonymThunder.Code.Autoloads;
|
||||
using CryptonymThunder.Code.Extensions;
|
||||
using CryptonymThunder.Code.Presenters;
|
||||
@@ -101,4 +102,12 @@ public class GodotWorldQuery(GamePresenter ownerNode) : IWorldQuery
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<Vector3> GetPath(Vector3 start, Vector3 end)
|
||||
{
|
||||
var map = _godotWorld.NavigationMap;
|
||||
var pathPoints = NavigationServer3D.MapGetPath(map, start.ToGodot(), end.ToGodot(), true);
|
||||
|
||||
return pathPoints.Select(p => p.ToGameCore()).ToList();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user