Initial Commit

This commit is contained in:
Simeon Radivoev 2022-02-12 12:53:50 +02:00
commit ee5c2f922d
Signed by: simeonradivoev
GPG key ID: 7611A451D2A5D37A
2255 changed files with 547750 additions and 0 deletions

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: f873be1f9d82e254593f0e546121c8ad
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View 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);
}
});
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 54297fbb8ccd22841998510566bbac5e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -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(); });
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d002725e916824f4e91db1ecccbee637
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,11 @@
using Unity.Entities;
namespace DefaultNamespace
{
public class ActorAnimationResetSystem : ComponentSystem
{
protected override void OnUpdate()
{
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6accfe0b33196564a8bdbae4d70df0e8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View 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;
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ddbd346c0b4cce64790a5629aeb244c8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View 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) };
});
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2795c755ec62205478f72e4e69d87d5a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View 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;
}
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f324081ba101cbd489288a93a667f381
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View 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());
}
});
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2d753cf45e2c5a84d8ca3dbea2c75a6a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View 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);
}
});
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 03b37e129a944c64caff945d57875398
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View 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();
}
});
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: bd60b50a76b37f54a8e73de127a08daa
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View 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();
}
});
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 304959ce2b8b20a44bc5b9c9eb2d4612
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View 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);
}
}
});
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7b986bf4cd04217499c861430421fa42
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View 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");
}
});
}
}
});
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a32ed2ad3bce0ec4fb8546d5accd8656
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View 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;
});
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9125a53a5d062ae4bb610abc213b675f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View 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();
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6e3fc48ba5a0ccf4ea3aad65e749ab3c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View 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));
}
}
});
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: fc3f9a02683560144b3a62c4af6addd3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View 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;
}
});
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 77982375f38720a4b9a451d005ebd3f9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View 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);
}
});
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8514d45ce52194a45b004bc633d33263
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View 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
});
});
}
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1ed5337761ebae04b937412ddd34cf47
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 4e32da8f515eb7844887bbaabb4694b1
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View 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());
}
});
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e44e3c7f9a143b14cadcd63710d28975
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View 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;
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 36011162a5b4119419ad80e11512f872
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View 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
{
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d2681da5e82636541bb6f573b1c5b88e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View 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);
}
});
}
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 82a2563a6596b764c9cf45364a01be1e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View 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);
}
}
});
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: bfd009e9173f9f349b92630c8d055e8a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View 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);
}
});
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5b25a42d216466849a664d9413213670
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View 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);
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b7722c79edb14354da2fe990b468c1cd
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View 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);
}
});
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: fa6fe75a8af67ef4985ea41edb96a4ed
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View 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();
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5e785b5f27074e64ea3102d117406dce
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: e77b7d13d1814164280d90e02fc59064
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View 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;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ef39a98683c52864d846421dc14c9401
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View 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;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e22016dc3c17bb849afc787c8d4d8abe
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View 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);
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8286d73d7aaeff94f803396767d8f590
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View 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);
}
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8a7c6501fc4d7294b87eca0f2aafa2ed
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View 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);
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 535ade2fff3ef7b4884e6b102f12fdcc
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View 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;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1f16dfa58ee27c14480c68b9ab406203
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View 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();
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: dee8253f18bbcf240abfcb80b705d894
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,7 @@
using System;
namespace DefaultNamespace
{
[Flags]
public enum ItemUseFlags { UseOnlyGrounded = 1 << 0, UseOnlyInteractive = 1 << 1, InteruptAttack = 1 << 2 }
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2082c72c7f4737b44920e76055cf990e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View 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;
}
});
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ccb01c4fd6f8d154b82b406cc27c0cb0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View 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);
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0c6e2d007bec8d946aac933c54d94256
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 1a20788f7ddc9fe4a819d7dcd6f21b1d
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View 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;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b427073c5a8f24f4fb88c203b98d5d37
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View 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();
}
}
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d9a8f6a25f16cb4479d04e90f5156ae0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View 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;
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b8db9e9730280d2409d57861dd6059af
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 3c056491586d7ff4092d72a8f9eb5e10
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View 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");
});
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: dcac359cadd69dd4bbe80b4a061eae8d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View 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;
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 55d43c6c8c8cb9b448b8695696fb9504
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View 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;
});
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7292f583249350144bdce9b1071a6df4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View 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());
}
});
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a4494fd3c0723cc43a1236b7f520171e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View 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
}
}

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 331d28c3b2d44a43a692314b74bcd323
timeCreated: 1642631929

View 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;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6f6a5c3f34ce5b947881478a63e4d587
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View 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;
}
}
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ffff4ebe0bd4a144f9487327a951843a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View 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