private static void ParseDamageTypeDefinition(string gameConstantsFilePath) { Debug.Assert(gameConstantsFilePath != null, nameof(gameConstantsFilePath) + " != null"); Debug.Assert(File.Exists(gameConstantsFilePath), nameof(gameConstantsFilePath) + " must exist"); XDocument gameConstantsFile = XDocument.Load(gameConstantsFilePath); Debug.Assert(gameConstantsFile.Root != null, "gameConstantsFile.Root != null"); foreach (XElement xElement in gameConstantsFile.Root.Elements()) { if (!xElement.Name.ToString().Equals(Tags.DAMAGE_TYPES, StringComparison.InvariantCultureIgnoreCase)) { continue; } List <Damage> damages = DamageUtility.ParseFromString(xElement.Value); foreach (Damage damage in damages) { if (GlobalStore.DAMAGE_REGISTRY.Contains(damage)) { Debug.Assert(damage != null, nameof(commons.damage) + " != null"); Log.Warning( $"Found duplicated damage type definition \"{damage.Name}\" was previously defined."); continue; } GlobalStore.DAMAGE_REGISTRY.Add(damage); } break; } }
public void Damage(float damageAmount) { //subtract damage amount when Damage function is called currentHealth -= damageAmount; //Check if health has fallen below zero if (currentHealth <= 0) { currentHealth = 0; if (gameObject.tag != "Player") { //if health has fallen below zero, deactivate it gameObject.SetActive(false); if (explosionParticle) { Instantiate(explosionParticle, this.transform.position, Quaternion.identity); // var obj = GameObject.CreatePrimitive(PrimitiveType.Sphere); // obj.name = "tester"; // obj.transform.localScale = new Vector3(10, 10, 10); // obj.transform.position = gameObject.transform.position; // print("radius is " + obj.GetComponent<SphereCollider>().radius.ToString()); DamageUtility.AreaDamageThings(gameObject.transform.position, 20, 70.0f); } } else { UnityEngine.SceneManagement.SceneManager.LoadScene(UnityEngine.SceneManagement.SceneManager.GetActiveScene().name); } } if (TookDamage != null) { TookDamage(damageAmount, currentHealth); } }
public IEnumerator AttackVFX(Transform _start, IDestructible _end, float _time, bool _miss = false) { var T = 0.0f; line.SetPosition(0, _start.position); line.SetPosition(1, _start.position); var endPos = _miss ? DamageUtility.GetMissPosition(_start, _end.GetTransform(), _end.SizeType) : _start.position; while (T < _time) { if (!_miss) { endPos = Vector3.MoveTowards(line.GetPosition(1), _end.GetPointToAttack(_start.position), speed * Time.deltaTime); } line.SetPosition(0, _start.position); line.SetPosition(1, endPos); yield return(null); T += Time.deltaTime; } HideLaser(); }
protected virtual IEnumerator Attack() { //Подготовка к выстрелу yield return(Preparation()); GetTarget(); if (target == null) { yield break; } var destructible = target.destructible; if (destructible == null) { yield break; } //Попадание if (DamageUtility.CheckHit(data, target, Vector3.Distance(transform.position, target.transform.position))) { yield return(effects.AttackVFX(startPos, destructible, rate * timeLerpRateToAttack)); var damage = new Damage(armorDamage, shieldDamage, critical, accuracy); destructible.ApplyDamage(damage, startPos.position); } else { yield return(effects.AttackVFX(startPos, destructible, rate * timeLerpRateToAttack, true)); destructible.ApplyMiss(startPos.position); } }
public void ParseFromString_Test() { List <Damage> l = DamageUtility.ParseFromString(DAMAGE_STRING); Assert.IsNotNull(l); Assert.IsTrue(l.Any()); Assert.AreEqual(99, l.Count); }
//отрицательное значение - урон, положительное - ремонт private float CalculateDamageArmor(Damage _damage) { //var result = -_damage.ArmorDmg; var result = -DamageUtility.GetDamageValue(_damage, true); //var armor = GetArmor(); //TODO: return(result); }
//отрицательное значение - урон, положительное - ремонт private float CalculateDamageShield(Damage _damage) { //var result = -_damage.ShieldDmg; var result = -DamageUtility.GetDamageValue(_damage, false); //var shield = GetShield(); //TODO: return(result); }
public void ParseFromString_TestNullEmptyOrWhitespace() { List <Damage> l0 = DamageUtility.ParseFromString(null); Assert.IsNotNull(l0); Assert.IsFalse(l0.Any()); List <Damage> l1 = DamageUtility.ParseFromString(string.Empty); Assert.IsNotNull(l1); Assert.IsFalse(l1.Any()); List <Damage> l2 = DamageUtility.ParseFromString("\n \t\r\n"); Assert.IsNotNull(l2); Assert.IsFalse(l2.Any()); }
public static IEnumerable <XElement> ParseDamageToArmourMatrixAsXElement() { List <XElement> elements = new List <XElement>(); foreach (Damage damage in DamageUtility.GetAll()) { if (damage.IsBuiltInType) { elements.AddRange(from damageToArmour in GetDamageToArmourMatrixByDamage(damage) where Math.Abs(damageToArmour.DamageToArmourFactor - 1.0f) > 0.000001f select damageToArmour.ToXElement()); } else { elements.AddRange(GetDamageToArmourMatrixByDamage(damage).Select(damageToArmour => damageToArmour.ToXElement())); } } return(elements); }
/// <summary> /// Perform the impact action. /// </summary> /// <param name="castID">The ID of the cast.</param> /// <param name="source">The object that caused the cast.</param> /// <param name="target">The object that was hit by the cast.</param> /// <param name="hit">The raycast that caused the impact.</param> protected override void ImpactInternal(uint castID, GameObject source, GameObject target, RaycastHit hit) { var damageTarget = DamageUtility.GetDamageTarget(target); if (damageTarget == null || !damageTarget.IsAlive()) { if (m_InterruptImpactOnNullHealth) { m_MagicItem.InterruptImpact(); } return; } var pooledDamageData = GenericObjectPool.Get <DamageData>(); pooledDamageData.SetDamage(m_Amount, source.transform.position, (source.transform.position - target.transform.position), m_ForceMagnitude, m_ForceFrames, 0, source, this, null); if (m_DamageProcessor == null) { m_DamageProcessor = DamageProcessor.Default; } m_DamageProcessor.Process(damageTarget, pooledDamageData); GenericObjectPool.Return(pooledDamageData); }
/// <summary> /// The object has collided with another object. /// </summary> /// <param name="hit">The RaycastHit of the object. Can be null.</param> protected override void OnCollision(RaycastHit?hit) { base.OnCollision(hit); var forceDestruct = false; if (m_CollisionMode == CollisionMode.Collide) { // When there is a collision the object should move to the position that was hit so if it's not destroyed then it looks like it // is penetrating the hit object. if (hit != null && hit.HasValue && m_Collider != null) { var closestPoint = m_Collider.ClosestPoint(hit.Value.point); m_Transform.position += (hit.Value.point - closestPoint); // Only set the parent to the hit transform on uniform objects to prevent stretching. if (MathUtility.IsUniform(hit.Value.transform.localScale)) { // The parent layer must be within the sticky layer mask. if (MathUtility.InLayerMask(hit.Value.transform.gameObject.layer, m_StickyLayers)) { m_Transform.parent = hit.Value.transform; // If the destructible sticks to a character then the object should be added as a sub collider so collisions will be ignored. m_StickyCharacterLocomotion = hit.Value.transform.gameObject.GetCachedComponent <UltimateCharacterLocomotion>(); if (m_StickyCharacterLocomotion != null) { m_StickyCharacterLocomotion.AddIgnoredCollider(m_Collider); } } else { forceDestruct = true; } } } if (m_TrailRenderer != null) { m_TrailRenderer.enabled = false; } } var destructionDelay = m_DestructionDelay; if (m_ParticleSystem != null && m_WaitForParticleStop) { destructionDelay = m_ParticleSystem.main.duration; m_ParticleSystem.Stop(true, ParticleSystemStopBehavior.StopEmitting); Stop(); } // The object may not have been initialized before it collides. if (m_GameObject == null) { InitializeComponentReferences(); } if (hit != null && hit.HasValue) { var hitValue = hit.Value; var hitGameObject = hitValue.collider.gameObject; // The shield can absorb some (or none) of the damage from the destructible. var damageAmount = m_DamageAmount; #if ULTIMATE_CHARACTER_CONTROLLER_MELEE ShieldCollider shieldCollider; if ((shieldCollider = hitGameObject.GetCachedComponent <ShieldCollider>()) != null) { damageAmount = shieldCollider.Shield.Damage(this, damageAmount); } #endif // Allow a custom event to be received. EventHandler.ExecuteEvent <float, Vector3, Vector3, GameObject, object, Collider>(hitGameObject, "OnObjectImpact", damageAmount, hitValue.point, m_Velocity.normalized * m_ImpactForce, m_Originator, this, hitValue.collider); if (m_OnImpactEvent != null) { m_OnImpactEvent.Invoke(damageAmount, hitValue.point, m_Velocity.normalized * m_ImpactForce, m_Originator); } // If the shield didn't absorb all of the damage then it should be applied to the character. if (damageAmount > 0) { var damageTarget = DamageUtility.GetDamageTarget(hitGameObject); if (damageTarget != null) { var pooledDamageData = GenericObjectPool.Get <DamageData>(); pooledDamageData.SetDamage(this, damageAmount, hitValue.point, -hitValue.normal, m_ImpactForce, m_ImpactForceFrames, 0, hitValue.collider); var damageProcessorModule = hitGameObject.GetCachedComponent <DamageProcessorModule>(); if (damageProcessorModule != null) { damageProcessorModule.ProcessDamage(m_DamageProcessor, damageTarget, pooledDamageData); } else { if (m_DamageProcessor == null) { m_DamageProcessor = DamageProcessor.Default; } m_DamageProcessor.Process(damageTarget, pooledDamageData); } GenericObjectPool.Return(pooledDamageData); } else if (m_ImpactForce > 0) { // If the damage target exists it will apply a force to the rigidbody in addition to procesing the damage. Otherwise just apply the force to the rigidbody. var collisionRigidbody = hitGameObject.GetCachedParentComponent <Rigidbody>(); if (collisionRigidbody != null && !collisionRigidbody.isKinematic) { collisionRigidbody.AddForceAtPosition(m_ImpactForce * MathUtility.RigidbodyForceMultiplier * -hitValue.normal, hitValue.point); } else { var forceObject = hitGameObject.GetCachedParentComponent <IForceObject>(); if (forceObject != null) { forceObject.AddForce(m_Transform.forward * m_ImpactForce); } } } } // An optional state can be activated on the hit object. if (!string.IsNullOrEmpty(m_ImpactStateName)) { StateManager.SetState(hitGameObject, m_ImpactStateName, true); // If the timer isn't -1 then the state should be disabled after a specified amount of time. If it is -1 then the state // will have to be disabled manually. if (m_ImpactStateDisableTimer != -1) { StateManager.DeactivateStateTimer(hitGameObject, m_ImpactStateName, m_ImpactStateDisableTimer); } } } // The object can destroy itself after a small delay. if (m_DestroyEvent == null && (m_DestroyOnCollision || forceDestruct || destructionDelay > 0)) { m_DestroyEvent = SchedulerBase.ScheduleFixed(destructionDelay, Destruct, hit); } }
private static void SaveToGameConstantsFilePrepare([NotNull] string gameConstantsFilePath) { DamageUtility.CleanDamageDeclaration(gameConstantsFilePath); ArmourUtility.CleanArmourDeclaration(gameConstantsFilePath); DamageToArmourUtility.CleanDamageToArmourDeclaration(gameConstantsFilePath); }
private static void SaveToGameConstantsFileInternal([NotNull] string gameConstantsFilePath) { XmlUtility.ReplaceValueForTag(gameConstantsFilePath, Tags.DAMAGE_TYPES, DamageUtility.GetAllAsString()); XmlUtility.ReplaceValueForTag(gameConstantsFilePath, Tags.ARMOR_TYPES, ArmourUtility.GetAllAsString()); XmlUtility.InsertElement(gameConstantsFilePath, DamageToArmourUtility.ParseDamageToArmourMatrixAsXElement(), Tags.ARMOR_TYPES); }
/// <summary> /// Do the explosion. /// </summary> /// <param name="damageAmount">The amount of damage to apply to the hit objects.</param> /// <param name="impactForce">The amount of force to apply to the hit object.</param> /// <param name="impactForceFrames">The number of frames to add the force to.</param> /// <param name="originator">The originator of the object.</param> public void Explode(float damageAmount, float impactForce, int impactForceFrames, GameObject originator) { Rigidbody colliderRigidbody = null; IForceObject forceObject = null; var hitCount = Physics.OverlapSphereNonAlloc(m_Transform.position, m_Radius, m_CollidersHit, m_ImpactLayers, QueryTriggerInteraction.Ignore); #if UNITY_EDITOR if (hitCount == m_MaxCollisionCount) { Debug.LogWarning("Warning: The maximum number of colliders have been hit by " + m_GameObject.name + ". Consider increasing the Max Collision Count value."); } #endif for (int i = 0; i < hitCount; ++i) { // A GameObject can contain multiple colliders. Prevent the explosion from occurring on the same GameObject multiple times. if (m_ObjectExplosions.Contains(m_CollidersHit[i].gameObject)) { continue; } m_ObjectExplosions.Add(m_CollidersHit[i].gameObject); // The base character GameObject should only be checked once. if ((forceObject = m_CollidersHit[i].gameObject.GetCachedParentComponent <IForceObject>()) != null) { if (m_ObjectExplosions.Contains(forceObject)) { continue; } m_ObjectExplosions.Add(forceObject); } // OverlapSphere can return objects that are in a different room. Perform a cast to ensure the object is within the explosion range. if (m_LineOfSight) { // Add a slight vertical offset to prevent a floor collider from getting in the way of the cast. var position = m_Transform.TransformPoint(0, 0.1f, 0); var direction = m_CollidersHit[i].transform.position - position; if (Physics.Raycast(position - direction.normalized * 0.1f, direction, out m_RaycastHit, direction.magnitude, m_ImpactLayers, QueryTriggerInteraction.Ignore) && !(m_RaycastHit.transform.IsChildOf(m_CollidersHit[i].transform) #if FIRST_PERSON_CONTROLLER // The cast should not hit any colliders who are a child of the camera. || m_RaycastHit.transform.gameObject.GetCachedParentComponent <FirstPersonController.Character.FirstPersonObjects>() != null #endif )) { // If the collider is part of a character then ensure the head can't be hit. var parentAnimator = m_CollidersHit[i].transform.gameObject.GetCachedParentComponent <Animator>(); if (parentAnimator != null && parentAnimator.isHuman) { var head = parentAnimator.GetBoneTransform(HumanBodyBones.Head); direction = head.position - position; if (Physics.Raycast(position, direction, out m_RaycastHit, direction.magnitude, m_ImpactLayers, QueryTriggerInteraction.Ignore) && !m_RaycastHit.transform.IsChildOf(m_CollidersHit[i].transform) && !m_CollidersHit[i].transform.IsChildOf(m_RaycastHit.transform) && m_RaycastHit.transform.IsChildOf(m_Transform) #if FIRST_PERSON_CONTROLLER // The cast should not hit any colliders who are a child of the camera. && m_RaycastHit.transform.gameObject.GetCachedParentComponent <FirstPersonController.Character.FirstPersonObjects>() == null #endif ) { continue; } } else { continue; } } } // The shield can absorb some (or none) of the damage from the explosion. var hitDamageAmount = damageAmount; #if ULTIMATE_CHARACTER_CONTROLLER_MELEE ShieldCollider shieldCollider; if ((shieldCollider = m_CollidersHit[i].transform.gameObject.GetCachedComponent <ShieldCollider>()) != null) { hitDamageAmount = shieldCollider.Shield.Damage(this, hitDamageAmount); } #endif // ClosestPoint only works with a subset of collider types. Vector3 closestPoint; if (m_CollidersHit[i] is BoxCollider || m_CollidersHit[i] is SphereCollider || m_CollidersHit[i] is CapsuleCollider || (m_CollidersHit[i] is MeshCollider && (m_CollidersHit[i] as MeshCollider).convex)) { closestPoint = m_CollidersHit[i].ClosestPoint(m_Transform.position); } else { closestPoint = m_CollidersHit[i].ClosestPointOnBounds(m_Transform.position); } var hitDirection = closestPoint - m_Transform.position; // Allow a custom event to be received. EventHandler.ExecuteEvent <float, Vector3, Vector3, GameObject, object, Collider>(m_CollidersHit[i].transform.gameObject, "OnObjectImpact", hitDamageAmount, closestPoint, hitDirection * m_ImpactForce, originator, this, m_CollidersHit[i]); if (m_OnImpactEvent != null) { m_OnImpactEvent.Invoke(hitDamageAmount, closestPoint, hitDirection * m_ImpactForce, originator); } // If the shield didn't absorb all of the damage then it should be applied to the character. if (hitDamageAmount > 0) { var damageTarget = DamageUtility.GetDamageTarget(m_CollidersHit[i].gameObject); if (damageTarget != null) { // If the Damage Target exists it will apply an explosive force to the character/character in addition to deducting the health. // Otherwise just apply the force to the character/rigidbody. var pooledDamageData = GenericObjectPool.Get <DamageData>(); var damageModifier = Mathf.Max(1 - (hitDirection.magnitude / m_Radius), 0.01f); pooledDamageData.SetDamage(hitDamageAmount * damageModifier, m_Transform.position, hitDirection.normalized, impactForce * damageModifier, impactForceFrames, m_Radius, originator, this, null); if (m_DamageProcessor == null) { m_DamageProcessor = DamageProcessor.Default; } m_DamageProcessor.Process(damageTarget, pooledDamageData); GenericObjectPool.Return(pooledDamageData); } else if (forceObject != null) { var damageModifier = Mathf.Max(1 - (hitDirection.magnitude / m_Radius), 0.01f); forceObject.AddForce(impactForce * damageModifier * hitDirection.normalized); } else if ((colliderRigidbody = m_CollidersHit[i].gameObject.GetCachedComponent <Rigidbody>()) != null) { colliderRigidbody.AddExplosionForce(impactForce * MathUtility.RigidbodyForceMultiplier, m_Transform.position, m_Radius); } } } m_ObjectExplosions.Clear(); // An audio clip can play when the object explodes. m_ExplosionAudioClipSet.PlayAudioClip(m_GameObject); m_DestructionEvent = SchedulerBase.Schedule(m_Lifespan, Destroy); }