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,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: