-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #6 from Doprez/release-2-0
Release 2.0
- Loading branch information
Showing
18 changed files
with
635 additions
and
235 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
using Doprez.Stride.Animations.Data; | ||
using Stride.Core; | ||
using Stride.Engine; | ||
|
||
namespace Doprez.Stride.Animations; | ||
[DataContract("DoprezAnimationEvent")] | ||
[ComponentCategory("Animation")] | ||
[AllowMultipleComponents] | ||
public class AnimationEvent : SyncScript | ||
{ | ||
[DataMember(0)] | ||
public string EventName { get; set; } | ||
|
||
[DataMember(10)] | ||
public AnimationEventData EventData { get; set; } | ||
[DataMember(11)] | ||
public AnimationTriggerAction TriggerAction { get; set; } = AnimationTriggerAction.Once; | ||
|
||
public delegate void NotifyAnimationEvent(); | ||
|
||
/// <summary> | ||
/// Triggered at the beginning of the Animation Event only once by default | ||
/// <para>Will be continuous or single based on <see cref="TriggerAction"/></para> | ||
/// </summary> | ||
public event NotifyAnimationEvent AnimationEventTriggered; | ||
/// <summary> | ||
/// Triggered once the Animation is no longer running | ||
/// </summary> | ||
public event NotifyAnimationEvent AnimationEventEnded; | ||
|
||
private AnimationComponent _animations; | ||
private bool _animationWasPlaying = false; | ||
private bool _triggerHasRun = false; | ||
|
||
public override void Start() | ||
{ | ||
base.Start(); | ||
_animations = Entity.Get<AnimationComponent>(); | ||
} | ||
|
||
private void CheckAnimationEventTriggered() | ||
{ | ||
if (_animations.PlayingAnimations.Count == 0) | ||
return; | ||
if (!_animations.IsPlaying(EventData.AnimationName)) | ||
return; | ||
if (_triggerHasRun) | ||
return; | ||
|
||
_animationWasPlaying = true; | ||
var playing = _animations.PlayingAnimations; | ||
|
||
for (int i = 0; i < playing.Count; i++) | ||
{ | ||
if (playing[i].CurrentTime.TotalMilliseconds >= EventData.EventStartTime | ||
&& playing[i].Name.Equals(EventData.AnimationName)) | ||
{ | ||
AnimationEventTriggered?.Invoke(); | ||
switch (TriggerAction) | ||
{ | ||
case AnimationTriggerAction.Once: | ||
_triggerHasRun = true; | ||
break; | ||
case AnimationTriggerAction.Continuous: | ||
break; | ||
} | ||
} | ||
} | ||
} | ||
|
||
private void CheckAnimationEventEnded() | ||
{ | ||
if (_animationWasPlaying && !_animations.IsPlaying(EventData.AnimationName)) | ||
{ | ||
AnimationEventEnded?.Invoke(); | ||
_animationWasPlaying = false; | ||
_triggerHasRun = false; | ||
} | ||
} | ||
|
||
public override void Update() | ||
{ | ||
CheckAnimationEventTriggered(); | ||
CheckAnimationEventEnded(); | ||
} | ||
} | ||
|
||
public enum AnimationTriggerAction | ||
{ | ||
/// <summary> | ||
/// Only runs once on the trigger start | ||
/// </summary> | ||
Once, | ||
/// <summary> | ||
/// Runs every time the animation is played | ||
/// </summary> | ||
Continuous, | ||
} |
21 changes: 21 additions & 0 deletions
21
Doprez.Stride/Components/Animations/Data/AnimationEventData.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
using Stride.Core; | ||
|
||
namespace Doprez.Stride.Animations.Data; | ||
|
||
[DataContract(nameof(AnimationEventData))] | ||
[Display("EventData")] | ||
public struct AnimationEventData | ||
{ | ||
/// <summary> | ||
/// Set the Name of the Animation in the AnimationComponent | ||
/// </summary> | ||
[DataMember(0)] | ||
public string AnimationName { get; set; } | ||
|
||
/// <summary> | ||
/// Set the Start Time of the Animation Event in Milliseconds | ||
/// </summary> | ||
[DataMember(10)] | ||
[Display("Start Time")] | ||
public double EventStartTime { get; set; } | ||
} |
8 changes: 0 additions & 8 deletions
8
Doprez.Stride/ModelCategory/Data/LODData.cs → ....Stride/Components/Models/Data/LODData.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
6 changes: 1 addition & 5 deletions
6
Doprez.Stride/ModelCategory/LOD.cs → Doprez.Stride/Components/Models/SimpleLOD.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
185 changes: 185 additions & 0 deletions
185
Doprez.Stride/Components/Navigation/AdvancedPathFinder.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,185 @@ | ||
using Stride.Core; | ||
using Stride.Engine.Design; | ||
using Stride.Engine; | ||
using Stride.Navigation; | ||
using Stride.Physics; | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Threading.Tasks; | ||
using Stride.Core.Mathematics; | ||
|
||
namespace Doprez.Stride.Navigation; | ||
[DataContract("DoprezAdvancedNavigation")] | ||
[ComponentCategory("Navigation")] | ||
public class AdvancedPathFinder : StartupScript | ||
{ | ||
public float MovementSpeed { get; set; } = 400; | ||
public string NavGroupName { get; set; } | ||
public CharacterComponent CharacterComponent { get; set; } | ||
|
||
[DataMemberIgnore] | ||
public Vector3 TargetPosition; | ||
[DataMemberIgnore] | ||
public bool HasPath { get; private set; } | ||
|
||
private GameSettings _gameSettings; | ||
private NavigationComponent _navigationComponent = new(); | ||
private List<Vector3> _waypoints = new(); | ||
private int _waypointIndex = 0; | ||
|
||
/// <summary> | ||
/// <para>Gets the distance from the current position directly to the Target</para> | ||
/// </summary> | ||
public float DistanceToTarget | ||
{ | ||
get | ||
{ | ||
return Vector3.Distance(Entity.Transform.WorldMatrix.TranslationVector, TargetPosition); | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// <para>Returns the distance between the current position and the next waypoint</para> | ||
/// </summary> | ||
public float DistanceToNextWaypoint | ||
{ | ||
get | ||
{ | ||
if (_waypoints.Count == 0) | ||
{ | ||
return 0; | ||
} | ||
return Vector3.Distance(Entity.Transform.WorldMatrix.TranslationVector, _waypoints[_waypointIndex]); | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// <para>Returns the distance between each node in a path</para> | ||
/// <para>not the most efficient method to use per frame but logically is better than DistanceToTarget</para> | ||
/// </summary> | ||
public float CurrentPathDistance | ||
{ | ||
get | ||
{ | ||
float distance = 0; | ||
if (_waypoints.Count == 0) | ||
{ | ||
return distance; | ||
} | ||
for (int i = 0; i < _waypoints.Count - 1; i++) | ||
{ | ||
distance += Vector3.Distance(_waypoints[i], _waypoints[i + 1]); | ||
} | ||
return distance; | ||
} | ||
} | ||
|
||
public override void Start() | ||
{ | ||
_gameSettings = Services.GetService<IGameSettingsService>()?.Settings; | ||
|
||
var navSettings = _gameSettings.Configurations.Get<NavigationSettings>(); | ||
_navigationComponent.GroupId = navSettings.Groups.FirstOrDefault(x => x.Name == NavGroupName).Id; | ||
|
||
Entity.Add(_navigationComponent); | ||
} | ||
|
||
/// <summary> | ||
/// Stops the pathfinder and resets some base values | ||
/// </summary> | ||
public void Reset() | ||
{ | ||
ClearGoal(); | ||
CharacterComponent.SetVelocity(Vector3.Zero); | ||
} | ||
|
||
/// <summary> | ||
/// Finds a path to the targetWaypoint | ||
/// </summary> | ||
/// <param name="targetWaypoint"></param> | ||
public void SetWaypoint(Vector3 targetWaypoint) | ||
{ | ||
ClearGoal(); | ||
TargetPosition = targetWaypoint; | ||
if (_navigationComponent.TryFindPath(TargetPosition, _waypoints)) | ||
{ | ||
_waypointIndex = 0; | ||
HasPath = true; | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Finds a path to the targetWaypoint asynchronously | ||
/// </summary> | ||
/// <param name="targetWaypoint"></param> | ||
public async Task SetWaypointAsync(Vector3 targetWaypoint) | ||
{ | ||
ClearGoal(); | ||
TargetPosition = targetWaypoint; | ||
var foundPath = await Task.FromResult(_navigationComponent.TryFindPath(TargetPosition, _waypoints)); | ||
if (foundPath) | ||
{ | ||
HasPath = true; | ||
_waypointIndex = 0; | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Moves the unit in the direction of the path created by <see cref="SetWaypoint"/> or <see cref="SetWaypointAsync"/> | ||
/// </summary> | ||
public void Move() | ||
{ | ||
if (_waypoints.Count == 0) | ||
{ | ||
return; | ||
} | ||
|
||
var nextWaypointPosition = _waypoints[_waypointIndex]; | ||
var distanceToWaypoint = Vector3.Distance(Entity.WorldPosition(), nextWaypointPosition); | ||
|
||
// When the distance between the character and the next waypoint is large enough, move closer to the waypoint | ||
if (distanceToWaypoint > 0.5) | ||
{ | ||
var direction = nextWaypointPosition - Entity.WorldPosition(); | ||
direction.Normalize(); | ||
direction *= MovementSpeed * this.DeltaTime(); | ||
CharacterComponent.SetVelocity(direction); | ||
} | ||
else | ||
{ | ||
// If we are close enough to the waypoint, set the next waypoint or we are done and we do a final cleanup | ||
if (_waypointIndex + 1 < _waypoints.Count) | ||
{ | ||
_waypointIndex++; | ||
} | ||
else | ||
{ | ||
ClearGoal(); | ||
} | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Rotates the unit in the direction of the path created by SetWaypoint or SetWaypointAsync | ||
/// </summary> | ||
public void Rotate() | ||
{ | ||
if (_waypoints.Count == 0) | ||
{ | ||
return; | ||
} | ||
|
||
var currentPosition = Entity.Transform.WorldMatrix.TranslationVector; | ||
|
||
var angleInRadians = (float)Math.Atan2(_waypoints[_waypointIndex].Z - currentPosition.Z, _waypoints[_waypointIndex].X - currentPosition.X); | ||
|
||
CharacterComponent.Orientation = Quaternion.RotationY(-angleInRadians); | ||
} | ||
|
||
private void ClearGoal() | ||
{ | ||
_waypoints.Clear(); | ||
HasPath = false; | ||
} | ||
} |
Oops, something went wrong.