Initial Commit
This commit is contained in:
commit
ee5c2f922d
2255 changed files with 547750 additions and 0 deletions
8
Assets/Scripts/Systems/Actor.meta
Normal file
8
Assets/Scripts/Systems/Actor.meta
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: f873be1f9d82e254593f0e546121c8ad
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
125
Assets/Scripts/Systems/Actor/ActorAimingAnimationSystem.cs
Normal file
125
Assets/Scripts/Systems/Actor/ActorAimingAnimationSystem.cs
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
using System;
|
||||
using Unity.Entities;
|
||||
using UnityEngine;
|
||||
using Zenject;
|
||||
|
||||
namespace DefaultNamespace
|
||||
{
|
||||
[UpdateInGroup(typeof(PresentationSystemGroup)), UpdateBefore(typeof(ActorIkSystem))]
|
||||
public class ActorAimingAnimationSystem : InjectableComponentSystem
|
||||
{
|
||||
[Serializable]
|
||||
public class Settings
|
||||
{
|
||||
public float MinMouseDistanceBarrel;
|
||||
public float TurnEase;
|
||||
public float WeaponEase;
|
||||
}
|
||||
|
||||
[Inject] private readonly Settings settings;
|
||||
|
||||
protected override void OnSystemUpdate()
|
||||
{
|
||||
Entities.WithAllReadOnly<RigidBody2DData, ActorBodyParts>()
|
||||
.ForEach(
|
||||
(
|
||||
Entity entitiy,
|
||||
ActorAnimationPropertiesData animationProperties,
|
||||
ref Rotation2D rotation,
|
||||
ref ActorData actor,
|
||||
ref ActorAnimationData animation,
|
||||
ref AnimatorStateData animationState) =>
|
||||
{
|
||||
var rigidBody = EntityManager.GetComponentData<RigidBody2DData>(entitiy);
|
||||
var parts = EntityManager.GetComponentObject<ActorBodyParts>(entitiy);
|
||||
|
||||
if (animationState.State.IsTag("Interactive") || animationState.State.IsTag("CanLook"))
|
||||
{
|
||||
var playerPosition = rigidBody.Position +
|
||||
(EntityManager.HasComponent<AimCenterData>(entitiy)
|
||||
? EntityManager.GetComponentData<AimCenterData>(entitiy).Offset
|
||||
: Vector2.zero);
|
||||
var hipLookDir = (actor.Aim - playerPosition).normalized;
|
||||
var hipAngle = Vector2.SignedAngle(Vector2.up, hipLookDir);
|
||||
rotation.Axis = Mathf.Sign(hipAngle);
|
||||
if (!EntityManager.HasComponent<ActorWeaponReferenceData>(entitiy))
|
||||
{
|
||||
hipAngle = -90;
|
||||
}
|
||||
if (parts.Hip != null)
|
||||
{
|
||||
var rot = Mathf.LerpAngle(
|
||||
animation.LastRotation,
|
||||
Mathf.Clamp(Mathf.Abs(hipAngle), animationProperties.HipAngleRange.x, animationProperties.HipAngleRange.y),
|
||||
settings.TurnEase * Time.DeltaTime);
|
||||
animation.LastRotation = rot;
|
||||
parts.Hip.localRotation = Quaternion.Slerp(
|
||||
parts.Hip.localRotation,
|
||||
Quaternion.Euler(0, 0, rot),
|
||||
animation.LookWeight);
|
||||
|
||||
if (parts.Head != null)
|
||||
{
|
||||
Vector2 lookDir = parts.Head.parent.InverseTransformPoint(actor.Look).normalized;
|
||||
var headAngle = Vector2.SignedAngle(animationProperties.HeadForward, lookDir);
|
||||
var headRot = Mathf.LerpAngle(
|
||||
animation.LastHeadRotation,
|
||||
Mathf.Clamp(headAngle, animationProperties.HeadAngleRange.x, animationProperties.HeadAngleRange.y),
|
||||
settings.TurnEase * Time.DeltaTime);
|
||||
parts.Head.localRotation = Quaternion.Slerp(
|
||||
parts.Head.localRotation,
|
||||
Quaternion.Euler(0, 0, headRot + parts.DefaultHeadAngle),
|
||||
animation.HeadLookWeight * animation.LookWeight);
|
||||
animation.LastHeadRotation = headRot;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Entities.WithAllReadOnly<Animator, ActorBodyParts>()
|
||||
.ForEach(
|
||||
(
|
||||
Entity entity,
|
||||
ActorAnimationPropertiesData animationData,
|
||||
ref ActorData actor,
|
||||
ref ActorAnimationData animation,
|
||||
ref AnimatorStateData animationState,
|
||||
ref ActorWeaponReferenceData weaponReference) =>
|
||||
{
|
||||
var weaponEntity = weaponReference.Weapon;
|
||||
|
||||
if (EntityManager.Exists(weaponEntity) && EntityManager.HasComponent<WeaponPartsData>(weaponEntity))
|
||||
{
|
||||
var animator = EntityManager.GetComponentObject<Animator>(entity);
|
||||
var parts = EntityManager.GetComponentObject<ActorBodyParts>(entity);
|
||||
|
||||
if (parts.WeaponContainer != null && animationState.State.IsTag("Interactive"))
|
||||
{
|
||||
var barrelDistance = Vector2.Distance(parts.WeaponContainer.position, actor.Aim);
|
||||
if (barrelDistance >= settings.MinMouseDistanceBarrel)
|
||||
{
|
||||
var weapon = EntityManager.GetSharedComponentData<WeaponPartsData>(weaponEntity);
|
||||
Vector2 hipLocalLookPoint = parts.Hip.InverseTransformPoint(actor.Aim);
|
||||
Vector2 hipLocalGunPos =
|
||||
parts.Hip.InverseTransformPoint(weapon.Barrel != null ? weapon.Barrel.position : Vector3.zero);
|
||||
var gunLookDir = (hipLocalLookPoint - hipLocalGunPos).normalized;
|
||||
var gunAngle = Vector2.SignedAngle(Vector2.up, gunLookDir);
|
||||
if (EntityManager.HasComponent<ActorWeaponAccuracyData>(entity))
|
||||
{
|
||||
gunAngle -= EntityManager.GetComponentData<ActorWeaponAccuracyData>(entity).Accuracy;
|
||||
}
|
||||
var rot = Mathf.LerpAngle(
|
||||
animation.LastGunRotation,
|
||||
Mathf.Clamp(gunAngle, animationData.WeaponAngleRange.x, animationData.WeaponAngleRange.y),
|
||||
settings.WeaponEase * Time.DeltaTime);
|
||||
animation.LastGunRotation = rot;
|
||||
parts.WeaponContainer.localRotation = Quaternion.Euler(0, 0, rot);
|
||||
}
|
||||
}
|
||||
|
||||
animator.SetLayerWeight(1, 1);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 54297fbb8ccd22841998510566bbac5e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
using Unity.Entities;
|
||||
|
||||
namespace DefaultNamespace
|
||||
{
|
||||
[UpdateInGroup(typeof(PresentationSystemGroup))]
|
||||
public class ActorAnimationEventResetSystem : ComponentSystem
|
||||
{
|
||||
protected override void OnUpdate()
|
||||
{
|
||||
Entities.ForEach((ref ActorAnimationEventData e) => { e = new ActorAnimationEventData(); });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d002725e916824f4e91db1ecccbee637
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
11
Assets/Scripts/Systems/Actor/ActorAnimationResetSystem.cs
Normal file
11
Assets/Scripts/Systems/Actor/ActorAnimationResetSystem.cs
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
using Unity.Entities;
|
||||
|
||||
namespace DefaultNamespace
|
||||
{
|
||||
public class ActorAnimationResetSystem : ComponentSystem
|
||||
{
|
||||
protected override void OnUpdate()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 6accfe0b33196564a8bdbae4d70df0e8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
191
Assets/Scripts/Systems/Actor/ActorAnimationSystem.cs
Normal file
191
Assets/Scripts/Systems/Actor/ActorAnimationSystem.cs
Normal file
|
|
@ -0,0 +1,191 @@
|
|||
using Assets.Scripts.Events;
|
||||
using DefaultNamespace;
|
||||
using Events;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Unity.Entities;
|
||||
using UnityEngine;
|
||||
using Zenject;
|
||||
|
||||
[UpdateInGroup(typeof(PresentationSystemGroup)), UpdateAfter(typeof(PlayerAnimationSystem)), UpdateAfter(typeof(EnemyDriverSystem))]
|
||||
public class ActorAnimationSystem : InjectableComponentSystem
|
||||
{
|
||||
[Serializable]
|
||||
public class Settings
|
||||
{
|
||||
public AnimationCurve LandForceCurve;
|
||||
public Vector2 LandForceRange;
|
||||
public ParticleSystem LandParticles;
|
||||
public float MaxLandAngle;
|
||||
public float MaxStepFrequency;
|
||||
public ParticleSystem StepParticles;
|
||||
}
|
||||
|
||||
[Inject] private readonly Hashes hashes;
|
||||
|
||||
[Inject] private readonly Settings settings;
|
||||
[Inject] private readonly SoundManager soundManager;
|
||||
|
||||
protected override void OnSystemUpdate()
|
||||
{
|
||||
ResetAnimations();
|
||||
UpdateAnimators();
|
||||
RebindAnimators();
|
||||
UpdateWeaponProps();
|
||||
}
|
||||
|
||||
private void ResetAnimations()
|
||||
{
|
||||
Entities.ForEach(
|
||||
(ref ActorData actorData, ref ActorAnimationData actorAnimationData, ref EntityDeathEvent deathEvent) =>
|
||||
{
|
||||
actorAnimationData = new ActorAnimationData();
|
||||
});
|
||||
}
|
||||
|
||||
private void UpdateAnimators()
|
||||
{
|
||||
Entities.WithAllReadOnly<Animator, Rigidbody2D, ActorFacade>()
|
||||
.ForEach(
|
||||
(
|
||||
Entity entity,
|
||||
ref RigidBody2DData rigidbodyData,
|
||||
ref ActorData actor,
|
||||
ref AnimatorStateData animationState,
|
||||
ref ActorAnimationData animation) =>
|
||||
{
|
||||
var animator = EntityManager.GetComponentObject<Animator>(entity);
|
||||
var rigidbody = EntityManager.GetComponentObject<Rigidbody2D>(entity);
|
||||
var facade = EntityManager.GetComponentObject<ActorFacade>(entity);
|
||||
|
||||
animator.SetBool(hashes.Grounded, actor.Grounded);
|
||||
animator.SetFloat(hashes.Walk, animation.WalkMultiply);
|
||||
animator.SetFloat(hashes.WalkDir, animation.WalkDir);
|
||||
animator.SetBool(hashes.Jump, animation.Triggers.HasFlag(AnimationTriggerType.Jump));
|
||||
animator.SetBool(hashes.Jump, animation.Triggers.HasFlag(AnimationTriggerType.Jump));
|
||||
animator.SetBool(hashes.Attack, animation.Triggers.HasFlag(AnimationTriggerType.Attack));
|
||||
animator.SetBool(hashes.UseItem, animation.Triggers.HasFlag(AnimationTriggerType.ItemUse));
|
||||
animator.SetBool(hashes.Pickup, animation.Triggers.HasFlag(AnimationTriggerType.Pickup));
|
||||
animator.SetBool(hashes.Melee, animation.Triggers.HasFlag(AnimationTriggerType.Melee));
|
||||
animator.SetBool(hashes.JumpObsticle, animation.Triggers.HasFlag(AnimationTriggerType.JumpObsticle));
|
||||
animator.SetInteger(hashes.UseType, (int)animation.UseType);
|
||||
animator.SetBool(hashes.AdditiveUse, animation.ItemUseAdditive);
|
||||
|
||||
ManageLanding(animator, rigidbody, ref animation, actor, facade);
|
||||
|
||||
var weaponLayer = animator.GetLayerIndex("Weapon");
|
||||
if (weaponLayer >= 0)
|
||||
{
|
||||
animator.SetLayerWeight(weaponLayer, EntityManager.HasComponent<ActorWeaponReferenceData>(entity) ? 1 : 0);
|
||||
}
|
||||
|
||||
if (!actor.Grounded)
|
||||
{
|
||||
animation.Landed = false;
|
||||
}
|
||||
|
||||
if (animation.Triggers.HasFlag(AnimationTriggerType.Jump))
|
||||
{
|
||||
facade.JumpSoundLibrary?.PlayRandomOneShot(facade.FeetAudio);
|
||||
}
|
||||
|
||||
animation.Triggers = AnimationTriggerType.None;
|
||||
|
||||
ManageSteps(ref animation, actor, rigidbodyData, facade);
|
||||
|
||||
if (animationState.State.IsName("Attack"))
|
||||
{
|
||||
animator.SetFloat(hashes.AttackSpeed, Mathf.Max(animationState.State.length / (1f / animation.AttackSpeed)));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void ManageLanding(Animator animator, Rigidbody2D rigidbody, ref ActorAnimationData animation, ActorData actor, ActorFacade facade)
|
||||
{
|
||||
if (actor.Grounded && !animation.Landed)
|
||||
{
|
||||
var contacts = new ContactPoint2D[6];
|
||||
var contactCount = rigidbody.GetContacts(contacts);
|
||||
if (contactCount > 0)
|
||||
{
|
||||
var maxCollisionForce = contacts.Take(contactCount).Max(c => c.normalImpulse);
|
||||
if (maxCollisionForce >= settings.LandForceRange.x)
|
||||
{
|
||||
animator.SetTrigger(hashes.Land);
|
||||
var landForcePercent = settings.LandForceCurve.Evaluate(
|
||||
Mathf.Clamp01((maxCollisionForce - settings.LandForceRange.x) / (settings.LandForceRange.y - settings.LandForceRange.x)));
|
||||
var landingLayer = animator.GetLayerIndex("Landing");
|
||||
if (landingLayer >= 0)
|
||||
{
|
||||
animator.SetLayerWeight(landingLayer, landForcePercent);
|
||||
}
|
||||
animation.Landed = true;
|
||||
facade.LandSoundLibrary?.PlayRandomOneShot(facade.FeetAudio, landForcePercent);
|
||||
for (var j = 0; j < contactCount; j++)
|
||||
{
|
||||
settings.LandParticles.Emit(
|
||||
new ParticleSystem.EmitParams { position = contacts[j].point },
|
||||
Mathf.RoundToInt(landForcePercent * 10f / contactCount));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ManageSteps(ref ActorAnimationData animation, ActorData actor, RigidBody2DData rigidbodyData, ActorFacade facade)
|
||||
{
|
||||
animation.StepTimer = Mathf.Max(0, animation.StepTimer - Time.DeltaTime);
|
||||
if (Mathf.Sign(facade.StepAmount) != animation.LastStepSign && actor.Grounded && animation.WalkMultiply > 0)
|
||||
{
|
||||
animation.LastStepSign = Mathf.Sign(facade.StepAmount);
|
||||
if (animation.StepTimer <= 0)
|
||||
{
|
||||
facade.StepSoundsLibrary?.PlayRandomOneShot(facade.FeetAudio);
|
||||
animation.StepTimer += settings.MaxStepFrequency;
|
||||
settings.StepParticles.Emit(new ParticleSystem.EmitParams { position = rigidbodyData.Position }, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateWeaponProps()
|
||||
{
|
||||
Entities.ForEach(
|
||||
(Animator animator, ref ActorWeaponReferenceData reference) =>
|
||||
{
|
||||
var weaponAnimator = EntityManager.GetComponentObject<Animator>(reference.Weapon);
|
||||
if (weaponAnimator.isActiveAndEnabled)
|
||||
{
|
||||
var state = weaponAnimator.GetCurrentAnimatorStateInfo(0);
|
||||
animator.SetBool(hashes.Reloading, state.IsTag("Reloading"));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void RebindAnimators()
|
||||
{
|
||||
Entities.ForEach(
|
||||
(Entity entity, Animator animator, ref AnimatorRebindEventData e) =>
|
||||
{
|
||||
animator.Rebind();
|
||||
PostUpdateCommands.RemoveComponent<AnimatorRebindEventData>(entity);
|
||||
});
|
||||
}
|
||||
|
||||
private class Hashes : IHashes
|
||||
{
|
||||
public readonly int AdditiveUse;
|
||||
public readonly int Attack;
|
||||
public readonly int AttackSpeed;
|
||||
public readonly int Grounded;
|
||||
public readonly int Jump;
|
||||
public readonly int JumpObsticle;
|
||||
public readonly int Land;
|
||||
public readonly int Melee;
|
||||
public readonly int Pickup;
|
||||
public readonly int Reloading;
|
||||
public readonly int UseItem;
|
||||
public readonly int UseType;
|
||||
public readonly int Walk;
|
||||
public readonly int WalkDir;
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Systems/Actor/ActorAnimationSystem.cs.meta
Normal file
11
Assets/Scripts/Systems/Actor/ActorAnimationSystem.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ddbd346c0b4cce64790a5629aeb244c8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
18
Assets/Scripts/Systems/Actor/ActorBoundCopySystem.cs
Normal file
18
Assets/Scripts/Systems/Actor/ActorBoundCopySystem.cs
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
using Unity.Entities;
|
||||
using UnityEngine;
|
||||
|
||||
namespace DefaultNamespace
|
||||
{
|
||||
public class ActorBoundCopySystem : ComponentSystem
|
||||
{
|
||||
protected override void OnUpdate()
|
||||
{
|
||||
Entities.ForEach(
|
||||
(CapsuleCollider2D collider, ref ActorBoundsData actorBounds) =>
|
||||
{
|
||||
var bounds = collider.bounds;
|
||||
actorBounds = new ActorBoundsData { Rect = new Rect(bounds.min, bounds.size) };
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Systems/Actor/ActorBoundCopySystem.cs.meta
Normal file
11
Assets/Scripts/Systems/Actor/ActorBoundCopySystem.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 2795c755ec62205478f72e4e69d87d5a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
106
Assets/Scripts/Systems/Actor/ActorDeathSystem.cs
Normal file
106
Assets/Scripts/Systems/Actor/ActorDeathSystem.cs
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
using Events;
|
||||
using System;
|
||||
using Unity.Entities;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Experimental.U2D.IK;
|
||||
using Zenject;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace DefaultNamespace
|
||||
{
|
||||
/// <summary>
|
||||
/// Overrides <see cref="EntityDeathSystem"/> and does fancy animations if specified.
|
||||
/// </summary>
|
||||
[UpdateInGroup(typeof(LateSimulationSystemGroup)), UpdateBefore(typeof(EntityDeathSystem))]
|
||||
public class ActorDeathSystem : InjectableComponentSystem
|
||||
{
|
||||
[Serializable]
|
||||
public class Settings
|
||||
{
|
||||
public string CorpseLayer;
|
||||
public float DeathForce;
|
||||
public PhysicsMaterial2D PhysicsMaterial;
|
||||
}
|
||||
|
||||
[Inject] private readonly Settings settings;
|
||||
|
||||
protected override void OnSystemUpdate()
|
||||
{
|
||||
Entities.WithAllReadOnly<EntityDeathEvent>()
|
||||
.ForEach(
|
||||
(Entity entity, ref ActorData actor, ref Rotation2D rotation) =>
|
||||
{
|
||||
if (EntityManager.TryGetComponentObject(entity, out Transform transform))
|
||||
{
|
||||
if (EntityManager.TryGetComponentData(entity, out ActorDeathAnimationData deathAnimationData))
|
||||
{
|
||||
if (deathAnimationData.Time > 0)
|
||||
{
|
||||
AnimateDeath(entity, transform, ref actor, ref rotation);
|
||||
Object.Destroy(transform.gameObject, deathAnimationData.Time);
|
||||
}
|
||||
else if (deathAnimationData.Time == 0)
|
||||
{
|
||||
Object.Destroy(transform.gameObject);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Object.Destroy(transform.gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
PostUpdateCommands.DestroyEntity(entity);
|
||||
});
|
||||
}
|
||||
|
||||
private void AnimateDeath(Entity entity, Transform transform, ref ActorData actor, ref Rotation2D rotation)
|
||||
{
|
||||
var axis = Mathf.Sign(actor.Aim.x);
|
||||
var dir = Vector2.right * rotation.Axis;
|
||||
var force = settings.DeathForce;
|
||||
if (EntityManager.TryGetComponentData<ActorDeathData>(entity, out var deathData))
|
||||
{
|
||||
axis = Mathf.Sign(-deathData.Direction.x);
|
||||
dir = deathData.Direction;
|
||||
force *= deathData.Force;
|
||||
}
|
||||
|
||||
if (EntityManager.TryGetComponentObject(entity, out Animator animator))
|
||||
{
|
||||
animator.SetInteger("Dead", axis != Mathf.Sign(rotation.Axis) ? -1 : 1);
|
||||
var weaponLayer = animator.GetLayerIndex("Weapon");
|
||||
if (weaponLayer >= 0)
|
||||
{
|
||||
animator.SetLayerWeight(weaponLayer, 0);
|
||||
}
|
||||
}
|
||||
|
||||
var colliders = transform.GetComponentsInChildren<Collider2D>();
|
||||
foreach (var col in colliders)
|
||||
{
|
||||
col.gameObject.layer = LayerMask.NameToLayer(settings.CorpseLayer);
|
||||
col.sharedMaterial = settings.PhysicsMaterial;
|
||||
}
|
||||
|
||||
if (EntityManager.TryGetComponentObject<Rigidbody2D>(entity, out var rigidBody))
|
||||
{
|
||||
rigidBody.AddForce(dir * force, ForceMode2D.Impulse);
|
||||
rigidBody.sharedMaterial = settings.PhysicsMaterial;
|
||||
}
|
||||
|
||||
if (EntityManager.TryGetComponentObject<ActorBodyParts>(entity, out var bodyParts))
|
||||
{
|
||||
if (bodyParts.WeaponContainer != null)
|
||||
{
|
||||
Object.Destroy(bodyParts.WeaponContainer.gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
if (EntityManager.TryGetComponentObject<IKManager2D>(entity, out var ikManager))
|
||||
{
|
||||
ikManager.enabled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Systems/Actor/ActorDeathSystem.cs.meta
Normal file
11
Assets/Scripts/Systems/Actor/ActorDeathSystem.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: f324081ba101cbd489288a93a667f381
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
70
Assets/Scripts/Systems/Actor/ActorGrenadeSystem.cs
Normal file
70
Assets/Scripts/Systems/Actor/ActorGrenadeSystem.cs
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
using Events;
|
||||
using Items;
|
||||
using System;
|
||||
using Unity.Entities;
|
||||
using UnityEngine;
|
||||
using UnityEngine.AddressableAssets;
|
||||
using Zenject;
|
||||
|
||||
namespace DefaultNamespace
|
||||
{
|
||||
[UpdateInGroup(typeof(PresentationSystemGroup)), UpdateBefore(typeof(ActorAnimationEventResetSystem))]
|
||||
public class ActorGrenadeSystem : InjectableComponentSystem
|
||||
{
|
||||
[Serializable]
|
||||
public class Settings
|
||||
{
|
||||
public string GrenadeLayer;
|
||||
public string GrenadeSortingLayer;
|
||||
public float MaxThrowForce;
|
||||
}
|
||||
|
||||
[Inject] private Settings settings;
|
||||
|
||||
protected override void OnSystemUpdate()
|
||||
{
|
||||
var deltaTime = Time.DeltaTime;
|
||||
|
||||
Entities.ForEach((ref ActorGrenadeData grenade) => { grenade.GrenadeTimer = Mathf.Max(0, grenade.GrenadeTimer - deltaTime); });
|
||||
|
||||
Entities.ForEach(
|
||||
(Entity entity, ref FireGrenadeEvent e, ref ActorData actor, ref RigidBody2DData actorRigidBody) =>
|
||||
{
|
||||
var aim = actor.Aim;
|
||||
var position = actorRigidBody.Position;
|
||||
|
||||
var grenadeLoadOperation = Addressables.LoadAssetAsync<GrenadeItem>(e.GrenadePrefab.ToString());
|
||||
grenadeLoadOperation.Completed += operation => operation.Result.Template.InstantiateAsync().Completed += op =>
|
||||
{
|
||||
var center = position;
|
||||
if (EntityManager.HasComponent<AimCenterData>(entity))
|
||||
{
|
||||
center += EntityManager.GetComponentData<AimCenterData>(entity).Offset;
|
||||
}
|
||||
var dir = (aim - center).normalized * settings.MaxThrowForce;
|
||||
var grenadeEntityObj = op.Result;
|
||||
grenadeEntityObj.gameObject.layer = LayerMask.NameToLayer(settings.GrenadeLayer);
|
||||
var rigidBody = grenadeEntityObj.GetComponent<Rigidbody2D>();
|
||||
if (rigidBody != null)
|
||||
{
|
||||
rigidBody.MovePosition(center);
|
||||
rigidBody.velocity = dir;
|
||||
}
|
||||
};
|
||||
PostUpdateCommands.RemoveComponent<FireGrenadeEvent>(entity);
|
||||
});
|
||||
|
||||
Entities.WithNone<EntityDeathEvent>()
|
||||
.ForEach(
|
||||
(Entity entity, ref GrenadeData grenade) =>
|
||||
{
|
||||
grenade.Lifetime = Mathf.Max(0, grenade.Lifetime - deltaTime);
|
||||
|
||||
if (grenade.Lifetime <= 0)
|
||||
{
|
||||
PostUpdateCommands.AddComponent(entity, new EntityDeathEvent());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Systems/Actor/ActorGrenadeSystem.cs.meta
Normal file
11
Assets/Scripts/Systems/Actor/ActorGrenadeSystem.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 2d753cf45e2c5a84d8ca3dbea2c75a6a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
40
Assets/Scripts/Systems/Actor/ActorGroundCheckSystem.cs
Normal file
40
Assets/Scripts/Systems/Actor/ActorGroundCheckSystem.cs
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using Unity.Entities;
|
||||
using UnityEngine;
|
||||
using Zenject;
|
||||
|
||||
namespace DefaultNamespace
|
||||
{
|
||||
[UpdateInGroup(typeof(SimulationSystemGroup))]
|
||||
public class ActorGroundCheckSystem : InjectableComponentSystem
|
||||
{
|
||||
[Serializable]
|
||||
public class Settings
|
||||
{
|
||||
public float GroundCheckDistance;
|
||||
public LayerMask GroundMask;
|
||||
public float MaxGroundCheckDistance;
|
||||
}
|
||||
|
||||
[Inject] private readonly Settings settings;
|
||||
private readonly RaycastHit2D[] hits = new RaycastHit2D[1];
|
||||
|
||||
protected override void OnSystemUpdate()
|
||||
{
|
||||
Entities.ForEach(
|
||||
(Rigidbody2D rigidBody, ref ActorData actor) =>
|
||||
{
|
||||
var filter = new ContactFilter2D { useLayerMask = true, layerMask = settings.GroundMask };
|
||||
var hitCount = rigidBody.Cast(Vector2.down, filter, hits, settings.MaxGroundCheckDistance);
|
||||
actor.Grounded = hitCount > 0 && hits.Any(h => h.distance <= settings.GroundCheckDistance);
|
||||
actor.GroundUp = hitCount > 0 ? hits[0].normal : Vector2.up;
|
||||
actor.GroundDinstance = hitCount > 0 ? hits.Min(h => h.distance) : -1;
|
||||
if (hitCount > 0)
|
||||
{
|
||||
Debug.DrawLine(hits[0].point, hits[0].point + hits[0].normal * hits[0].distance, Color.red);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Systems/Actor/ActorGroundCheckSystem.cs.meta
Normal file
11
Assets/Scripts/Systems/Actor/ActorGroundCheckSystem.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 03b37e129a944c64caff945d57875398
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
22
Assets/Scripts/Systems/Actor/ActorIkSystem.cs
Normal file
22
Assets/Scripts/Systems/Actor/ActorIkSystem.cs
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
using Unity.Entities;
|
||||
using UnityEngine.Experimental.U2D.IK;
|
||||
|
||||
namespace DefaultNamespace
|
||||
{
|
||||
[UpdateInGroup(typeof(PresentationSystemGroup))]
|
||||
public class ActorIkSystem : ComponentSystem
|
||||
{
|
||||
protected override void OnUpdate()
|
||||
{
|
||||
Entities.ForEach(
|
||||
(IKManager2D manager, ref ActorData actorData) =>
|
||||
{
|
||||
manager.enabled = false;
|
||||
if (manager.gameObject.activeInHierarchy)
|
||||
{
|
||||
manager.UpdateManager();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Systems/Actor/ActorIkSystem.cs.meta
Normal file
11
Assets/Scripts/Systems/Actor/ActorIkSystem.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: bd60b50a76b37f54a8e73de127a08daa
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
21
Assets/Scripts/Systems/Actor/ActorMeleeIkSystem.cs
Normal file
21
Assets/Scripts/Systems/Actor/ActorMeleeIkSystem.cs
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
using Unity.Entities;
|
||||
|
||||
namespace DefaultNamespace
|
||||
{
|
||||
[UpdateInGroup(typeof(PresentationSystemGroup)), UpdateAfter(typeof(ActorIkSystem))]
|
||||
public class ActorMeleeIkSystem : ComponentSystem
|
||||
{
|
||||
protected override void OnUpdate()
|
||||
{
|
||||
Entities.ForEach(
|
||||
(MeleeIkManager2D manager) =>
|
||||
{
|
||||
manager.enabled = false;
|
||||
if (manager.gameObject.activeInHierarchy)
|
||||
{
|
||||
manager.UpdateManager();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Systems/Actor/ActorMeleeIkSystem.cs.meta
Normal file
11
Assets/Scripts/Systems/Actor/ActorMeleeIkSystem.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 304959ce2b8b20a44bc5b9c9eb2d4612
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
93
Assets/Scripts/Systems/Actor/ActorMeleeSystem.cs
Normal file
93
Assets/Scripts/Systems/Actor/ActorMeleeSystem.cs
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
using Cinemachine;
|
||||
using System;
|
||||
using Unity.Entities;
|
||||
using UnityEngine;
|
||||
using Zenject;
|
||||
|
||||
namespace DefaultNamespace
|
||||
{
|
||||
[UpdateInGroup(typeof(PresentationSystemGroup)), UpdateBefore(typeof(ActorAnimationEventResetSystem))]
|
||||
public class ActorMeleeSystem : InjectableComponentSystem
|
||||
{
|
||||
[Serializable]
|
||||
public class Settings
|
||||
{
|
||||
public ParticleSystem BloodParticles;
|
||||
public CinemachineImpulseSource HitImpulse;
|
||||
public float HitImpulseSize;
|
||||
public SoundLibrary MeleeHitSounds;
|
||||
public CinemachineImpulseSource MeleeImpulse;
|
||||
public float MeleeImpulseSize;
|
||||
}
|
||||
|
||||
//[Inject] private MeleeActorGroup meleeActorGroup;
|
||||
[Inject] private readonly Settings settings;
|
||||
[Inject] private readonly SoundManager soundManager;
|
||||
|
||||
protected override void OnSystemUpdate()
|
||||
{
|
||||
Entities.WithAll<Rigidbody2D>()
|
||||
.ForEach(
|
||||
(Entity entity, ActorMeleeSharedData meleeShared, ref ActorAnimationEventData e, ref ActorMeleeData melee) =>
|
||||
{
|
||||
var rigidBody = EntityManager.GetComponentObject<Rigidbody2D>(entity);
|
||||
melee.MeleeTimer = Mathf.Max(0, melee.MeleeTimer - Time.DeltaTime);
|
||||
|
||||
if (e.Melee)
|
||||
{
|
||||
var center = rigidBody.position;
|
||||
if (EntityManager.TryGetComponentData<AimCenterData>(entity, out var aimCenter))
|
||||
{
|
||||
center += aimCenter.Offset;
|
||||
}
|
||||
var hits = Physics2D.CircleCastAll(
|
||||
center,
|
||||
meleeShared.Range,
|
||||
rigidBody.transform.right,
|
||||
Time.DeltaTime,
|
||||
meleeShared.MeleeMask);
|
||||
var hitFlag = false;
|
||||
foreach (var hit in hits)
|
||||
{
|
||||
var angle = Vector2.Angle(rigidBody.transform.right, hit.normal);
|
||||
if (angle <= meleeShared.Angle * 0.5f)
|
||||
{
|
||||
var actorFacade = hit.transform.GetComponentInParent<ActorFacade>();
|
||||
if (actorFacade != null &&
|
||||
entity != actorFacade.Entity &&
|
||||
EntityManager.HasComponent<ActorData>(actorFacade.Entity))
|
||||
{
|
||||
var enemyData = EntityManager.GetComponentData<ActorData>(actorFacade.Entity);
|
||||
enemyData.Health = Mathf.Max(0, enemyData.Health - meleeShared.Damage);
|
||||
if (enemyData.Health <= 0)
|
||||
{
|
||||
PostUpdateCommands.PostEntityEvent(
|
||||
EntityManager,
|
||||
actorFacade.Entity,
|
||||
new ActorDeathData { Direction = -hit.normal, Force = meleeShared.Damage });
|
||||
}
|
||||
hit.rigidbody.AddForce(-hit.normal * meleeShared.Knockback, ForceMode2D.Impulse);
|
||||
EntityManager.SetComponentData(actorFacade.Entity, enemyData);
|
||||
soundManager.PlayClip(PostUpdateCommands, settings.MeleeHitSounds, hit.point);
|
||||
settings.BloodParticles.Emit(
|
||||
new ParticleSystem.EmitParams
|
||||
{
|
||||
position = hit.point, rotation = Vector2.SignedAngle(Vector2.up, hit.normal)
|
||||
},
|
||||
1);
|
||||
hitFlag = true;
|
||||
settings.HitImpulse.GenerateImpulseAt(hit.point, Vector3.one * settings.HitImpulseSize);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!hitFlag)
|
||||
{
|
||||
settings.HitImpulse.GenerateImpulse(Vector3.one * settings.MeleeImpulseSize);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Systems/Actor/ActorMeleeSystem.cs.meta
Normal file
11
Assets/Scripts/Systems/Actor/ActorMeleeSystem.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 7b986bf4cd04217499c861430421fa42
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
114
Assets/Scripts/Systems/Actor/ActorWeaponInitializationSystem.cs
Normal file
114
Assets/Scripts/Systems/Actor/ActorWeaponInitializationSystem.cs
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
using Assets.Scripts.Events;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Trive.Mono.Utils;
|
||||
using Unity.Entities;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Experimental.U2D.IK;
|
||||
using Zenject;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace DefaultNamespace
|
||||
{
|
||||
[UpdateInGroup(typeof(InitializationSystemGroup))]
|
||||
public class ActorWeaponInitializationSystem : InjectableComponentSystem
|
||||
{
|
||||
[Serializable]
|
||||
public class Settings
|
||||
{
|
||||
public AnimationClip FirePlaceholder;
|
||||
public AnimationClip IdlePlaceholder;
|
||||
public AnimationClip ReloadPlaceholder;
|
||||
}
|
||||
|
||||
[Inject] private readonly Settings settings;
|
||||
|
||||
protected override void OnSystemUpdate()
|
||||
{
|
||||
Entities.WithNone<ActorWeaponReferenceData>()
|
||||
.WithAllReadOnly<ActorBodyParts, ActorWeaponPropertiesData>()
|
||||
.ForEach(
|
||||
(Entity actorEntity, ActorWeaponPropertiesData weaponProp) =>
|
||||
{
|
||||
var weapon = weaponProp.Weapon;
|
||||
var parts = EntityManager.GetComponentObject<ActorBodyParts>(actorEntity);
|
||||
|
||||
if (parts.WeaponContainer != null)
|
||||
{
|
||||
var op = weapon.Template.IsValid()
|
||||
? weapon.Template.OperationHandle.Convert<GameObject>()
|
||||
: weapon.Template.LoadAssetAsync<GameObject>();
|
||||
if (op.IsValid() && op.IsDone)
|
||||
{
|
||||
PostUpdateActions.Enqueue(
|
||||
() =>
|
||||
{
|
||||
var go = Object.Instantiate(op.Result, parts.WeaponContainer, false);
|
||||
var goEntity = go.GetComponent<DestroyOnlyGameObjectEntity>();
|
||||
if (goEntity != null)
|
||||
{
|
||||
go.transform.localPosition = Vector3.zero;
|
||||
var weaponEntity = goEntity.Entity;
|
||||
|
||||
var rightArmIk = go.TryFindChildGlobal<LimbSolver2D>("$RightArmIk");
|
||||
if (rightArmIk != null)
|
||||
{
|
||||
rightArmIk.GetChain(0).effector = parts.RightHandBone;
|
||||
}
|
||||
var leftArmIk = go.TryFindChildGlobal<LimbSolver2D>("$LeftArmIk");
|
||||
if (leftArmIk != null)
|
||||
{
|
||||
leftArmIk.GetChain(0).effector = parts.LeftHandBone;
|
||||
}
|
||||
|
||||
EntityManager.AddComponentData(weaponEntity, new AnimatorStateData());
|
||||
EntityManager.AddSharedComponentData(weaponEntity, new WeaponPropertiesData { Weapon = weapon });
|
||||
EntityManager.AddComponentData(
|
||||
weaponEntity,
|
||||
new WeaponData
|
||||
{
|
||||
Ammo = weapon.Data.AmmoCapacity - weapon.Data.ClipCapacity, ClipAmmo = weapon.Data.ClipCapacity
|
||||
});
|
||||
EntityManager.AddComponentData(weaponEntity, new WeaponAnimationData());
|
||||
EntityManager.AddComponentData(actorEntity, new ActorWeaponReferenceData { Weapon = weaponEntity });
|
||||
EntityManager.AddComponent(weaponEntity, ComponentType.ReadWrite<WeaponAccuracyData>());
|
||||
EntityManager.AddSharedComponentData(
|
||||
weaponEntity,
|
||||
new WeaponPartsData
|
||||
{
|
||||
Audio = go.FindChildGlobal<AudioSource>("$Audio"),
|
||||
Barrel = go.FindChildGlobal<Transform>("$Barrel"),
|
||||
ShellsExit = go.FindChildGlobal<Transform>("$ShellsExit")
|
||||
});
|
||||
if (EntityManager.HasComponent<Animator>(actorEntity))
|
||||
{
|
||||
var animator = EntityManager.GetComponentObject<Animator>(actorEntity);
|
||||
var overrideController = new AnimatorOverrideController(animator.runtimeAnimatorController);
|
||||
overrideController.ApplyOverrides(
|
||||
new List<KeyValuePair<AnimationClip, AnimationClip>>
|
||||
{
|
||||
new KeyValuePair<AnimationClip, AnimationClip>(
|
||||
settings.FirePlaceholder,
|
||||
weapon.AnimationData.FireAnimation),
|
||||
new KeyValuePair<AnimationClip, AnimationClip>(
|
||||
settings.ReloadPlaceholder,
|
||||
weapon.AnimationData.ReloadAnimation),
|
||||
new KeyValuePair<AnimationClip, AnimationClip>(
|
||||
settings.IdlePlaceholder,
|
||||
weapon.AnimationData.HoldingAnimation)
|
||||
});
|
||||
animator.runtimeAnimatorController = overrideController;
|
||||
EntityManager.AddComponent(actorEntity, ComponentType.ReadWrite<AnimatorRebindEventData>());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("Weapon template must have a DestroyOnlyGameObjectEntity component");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: a32ed2ad3bce0ec4fb8546d5accd8656
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
40
Assets/Scripts/Systems/Actor/ActorWeaponSystem.cs
Normal file
40
Assets/Scripts/Systems/Actor/ActorWeaponSystem.cs
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
using System;
|
||||
using UnityEngine;
|
||||
using Zenject;
|
||||
|
||||
namespace DefaultNamespace
|
||||
{
|
||||
public class ActorWeaponSystem : InjectableComponentSystem
|
||||
{
|
||||
[Serializable]
|
||||
public class Settings
|
||||
{
|
||||
public float AccuracyRegainSpeed;
|
||||
public AnimationCurve AccuracyRegainSpeedCurve;
|
||||
public float MaxAccuracyAttackTime;
|
||||
public float MaxAccuracyDegrade;
|
||||
}
|
||||
|
||||
[Inject] private readonly Settings settings;
|
||||
|
||||
protected override void OnSystemUpdate()
|
||||
{
|
||||
var timeDelta = Time.DeltaTime;
|
||||
|
||||
Entities.ForEach(
|
||||
(ref ActorWeaponReferenceData weaponReference, ref ActorWeaponAccuracyData accuracy) =>
|
||||
{
|
||||
accuracy.AccuracyAttackTime = Mathf.Clamp(accuracy.AccuracyAttackTime - timeDelta, 0, settings.MaxAccuracyAttackTime);
|
||||
accuracy.Accuracy = Mathf.MoveTowards(
|
||||
accuracy.Accuracy,
|
||||
0,
|
||||
timeDelta *
|
||||
settings.AccuracyRegainSpeed *
|
||||
accuracy.AccuracyRegainSpeed *
|
||||
settings.AccuracyRegainSpeedCurve.Evaluate(accuracy.AccuracyAttackTime / settings.MaxAccuracyAttackTime));
|
||||
accuracy.Accuracy = Mathf.Clamp(accuracy.Accuracy, -settings.MaxAccuracyDegrade, settings.MaxAccuracyDegrade);
|
||||
accuracy.AccuracyMultiply = 1;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Systems/Actor/ActorWeaponSystem.cs.meta
Normal file
11
Assets/Scripts/Systems/Actor/ActorWeaponSystem.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 9125a53a5d062ae4bb610abc213b675f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
22
Assets/Scripts/Systems/AdvancedComponentSystem.cs
Normal file
22
Assets/Scripts/Systems/AdvancedComponentSystem.cs
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using Unity.Entities;
|
||||
|
||||
namespace DefaultNamespace
|
||||
{
|
||||
public abstract class AdvancedComponentSystem : ComponentSystem
|
||||
{
|
||||
protected ConcurrentQueue<Action> PostUpdateActions = new ConcurrentQueue<Action>();
|
||||
|
||||
protected override void OnUpdate()
|
||||
{
|
||||
OnSystemUpdate();
|
||||
while (PostUpdateActions.TryDequeue(out var action))
|
||||
{
|
||||
action.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void OnSystemUpdate();
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Systems/AdvancedComponentSystem.cs.meta
Normal file
11
Assets/Scripts/Systems/AdvancedComponentSystem.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 6e3fc48ba5a0ccf4ea3aad65e749ab3c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
33
Assets/Scripts/Systems/AmmoPickupSystem.cs
Normal file
33
Assets/Scripts/Systems/AmmoPickupSystem.cs
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
using Events;
|
||||
using Unity.Entities;
|
||||
using UnityEngine;
|
||||
|
||||
namespace DefaultNamespace
|
||||
{
|
||||
[UpdateInGroup(typeof(PresentationSystemGroup)), UpdateAfter(typeof(ItemPickupSystem)), UpdateBefore(typeof(InventoryPickupSystem))]
|
||||
public class AmmoPickupSystem : AdvancedComponentSystem
|
||||
{
|
||||
protected override void OnSystemUpdate()
|
||||
{
|
||||
Entities.WithAll<Transform>()
|
||||
.ForEach(
|
||||
(Entity entity, AmmoDropComponent ammo, ref ItemPickupEventData pickup, ref ItemContainerAmountData amount) =>
|
||||
{
|
||||
if (EntityManager.TryGetComponentData<ActorWeaponReferenceData>(pickup.PlayerEntity, out var weaponReference) &&
|
||||
EntityManager.TryGetSharedComponentData<ActorWeaponPropertiesData>(pickup.PlayerEntity, out var weapon))
|
||||
{
|
||||
var weaponEntity = weaponReference.Weapon;
|
||||
var weaponData = EntityManager.GetComponentData<WeaponData>(weaponEntity);
|
||||
var transform = EntityManager.GetComponentObject<Transform>(entity);
|
||||
|
||||
if (weaponData.Ammo < weapon.Weapon.Data.AmmoCapacity)
|
||||
{
|
||||
weaponData.Ammo = Mathf.Min(weaponData.Ammo + amount.Amount, weapon.Weapon.Data.AmmoCapacity);
|
||||
EntityManager.SetComponentData(weaponEntity, weaponData);
|
||||
PostUpdateActions.Enqueue(() => Object.Destroy(transform.gameObject));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Systems/AmmoPickupSystem.cs.meta
Normal file
11
Assets/Scripts/Systems/AmmoPickupSystem.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: fc3f9a02683560144b3a62c4af6addd3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
23
Assets/Scripts/Systems/AnimatorStateCopySystem.cs
Normal file
23
Assets/Scripts/Systems/AnimatorStateCopySystem.cs
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
using Unity.Entities;
|
||||
using UnityEngine;
|
||||
|
||||
namespace DefaultNamespace
|
||||
{
|
||||
public class AnimatorStateCopySystem : ComponentSystem
|
||||
{
|
||||
protected override void OnUpdate()
|
||||
{
|
||||
Entities.ForEach(
|
||||
(Animator animator, ref AnimatorStateData data) =>
|
||||
{
|
||||
if (animator.isActiveAndEnabled)
|
||||
{
|
||||
data.State = animator.GetCurrentAnimatorStateInfo(0);
|
||||
var transitionInfo = animator.GetAnimatorTransitionInfo(0);
|
||||
data.TransitionName = transitionInfo.userNameHash;
|
||||
data.TransitionPath = transitionInfo.fullPathHash;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Systems/AnimatorStateCopySystem.cs.meta
Normal file
11
Assets/Scripts/Systems/AnimatorStateCopySystem.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 77982375f38720a4b9a451d005ebd3f9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
56
Assets/Scripts/Systems/CollisionSoundSystem.cs
Normal file
56
Assets/Scripts/Systems/CollisionSoundSystem.cs
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
using Unity.Entities;
|
||||
using UnityEngine;
|
||||
using Zenject;
|
||||
|
||||
namespace DefaultNamespace
|
||||
{
|
||||
public class CollisionSoundSystem : InjectableComponentSystem
|
||||
{
|
||||
private readonly ContactPoint2D[] contactsTmp = new ContactPoint2D[32];
|
||||
[Inject] private readonly SoundManager soundManager;
|
||||
|
||||
protected override void OnSystemUpdate()
|
||||
{
|
||||
var deltaTime = Time.DeltaTime;
|
||||
|
||||
Entities.WithNone<CollisionSoundTimer>()
|
||||
.WithAllReadOnly<CollisionSoundData, Rigidbody2D>()
|
||||
.ForEach(entity => { PostUpdateCommands.AddComponent(entity, new CollisionSoundTimer()); });
|
||||
|
||||
Entities.WithAll<Rigidbody2D>()
|
||||
.ForEach(
|
||||
(Entity entity, CollisionSoundData sound, ref CollisionSoundTimer timer) =>
|
||||
{
|
||||
if (timer.Time <= 0)
|
||||
{
|
||||
var rigidBody = EntityManager.GetComponentObject<Rigidbody2D>(entity);
|
||||
var contactCount = rigidBody.GetContacts(contactsTmp);
|
||||
float largestForce = 0;
|
||||
var largestIndex = -1;
|
||||
|
||||
for (var j = 0; j < contactCount; j++)
|
||||
{
|
||||
var contact = contactsTmp[j];
|
||||
if (contact.normalImpulse >= sound.ForceRange.x && contact.normalImpulse > largestForce)
|
||||
{
|
||||
largestForce = contact.normalImpulse;
|
||||
largestIndex = j;
|
||||
}
|
||||
}
|
||||
|
||||
if (largestIndex >= 0)
|
||||
{
|
||||
var contact = contactsTmp[largestIndex];
|
||||
var volume = (contact.normalImpulse - sound.ForceRange.x) / (sound.ForceRange.y - sound.ForceRange.x);
|
||||
soundManager.PlayClip(PostUpdateCommands, sound.Sound, rigidBody.position, 0.5f, Mathf.Clamp01(volume));
|
||||
timer.Time = 0.3f;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
timer.Time = Mathf.Max(0, timer.Time - deltaTime);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Systems/CollisionSoundSystem.cs.meta
Normal file
11
Assets/Scripts/Systems/CollisionSoundSystem.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 8514d45ce52194a45b004bc633d33263
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
44
Assets/Scripts/Systems/DebugSpawnSystem.cs
Normal file
44
Assets/Scripts/Systems/DebugSpawnSystem.cs
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
using DefaultNamespace.Util;
|
||||
using System;
|
||||
using Unity.Entities;
|
||||
using UnityEngine;
|
||||
using UnityEngine.AddressableAssets;
|
||||
using Zenject;
|
||||
using Hash128 = Unity.Entities.Hash128;
|
||||
|
||||
namespace DefaultNamespace
|
||||
{
|
||||
public class DebugSpawnSystem : InjectableComponentSystem
|
||||
{
|
||||
[Serializable]
|
||||
public class Settings
|
||||
{
|
||||
}
|
||||
|
||||
[Inject] private readonly Settings settings;
|
||||
[Inject(Id = AssetManifest.HealthKit)] private AssetReferenceT<ItemPrefab> helthKit;
|
||||
|
||||
protected override void OnSystemUpdate()
|
||||
{
|
||||
if (Input.GetKeyDown(KeyCode.BackQuote))
|
||||
{
|
||||
Entities.ForEach(
|
||||
(ref RigidBody2DData playerRigidBody, ref PlayerData playerData) =>
|
||||
{
|
||||
var entity = PostUpdateCommands.CreateEntity();
|
||||
PostUpdateCommands.AddComponent(
|
||||
entity,
|
||||
new ItemDropEvent
|
||||
{
|
||||
Item = new ItemData(new Hash128(helthKit.AssetGUID), 1),
|
||||
Pos = playerRigidBody.Position,
|
||||
Velocity = Vector2.zero,
|
||||
Inventory = Entity.Null,
|
||||
ToSlot = -1,
|
||||
FromSlot = -1
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Systems/DebugSpawnSystem.cs.meta
Normal file
11
Assets/Scripts/Systems/DebugSpawnSystem.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 1ed5337761ebae04b937412ddd34cf47
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/Scripts/Systems/Enemy.meta
Normal file
8
Assets/Scripts/Systems/Enemy.meta
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 4e32da8f515eb7844887bbaabb4694b1
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
82
Assets/Scripts/Systems/Enemy/EnemyDeathSystem.cs
Normal file
82
Assets/Scripts/Systems/Enemy/EnemyDeathSystem.cs
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
using Cinemachine;
|
||||
using DefaultNamespace;
|
||||
using Events;
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using Zenject;
|
||||
using Entity = Unity.Entities.Entity;
|
||||
using Hash128 = Unity.Entities.Hash128;
|
||||
using Random = UnityEngine.Random;
|
||||
|
||||
public class EnemyDeathSystem : InjectableComponentSystem
|
||||
{
|
||||
[Serializable]
|
||||
public class Settings
|
||||
{
|
||||
public CinemachineImpulseSource EnemyImpulseSource;
|
||||
public float ImpulseSourceSize;
|
||||
public float ItemDropShootForce;
|
||||
}
|
||||
|
||||
[Inject] private readonly ParticleSystemFactory particleFactory;
|
||||
[Inject] private readonly Settings settings;
|
||||
|
||||
[Inject] private readonly SoundManager soundManager;
|
||||
|
||||
protected override void OnSystemUpdate()
|
||||
{
|
||||
Entities.WithNone<EntityDeathEvent>()
|
||||
.ForEach(
|
||||
(Entity entity, Transform transform, ref Enemy enemy, ref ActorData actor) =>
|
||||
{
|
||||
Vector2 pos = transform.position;
|
||||
|
||||
if (actor.Health <= 0)
|
||||
{
|
||||
if (EntityManager.HasComponent<EnemyPrefabComponent>(entity))
|
||||
{
|
||||
var prefab = EntityManager.GetComponentObject<EnemyPrefabComponent>(entity);
|
||||
settings.EnemyImpulseSource.GenerateImpulseAt(pos, Vector3.one * settings.ImpulseSourceSize);
|
||||
prefab.Prefab.OperationHandle.Convert<EnemyPrefab>().Completed += operation =>
|
||||
{
|
||||
var particles = particleFactory.Create(new Hash128(operation.Result.DeathParticles.AssetGUID));
|
||||
particles.Completed += particleOperation =>
|
||||
{
|
||||
particleOperation.Result.GetComponent<ParticleSystem>().Emit(new ParticleSystem.EmitParams { position = pos }, 1);
|
||||
};
|
||||
foreach (var library in operation.Result.DeathSounds)
|
||||
{
|
||||
soundManager.PlayClip(EntityManager, library, pos);
|
||||
}
|
||||
|
||||
foreach (var drop in operation.Result.Drops)
|
||||
{
|
||||
var r = Random.value;
|
||||
if (r < drop.Chance)
|
||||
{
|
||||
var count = Random.Range(drop.MinCount, drop.MaxCount);
|
||||
if (count > 0)
|
||||
{
|
||||
var e = EntityManager.CreateEntity();
|
||||
EntityManager.AddComponentData(
|
||||
e,
|
||||
new ItemDropEvent
|
||||
{
|
||||
Item = new ItemData(new Hash128(drop.Item.AssetGUID), count),
|
||||
Pos = pos,
|
||||
Velocity = Random.insideUnitCircle * settings.ItemDropShootForce,
|
||||
Inventory = Entity.Null,
|
||||
ToSlot = -1,
|
||||
FromSlot = -1
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
PostUpdateCommands.AddComponent(entity, new EntityDeathEvent());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Systems/Enemy/EnemyDeathSystem.cs.meta
Normal file
11
Assets/Scripts/Systems/Enemy/EnemyDeathSystem.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: e44e3c7f9a143b14cadcd63710d28975
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
237
Assets/Scripts/Systems/Enemy/EnemyDriverSystem.cs
Normal file
237
Assets/Scripts/Systems/Enemy/EnemyDriverSystem.cs
Normal file
|
|
@ -0,0 +1,237 @@
|
|||
using DefaultNamespace;
|
||||
using DefaultNamespace.Navigation;
|
||||
using Polycrime;
|
||||
using System;
|
||||
using Unity.Entities;
|
||||
using UnityEngine;
|
||||
using Zenject;
|
||||
|
||||
[UpdateInGroup(typeof(PresentationSystemGroup)), UpdateBefore(typeof(ActorAnimationEventResetSystem))]
|
||||
public class EnemyDriverSystem : InjectableComponentSystem
|
||||
{
|
||||
[Serializable]
|
||||
public class Settings
|
||||
{
|
||||
public float DefaultReachTime;
|
||||
public float JumpMinHeight;
|
||||
public float MaxAirForce;
|
||||
public float MaxForce;
|
||||
public float MinPlayerDistance;
|
||||
public float MoveForce;
|
||||
public Vector3 MovePidParams;
|
||||
public float NodeMinDistance;
|
||||
public float RepathCooldown;
|
||||
public ParticleSystem StabBloodParticles;
|
||||
public SoundLibrary StabSounds;
|
||||
public float ViewDistance;
|
||||
public LayerMask VisibilityLayerMask;
|
||||
}
|
||||
|
||||
[Inject] private Settings settings;
|
||||
[Inject] private SoundManager soundManager;
|
||||
|
||||
protected override void OnSystemUpdate()
|
||||
{
|
||||
ManageEnemies();
|
||||
ManagePathActors();
|
||||
ManageRangeEnemies();
|
||||
}
|
||||
|
||||
private void ManageEnemies()
|
||||
{
|
||||
var timeDelta = Time.DeltaTime;
|
||||
|
||||
Entities.ForEach(
|
||||
(ref ActorNpcData npc) =>
|
||||
{
|
||||
npc.AttackCooldown = Mathf.Max(0, npc.AttackCooldown - timeDelta);
|
||||
npc.ActionCooldown = Mathf.Max(0, npc.ActionCooldown - timeDelta);
|
||||
npc.JumpingTimer = Mathf.Max(0, npc.JumpingTimer - timeDelta);
|
||||
});
|
||||
}
|
||||
|
||||
private void ManageRangeEnemies()
|
||||
{
|
||||
Entities.ForEach(
|
||||
(
|
||||
ActorWeaponPropertiesData weaponComponent,
|
||||
ref ActorWeaponReferenceData weaponReference,
|
||||
ref ActorAnimationData animation,
|
||||
ref Enemy enemy) =>
|
||||
{
|
||||
animation.AttackSpeed = weaponComponent.Weapon.Data.RateOfFire;
|
||||
});
|
||||
}
|
||||
|
||||
private void ManagePathActors()
|
||||
{
|
||||
var timeDelta = Time.DeltaTime;
|
||||
|
||||
Entities.WithAll<PathNode>()
|
||||
.ForEach(
|
||||
(
|
||||
Entity entity,
|
||||
Rigidbody2D rigidBody,
|
||||
ref NavigationAgentData navigationAgent,
|
||||
ref RigidBody2DData rigidBodyData,
|
||||
ref ActorNpcData npc,
|
||||
ref ActorData actor,
|
||||
ref ActorAnimationData animation) =>
|
||||
{
|
||||
var aimCenter = EntityManager.HasComponent<AimCenterData>(entity)
|
||||
? EntityManager.GetComponentData<AimCenterData>(entity)
|
||||
: default;
|
||||
var path = EntityManager.GetBuffer<PathNode>(entity);
|
||||
|
||||
//pathHolder.RepathCooldown = Mathf.Max(0, pathHolder.RepathCooldown - timeDelta);
|
||||
|
||||
//npc.XPid.SetFactors(settings.MovePidParams);
|
||||
|
||||
/*Vector2 targetVelocity = Vector2.zero;
|
||||
|
||||
if (pathHolder.Path != null && pathHolder.Path.IsDone())
|
||||
{
|
||||
int currentTargetIndex = FindNextTarget(rigidBodyData.Position, pathHolder);
|
||||
if (currentTargetIndex >= pathHolder.Path.vectorPath.Count)
|
||||
{
|
||||
pathHolder.Path = null;
|
||||
return;
|
||||
}
|
||||
Vector2 nextTarget = pathHolder.Path.vectorPath[currentTargetIndex];
|
||||
Vector2 currentTarget = currentTargetIndex > 0 ? (Vector2)pathHolder.Path.vectorPath[Mathf.Max(currentTargetIndex - 1, 0)] : rigidBodyData.Position;
|
||||
var nextNode = (PointNode)pathHolder.Path.path[currentTargetIndex];
|
||||
var currentNode = (PointNode)pathHolder.Path.path[Mathf.Max(currentTargetIndex - 1, 0)];
|
||||
Vector2 nodeDir = nextTarget - currentTarget;
|
||||
|
||||
if (npc.JumpingTimer > 0)
|
||||
{
|
||||
actor.Aim = rigidBodyData.Position + new Vector2(nodeDir.x, 0) + aimCenter.Offset;
|
||||
if (actor.Grounded) npc.JumpingTimer = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
float distance = Vector2.Distance(nextTarget, rigidBodyData.Position);
|
||||
if (distance < settings.NodeMinDistance && currentTargetIndex < pathHolder.Path.vectorPath.Count && actor.Grounded)
|
||||
{
|
||||
currentTargetIndex++;
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector2 rawDelta = (Vector2)nextTarget - rigidBodyData.Position;
|
||||
if (currentTargetIndex < pathHolder.Path.vectorPath.Count && actor.Grounded)
|
||||
{
|
||||
jumpNodesTmp.Clear();
|
||||
currentNode.gameObject.GetComponents(jumpNodesTmp);
|
||||
var currentJumpNode = jumpNodesTmp.FirstOrDefault(n => n.IsEnd(nextNode.gameObject));
|
||||
if (currentJumpNode != null)
|
||||
{
|
||||
Jump(currentJumpNode.ReachTime, rigidBody, rigidBodyData.Position, nodeDir, nextTarget, ref npc, ref actor, ref animation, aimCenter);
|
||||
}
|
||||
else
|
||||
{
|
||||
jumpNodesTmp.Clear();
|
||||
nextNode.gameObject.GetComponents(jumpNodesTmp);
|
||||
currentJumpNode = jumpNodesTmp.FirstOrDefault(n => n.IsEnd(currentNode.gameObject));
|
||||
if (currentJumpNode != null)
|
||||
{
|
||||
Jump(currentJumpNode.ReachTime, rigidBody, rigidBodyData.Position, nodeDir, nextTarget, ref npc, ref actor, ref animation, aimCenter);
|
||||
}
|
||||
else if (Mathf.Abs(rawDelta.y) >= settings.JumpMinHeight)
|
||||
{
|
||||
Jump(settings.DefaultReachTime, rigidBody, rigidBodyData.Position, nodeDir, nextTarget, ref npc, ref actor, ref animation, aimCenter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (npc.JumpingTimer <= 0)
|
||||
{
|
||||
targetVelocity = rawDelta.normalized * settings.MoveForce;
|
||||
animation.WalkMultiply = Mathf.Clamp01(Mathf.Abs(targetVelocity.x) / settings.MoveForce);
|
||||
animation.WalkDir = (Mathf.Sign(rigidBody.transform.right.x) == Mathf.Sign(nodeDir.x) ? -1 : 1) * animation.WalkMultiply;
|
||||
if (Target.Exists(entity))
|
||||
{
|
||||
var target = Target[entity];
|
||||
if (EntityManager.HasComponent<Transform>(target.Target))
|
||||
{
|
||||
var targetTransform = EntityManager.GetComponentObject<Transform>(target.Target);
|
||||
actor.Aim = distance <= settings.ViewDistance && CanSeeTarget(rigidBody, targetTransform, aimCenter) ? (Vector2)targetTransform.transform.position + aimCenter.Offset : rigidBody.position + new Vector2(nodeDir.x, 0) + aimCenter.Offset * 0.5f;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pathHolder.CurrentTarget = currentTargetIndex;
|
||||
}
|
||||
else
|
||||
{
|
||||
targetVelocity = Vector2.zero;
|
||||
animation.WalkMultiply = 0;
|
||||
}
|
||||
|
||||
npc.XPid = npc.XPid.Update(targetVelocity.x, rigidBodyData.Velocity.x, Time.deltaTime,out var val);
|
||||
Vector2 delta = Vector2.ClampMagnitude(new Vector2(val, 0), Mathf.Lerp(settings.MaxForce,settings.MaxAirForce,actor.Grounded ? 0 : 1));
|
||||
rigidBody.AddForce(delta);
|
||||
*/
|
||||
|
||||
var currentNodeIndex = navigationAgent.currentIndex;
|
||||
var nextNodeIndex = navigationAgent.currentIndex + 1;
|
||||
|
||||
if (nextNodeIndex < path.Length)
|
||||
{
|
||||
var currentNode = path[currentNodeIndex];
|
||||
var nextNode = path[nextNodeIndex];
|
||||
var distance = Vector2.Distance(nextNode.pos, rigidBodyData.Position);
|
||||
var nodeDir = nextNode.pos - currentNode.pos;
|
||||
animation.WalkMultiply = 1;
|
||||
actor.Aim = rigidBodyData.Position + new Vector2(nextNode.pos.x, 0) + aimCenter.Offset;
|
||||
animation.WalkDir = (Mathf.Sign(rigidBody.transform.right.x) == Mathf.Sign(nodeDir.x) ? -1 : 1) * animation.WalkMultiply;
|
||||
if (EntityManager.TryGetComponentData<ActorTargetData>(entity, out var target))
|
||||
{
|
||||
if (EntityManager.HasComponent<Transform>(target.Target))
|
||||
{
|
||||
var targetTransform = EntityManager.GetComponentObject<Transform>(target.Target);
|
||||
actor.Aim = distance <= settings.ViewDistance && CanSeeTarget(rigidBody, targetTransform, aimCenter)
|
||||
? (Vector2)targetTransform.transform.position + aimCenter.Offset
|
||||
: rigidBody.position + new Vector2(nodeDir.x, 0) + aimCenter.Offset * 0.5f;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
animation.WalkMultiply = 0;
|
||||
}
|
||||
|
||||
animation.AttackSpeed = 1;
|
||||
});
|
||||
}
|
||||
|
||||
private bool CanSeeTarget(Rigidbody2D source, Transform target, AimCenterData aimCenter)
|
||||
{
|
||||
var dir = (Vector2)target.position + aimCenter.Offset - (source.position + aimCenter.Offset);
|
||||
var distance = dir.magnitude;
|
||||
var hit = Physics2D.Raycast(source.position + aimCenter.Offset, dir / distance, distance, settings.VisibilityLayerMask);
|
||||
return hit.transform == target;
|
||||
}
|
||||
|
||||
private void Jump(
|
||||
float reachTime,
|
||||
Rigidbody2D rigidBody,
|
||||
Vector2 pos,
|
||||
Vector2 dir,
|
||||
Vector2 target,
|
||||
ref ActorNpcData npc,
|
||||
ref ActorData actor,
|
||||
ref ActorAnimationData animation,
|
||||
AimCenterData aimCenter)
|
||||
{
|
||||
npc.JumpingTimer = reachTime;
|
||||
rigidBody.velocity = TrajectoryMath.CalculateVelocity(pos, target, reachTime, rigidBody.gravityScale);
|
||||
animation.WalkDir = Mathf.Sign(rigidBody.transform.right.x) == Mathf.Sign(dir.x) ? -1 : 1;
|
||||
actor.Grounded = false;
|
||||
actor.Aim = pos + dir + aimCenter.Offset;
|
||||
animation.WalkMultiply = 0;
|
||||
animation.Triggers |= AnimationTriggerType.Jump;
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Systems/Enemy/EnemyDriverSystem.cs.meta
Normal file
11
Assets/Scripts/Systems/Enemy/EnemyDriverSystem.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 36011162a5b4119419ad80e11512f872
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
45
Assets/Scripts/Systems/Enemy/EnemyInitializationSystem.cs
Normal file
45
Assets/Scripts/Systems/Enemy/EnemyInitializationSystem.cs
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
using AI;
|
||||
using Unity.Entities;
|
||||
|
||||
namespace DefaultNamespace
|
||||
{
|
||||
[UpdateInGroup(typeof(InitializationSystemGroup))]
|
||||
public class EnemyInitializationSystem : ComponentSystem
|
||||
{
|
||||
protected override void OnUpdate()
|
||||
{
|
||||
Entities.WithAll<EnemyPrefabComponent>()
|
||||
.WithNone<EnemyActorGoapInitialized>()
|
||||
.ForEach(
|
||||
(Entity entity, GoapAgentData data) =>
|
||||
{
|
||||
data.Goals.Add(((int)GoapKeys.Attacks, true));
|
||||
|
||||
PostUpdateCommands.AddComponent(entity, new EnemyActorGoapInitialized());
|
||||
});
|
||||
|
||||
Entities.WithNone<ActorGrenadeData>()
|
||||
.ForEach((Entity entitiy, ActorGrenadeComponent grenade) => { PostUpdateCommands.AddComponent(entitiy, new ActorGrenadeData()); });
|
||||
|
||||
Entities.WithNone<ActorData, ActorDataInitialization>()
|
||||
.ForEach(
|
||||
(Entity entity, EnemyPrefabComponent prefab) =>
|
||||
{
|
||||
prefab.Prefab.OperationHandle.Convert<EnemyPrefab>().Completed += operation =>
|
||||
{
|
||||
EntityManager.AddComponentData(entity, new ActorData { Health = operation.Result.MaxHealth });
|
||||
EntityManager.RemoveComponent<ActorDataInitialization>(entity);
|
||||
};
|
||||
PostUpdateCommands.AddComponent(entity, new ActorDataInitialization());
|
||||
});
|
||||
}
|
||||
|
||||
private struct ActorDataInitialization : ISystemStateComponentData
|
||||
{
|
||||
}
|
||||
|
||||
private struct EnemyActorGoapInitialized : IComponentData
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d2681da5e82636541bb6f573b1c5b88e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
63
Assets/Scripts/Systems/Enemy/EnemySpawnSystem.cs
Normal file
63
Assets/Scripts/Systems/Enemy/EnemySpawnSystem.cs
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
using Events;
|
||||
using Trive.Mono.Utils;
|
||||
using Unity.Collections;
|
||||
using Unity.Entities;
|
||||
using UnityEngine;
|
||||
using Zenject;
|
||||
|
||||
namespace DefaultNamespace
|
||||
{
|
||||
[UpdateAfter(typeof(EnemyDeathSystem))]
|
||||
public class EnemySpawnSystem : InjectableComponentSystem
|
||||
{
|
||||
private NativeQueue<int> DeathsQueue = new NativeQueue<int>(Allocator.Persistent);
|
||||
[Inject] private Unity.Entities.World world;
|
||||
|
||||
protected override void OnDestroy()
|
||||
{
|
||||
DeathsQueue.Dispose();
|
||||
}
|
||||
|
||||
protected override void OnSystemUpdate()
|
||||
{
|
||||
Entities.ForEach(
|
||||
(Spawner spawner) =>
|
||||
{
|
||||
spawner.SpawnTimer = Mathf.Max(0, spawner.SpawnTimer - Time.DeltaTime);
|
||||
if (spawner.SpawnTimer <= 0 && spawner.CurrentCount < spawner.MaxTotalSpawns)
|
||||
{
|
||||
spawner.SpawnTimer = spawner.MaxSpawnInterval;
|
||||
var spawnCount = Mathf.Min(spawner.MaxTotalSpawns - spawner.CurrentCount, spawner.MaxSpawns);
|
||||
for (var j = 0; j < spawnCount; j++)
|
||||
{
|
||||
var pos = (Vector2)spawner.transform.position + Random.insideUnitCircle * spawner.SpawnRadius;
|
||||
spawner.EnemyPrefab.Template.InstantiateAsync(pos, Quaternion.identity).Completed += operation =>
|
||||
{
|
||||
var entity = operation.Result.gameObject.ConvertToEntity(world);
|
||||
operation.Result.gameObject.GetComponent<ActorFacade>().Entity = entity;
|
||||
operation.Result.gameObject.GetComponent<ActorFacade>().World = World;
|
||||
world.EntityManager.AddComponentData(entity, new SpawnInfo { SpawnerId = spawner.GetInstanceID() });
|
||||
};
|
||||
spawner.CurrentCount++;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Entities.WithAllReadOnly<EntityDeathEvent, SpawnInfo>()
|
||||
.ForEach(entity => { DeathsQueue.Enqueue(EntityManager.GetComponentData<SpawnInfo>(entity).SpawnerId); });
|
||||
|
||||
while (DeathsQueue.Count > 0)
|
||||
{
|
||||
var enemy = DeathsQueue.Dequeue();
|
||||
Entities.ForEach(
|
||||
(Spawner spawner) =>
|
||||
{
|
||||
if (spawner.GetInstanceID() == enemy)
|
||||
{
|
||||
spawner.CurrentCount = Mathf.Max(spawner.CurrentCount - 1, 0);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Systems/Enemy/EnemySpawnSystem.cs.meta
Normal file
11
Assets/Scripts/Systems/Enemy/EnemySpawnSystem.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 82a2563a6596b764c9cf45364a01be1e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
51
Assets/Scripts/Systems/Enemy/EnemyTargetFinderSystem.cs
Normal file
51
Assets/Scripts/Systems/Enemy/EnemyTargetFinderSystem.cs
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
using AI;
|
||||
using Unity.Entities;
|
||||
using UnityEngine;
|
||||
|
||||
namespace DefaultNamespace
|
||||
{
|
||||
public class EnemyTargetFinderSystem : ComponentSystem
|
||||
{
|
||||
protected override void OnUpdate()
|
||||
{
|
||||
Entities.ForEach(
|
||||
(ref Enemy enemy, ref RigidBody2DData actorRigidBody, ref ActorTargetData target) =>
|
||||
{
|
||||
if (!EntityManager.Exists(target.Target))
|
||||
{
|
||||
var closestDist = float.MaxValue;
|
||||
var actorPos = actorRigidBody.Position;
|
||||
var finalTarget = Entity.Null;
|
||||
Entities.ForEach(
|
||||
(Entity playerEntity, ref RigidBody2DData rigidBody, ref PlayerData playerData) =>
|
||||
{
|
||||
var d = Vector2.SqrMagnitude(actorPos - rigidBody.Position);
|
||||
if (d < closestDist)
|
||||
{
|
||||
closestDist = d;
|
||||
finalTarget = playerEntity;
|
||||
}
|
||||
});
|
||||
target.Target = finalTarget;
|
||||
}
|
||||
});
|
||||
|
||||
Entities.ForEach(
|
||||
(GoapAgentData agent, ref ActorTargetData target) =>
|
||||
{
|
||||
if (agent.States != null)
|
||||
{
|
||||
var targetVal = (GoapKeys.HasTarget, true);
|
||||
if (EntityManager.Exists(target.Target))
|
||||
{
|
||||
agent.States.Add(targetVal);
|
||||
}
|
||||
else
|
||||
{
|
||||
agent.States.Remove(targetVal);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Systems/Enemy/EnemyTargetFinderSystem.cs.meta
Normal file
11
Assets/Scripts/Systems/Enemy/EnemyTargetFinderSystem.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: bfd009e9173f9f349b92630c8d055e8a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
34
Assets/Scripts/Systems/EntityDeathSystem.cs
Normal file
34
Assets/Scripts/Systems/EntityDeathSystem.cs
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
using Events;
|
||||
using Unity.Entities;
|
||||
using UnityEngine;
|
||||
|
||||
namespace DefaultNamespace
|
||||
{
|
||||
[UpdateInGroup(typeof(LateSimulationSystemGroup))]
|
||||
public class EntityDeathSystem : AdvancedComponentSystem
|
||||
{
|
||||
protected override void OnSystemUpdate()
|
||||
{
|
||||
Entities.ForEach(
|
||||
(Entity entity, ref EntityDeathEvent e) =>
|
||||
{
|
||||
if (EntityManager.HasComponent<Transform>(entity))
|
||||
{
|
||||
PostUpdateActions.Enqueue(
|
||||
() =>
|
||||
{
|
||||
Object.Destroy(EntityManager.GetComponentObject<Transform>(entity).gameObject);
|
||||
if (EntityManager.Exists(entity))
|
||||
{
|
||||
EntityManager.DestroyEntity(entity);
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
PostUpdateCommands.DestroyEntity(entity);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Systems/EntityDeathSystem.cs.meta
Normal file
11
Assets/Scripts/Systems/EntityDeathSystem.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 5b25a42d216466849a664d9413213670
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
21
Assets/Scripts/Systems/EventRemovalSystem.cs
Normal file
21
Assets/Scripts/Systems/EventRemovalSystem.cs
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
using Events;
|
||||
using Unity.Entities;
|
||||
|
||||
namespace DefaultNamespace
|
||||
{
|
||||
[UpdateInGroup(typeof(SimulationSystemGroup))]
|
||||
public class EventRemovalSystem : ComponentSystem
|
||||
{
|
||||
private EntityQuery group;
|
||||
|
||||
protected override void OnCreate()
|
||||
{
|
||||
group = GetEntityQuery(ComponentType.ReadOnly<EventData>());
|
||||
}
|
||||
|
||||
protected override void OnUpdate()
|
||||
{
|
||||
EntityManager.DestroyEntity(group);
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Systems/EventRemovalSystem.cs.meta
Normal file
11
Assets/Scripts/Systems/EventRemovalSystem.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b7722c79edb14354da2fe990b468c1cd
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
78
Assets/Scripts/Systems/FragGrenadeSystem.cs
Normal file
78
Assets/Scripts/Systems/FragGrenadeSystem.cs
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
using Cinemachine;
|
||||
using Events;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Unity.Entities;
|
||||
using UnityEngine;
|
||||
using Zenject;
|
||||
|
||||
namespace DefaultNamespace
|
||||
{
|
||||
[UpdateInGroup(typeof(PresentationSystemGroup)), UpdateAfter(typeof(ActorGrenadeSystem))]
|
||||
public class FragGrenadeSystem : InjectableComponentSystem
|
||||
{
|
||||
[Serializable]
|
||||
public class Settings
|
||||
{
|
||||
public SoundLibrary ExplosionSound;
|
||||
public CinemachineImpulseSource ImpulseSource;
|
||||
public ParticleSystem Particles;
|
||||
}
|
||||
|
||||
[Inject] private Settings settings;
|
||||
[Inject] private SoundManager soundManager;
|
||||
|
||||
protected override void OnSystemUpdate()
|
||||
{
|
||||
Entities.ForEach(
|
||||
(ref EntityDeathEvent e, ref FragGrenadeData fragGrenade, ref GrenadeData grenade, ref RigidBody2DData rigidBody) =>
|
||||
{
|
||||
settings.Particles.Emit(new ParticleSystem.EmitParams { position = rigidBody.Position }, 1);
|
||||
settings.ImpulseSource.GenerateImpulseAt(rigidBody.Position, Vector3.one);
|
||||
soundManager.PlayClip(PostUpdateCommands, settings.ExplosionSound, rigidBody.Position);
|
||||
|
||||
var overlaps = new Dictionary<Entity, float>();
|
||||
var overlapColliders = Physics2D.OverlapCircleAll(rigidBody.Position, fragGrenade.Range);
|
||||
foreach (var collider in overlapColliders)
|
||||
{
|
||||
var actorFacade = collider.GetComponentInParent<ActorFacade>();
|
||||
if (actorFacade != null && EntityManager.HasComponent<ActorData>(actorFacade.Entity))
|
||||
{
|
||||
var currentDistance = Vector2.Distance(rigidBody.Position, collider.transform.TransformPoint(collider.offset));
|
||||
if (!overlaps.TryGetValue(actorFacade.Entity, out var distance))
|
||||
{
|
||||
distance = float.MaxValue;
|
||||
}
|
||||
if (currentDistance < distance)
|
||||
{
|
||||
overlaps.Add(actorFacade.Entity, currentDistance);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var overlap in overlaps)
|
||||
{
|
||||
var actor = EntityManager.GetComponentData<ActorData>(overlap.Key);
|
||||
|
||||
var dmg = grenade.DamageEase.Ease(1 - Mathf.Clamp01(overlap.Value / fragGrenade.Range)) * grenade.Damage;
|
||||
actor.Health = Mathf.Max(0, actor.Health - dmg);
|
||||
if (actor.Health <= 0)
|
||||
{
|
||||
var overlapRigidBody = EntityManager.GetComponentObject<Rigidbody2D>(overlap.Key);
|
||||
var center = overlapRigidBody.position;
|
||||
if (EntityManager.TryGetComponentData<AimCenterData>(overlap.Key, out var aim))
|
||||
{
|
||||
center += aim.Offset;
|
||||
}
|
||||
PostUpdateCommands.PostEntityEvent(
|
||||
EntityManager,
|
||||
overlap.Key,
|
||||
new ActorDeathData { Direction = (center - rigidBody.Position).normalized, Force = dmg });
|
||||
}
|
||||
|
||||
EntityManager.SetComponentData(overlap.Key, actor);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Systems/FragGrenadeSystem.cs.meta
Normal file
11
Assets/Scripts/Systems/FragGrenadeSystem.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: fa6fe75a8af67ef4985ea41edb96a4ed
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
33
Assets/Scripts/Systems/InjectableComponentSystem.cs
Normal file
33
Assets/Scripts/Systems/InjectableComponentSystem.cs
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using Unity.Entities;
|
||||
using Zenject;
|
||||
|
||||
namespace DefaultNamespace
|
||||
{
|
||||
public abstract class InjectableComponentSystem : ComponentSystem
|
||||
{
|
||||
private bool injected;
|
||||
protected ConcurrentQueue<Action> PostUpdateActions = new ConcurrentQueue<Action>();
|
||||
|
||||
[Inject]
|
||||
private void OnInject()
|
||||
{
|
||||
injected = true;
|
||||
}
|
||||
|
||||
protected override void OnUpdate()
|
||||
{
|
||||
if (injected)
|
||||
{
|
||||
OnSystemUpdate();
|
||||
}
|
||||
while (PostUpdateActions.TryDequeue(out var action))
|
||||
{
|
||||
action.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void OnSystemUpdate();
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Systems/InjectableComponentSystem.cs.meta
Normal file
11
Assets/Scripts/Systems/InjectableComponentSystem.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 5e785b5f27074e64ea3102d117406dce
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/Scripts/Systems/Items.meta
Normal file
8
Assets/Scripts/Systems/Items.meta
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: e77b7d13d1814164280d90e02fc59064
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
33
Assets/Scripts/Systems/Items/GrenadeUseSystem.cs
Normal file
33
Assets/Scripts/Systems/Items/GrenadeUseSystem.cs
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
using Events;
|
||||
using Items;
|
||||
using Unity.Entities;
|
||||
using UnityEngine;
|
||||
|
||||
namespace DefaultNamespace
|
||||
{
|
||||
public class GrenadeUseSystem : ItemUseSystemAbstract<GrenadeItem>
|
||||
{
|
||||
public override ItemUseFlags Flags => ItemUseFlags.UseOnlyInteractive;
|
||||
|
||||
public override ItemUseType UseType => ItemUseType.Grenade;
|
||||
|
||||
public override bool IsAdditiveUsage => true;
|
||||
|
||||
protected override void Use(GrenadeItem prefab, ref ItemData itemData, Entity user, Entity inventory)
|
||||
{
|
||||
itemData.Amount--;
|
||||
entityManager.PostEntityEvent<InventoryDirtyEventData>(inventory);
|
||||
entityManager.PostEntityEvent(user, new FireGrenadeEvent { GrenadePrefab = itemData.Item });
|
||||
}
|
||||
|
||||
protected override bool Validate(GrenadeItem prefab, Entity user, Entity inventory)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public override Sprite GetItemIcon(GrenadeItem prefab)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Systems/Items/GrenadeUseSystem.cs.meta
Normal file
11
Assets/Scripts/Systems/Items/GrenadeUseSystem.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ef39a98683c52864d846421dc14c9401
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
48
Assets/Scripts/Systems/Items/HealthPackUseSystem.cs
Normal file
48
Assets/Scripts/Systems/Items/HealthPackUseSystem.cs
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
using Events;
|
||||
using Items;
|
||||
using Unity.Entities;
|
||||
using UnityEngine;
|
||||
|
||||
namespace DefaultNamespace
|
||||
{
|
||||
public class HealthPackUseSystem : ItemUseSystemAbstract<HealthKitItem>
|
||||
{
|
||||
public override ItemUseFlags Flags => ItemUseFlags.UseOnlyInteractive | ItemUseFlags.UseOnlyGrounded;
|
||||
|
||||
public override ItemUseType UseType => ItemUseType.HealthPack;
|
||||
|
||||
public override bool IsAdditiveUsage => false;
|
||||
|
||||
protected override void Use(HealthKitItem prefab, ref ItemData itemData, Entity user, Entity inventory)
|
||||
{
|
||||
var facade = entityManager.GetComponentObject<PlayerFacade>(user);
|
||||
var actorData = entityManager.GetComponentData<ActorData>(user);
|
||||
|
||||
actorData.Health = Mathf.Min(actorData.Health + prefab.Health, facade.MaxHealth);
|
||||
itemData.Amount--;
|
||||
|
||||
entityManager.SetComponentData(user, actorData);
|
||||
entityManager.PostEntityEvent<InventoryDirtyEventData>(user);
|
||||
}
|
||||
|
||||
protected override bool Validate(HealthKitItem prefab, Entity user, Entity inventory)
|
||||
{
|
||||
if (!entityManager.HasComponent<ActorData>(user))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
var playerFacade = entityManager.GetComponentObject<PlayerFacade>(user);
|
||||
if (playerFacade == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
var actorData = entityManager.GetComponentData<ActorData>(user);
|
||||
return actorData.Health < playerFacade.MaxHealth;
|
||||
}
|
||||
|
||||
public override Sprite GetItemIcon(HealthKitItem prefab)
|
||||
{
|
||||
return prefab.UseItemIcon;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Systems/Items/HealthPackUseSystem.cs.meta
Normal file
11
Assets/Scripts/Systems/Items/HealthPackUseSystem.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: e22016dc3c17bb849afc787c8d4d8abe
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
28
Assets/Scripts/Systems/Items/IItemUseSystem.cs
Normal file
28
Assets/Scripts/Systems/Items/IItemUseSystem.cs
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
using Unity.Entities;
|
||||
using UnityEngine;
|
||||
|
||||
namespace DefaultNamespace
|
||||
{
|
||||
public interface IItemUseSystem
|
||||
{
|
||||
ItemUseFlags Flags { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The use type in animator. Converst to integer index.
|
||||
/// </summary>
|
||||
ItemUseType UseType { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Should use animation be on additive layer
|
||||
/// </summary>
|
||||
bool IsAdditiveUsage { get; }
|
||||
|
||||
bool CanUse(ItemPrefab prefab);
|
||||
|
||||
bool Validate(ItemPrefab prefab, Entity user, Entity inventory);
|
||||
|
||||
Sprite GetItemIcon(ItemPrefab prefab);
|
||||
|
||||
void Use(ItemPrefab prefab, ref ItemData itemData, Entity user, Entity inventory);
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Systems/Items/IItemUseSystem.cs.meta
Normal file
11
Assets/Scripts/Systems/Items/IItemUseSystem.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 8286d73d7aaeff94f803396767d8f590
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
59
Assets/Scripts/Systems/Items/InventoryPickupSystem.cs
Normal file
59
Assets/Scripts/Systems/Items/InventoryPickupSystem.cs
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
using Events;
|
||||
using System.Collections.Generic;
|
||||
using Unity.Entities;
|
||||
using UnityEngine;
|
||||
|
||||
namespace DefaultNamespace
|
||||
{
|
||||
[UpdateInGroup(typeof(PresentationSystemGroup)), UpdateAfter(typeof(ItemPickupSystem))]
|
||||
public class InventoryPickupSystem : ComponentSystem
|
||||
{
|
||||
protected override void OnUpdate()
|
||||
{
|
||||
var toDelete = new List<Object>();
|
||||
|
||||
Entities.ForEach(
|
||||
(Rigidbody2D rigidBody, ref ItemPickupEventData pickup, ref ItemContainerData item) =>
|
||||
{
|
||||
var playerInventory = EntityManager.GetBuffer<Slot>(pickup.PlayerEntity);
|
||||
var pickedUpItemFlag = false;
|
||||
for (var j = 0; j < playerInventory.Length; j++)
|
||||
{
|
||||
var data = playerInventory[j];
|
||||
if (data.Item.Item == item.ItemPrefab)
|
||||
{
|
||||
data.Item.Amount++;
|
||||
playerInventory[j] = data;
|
||||
PostUpdateCommands.PostEntityEvent<InventoryDirtyEventData>(EntityManager, pickup.PlayerEntity);
|
||||
toDelete.Add(rigidBody.gameObject);
|
||||
pickedUpItemFlag = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//add in free spot
|
||||
if (!pickedUpItemFlag)
|
||||
{
|
||||
for (var j = 0; j < playerInventory.Length; j++)
|
||||
{
|
||||
var data = playerInventory[j];
|
||||
if (!data.Item.Item.IsValid)
|
||||
{
|
||||
data.Item.Item = item.ItemPrefab;
|
||||
data.Item.Amount = 1;
|
||||
playerInventory[j] = data;
|
||||
PostUpdateCommands.PostEntityEvent<InventoryDirtyEventData>(EntityManager, pickup.PlayerEntity);
|
||||
toDelete.Add(rigidBody.gameObject);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
foreach (var o in toDelete)
|
||||
{
|
||||
Object.Destroy(o);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Systems/Items/InventoryPickupSystem.cs.meta
Normal file
11
Assets/Scripts/Systems/Items/InventoryPickupSystem.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 8a7c6501fc4d7294b87eca0f2aafa2ed
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
37
Assets/Scripts/Systems/Items/InventorySystem.cs
Normal file
37
Assets/Scripts/Systems/Items/InventorySystem.cs
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
using Events;
|
||||
using Unity.Entities;
|
||||
|
||||
namespace DefaultNamespace
|
||||
{
|
||||
[UpdateInGroup(typeof(PresentationSystemGroup)), UpdateAfter(typeof(PlayerActionMapSystem))]
|
||||
public class InventorySystem : ComponentSystem
|
||||
{
|
||||
protected override void OnUpdate()
|
||||
{
|
||||
Entities.WithAll<Slot>()
|
||||
.ForEach(
|
||||
(Entity entity, ref PlayerData player, ref PlayerInput input) =>
|
||||
{
|
||||
var inventoryDirtyFlag = false;
|
||||
var inventory = EntityManager.GetBuffer<Slot>(entity);
|
||||
for (var j = 0; j < inventory.Length; j++)
|
||||
{
|
||||
var slot = inventory[j];
|
||||
if (slot.Item.Amount <= 0 && slot.Item.Item.IsValid)
|
||||
{
|
||||
slot.Item = new ItemData();
|
||||
inventory[j] = slot;
|
||||
inventoryDirtyFlag = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (inventoryDirtyFlag)
|
||||
{
|
||||
PostUpdateCommands.PostEntityEvent<InventoryDirtyEventData>(EntityManager, entity);
|
||||
}
|
||||
});
|
||||
|
||||
PostUpdateCommands.RemoveEventComponents<InventoryDirtyEventData>(Entities);
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Systems/Items/InventorySystem.cs.meta
Normal file
11
Assets/Scripts/Systems/Items/InventorySystem.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 535ade2fff3ef7b4884e6b102f12fdcc
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
146
Assets/Scripts/Systems/Items/ItemDropSystem.cs
Normal file
146
Assets/Scripts/Systems/Items/ItemDropSystem.cs
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
using Events;
|
||||
using Items;
|
||||
using UnityEngine;
|
||||
using UnityEngine.AddressableAssets;
|
||||
using Zenject;
|
||||
using Entity = Unity.Entities.Entity;
|
||||
|
||||
namespace DefaultNamespace
|
||||
{
|
||||
public class ItemDropSystem : InjectableComponentSystem
|
||||
{
|
||||
[Inject] private readonly ItemContainerFactory itemContainerFactory;
|
||||
|
||||
protected override void OnSystemUpdate()
|
||||
{
|
||||
Entities.WithNone<AssetReferenceData<ItemPrefab>>()
|
||||
.ForEach(
|
||||
(Entity entity, ref ItemDropEvent drop) =>
|
||||
{
|
||||
PostUpdateCommands.AddSharedComponent(
|
||||
entity,
|
||||
new AssetReferenceData<ItemPrefab>(Addressables.LoadAssetAsync<ItemPrefab>(drop.Item.Item.ToString())));
|
||||
});
|
||||
|
||||
Entities.ForEach(
|
||||
(Entity entity, AssetReferenceData<ItemPrefab> itemPrefab, ref ItemDropEvent drop) =>
|
||||
{
|
||||
if (!itemPrefab.Operation.IsValid)
|
||||
{
|
||||
PostUpdateCommands.DestroyEntity(entity);
|
||||
}
|
||||
else if (itemPrefab.Operation.IsDone)
|
||||
{
|
||||
var pos = drop.Pos;
|
||||
var dropInventory = drop.Inventory;
|
||||
var dropItem = drop.Item;
|
||||
var dropVelocity = drop.Velocity;
|
||||
|
||||
if (EntityManager.Exists(drop.Inventory))
|
||||
{
|
||||
var inventory = EntityManager.GetBuffer<Slot>(drop.Inventory);
|
||||
|
||||
Slot ItemModification(Slot slot, bool set)
|
||||
{
|
||||
if (set)
|
||||
{
|
||||
slot.Item = dropItem;
|
||||
}
|
||||
else
|
||||
{
|
||||
slot.Item.Amount += dropItem.Amount;
|
||||
slot.Item.Item = dropItem.Item;
|
||||
}
|
||||
|
||||
PostUpdateCommands.DestroyEntity(entity);
|
||||
PostUpdateCommands.PostEntityEvent(EntityManager, dropInventory, new InventoryDirtyEventData());
|
||||
return slot;
|
||||
}
|
||||
|
||||
//put in specific empty slot or combine with existing item in that slot
|
||||
if (drop.ToSlot > 0 && drop.ToSlot < inventory.Length)
|
||||
{
|
||||
var toSlotData = inventory[drop.ToSlot];
|
||||
if (CanDrop(toSlotData, itemPrefab.Operation.Result) &&
|
||||
(!toSlotData.HasItem() || toSlotData.Item.Item == dropItem.Item))
|
||||
{
|
||||
inventory[drop.ToSlot] = ItemModification(toSlotData, !toSlotData.HasItem());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//combine with existing item
|
||||
if (inventory.NativeFirstOrOptional(slot => slot.Item.Item == dropItem.Item)
|
||||
.NativeModify(s => ItemModification(s, false)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//move item in destination slot to slot drag came from if possible and occupy new slot with new item
|
||||
if (drop.ToSlot > 0 && drop.ToSlot < inventory.Length)
|
||||
{
|
||||
var toSlotData = inventory[drop.ToSlot];
|
||||
if (CanDrop(toSlotData, itemPrefab.Operation.Result) && drop.FromSlot >= 0 && drop.FromSlot < inventory.Length)
|
||||
{
|
||||
var fromSlotData = inventory[drop.FromSlot];
|
||||
if (!fromSlotData.HasItem())
|
||||
{
|
||||
//todo check for slot compatibility
|
||||
fromSlotData.Item = toSlotData.Item;
|
||||
inventory[drop.FromSlot] = fromSlotData;
|
||||
inventory[drop.ToSlot] = ItemModification(toSlotData, true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//put in free slot
|
||||
if (inventory.NativeFirstOrOptional(slot => !slot.HasItem() && CanDrop(slot, itemPrefab.Operation.Result))
|
||||
.NativeModify(s => ItemModification(s, true)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//drop on ground near inventory
|
||||
if (EntityManager.HasComponent<Rigidbody2D>(drop.Inventory))
|
||||
{
|
||||
pos = EntityManager.GetComponentObject<Rigidbody2D>(drop.Inventory).position;
|
||||
}
|
||||
}
|
||||
|
||||
itemContainerFactory.Create(itemPrefab.Operation.Result, dropItem.Item).Completed += asyncOperation =>
|
||||
{
|
||||
var rigidbody = asyncOperation.Result.GetComponent<Rigidbody2D>();
|
||||
rigidbody.position = pos;
|
||||
rigidbody.velocity = dropVelocity;
|
||||
};
|
||||
|
||||
PostUpdateCommands.DestroyEntity(entity);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private bool CanDrop(Slot slot, ItemPrefab prefab)
|
||||
{
|
||||
switch (slot.Type)
|
||||
{
|
||||
case SlotType.None:
|
||||
return true;
|
||||
|
||||
case SlotType.RangedWeapon:
|
||||
return prefab is RangedWeaponItem;
|
||||
|
||||
case SlotType.MeleeWeapon:
|
||||
return false;
|
||||
|
||||
case SlotType.Grenade:
|
||||
return prefab is GrenadeItem;
|
||||
|
||||
case SlotType.Health:
|
||||
return prefab is IHealItem;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Systems/Items/ItemDropSystem.cs.meta
Normal file
11
Assets/Scripts/Systems/Items/ItemDropSystem.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 1f16dfa58ee27c14480c68b9ab406203
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
136
Assets/Scripts/Systems/Items/ItemPickupSystem.cs
Normal file
136
Assets/Scripts/Systems/Items/ItemPickupSystem.cs
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
using Events;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Unity.Collections;
|
||||
using Unity.Entities;
|
||||
using UnityEngine;
|
||||
using Zenject;
|
||||
|
||||
namespace DefaultNamespace
|
||||
{
|
||||
[UpdateInGroup(typeof(PresentationSystemGroup)), UpdateAfter(typeof(PlayerMoveSystem)), UpdateBefore(typeof(ActorAnimationEventResetSystem))]
|
||||
public class ItemPickupSystem : InjectableComponentSystem
|
||||
{
|
||||
[Serializable]
|
||||
public class Settings
|
||||
{
|
||||
public float PickupDistance;
|
||||
public SoundLibrary PickupSound;
|
||||
}
|
||||
|
||||
[Inject] private readonly Settings settings;
|
||||
[Inject] private readonly SoundManager soundManager;
|
||||
private NativeList<Entity> CloseItems;
|
||||
private HashSet<Entity> TakenItems;
|
||||
|
||||
protected override void OnCreate()
|
||||
{
|
||||
TakenItems = new HashSet<Entity>();
|
||||
CloseItems = new NativeList<Entity>(Allocator.Persistent);
|
||||
}
|
||||
|
||||
protected override void OnSystemUpdate()
|
||||
{
|
||||
TakenItems.Clear();
|
||||
|
||||
//waiting for pickup animation even to do the actual pickup if possible
|
||||
//it will cancel the pickup even if animation state is not on tagged state with tag 'PickingUp'
|
||||
ManageItemPickupEvents();
|
||||
|
||||
//only add actor pickup event to be processed in the upper loop
|
||||
ManagePlayerPickupEvents();
|
||||
|
||||
Entities.ForEach((Entity entity, ref ItemPickupEventData pickup) => { PostUpdateCommands.RemoveComponent<ItemPickupEventData>(entity); });
|
||||
}
|
||||
|
||||
private void ManageItemPickupEvents()
|
||||
{
|
||||
Entities.ForEach(
|
||||
(
|
||||
Entity playerEntity,
|
||||
ref RigidBody2DData playerRigidBody,
|
||||
ref ActorPickupEvent pickupEvent,
|
||||
ref ActorAnimationEventData animationEvent,
|
||||
ref AnimatorStateData animatorState,
|
||||
ref ActorAnimationData animation) =>
|
||||
{
|
||||
if (animationEvent.PickedUp)
|
||||
{
|
||||
var itemRigidbody = EntityManager.GetComponentObject<Rigidbody2D>(pickupEvent.Item);
|
||||
var d = Vector2.Distance(itemRigidbody.position, playerRigidBody.Position);
|
||||
if (d <= settings.PickupDistance)
|
||||
{
|
||||
PostUpdateCommands.AddComponent(pickupEvent.Item, new ItemPickupEventData(playerEntity));
|
||||
soundManager.PlayClip(PostUpdateCommands, settings.PickupSound, itemRigidbody.position);
|
||||
}
|
||||
|
||||
PostUpdateCommands.RemoveComponent<ActorPickupEvent>(playerEntity);
|
||||
}
|
||||
else if (animationEvent.PickedCanceled)
|
||||
{
|
||||
PostUpdateCommands.RemoveComponent<ActorPickupEvent>(playerEntity);
|
||||
animation.Triggers &= ~AnimationTriggerType.Pickup;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void ManagePlayerPickupEvents()
|
||||
{
|
||||
var pickupDistanceSqr = settings.PickupDistance * settings.PickupDistance;
|
||||
|
||||
Entities.WithNone<ActorPickupEvent>()
|
||||
.ForEach(
|
||||
(
|
||||
Entity playerEntity,
|
||||
PlayerFacade playerFacade,
|
||||
ref PlayerInput input,
|
||||
ref AnimatorStateData animationState,
|
||||
ref ActorAnimationData animation,
|
||||
ref PlayerData player) =>
|
||||
{
|
||||
if (input.Pickup && animationState.State.IsTag("Interactive"))
|
||||
{
|
||||
CloseItems.Clear();
|
||||
Entities.WithNone<ItemPickupEventData>()
|
||||
.ForEach(
|
||||
(Entity entity, ref RigidBody2DData rigidBody, ref ItemContainerData item) =>
|
||||
{
|
||||
var d = Vector2.SqrMagnitude(rigidBody.Position - (Vector2)playerFacade.transform.position);
|
||||
if (d <= pickupDistanceSqr)
|
||||
{
|
||||
CloseItems.Add(entity);
|
||||
}
|
||||
});
|
||||
|
||||
for (var i = 0; i < CloseItems.Length; i++)
|
||||
{
|
||||
var itemIndex = CloseItems[i];
|
||||
if (player.PickupIndex == i && !TakenItems.Contains(itemIndex))
|
||||
{
|
||||
TakenItems.Add(itemIndex);
|
||||
PostUpdateCommands.AddComponent(playerEntity, new ActorPickupEvent { Item = itemIndex });
|
||||
animation.Triggers |= AnimationTriggerType.Pickup;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
player.PickupIndex -= input.ScrollInput;
|
||||
if (player.PickupIndex < 0)
|
||||
{
|
||||
player.PickupIndex += CloseItems.Length;
|
||||
}
|
||||
else if (player.PickupIndex >= CloseItems.Length)
|
||||
{
|
||||
player.PickupIndex -= CloseItems.Length;
|
||||
}
|
||||
player.PickupIndex = Mathf.Min(player.PickupIndex, Mathf.Max(CloseItems.Length - 1, 0));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected override void OnDestroy()
|
||||
{
|
||||
CloseItems.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Systems/Items/ItemPickupSystem.cs.meta
Normal file
11
Assets/Scripts/Systems/Items/ItemPickupSystem.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: dee8253f18bbcf240abfcb80b705d894
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
7
Assets/Scripts/Systems/Items/ItemUseFlags.cs
Normal file
7
Assets/Scripts/Systems/Items/ItemUseFlags.cs
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
using System;
|
||||
|
||||
namespace DefaultNamespace
|
||||
{
|
||||
[Flags]
|
||||
public enum ItemUseFlags { UseOnlyGrounded = 1 << 0, UseOnlyInteractive = 1 << 1, InteruptAttack = 1 << 2 }
|
||||
}
|
||||
11
Assets/Scripts/Systems/Items/ItemUseFlags.cs.meta
Normal file
11
Assets/Scripts/Systems/Items/ItemUseFlags.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 2082c72c7f4737b44920e76055cf990e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
145
Assets/Scripts/Systems/Items/ItemUseSystem.cs
Normal file
145
Assets/Scripts/Systems/Items/ItemUseSystem.cs
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
using Events;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Unity.Entities;
|
||||
using UnityEngine;
|
||||
using UnityEngine.AddressableAssets;
|
||||
using Zenject;
|
||||
|
||||
namespace DefaultNamespace
|
||||
{
|
||||
[UpdateInGroup(typeof(PresentationSystemGroup)), UpdateBefore(typeof(ActorAnimationSystem))]
|
||||
public class ItemUseSystem : InjectableComponentSystem
|
||||
{
|
||||
[Inject] private List<IItemUseSystem> useSystems;
|
||||
|
||||
protected override void OnSystemUpdate()
|
||||
{
|
||||
Entities.ForEach(
|
||||
(Entity entity, ref ItemUseEventData e) =>
|
||||
{
|
||||
var inventoryEntity = e.Inventory;
|
||||
var inventory = EntityManager.GetBuffer<Slot>(e.Inventory);
|
||||
|
||||
if (!e.Validating)
|
||||
{
|
||||
if (e.Slot < inventory.Length && inventory[e.Slot].HasItem())
|
||||
{
|
||||
e.Validating = true;
|
||||
|
||||
var item = inventory[e.Slot];
|
||||
Addressables.LoadAssetAsync<ItemPrefab>(item.Item.Item.ToString()).Completed += operation =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var ev = EntityManager.GetComponentData<ItemUseEventData>(entity);
|
||||
var actor = EntityManager.GetComponentData<ActorData>(entity);
|
||||
IEnumerable<IItemUseSystem> validatedSystemsEnumerable = useSystems;
|
||||
if (EntityManager.HasComponent<AnimatorStateData>(entity))
|
||||
{
|
||||
var state = EntityManager.GetComponentData<AnimatorStateData>(entity);
|
||||
validatedSystemsEnumerable = validatedSystemsEnumerable.Where(
|
||||
s =>
|
||||
{
|
||||
if (s.Flags.HasFlag(ItemUseFlags.UseOnlyInteractive) && !state.State.IsTag("Interactive"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!s.Flags.HasFlag(ItemUseFlags.InteruptAttack) && state.State.IsName("Attack"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (s.Flags.HasFlag(ItemUseFlags.UseOnlyGrounded) && !actor.Grounded)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
var validatedSystems = validatedSystemsEnumerable.Where(
|
||||
s => s.CanUse(operation.Result) && s.Validate(operation.Result, entity, inventoryEntity))
|
||||
.ToArray();
|
||||
ev.Invalid = operation.Result == null || validatedSystems.Length <= 0;
|
||||
if (validatedSystems.Length > 0)
|
||||
{
|
||||
//trigger animation
|
||||
var animation = EntityManager.GetComponentData<ActorAnimationData>(entity);
|
||||
animation.Triggers |= AnimationTriggerType.ItemUse;
|
||||
animation.UseType = validatedSystems[0].UseType;
|
||||
animation.ItemUseAdditive = validatedSystems[0].IsAdditiveUsage;
|
||||
EntityManager.SetComponentData(entity, animation);
|
||||
|
||||
if (EntityManager.HasComponent<ActorBodyParts>(entity))
|
||||
{
|
||||
var parts = EntityManager.GetComponentObject<ActorBodyParts>(entity);
|
||||
if (parts.ItemRenderer != null)
|
||||
{
|
||||
parts.ItemRenderer.sprite = validatedSystems[0].GetItemIcon(operation.Result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EntityManager.SetComponentData(entity, ev);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogException(ex);
|
||||
EntityManager.RemoveComponent<ItemUseEventData>(entity);
|
||||
}
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
e.Invalid = true;
|
||||
}
|
||||
|
||||
PostUpdateCommands.SetComponent(entity, e);
|
||||
}
|
||||
else if (e.Done)
|
||||
{
|
||||
var item = inventory[e.Slot];
|
||||
var eLocal = e;
|
||||
|
||||
Addressables.LoadAssetAsync<ItemPrefab>(item.Item.Item.ToString()).Completed += operation =>
|
||||
{
|
||||
if (operation.Result != null)
|
||||
{
|
||||
var inv = EntityManager.GetBuffer<Slot>(eLocal.Inventory);
|
||||
var slot = inv[eLocal.Slot];
|
||||
foreach (var system in useSystems.Where(
|
||||
s => s.CanUse(operation.Result) && s.Validate(operation.Result, entity, eLocal.Inventory)))
|
||||
{
|
||||
if (slot.HasItem())
|
||||
{
|
||||
system.Use(operation.Result, ref slot.Item, entity, eLocal.Inventory);
|
||||
}
|
||||
}
|
||||
inv = EntityManager.GetBuffer<Slot>(eLocal.Inventory);
|
||||
inv[eLocal.Slot] = slot;
|
||||
}
|
||||
};
|
||||
PostUpdateCommands.RemoveComponent<ItemUseEventData>(entity);
|
||||
}
|
||||
else if (e.Invalid)
|
||||
{
|
||||
PostUpdateCommands.RemoveComponent<ItemUseEventData>(entity);
|
||||
}
|
||||
});
|
||||
|
||||
Entities.ForEach(
|
||||
(Entity entity, ref ItemUseEventData itemEvent, ref ActorAnimationEventData e) =>
|
||||
{
|
||||
if (e.ItemUsed && !itemEvent.Invalid)
|
||||
{
|
||||
itemEvent.Done = true;
|
||||
}
|
||||
else if (e.ItemUsedCancled)
|
||||
{
|
||||
itemEvent.Invalid = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Systems/Items/ItemUseSystem.cs.meta
Normal file
11
Assets/Scripts/Systems/Items/ItemUseSystem.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ccb01c4fd6f8d154b82b406cc27c0cb0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
43
Assets/Scripts/Systems/Items/ItemUseSystemAbstract.cs
Normal file
43
Assets/Scripts/Systems/Items/ItemUseSystemAbstract.cs
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
using Unity.Entities;
|
||||
using UnityEngine;
|
||||
using Zenject;
|
||||
|
||||
namespace DefaultNamespace
|
||||
{
|
||||
public abstract class ItemUseSystemAbstract<T> : IItemUseSystem where T : ItemPrefab
|
||||
{
|
||||
[Inject] protected readonly EntityManager entityManager;
|
||||
|
||||
bool IItemUseSystem.CanUse(ItemPrefab prefab)
|
||||
{
|
||||
return prefab is T;
|
||||
}
|
||||
|
||||
void IItemUseSystem.Use(ItemPrefab prefab, ref ItemData itemData, Entity user, Entity inventory)
|
||||
{
|
||||
Use((T)prefab, ref itemData, user, inventory);
|
||||
}
|
||||
|
||||
bool IItemUseSystem.Validate(ItemPrefab prefab, Entity user, Entity inventory)
|
||||
{
|
||||
return Validate((T)prefab, user, inventory);
|
||||
}
|
||||
|
||||
Sprite IItemUseSystem.GetItemIcon(ItemPrefab prefab)
|
||||
{
|
||||
return GetItemIcon((T)prefab);
|
||||
}
|
||||
|
||||
public abstract ItemUseFlags Flags { get; }
|
||||
|
||||
public abstract ItemUseType UseType { get; }
|
||||
|
||||
public abstract bool IsAdditiveUsage { get; }
|
||||
|
||||
public abstract Sprite GetItemIcon(T prefab);
|
||||
|
||||
protected abstract void Use(T prefab, ref ItemData itemData, Entity user, Entity inventory);
|
||||
|
||||
protected abstract bool Validate(T prefab, Entity user, Entity inventory);
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Systems/Items/ItemUseSystemAbstract.cs.meta
Normal file
11
Assets/Scripts/Systems/Items/ItemUseSystemAbstract.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 0c6e2d007bec8d946aac933c54d94256
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/Scripts/Systems/Navigation.meta
Normal file
8
Assets/Scripts/Systems/Navigation.meta
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 1a20788f7ddc9fe4a819d7dcd6f21b1d
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
140
Assets/Scripts/Systems/Navigation/FindPathJob.cs
Normal file
140
Assets/Scripts/Systems/Navigation/FindPathJob.cs
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Unity.Collections;
|
||||
using Unity.Jobs;
|
||||
using UnityEngine;
|
||||
|
||||
namespace DefaultNamespace.Navigation
|
||||
{
|
||||
public struct FindPathJob : IJob
|
||||
{
|
||||
private readonly Vector2 from;
|
||||
private readonly int to;
|
||||
[ReadOnly] private NativeList<NavigationBuilder.Point> points;
|
||||
[ReadOnly] private NativeMultiHashMap<int, PathNodeConnection> connectionsDictionary;
|
||||
public NativeList<PathNode> Path;
|
||||
|
||||
public FindPathJob(
|
||||
Vector2 from,
|
||||
int to,
|
||||
[ReadOnly] NativeList<NavigationBuilder.Point> points,
|
||||
[ReadOnly] NativeMultiHashMap<int, PathNodeConnection> connectionsDictionary)
|
||||
{
|
||||
this.from = from;
|
||||
this.to = to;
|
||||
this.points = points;
|
||||
this.connectionsDictionary = connectionsDictionary;
|
||||
Path = new NativeList<PathNode>(Allocator.Persistent);
|
||||
}
|
||||
|
||||
public void Execute()
|
||||
{
|
||||
var from = this.from;
|
||||
|
||||
var toPos = points[to].Pos;
|
||||
var closestStartPoint = points.FindMinIndex(p => (p.Pos - from).sqrMagnitude);
|
||||
var closestEndPoint = points.FindMinIndex(p => (p.Pos - toPos).sqrMagnitude);
|
||||
|
||||
if (closestStartPoint < 0 || closestEndPoint < 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var parents = new Dictionary<int, int>();
|
||||
var gScore = new NativeArray<float>(points.Length, Allocator.Temp);
|
||||
var fScore = new NativeArray<float>(points.Length, Allocator.Temp);
|
||||
var cons = new NativeArray<PathNodeConnection>(points.Length, Allocator.Temp);
|
||||
|
||||
try
|
||||
{
|
||||
var closed = new HashSet<int>();
|
||||
var open = new HashSet<int>();
|
||||
gScore.Fill(float.PositiveInfinity);
|
||||
fScore.Fill(float.PositiveInfinity);
|
||||
gScore[closestStartPoint] = 0;
|
||||
fScore[closestStartPoint] = CalculateHeuristic(closestStartPoint, closestEndPoint);
|
||||
open.Add(closestStartPoint);
|
||||
|
||||
while (open.Count > 0)
|
||||
{
|
||||
var fScoreLocal = fScore;
|
||||
var current = open.MinValue(i => fScoreLocal[i]);
|
||||
var qPoint = points[current];
|
||||
open.Remove(current);
|
||||
|
||||
if (current == closestEndPoint)
|
||||
{
|
||||
ConstructPath(parents, current, cons);
|
||||
break;
|
||||
}
|
||||
|
||||
foreach (var connection in connectionsDictionary.GetEnumerator(qPoint.FaltIndex))
|
||||
{
|
||||
if (closed.Contains(connection.Destination))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var gScoreVal = gScore[current] +
|
||||
(connection.Type == PathNodeConnectionType.Jump
|
||||
? connection.Distance * connection.Distance * connection.Distance
|
||||
: 0);
|
||||
var fScoreValue = gScoreVal + CalculateHeuristic(connection.Destination, closestEndPoint);
|
||||
|
||||
if (!open.Contains(connection.Destination)) // Discover a new node
|
||||
{
|
||||
open.Add(connection.Destination);
|
||||
}
|
||||
else if (gScoreVal >= gScore[connection.Destination])
|
||||
{
|
||||
continue; // This is not a better path.
|
||||
}
|
||||
|
||||
parents[connection.Destination] = current;
|
||||
gScore[connection.Destination] = gScoreVal;
|
||||
fScore[connection.Destination] = fScoreValue;
|
||||
cons[connection.Destination] = connection;
|
||||
|
||||
open.Add(connection.Destination);
|
||||
}
|
||||
|
||||
closed.Add(current);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogException(e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
gScore.Dispose();
|
||||
fScore.Dispose();
|
||||
cons.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private void ConstructPath(IDictionary<int, int> parents, int end, NativeArray<PathNodeConnection> cons)
|
||||
{
|
||||
Path.Add(new PathNode { ConnectionType = cons[end].Type, pos = points[end].Pos });
|
||||
|
||||
while (parents.TryGetValue(end, out var parent))
|
||||
{
|
||||
Path.Add(new PathNode { ConnectionType = cons[parent].Type, pos = points[parent].Pos });
|
||||
end = parent;
|
||||
}
|
||||
|
||||
var distanceFromStart = Vector2.Distance(Path[Path.Length - 1].pos, from);
|
||||
if (distanceFromStart > 0.05f)
|
||||
{
|
||||
Path.Add(new PathNode { pos = @from, ConnectionType = PathNodeConnectionType.Start });
|
||||
}
|
||||
|
||||
Path.Reverse();
|
||||
}
|
||||
|
||||
private float CalculateHeuristic(int from, int to)
|
||||
{
|
||||
return (points[from].Index2D - points[to].Index2D).sqrMagnitude;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Systems/Navigation/FindPathJob.cs.meta
Normal file
11
Assets/Scripts/Systems/Navigation/FindPathJob.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b427073c5a8f24f4fb88c203b98d5d37
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
180
Assets/Scripts/Systems/Navigation/NavigationAgentDriverSystem.cs
Normal file
180
Assets/Scripts/Systems/Navigation/NavigationAgentDriverSystem.cs
Normal file
|
|
@ -0,0 +1,180 @@
|
|||
using System;
|
||||
using Unity.Entities;
|
||||
using Unity.Jobs;
|
||||
using UnityEngine;
|
||||
using Zenject;
|
||||
|
||||
namespace DefaultNamespace.Navigation
|
||||
{
|
||||
public class NavigationAgentDriverSystem : InjectableComponentSystem
|
||||
{
|
||||
[Serializable]
|
||||
public class Settings
|
||||
{
|
||||
public LayerMask GroundMask;
|
||||
public float JumpSpeed;
|
||||
public float MinNodeDistnace = 0.1f;
|
||||
public float Speed;
|
||||
}
|
||||
|
||||
[Inject] private readonly NavigationBuilder builder;
|
||||
|
||||
[Inject] private readonly Settings settings;
|
||||
private readonly ContactPoint2D[] contactPoints = new ContactPoint2D[16];
|
||||
|
||||
protected override void OnSystemUpdate()
|
||||
{
|
||||
Entities.WithNone<PathNode>()
|
||||
.ForEach((Entity entity, ref NavigationAgentData agent) => { PostUpdateCommands.AddBuffer<PathNode>(entity); });
|
||||
|
||||
Entities.WithAll<PathNode, Rigidbody2D>()
|
||||
.ForEach(
|
||||
(Entity entity, NavigationCalculationData calculation, ref NavigationAgentData agent) =>
|
||||
{
|
||||
var rigidbody = EntityManager.GetComponentObject<Rigidbody2D>(entity);
|
||||
var path = EntityManager.GetBuffer<PathNode>(entity);
|
||||
|
||||
if (calculation.PathCalculationJobHandle.IsCompleted)
|
||||
{
|
||||
calculation.PathCalculationJobHandle.Complete();
|
||||
path.CopyFrom(calculation.PathCalculationJob.Path);
|
||||
calculation.PathCalculationJob.Path.Dispose();
|
||||
agent.currentTime = 0;
|
||||
agent.currentIndex = 0;
|
||||
agent.startPos = rigidbody.position;
|
||||
PostUpdateCommands.RemoveComponent<NavigationCalculationData>(entity);
|
||||
}
|
||||
});
|
||||
|
||||
Entities.WithAll<PathNode>()
|
||||
.ForEach(
|
||||
(Entity entity, Rigidbody2D rigidbody, ref NavigationAgentData agent) =>
|
||||
{
|
||||
var path = EntityManager.GetBuffer<PathNode>(entity);
|
||||
|
||||
agent.Grounded = false;
|
||||
|
||||
var hasDestination = agent.destination.HasValue;
|
||||
if (hasDestination)
|
||||
{
|
||||
var goalPos = agent.destination.Value;
|
||||
var closestEndPoint = builder.Points.FindMinIndex(p => (p.Pos - goalPos).sqrMagnitude);
|
||||
|
||||
if (closestEndPoint != agent.lastGoalPosIndex)
|
||||
{
|
||||
agent.lastGoalPosIndex = closestEndPoint;
|
||||
if (closestEndPoint >= 0)
|
||||
{
|
||||
var from = rigidbody.position;
|
||||
var job = new FindPathJob(from, closestEndPoint, builder.Points, builder.connectionsDictionary);
|
||||
PostUpdateCommands.AddSharedComponent(
|
||||
entity,
|
||||
new NavigationCalculationData { PathCalculationJob = job, PathCalculationJobHandle = job.Schedule() });
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (path.Length > 0)
|
||||
{
|
||||
path.Clear();
|
||||
}
|
||||
|
||||
var agentContacts = rigidbody.GetContacts(
|
||||
new ContactFilter2D { useLayerMask = true, layerMask = settings.GroundMask },
|
||||
contactPoints);
|
||||
//Bounds bounds = agentCollider.bounds;
|
||||
//bool grounded = contactPoints.Take(agentContacts).Any(c => Vector2.Angle(c.normal, Vector2.up) <= 22.5f);
|
||||
|
||||
/*float waypointMinDistance2 = waypointMinDistance * waypointMinDistance;
|
||||
int closestPointIndex = path.FindLastIndex(p => ((Vector2)bounds.ClosestPoint(p.pos) - p.pos).sqrMagnitude <= waypointMinDistance2);
|
||||
if (closestPointIndex > currentIndex)
|
||||
{
|
||||
currentIndex = closestPointIndex;
|
||||
currentTime = 0;
|
||||
}*/
|
||||
|
||||
for (var j = 1; j < path.Length; j++)
|
||||
{
|
||||
Debug.DrawLine(path[j - 1].pos + Vector2.up * 0.5f, path[j].pos + Vector2.up * 0.5f, Color.cyan);
|
||||
}
|
||||
|
||||
var currentIndex = agent.currentIndex;
|
||||
var nextIndex = agent.currentIndex + 1;
|
||||
|
||||
rigidbody.bodyType = nextIndex >= path.Length ? RigidbodyType2D.Dynamic : RigidbodyType2D.Kinematic;
|
||||
if (nextIndex < path.Length)
|
||||
{
|
||||
var firstPosition = currentIndex >= 0 ? path[currentIndex].pos : agent.startPos;
|
||||
var nextPosition = path[nextIndex].pos;
|
||||
var nextConnectionType = path[nextIndex].ConnectionType;
|
||||
var lastConnectionType = path[currentIndex].ConnectionType;
|
||||
var isNextJump = nextConnectionType == PathNodeConnectionType.Jump;
|
||||
var isNextDrop = nextConnectionType == PathNodeConnectionType.Drop;
|
||||
var isStart = lastConnectionType == PathNodeConnectionType.Start;
|
||||
|
||||
var nextMaxTime = currentIndex >= 0
|
||||
? isNextJump || isNextDrop ? settings.JumpSpeed : settings.Speed
|
||||
: Mathf.Max(Mathf.Clamp01(Vector2.Distance(agent.startPos, nextPosition)), settings.Speed);
|
||||
agent.currentTime += Time.DeltaTime;
|
||||
agent.currentTime = Mathf.Min(agent.currentTime, nextMaxTime);
|
||||
|
||||
var heightDelta = Mathf.Abs(firstPosition.y - nextPosition.y);
|
||||
|
||||
var percent = agent.currentTime / Mathf.Max(nextMaxTime, Time.DeltaTime);
|
||||
if (currentIndex >= 0 && !isStart && (isNextJump || isNextDrop || heightDelta > 0.1f))
|
||||
{
|
||||
var height = Mathf.Max(Mathf.Sqrt(heightDelta), 1);
|
||||
rigidbody.MovePosition(builder.SampleParabola(firstPosition, nextPosition, height, percent));
|
||||
|
||||
if (agent.currentTime >= nextMaxTime)
|
||||
{
|
||||
agent.currentIndex++;
|
||||
agent.currentTime -= nextMaxTime;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var dir = nextPosition - rigidbody.position;
|
||||
var dirMag = dir.magnitude;
|
||||
dir.Normalize();
|
||||
rigidbody.MovePosition(rigidbody.position + dir * Mathf.Min(dirMag, settings.Speed * Time.DeltaTime));
|
||||
if (dirMag <= settings.MinNodeDistnace)
|
||||
{
|
||||
agent.currentTime = 0;
|
||||
agent.currentIndex++;
|
||||
}
|
||||
|
||||
agent.Grounded = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
agent.lastGoalPosIndex = -1;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public struct NavigationCalculationData : ISystemStateSharedComponentData, IEquatable<NavigationCalculationData>
|
||||
{
|
||||
public FindPathJob PathCalculationJob;
|
||||
public JobHandle PathCalculationJobHandle;
|
||||
|
||||
public bool Equals(NavigationCalculationData other)
|
||||
{
|
||||
return PathCalculationJob.Equals(other.PathCalculationJob) && PathCalculationJobHandle.Equals(other.PathCalculationJobHandle);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is NavigationCalculationData other && Equals(other);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
return (PathCalculationJob.GetHashCode() * 397) ^ PathCalculationJobHandle.GetHashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d9a8f6a25f16cb4479d04e90f5156ae0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
39
Assets/Scripts/Systems/ParticleCollisionSystem.cs
Normal file
39
Assets/Scripts/Systems/ParticleCollisionSystem.cs
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
using Unity.Entities;
|
||||
using UnityEngine;
|
||||
using Zenject;
|
||||
|
||||
namespace DefaultNamespace
|
||||
{
|
||||
public class ParticleCollisionSystem : InjectableComponentSystem
|
||||
{
|
||||
[Inject] private SoundManager soundManager;
|
||||
|
||||
protected override void OnSystemUpdate()
|
||||
{
|
||||
Entities.WithAll<ParticleCollisionEventContainer>()
|
||||
.ForEach(
|
||||
(Entity entity, ParticleCollisionData collision) =>
|
||||
{
|
||||
var events = EntityManager.GetBuffer<ParticleCollisionEventContainer>(entity);
|
||||
foreach (var e in events)
|
||||
{
|
||||
var force = e.Evnt.velocity.magnitude;
|
||||
if (force >= collision.ImpactForceRange.x)
|
||||
{
|
||||
soundManager.PlayClip(EntityManager, collision.ImpactSounds, e.Evnt.intersection);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
events = EntityManager.GetBuffer<ParticleCollisionEventContainer>(entity);
|
||||
events.Clear();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
[InternalBufferCapacity(8)]
|
||||
public struct ParticleCollisionEventContainer : IBufferElementData
|
||||
{
|
||||
public ParticleCollisionEvent Evnt;
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Systems/ParticleCollisionSystem.cs.meta
Normal file
11
Assets/Scripts/Systems/ParticleCollisionSystem.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b8db9e9730280d2409d57861dd6059af
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/Scripts/Systems/Player.meta
Normal file
8
Assets/Scripts/Systems/Player.meta
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 3c056491586d7ff4092d72a8f9eb5e10
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
38
Assets/Scripts/Systems/Player/PlayerActionMapSystem.cs
Normal file
38
Assets/Scripts/Systems/Player/PlayerActionMapSystem.cs
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
using Unity.Entities;
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
using Zenject;
|
||||
|
||||
namespace DefaultNamespace
|
||||
{
|
||||
[UpdateInGroup(typeof(PresentationSystemGroup))]
|
||||
public class PlayerActionMapSystem : InjectableComponentSystem
|
||||
{
|
||||
[Inject] private EventSystem eventSystem;
|
||||
|
||||
protected override void OnSystemUpdate()
|
||||
{
|
||||
Entities.ForEach(
|
||||
(ref PlayerInput input) =>
|
||||
{
|
||||
input.HorizontalInput = Input.GetAxis("Horizontal");
|
||||
input.Attacking = Input.GetButton("Fire1");
|
||||
input.AttackPressed = Input.GetButtonDown("Fire1");
|
||||
input.Pickup = Input.GetButtonDown("PickUp");
|
||||
input.ScrollInput = Mathf.RoundToInt(Mathf.Sign(Input.GetAxis("Mouse ScrollWheel"))) *
|
||||
Mathf.CeilToInt(Mathf.Abs(Input.GetAxis("Mouse ScrollWheel")));
|
||||
input.Jump = Input.GetButton("Jump");
|
||||
input.JumpPressed = Input.GetButtonDown("Jump");
|
||||
input.Reload = Input.GetButtonDown("Reload");
|
||||
input.UseItem = Input.GetButtonDown("UseItem");
|
||||
input.OverUi = eventSystem.IsPointerOverGameObject();
|
||||
input.Melee = Input.GetButtonDown("Melee");
|
||||
input.Grenade = Input.GetButtonDown("Grenade");
|
||||
input.Drag = Input.GetMouseButton(0);
|
||||
input.Heal = Input.GetButtonDown("Heal");
|
||||
input.Run = Input.GetButton("Run");
|
||||
input.Vault = Input.GetButtonDown("Vault");
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Systems/Player/PlayerActionMapSystem.cs.meta
Normal file
11
Assets/Scripts/Systems/Player/PlayerActionMapSystem.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: dcac359cadd69dd4bbe80b4a061eae8d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
33
Assets/Scripts/Systems/Player/PlayerAnimationSystem.cs
Normal file
33
Assets/Scripts/Systems/Player/PlayerAnimationSystem.cs
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
using DefaultNamespace;
|
||||
using Unity.Entities;
|
||||
using UnityEngine;
|
||||
using Zenject;
|
||||
|
||||
[UpdateInGroup(typeof(PresentationSystemGroup)), UpdateAfter(typeof(PlayerActionMapSystem)), UpdateAfter(typeof(PlayerMoveSystem))]
|
||||
public class PlayerAnimationSystem : InjectableComponentSystem
|
||||
{
|
||||
//[Inject] private PlayerGroup playerGroup;
|
||||
[Inject] private readonly Hashes hashes;
|
||||
|
||||
protected override void OnSystemUpdate()
|
||||
{
|
||||
Entities.WithAll<Animator>()
|
||||
.ForEach(
|
||||
(
|
||||
Transform transform,
|
||||
ref RigidBody2DData rigidBodyData,
|
||||
ref ActorData actorData,
|
||||
ref PlayerInput input,
|
||||
ref AnimatorStateData animationState,
|
||||
ref ActorAnimationData animation) =>
|
||||
{
|
||||
float walkDir = Mathf.Sign(transform.right.x) == Mathf.Sign(input.HorizontalInput) ? -1 : 1;
|
||||
animation.WalkDir = walkDir;
|
||||
});
|
||||
}
|
||||
|
||||
private class Hashes : IHashes
|
||||
{
|
||||
public readonly int AttackSpeed;
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Systems/Player/PlayerAnimationSystem.cs.meta
Normal file
11
Assets/Scripts/Systems/Player/PlayerAnimationSystem.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 55d43c6c8c8cb9b448b8695696fb9504
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
167
Assets/Scripts/Systems/Player/PlayerCoverSystem.cs
Normal file
167
Assets/Scripts/Systems/Player/PlayerCoverSystem.cs
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
using System;
|
||||
using Tween;
|
||||
using Unity.Entities;
|
||||
using UnityEngine;
|
||||
using Zenject;
|
||||
|
||||
namespace DefaultNamespace
|
||||
{
|
||||
[UpdateInGroup(typeof(PresentationSystemGroup)), UpdateBefore(typeof(WeaponFiringSystem))]
|
||||
public class PlayerCoverSystem : InjectableComponentSystem
|
||||
{
|
||||
[Serializable]
|
||||
public class Settings
|
||||
{
|
||||
public AnimationCurve AccuracyLossCurve;
|
||||
[Range(0, 1)] public float AccuracyLossMultiply;
|
||||
public float CheckDistance;
|
||||
public float MaxVaultAngle;
|
||||
public float MaxVaultFromAngle;
|
||||
public float MinVaultHeight;
|
||||
public float Offset;
|
||||
}
|
||||
|
||||
[Inject] private readonly Settings settings;
|
||||
|
||||
[Inject] private TweenSystem tweenSystem;
|
||||
|
||||
protected override void OnSystemUpdate()
|
||||
{
|
||||
Entities.WithAllReadOnly<RigidBody2DData, ActorData>()
|
||||
.ForEach(
|
||||
(
|
||||
Entity entity,
|
||||
ActorBodyParts parts,
|
||||
ref ActorCoverRaycastData raycast,
|
||||
ref ActorWeaponReferenceData weapon,
|
||||
ref PlayerInput input,
|
||||
ref Rotation2D rotation,
|
||||
ref ActorBoundsData bounds) =>
|
||||
{
|
||||
var actor = EntityManager.GetComponentData<ActorData>(entity);
|
||||
var rigidbody = EntityManager.GetComponentData<RigidBody2DData>(entity);
|
||||
var weaponAccuracy = EntityManager.GetComponentData<WeaponAccuracyData>(weapon.Weapon);
|
||||
|
||||
var height = Mathf.Clamp(
|
||||
raycast.TopHit.y + settings.Offset - parts.WeaponContainer.transform.position.y,
|
||||
0,
|
||||
settings.CheckDistance);
|
||||
|
||||
var heightPercent = Mathf.Clamp01(height / settings.CheckDistance);
|
||||
weaponAccuracy.Accuracy *=
|
||||
Mathf.Clamp01(1 - settings.AccuracyLossCurve.Evaluate(heightPercent) * settings.AccuracyLossMultiply);
|
||||
|
||||
var hasCover = raycast.UpDistance + raycast.TopDistance >= 0.1f && raycast.HadTopHit;
|
||||
|
||||
var canVault = raycast.Height >= settings.MinVaultHeight &&
|
||||
raycast.UpDistance + raycast.TopDistance >= bounds.Rect.height &&
|
||||
!tweenSystem.HasTween(entity) &&
|
||||
Vector2.Angle(Vector2.up, raycast.TopNormal) <= settings.MaxVaultAngle &&
|
||||
Vector2.Angle(actor.GroundUp, Vector2.up) <= settings.MaxVaultFromAngle;
|
||||
|
||||
var halfWidth = bounds.Rect.width * 0.5f;
|
||||
var offset = Vector2.right * rotation.Axis * halfWidth;
|
||||
var topRight = new Vector2(raycast.ForwardHit.x, raycast.TopHit.y);
|
||||
|
||||
PostUpdateCommands.KeepData(EntityManager, hasCover, entity, new PlayerCoverData());
|
||||
PostUpdateCommands.KeepData(EntityManager, canVault, entity, new PlayerVaultData { VaultPoint = topRight });
|
||||
|
||||
if (input.Vault && canVault)
|
||||
{
|
||||
topRight += offset;
|
||||
var topLeft = raycast.TopHit;
|
||||
var bottomRight = new Vector2(raycast.ForwardHit.x, raycast.TopHit.y - raycast.Height) + offset;
|
||||
var playerPos = rigidbody.Position;
|
||||
var path = Vector2.Distance(playerPos, bottomRight) >= halfWidth
|
||||
? new[] { playerPos, bottomRight, topRight, topLeft }
|
||||
: new[] { bottomRight, topRight, topLeft };
|
||||
PostUpdateCommands.StartTween(entity, 0.6f, EaseType.easeInOutQuart, TweenFollowPath.Build(path, Space.World));
|
||||
}
|
||||
|
||||
PostUpdateCommands.SetComponent(weapon.Weapon, weaponAccuracy);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
[UpdateInGroup(typeof(PresentationSystemGroup)), UpdateBefore(typeof(PlayerWeaponSystem)), UpdateBefore(typeof(ActorIkSystem))]
|
||||
public class PlayerCoverSystemWeaponAdjust : InjectableComponentSystem
|
||||
{
|
||||
[Inject] private readonly PlayerCoverSystem.Settings settings;
|
||||
|
||||
protected override void OnSystemUpdate()
|
||||
{
|
||||
Entities.ForEach(
|
||||
(ActorBodyParts parts, ref ActorCoverRaycastData raycast, ref PlayerCoverData coverData) =>
|
||||
{
|
||||
var height = Mathf.Clamp(
|
||||
raycast.TopHit.y + settings.Offset - parts.WeaponContainer.transform.position.y,
|
||||
0,
|
||||
settings.CheckDistance);
|
||||
|
||||
parts.WeaponContainer.transform.position += new Vector3(0, height, 0);
|
||||
coverData.WeaponOffset = height;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
[UpdateInGroup(typeof(SimulationSystemGroup))]
|
||||
public class PlayerCoverSystemRaycast : InjectableComponentSystem
|
||||
{
|
||||
[Inject] private readonly PlayerCoverSystem.Settings settings;
|
||||
|
||||
protected override void OnSystemUpdate()
|
||||
{
|
||||
Entities.WithAllReadOnly<ActorBodyParts>()
|
||||
.WithNone<ActorCoverRaycastData>()
|
||||
.ForEach(entity => { PostUpdateCommands.AddComponent(entity, new ActorCoverRaycastData()); });
|
||||
|
||||
Entities.ForEach(
|
||||
(ref ActorCoverRaycastData raycast, ref Rotation2D rotation, ref ActorBoundsData bounds) =>
|
||||
{
|
||||
var boundsSize = bounds.Rect.size;
|
||||
var boundsCenter = bounds.Rect.center;
|
||||
|
||||
var forward = boundsCenter + Vector2.left * rotation.Axis * 0.5f + Vector2.up * boundsSize.y * 0.5f;
|
||||
|
||||
var bottomHit = Physics2D.BoxCast(
|
||||
forward,
|
||||
new Vector2(boundsSize.x, 0.05f),
|
||||
0,
|
||||
Vector2.down,
|
||||
boundsSize.y,
|
||||
LayerMask.GetMask("Ground"));
|
||||
var forwardHit = Physics2D.BoxCast(
|
||||
boundsCenter,
|
||||
boundsSize * 0.9f,
|
||||
0,
|
||||
Vector2.left * rotation.Axis,
|
||||
1,
|
||||
LayerMask.GetMask("Ground"));
|
||||
var topHit = Physics2D.BoxCast(
|
||||
forward,
|
||||
new Vector2(boundsSize.x, 0.05f),
|
||||
0,
|
||||
Vector2.up,
|
||||
boundsSize.y,
|
||||
LayerMask.GetMask("Ground"));
|
||||
|
||||
var hasBottom = bottomHit.collider != null;
|
||||
var hasForward = forwardHit.collider != null;
|
||||
|
||||
var hitDistance = hasBottom ? bottomHit.distance + 0.05f : boundsSize.y;
|
||||
var height = Mathf.Max(boundsSize.y - hitDistance, 0);
|
||||
|
||||
raycast.Height = height;
|
||||
raycast.TopHit = hasBottom ? bottomHit.point : forward + Vector2.down * boundsSize.y;
|
||||
raycast.TopNormal = hasBottom ? bottomHit.normal : Vector2.up;
|
||||
raycast.HadTopHit = hasBottom;
|
||||
raycast.TopDistance = hasBottom ? bottomHit.distance : boundsSize.y;
|
||||
raycast.ForwardDistance = hasForward ? forwardHit.distance : 1;
|
||||
raycast.ForwardHit = hasForward ? forwardHit.point : boundsCenter + Vector2.left * rotation.Axis;
|
||||
raycast.ForwardNormal = hasForward ? forwardHit.normal : Vector2.right * rotation.Axis;
|
||||
raycast.HadForwardHit = hasForward;
|
||||
raycast.UpDistance = topHit.collider != null ? topHit.distance : boundsSize.y;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Systems/Player/PlayerCoverSystem.cs.meta
Normal file
11
Assets/Scripts/Systems/Player/PlayerCoverSystem.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 7292f583249350144bdce9b1071a6df4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
41
Assets/Scripts/Systems/Player/PlayerDeathSystem.cs
Normal file
41
Assets/Scripts/Systems/Player/PlayerDeathSystem.cs
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
using Events;
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.AddressableAssets;
|
||||
using Zenject;
|
||||
using Entity = Unity.Entities.Entity;
|
||||
using Hash128 = Unity.Entities.Hash128;
|
||||
|
||||
namespace DefaultNamespace
|
||||
{
|
||||
public class PlayerDeathSystem : InjectableComponentSystem
|
||||
{
|
||||
[Serializable]
|
||||
public class Settings
|
||||
{
|
||||
public AssetReferenceGameObject DeathParticles;
|
||||
public SoundLibrary DeathSounds;
|
||||
}
|
||||
|
||||
[Inject] private readonly ParticleSystemFactory particleFactory;
|
||||
|
||||
[Inject] private readonly Settings settings;
|
||||
[Inject] private readonly SoundManager soundManager;
|
||||
|
||||
protected override void OnSystemUpdate()
|
||||
{
|
||||
Entities.ForEach(
|
||||
(Entity entity, ref PlayerData player, ref ActorData actor, ref RigidBody2DData rigidBody) =>
|
||||
{
|
||||
if (actor.Health <= 0)
|
||||
{
|
||||
var pos = rigidBody.Position;
|
||||
particleFactory.Create(new Hash128(settings.DeathParticles.AssetGUID)).Completed += operation =>
|
||||
operation.Result.GetComponent<ParticleSystem>().Emit(new ParticleSystem.EmitParams { position = pos }, 1);
|
||||
soundManager.PlayClip(PostUpdateCommands, settings.DeathSounds, rigidBody.Position);
|
||||
PostUpdateCommands.AddComponent(entity, new EntityDeathEvent());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Systems/Player/PlayerDeathSystem.cs.meta
Normal file
11
Assets/Scripts/Systems/Player/PlayerDeathSystem.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: a4494fd3c0723cc43a1236b7f520171e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
69
Assets/Scripts/Systems/Player/PlayerEmotionSystem.cs
Normal file
69
Assets/Scripts/Systems/Player/PlayerEmotionSystem.cs
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
using System;
|
||||
using Unity.Entities;
|
||||
using Unity.Mathematics;
|
||||
using UnityEngine;
|
||||
using Zenject;
|
||||
|
||||
namespace DefaultNamespace
|
||||
{
|
||||
/// <summary>
|
||||
/// Changes emotion states based on animation triggers.
|
||||
/// It also swaps the face sprites for each emotion.
|
||||
/// </summary>
|
||||
[UpdateInGroup(typeof(PresentationSystemGroup)), UpdateAfter(typeof(PlayerWeaponSystem)), UpdateBefore(typeof(ActorAnimationSystem))]
|
||||
// Triggers the attack animation trigger
|
||||
// Resets animation triggers, and we use them
|
||||
public class PlayerEmotionSystem : InjectableComponentSystem
|
||||
{
|
||||
[Serializable]
|
||||
public class Settings
|
||||
{
|
||||
public float EmotionDuration = 1;
|
||||
[Tooltip("Emotions")] public Sprite NormalEmotion;
|
||||
public Sprite AngryEmotion;
|
||||
}
|
||||
|
||||
[Inject] private Settings settings;
|
||||
|
||||
#region Overrides of InjectableComponentSystem
|
||||
|
||||
protected override void OnSystemUpdate()
|
||||
{
|
||||
Entities.WithAllReadOnly<ActorBodyParts>()
|
||||
.ForEach(
|
||||
(Entity entity, ref ActorAnimationData animationData) =>
|
||||
{
|
||||
EntityManager.TryGetComponentObject<ActorBodyParts>(entity, out var actorBodyParts);
|
||||
if (!actorBodyParts.EmotionRenderer)
|
||||
{
|
||||
return;
|
||||
}
|
||||
animationData.EmotionTimer = math.saturate(animationData.EmotionTimer - Time.DeltaTime);
|
||||
|
||||
if ((animationData.Triggers & AnimationTriggerType.Attack) != 0 || (animationData.Triggers & AnimationTriggerType.Melee) != 0)
|
||||
{
|
||||
animationData.Emotion = EmotionType.Angry;
|
||||
animationData.EmotionTimer = settings.EmotionDuration;
|
||||
}
|
||||
|
||||
if (animationData.EmotionTimer <= 0)
|
||||
{
|
||||
animationData.Emotion = EmotionType.Neutral;
|
||||
}
|
||||
|
||||
switch (animationData.Emotion)
|
||||
{
|
||||
case EmotionType.Angry:
|
||||
actorBodyParts.EmotionRenderer.sprite = settings.AngryEmotion;
|
||||
break;
|
||||
|
||||
default:
|
||||
actorBodyParts.EmotionRenderer.sprite = settings.NormalEmotion;
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 331d28c3b2d44a43a692314b74bcd323
|
||||
timeCreated: 1642631929
|
||||
64
Assets/Scripts/Systems/Player/PlayerLookSystem.cs
Normal file
64
Assets/Scripts/Systems/Player/PlayerLookSystem.cs
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
using Cinemachine;
|
||||
using Events;
|
||||
using Markers;
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using Zenject;
|
||||
|
||||
namespace DefaultNamespace
|
||||
{
|
||||
public class PlayerLookSystem : InjectableComponentSystem, IInitializable
|
||||
{
|
||||
[Serializable]
|
||||
public class Settings
|
||||
{
|
||||
public float GunCameraFollowSmoothing;
|
||||
public float MinMouseDistance;
|
||||
}
|
||||
|
||||
[Inject] private readonly Camera camera;
|
||||
[Inject] private readonly CinemachineVirtualCamera followCamera;
|
||||
[Inject] private readonly PlayerFacade playerFacade;
|
||||
|
||||
[Inject] private readonly Settings settings;
|
||||
private CapsuleCollider2D playerCollider;
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
playerCollider = playerFacade.GetComponent<CapsuleCollider2D>();
|
||||
}
|
||||
|
||||
protected override void OnSystemUpdate()
|
||||
{
|
||||
var enabledWindowsCount = Entities.WithAllReadOnly<WindowComponentData, EnabledComponentData>().ToEntityQuery().CalculateEntityCount();
|
||||
|
||||
Entities.ForEach(
|
||||
(ref Rotation2D rotation, ref PlayerData player, ref ActorData actor, ref PlayerInput input) =>
|
||||
{
|
||||
Vector2 lookPoint = camera.ScreenToWorldPoint(Input.mousePosition);
|
||||
if (CanAim(lookPoint) && !input.OverUi && enabledWindowsCount <= 0)
|
||||
{
|
||||
actor.Aim = lookPoint;
|
||||
actor.Look = lookPoint;
|
||||
}
|
||||
else if (input.OverUi)
|
||||
{
|
||||
actor.Look = lookPoint;
|
||||
}
|
||||
|
||||
var oldScrenX = followCamera.GetCinemachineComponent<CinemachineFramingTransposer>().m_ScreenX;
|
||||
var newScreenX = 0.5f + 0.1f * rotation.Axis;
|
||||
followCamera.GetCinemachineComponent<CinemachineFramingTransposer>().m_ScreenX = Mathf.MoveTowards(
|
||||
oldScrenX,
|
||||
newScreenX,
|
||||
Time.DeltaTime * settings.GunCameraFollowSmoothing);
|
||||
});
|
||||
}
|
||||
|
||||
public bool CanAim(Vector2 worldPoint)
|
||||
{
|
||||
var mouseDistance = Vector2.Distance(playerCollider.bounds.ClosestPoint(worldPoint), worldPoint);
|
||||
return !playerCollider.OverlapPoint(worldPoint) && mouseDistance >= settings.MinMouseDistance;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Systems/Player/PlayerLookSystem.cs.meta
Normal file
11
Assets/Scripts/Systems/Player/PlayerLookSystem.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 6f6a5c3f34ce5b947881478a63e4d587
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
258
Assets/Scripts/Systems/Player/PlayerMoveSystem.cs
Normal file
258
Assets/Scripts/Systems/Player/PlayerMoveSystem.cs
Normal file
|
|
@ -0,0 +1,258 @@
|
|||
using DefaultNamespace;
|
||||
using Polycrime;
|
||||
using System;
|
||||
using Trive.Core;
|
||||
using Trive.Mono.Utils;
|
||||
using Tween;
|
||||
using Unity.Entities;
|
||||
using UnityEngine;
|
||||
using Zenject;
|
||||
|
||||
[UpdateInGroup(typeof(SimulationSystemGroup)), UpdateAfter(typeof(PlayerActionMapSystem))]
|
||||
public class PlayerMoveSystem : InjectableComponentSystem, IInitializable
|
||||
{
|
||||
[Serializable]
|
||||
public class Settings
|
||||
{
|
||||
public float FallGravityMultiply = 2.5f;
|
||||
public float GroundSnapForce;
|
||||
public float JumpDirForcePercent = 1;
|
||||
public float JumpHeight;
|
||||
public ParticleSystem JumpParticles;
|
||||
public float LowJumpGravityMultiply = 2.5f;
|
||||
public float MaxAirForce = 1;
|
||||
public float MaxForce = 1;
|
||||
public float MaxGroundAngle = 45;
|
||||
public float MaxGroundSnapDistance;
|
||||
public float moveForce = 1;
|
||||
public PIDFloat movePid;
|
||||
public PIDFloat movePidVertical;
|
||||
public float ObsticleJumpTime = 0.2f;
|
||||
public AnimationCurve SlopeMoveForce;
|
||||
public LayerMask StepAssistMask;
|
||||
public float StepAssistMaxHeight;
|
||||
|
||||
[Tooltip("The maximum angle the player can vault from")] public float VaultFromAngleMax;
|
||||
|
||||
public float VaultMaxAngle;
|
||||
public Vector2 VaultObsicleRange;
|
||||
}
|
||||
|
||||
[Inject] private readonly AudioListener audioListener;
|
||||
[Inject] private readonly PlayerFacade playerFacade;
|
||||
[Inject] private readonly Settings settings;
|
||||
private Transform head;
|
||||
private float lastDir;
|
||||
private float lastStepSign;
|
||||
private float stepTimer;
|
||||
|
||||
[Inject] private TweenSystem tweenSystem;
|
||||
|
||||
private float DeltaTime => Time.fixedDeltaTime;
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
head = playerFacade.FindChildGlobal<Transform>("$Head");
|
||||
}
|
||||
|
||||
protected override void OnSystemUpdate()
|
||||
{
|
||||
Entities.WithAllReadOnly<ActorBoundsData, Rotation2D>()
|
||||
.ForEach(
|
||||
(
|
||||
Entity entity,
|
||||
Rigidbody2D rigidbody,
|
||||
ref PlayerData player,
|
||||
ref ActorData actor,
|
||||
ref AnimatorStateData animationState,
|
||||
ref PlayerInput input,
|
||||
ref ActorAnimationData animation) =>
|
||||
{
|
||||
var bounds = EntityManager.GetComponentData<ActorBoundsData>(entity);
|
||||
var rotation = EntityManager.GetComponentData<Rotation2D>(entity);
|
||||
|
||||
if (actor.Grounded)
|
||||
{
|
||||
player.AirControlAmount = 1;
|
||||
}
|
||||
|
||||
audioListener.transform.position = head.transform.position;
|
||||
|
||||
UpdateVelocity(rigidbody, actor, input, animationState, ref animation, rotation, player);
|
||||
|
||||
if (Mathf.Abs(input.HorizontalInput) > 0)
|
||||
{
|
||||
lastDir = Mathf.Sign(input.HorizontalInput);
|
||||
}
|
||||
|
||||
float snapMultiply = 1;
|
||||
|
||||
ManageVaulting(entity, rigidbody, bounds, actor, rotation, ref animation, ref input, ref snapMultiply, ref player);
|
||||
|
||||
ManageJumping(ref input, rigidbody, bounds, ref actor, ref animation);
|
||||
|
||||
SnapToGround(rigidbody, actor, snapMultiply);
|
||||
});
|
||||
}
|
||||
|
||||
private void ManageJumping(
|
||||
ref PlayerInput input,
|
||||
Rigidbody2D rigidbody,
|
||||
ActorBoundsData bounds,
|
||||
ref ActorData actor,
|
||||
ref ActorAnimationData animation)
|
||||
{
|
||||
if (actor.Grounded)
|
||||
{
|
||||
if (input.JumpPressed)
|
||||
{
|
||||
var boundsSize = bounds.Rect.size;
|
||||
var boundsCenter = bounds.Rect.center;
|
||||
|
||||
var rayStart = boundsCenter + Vector2.up * boundsSize.y * 0.5f;
|
||||
var hit = Physics2D.CircleCast(rayStart, boundsSize.x * 0.5f, Vector2.up, settings.JumpHeight, settings.StepAssistMask);
|
||||
|
||||
var maxJumpHeight = Mathf.Min(settings.JumpHeight, hit.collider != null ? hit.distance + boundsSize.x : settings.JumpHeight);
|
||||
var jumpVelY = Mathf.Sqrt(0 - 2 * Physics2D.gravity.y * maxJumpHeight);
|
||||
Vector3 jumpForce = Vector2.up * jumpVelY + new Vector2(input.HorizontalInput, 0) * settings.JumpDirForcePercent * jumpVelY;
|
||||
rigidbody.AddForce(jumpForce * rigidbody.mass, ForceMode2D.Impulse);
|
||||
actor.Grounded = false;
|
||||
settings.JumpParticles.Emit(new ParticleSystem.EmitParams { position = rigidbody.position }, 1);
|
||||
animation.Triggers |= AnimationTriggerType.Jump;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private float CalculateSlopeSpeed(Vector2 slopeNormal, float input, float rotationAxis)
|
||||
{
|
||||
var slotDer = Mathf.Sign(Vector2.SignedAngle(slopeNormal, Vector2.up));
|
||||
var slopeAngle = Vector2.Angle(slopeNormal, Vector2.up);
|
||||
|
||||
//must be looking in the same direction as the input for it to go negative
|
||||
return settings.SlopeMoveForce.Evaluate(
|
||||
slopeAngle / settings.MaxGroundAngle * (Mathf.Sign(input) == slotDer ? Mathf.Sign(rotationAxis) != Mathf.Sign(input) ? -1 : 1 : 1));
|
||||
}
|
||||
|
||||
private void UpdateVelocity(
|
||||
Rigidbody2D rigidbody,
|
||||
ActorData actor,
|
||||
PlayerInput input,
|
||||
AnimatorStateData animationState,
|
||||
ref ActorAnimationData animation,
|
||||
Rotation2D rotation,
|
||||
PlayerData playerData)
|
||||
{
|
||||
var slopeSpeedMultiply = CalculateSlopeSpeed(actor.GroundUp, input.HorizontalInput, rotation.Axis);
|
||||
var walkMultiply = Mathf.Min(Mathf.Abs(input.HorizontalInput), Mathf.Abs(rigidbody.velocity.x));
|
||||
animation.WalkMultiply = walkMultiply * slopeSpeedMultiply;
|
||||
|
||||
rigidbody.gravityScale = actor.Grounded ? 1 :
|
||||
rigidbody.velocity.y > 0 ? input.Jump ? 1 : settings.LowJumpGravityMultiply : settings.FallGravityMultiply;
|
||||
var desiredMoveForce = input.HorizontalInput *
|
||||
settings.moveForce *
|
||||
(animationState.State.IsTag("Interactive") || animationState.State.IsTag("CanMove") ? 1 : 0);
|
||||
var force = -Vector2.Perpendicular(actor.GroundUp) * desiredMoveForce * slopeSpeedMultiply;
|
||||
var groundOrientation = Vector2.SignedAngle(actor.GroundUp, Vector2.up);
|
||||
var rotatedVelocity = rigidbody.velocity.Rotate(groundOrientation);
|
||||
var actualLocalForce = rigidbody.velocity.x;
|
||||
var actualLocalVerticalForce = rigidbody.velocity.y;
|
||||
var maxForce = Mathf.Lerp(settings.MaxAirForce, settings.MaxForce, actor.Grounded ? 1 : 0) * playerData.AirControlAmount;
|
||||
var forceDelta = settings.movePid.Update(force.x, actualLocalForce, DeltaTime);
|
||||
var forceDeltaVertical = settings.movePidVertical.Update(force.y, actualLocalVerticalForce, DeltaTime);
|
||||
forceDelta = Mathf.Clamp(forceDelta, -maxForce, maxForce);
|
||||
forceDeltaVertical = Mathf.Clamp(forceDeltaVertical, -settings.MaxForce, settings.MaxForce) *
|
||||
(actor.GroundDinstance >= 0 ? 1 - Mathf.Clamp01(actor.GroundDinstance / settings.MaxGroundSnapDistance) : 0);
|
||||
rigidbody.AddForce(Vector2.right * forceDelta);
|
||||
rigidbody.AddForce(Vector2.up * forceDeltaVertical);
|
||||
}
|
||||
|
||||
private void SnapToGround(Rigidbody2D rigidbody, ActorData actor, float snapMultiply)
|
||||
{
|
||||
if (actor.GroundDinstance > 0 && actor.Grounded)
|
||||
{
|
||||
var inverseGroundDistance = 1 - Mathf.Clamp01(actor.GroundDinstance / settings.MaxGroundSnapDistance);
|
||||
rigidbody.AddForce(-actor.GroundUp * settings.GroundSnapForce * snapMultiply);
|
||||
}
|
||||
}
|
||||
|
||||
private void ManageVaulting(
|
||||
Entity entity,
|
||||
Rigidbody2D rigidbody,
|
||||
ActorBoundsData bounds,
|
||||
ActorData actor,
|
||||
Rotation2D rotation,
|
||||
ref ActorAnimationData animation,
|
||||
ref PlayerInput playerInput,
|
||||
ref float snapMultiply,
|
||||
ref PlayerData playerData)
|
||||
{
|
||||
var boundsSize = bounds.Rect.size;
|
||||
var boundsCenter = bounds.Rect.center;
|
||||
|
||||
var floorAxis = Mathf.FloorToInt(Mathf.Abs(playerInput.HorizontalInput));
|
||||
var axisSign = (int)Mathf.Sign(playerInput.HorizontalInput);
|
||||
var axisAndLookAreSame = Mathf.Sign(playerInput.HorizontalInput) != rotation.Axis;
|
||||
var forwardTop = boundsCenter +
|
||||
Vector2.left * rotation.Axis * boundsSize.x * (axisSign * floorAxis * -rotation.Axis * (axisAndLookAreSame ? 1 : 0)) +
|
||||
Vector2.up * boundsSize.y * 0.5f;
|
||||
|
||||
RaycastHit2D topHit, bottomHit;
|
||||
|
||||
topHit = Physics2D.CircleCast(forwardTop, boundsSize.x * 0.5f, Vector2.up, boundsSize.y, settings.StepAssistMask);
|
||||
bottomHit = Physics2D.CircleCast(
|
||||
forwardTop,
|
||||
boundsSize.x * 0.5f,
|
||||
Vector2.down,
|
||||
boundsSize.y + settings.VaultObsicleRange.y,
|
||||
settings.StepAssistMask);
|
||||
|
||||
var topDistance = topHit.collider != null ? topHit.distance + boundsSize.x * 0.5f : boundsSize.y;
|
||||
var bottomDistance = bottomHit.collider != null ? bottomHit.distance + boundsSize.x * 0.5f : boundsSize.y;
|
||||
var groundAngle = Vector2.Angle(bottomHit.normal, Vector2.up);
|
||||
var currentAngle = Vector2.Angle(actor.GroundUp, Vector2.up);
|
||||
|
||||
var totalSize = topDistance + bottomDistance;
|
||||
var obsticleHeight = boundsSize.y - Mathf.Min(bottomDistance, boundsSize.y);
|
||||
var obsticleDepth = Mathf.Max(bottomDistance - boundsSize.y, 0);
|
||||
|
||||
//Debug.DrawLine(forwardTop + Vector2.up * Vector2.up, forwardTop + Vector2.down * bottomDistance, Color.red);
|
||||
Debug.DrawLine(forwardTop + Vector2.down * boundsSize.y, forwardTop + Vector2.down * boundsSize.y + Vector2.up * obsticleHeight, Color.green);
|
||||
|
||||
if (groundAngle <= settings.VaultMaxAngle &&
|
||||
currentAngle <= settings.VaultFromAngleMax &&
|
||||
totalSize > boundsSize.y &&
|
||||
!tweenSystem.HasTween(entity))
|
||||
{
|
||||
if (obsticleHeight <= settings.StepAssistMaxHeight)
|
||||
{
|
||||
rigidbody.AddForce(Vector2.up * obsticleHeight * rigidbody.mass * 2, ForceMode2D.Impulse);
|
||||
snapMultiply = 0;
|
||||
}
|
||||
else if (true)
|
||||
{
|
||||
var target = Vector2.zero;
|
||||
var jumpedFlag = false;
|
||||
|
||||
if (obsticleHeight >= settings.VaultObsicleRange.x && obsticleHeight <= settings.VaultObsicleRange.y && actor.Grounded)
|
||||
{
|
||||
target = forwardTop + Vector2.down * Mathf.Min(bottomDistance, boundsSize.y);
|
||||
jumpedFlag = true;
|
||||
}
|
||||
|
||||
if (jumpedFlag)
|
||||
{
|
||||
var vel = TrajectoryMath.CalculateVelocityWithHeight(
|
||||
rigidbody.position,
|
||||
target,
|
||||
Mathf.Abs(rigidbody.position.y - target.y) + 0.5f,
|
||||
settings.FallGravityMultiply);
|
||||
//var vel = TrajectoryMath.CalculateVelocity(rigidbody.position, target,settings.ObsticleJumpTime, settings.FallGravityMultiply);
|
||||
var velDelta = vel - rigidbody.velocity;
|
||||
rigidbody.AddForce(velDelta * rigidbody.mass, ForceMode2D.Impulse);
|
||||
//PostUpdateCommands.StartTween(entity,0.5f,EaseType.linear,TweenFollowPath.Build(new []{rigidbody.position,rigidbody.position + new Vector2(0,target.y - rigidbody.position.y),target},Space.World));
|
||||
animation.Triggers |= AnimationTriggerType.JumpObsticle;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Systems/Player/PlayerMoveSystem.cs.meta
Normal file
11
Assets/Scripts/Systems/Player/PlayerMoveSystem.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ffff4ebe0bd4a144f9487327a951843a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
24
Assets/Scripts/Systems/Player/PlayerQuickActionsSystem.cs
Normal file
24
Assets/Scripts/Systems/Player/PlayerQuickActionsSystem.cs
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
using Events;
|
||||
using Unity.Entities;
|
||||
|
||||
namespace DefaultNamespace
|
||||
{
|
||||
public class PlayerQuickActionsSystem : ComponentSystem
|
||||
{
|
||||
protected override void OnUpdate()
|
||||
{
|
||||
Entities.WithAllReadOnly<Slot>()
|
||||
.ForEach(
|
||||
(Entity entity, ref PlayerInput input) =>
|
||||
{
|
||||
var inv = EntityManager.GetBuffer<Slot>(entity);
|
||||
if (input.Heal && inv.Begin().Any(s => s.Type == SlotType.Health) && !EntityManager.HasComponent<ItemUseEventData>(entity))
|
||||
{
|
||||
PostUpdateCommands.AddComponent(
|
||||
entity,
|
||||
new ItemUseEventData { Inventory = entity, Slot = inv.Begin().IndexOf(e => e.Type == SlotType.Health) });
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue