public void OnDamageTaken(Entity source, DamageInfo damageInfo) { Vector3 point = damageInfo.point.HasValue ? damageInfo.point.Value : transform.position; Vector3 normal = damageInfo.normal.HasValue ? damageInfo.normal.Value : transform.forward; if (referenceCamera) { if ((point - referenceCamera.transform.position).sqrMagnitude > maxDistanceFromCamera * maxDistanceFromCamera) { return; } } // Verify a TextParticle prefab is specified if (textParticlePrefab) { // Instantiate a TextParticle TextParticle clone = Instantiate(textParticlePrefab, point, Quaternion.LookRotation(-normal)) as TextParticle; // Set TextParticle's text, color, and gravity values clone.text = damageInfo.damage.ToString(); clone.color = damageInfo.critical ? criticalDamageColor : standardDamageColor; clone.gravity = particleGravity; // Calculate and set startVelocity for TextParticle based on impact normal (-clone.transform.forward) and random values Vector3 velocity = clone.transform.forward.RandomSpread(normalMaxSpreadAngle) * Random.Range(normalVelocityMin, normalVelocityMax) * (flipNormalVelocity ? 1 : -1); velocity.y += Random.Range(upVelocityMin, upVelocityMax); clone.startVelocity = velocity; // If scale and transparency AnimationCurves specified, set them for the TextParticle if (particleScaleOverLifetime.keys.Length > 0) { clone.scaleOverLifetime = particleScaleOverLifetime; } if (particleTransparencyOverLifetime.keys.Length > 0) { clone.transparencyOverLifetime = particleTransparencyOverLifetime; } // Show a corresponding Critical Message if needed if (damageInfo.critical && showCriticalMessage) { // Clone a new TextParticle for critical message clone = Instantiate(textParticlePrefab, point, Quaternion.LookRotation(-normal)) as TextParticle; // Set critical message text, color and gravity values clone.text = criticalMessage; clone.color = criticalMessageColor; clone.gravity = criticalMessageGravity; // Calculate and set velocity as usual, then multiply by criticalVelocityMultiplier to accentuate this particle velocity = clone.transform.forward.RandomSpread(normalMaxSpreadAngle) * Random.Range(normalVelocityMin, normalVelocityMax) * (flipNormalVelocity ? 1 : -1); velocity.y += Random.Range(upVelocityMin, upVelocityMax); velocity *= criticalVelocityMultiplier; clone.startVelocity = velocity; // Set AnimationCurves if provided if (criticalScaleOverLifetime.keys.Length > 0) { clone.scaleOverLifetime = criticalScaleOverLifetime; } if (criticalTransparencyOverLifetime.keys.Length > 0) { clone.transparencyOverLifetime = criticalTransparencyOverLifetime; } } } }
void OnEntityDamaged(Entity source, DamageInfo info) { // Reset regen enabled timer and disable regeneration for now. regenEnableTime = Time.time + damageResetTime; regenEnabled = false; }
// Main method for handling collision and instantiating prefabs. protected virtual bool HandleCollision(Collider otherCollider, Vector3 point, Vector3 normal) { // If specified, unparent any active particles and allow them to continue if (unparentParticles) { ParticleSystem[] particles = GetComponentsInChildren <ParticleSystem>(); foreach (ParticleSystem particle in particles) { if (particle.isPlaying) { // Stop the particle from continuing to add new particles. particle.Stop(); particle.transform.parent = null; // Add the DestroyAfterParticlesComplete which will destroy the orphaned object when particles are done. particle.gameObject.AddComponent <DestroyAfterParticlesComplete>(); } } } // Instantiate prefabs // Obtain layer and tag of collided object. int otherLayer = 1 << otherCollider.gameObject.layer; string otherTag = otherCollider.gameObject.tag; bool prefabAdded = false; // Iterate through each potential impact prefab and check if the collided object is valid for it to be instantiated. foreach (ImpactPrefab impactPrefab in impactPrefabs) { // If the collided objects meets the following criteria // Note: The if statement is setup to short circuit with fastest checks up front and slower checks at the back. if (impactPrefab.prefab && // If a prefab specified AND !(prefabAdded & impactPrefab.exclusive) && // No prefab already instantiated while this one is exclusive AND ((otherLayer & impactPrefab.validLayers) != 0 || // ( Valid layer OR System.Array.IndexOf(impactPrefab.validTags, otherTag) >= 0 || // Valid tag OR ContainsBehaviour(otherCollider.gameObject, impactPrefab.validTypes)) && // Valid MonoBehaviour type ) AND !ContainsBehaviour(otherCollider.gameObject, impactPrefab.excludeTypes)) // Does not contain excluded MonoBehaviours { // Phew! If we've passed the above, instantiate the prefab. // Calculate prefab rotation based on settings Quaternion prefabRotation = Quaternion.LookRotation(-normal * (impactPrefab.flipFaceDirection ? -1 : 1)) * Quaternion.Euler(0, 0, Random.Range(impactPrefab.prefabRotationMin, impactPrefab.prefabRotationMax)); GameObject clone = Instantiate(impactPrefab.prefab, point + normal * impactPrefab.prefabNormalOffset, prefabRotation) as GameObject; clone.transform.localScale = Vector3.one * impactPrefab.prefabScale; // Attach to collided object if specified if (impactPrefab.attachToCollisionObject) { clone.transform.parent = otherCollider.transform; } prefabAdded = true; } } // If impactForce specified and collision is with a rigidbody, add impact force. Rigidbody otherRigidbody = otherCollider.GetComponent <Rigidbody>(); if (impactForce != 0 && otherRigidbody) { otherRigidbody.AddForceAtPosition(normal * -impactForce, point, ForceMode.Impulse); } // If we collided with an Entity, add damage to it. Entity entity = otherCollider.gameObject.GetComponentInParent <Entity>(); if (entity) { // Add damage details of impact to damageInfo structure. damageInfo.critical = Random.Range(0f, 1.0f) <= criticalChance; damageInfo.damage = damageInfo.critical ? Random.Range(criticalDamageMin, criticalDamageMax + 1) : Random.Range(damageMin, damageMax + 1); damageInfo.point = point; damageInfo.normal = normal; // Tell Entity to take damage. entity.TakeDamage(damageInfo); } // If explosionForce specified, add explosive force to any rigidbodies within explosionRadius if (explosionForce != 0) { // Save explosionRadius squared for comparison float explosionRadiusSquared = explosionRadius * explosionRadius; // Get all rigidbodies in scene and iterate through each to see if it is within explosionRadius Rigidbody[] allRigidBodies = GameObject.FindObjectsOfType <Rigidbody>(); foreach (Rigidbody rb in allRigidBodies) { Vector3 vectorToRigidbody = rb.position - point; // If the rigidbody is within the explosionRadius, apply explosionForce if (explosionRadius == 0 || vectorToRigidbody.sqrMagnitude <= explosionRadiusSquared) { // Add explosion force. rb.AddExplosionForce(explosionForce, point, explosionRadius); // If the rigidbody is an entity and not the one of the direct hit, apply damage Entity rbEntity = rb.gameObject.GetComponentInParent <Entity>(); if (rbEntity != null && rbEntity != entity) { // Calculate explosion damage based on proximity to explosion and radius. float explosionProximityRatio = Mathf.InverseLerp(explosionRadiusSquared, 0, vectorToRigidbody.sqrMagnitude); int explosiveDamage = (int)((float)Random.Range(damageMin, damageMax + 1) * explosionProximityRatio); if (explosiveDamage > 0) { // Apply damage to Entity caught in explosion DamageInfo explosionDamageInfo = new DamageInfo(explosiveDamage, false, rb.position, vectorToRigidbody.normalized, damageInfo.source); rbEntity.TakeDamage(explosionDamageInfo); } } } } } // Stop this projectile mVelocity *= 0; if (mCollider) { mCollider.isTrigger = true; } if (mRigidbody) { mRigidbody.isKinematic = true; mRigidbody.position = point; Destroy(mRigidbody); } // Set position to that of the point of impact transform.position = point; // Stop raycasting per frame. raycastPerFrame = false; // Destroy this Projectile either immediately or with specified delay. if (postponeDestroyTime == 0) { Destroy(gameObject); } else { Destroy(gameObject, postponeDestroyTime); } return(true); }