/// <summary> /// method on arrow hit flesh material ( calling hit reaction ) /// </summary> /// <param name="arrow">current arrow</param> /// <param name="rayhit">raycasthit info struct</param> public void OnArrowHitFleshEvent(Arrow arrow, RaycastHit rayhit) { BodyColliderScript bcs = rayhit.collider.GetComponent <BodyColliderScript>(); if (bcs) { #if DEBUG_INFO if (!bcs.ParentRagdollManager) { Debug.LogWarning("Cannot find 'RagdollManager' component on 'BodyColliderScript'."); } #endif if (bcs.ownerGameCharacter != null) { int[] parts = new int[] { bcs.index }; bool block = false; bcs.ownerGameCharacter.attack_hit_notify(arrow.owner, -1, 0, ref block, false, arrow.velocity / 12.0f, parts); if (!bcs.ownerGameCharacter.isDead) { bcs.ParentRagdollManager.startHitReaction(parts, arrow.velocity / 4.0f); } } else { Debug.LogWarning("arrow victim does not hold IGameCharacter reference"); } } #if DEBUG_INFO else { Debug.LogWarning("Cannot find 'BodyColliderScript' on flesh material collider."); } #endif }
/// <summary> /// update arrows lifetime and transform /// </summary> public static void UpdateArrows() { #if DEBUG_INFO if (m_active_arrows == null) { Debug.LogError("object cannot be null"); return; } #endif if (Time.timeScale == 0.0f) { return; } for (int i = 0; i < m_active_arrows.Count; ++i) { Arrow arrow = m_active_arrows[i]; if (arrow == null) { continue; } // update arrows lifetime if (arrow.advanceLifetime) { arrow.lifetime += Time.deltaTime; // I am doing this way instead of parenting by unity // because i think i noticed scaling errors / bugs // this way there is no scaling if (arrow.parent) { arrow.gobject.transform.position = arrow.parent.TransformPoint(arrow.pos_offset); arrow.gobject.transform.rotation = arrow.parent.rotation * arrow.rot_offset; } if (arrow.lifetime > arrow.maxLifetime) { returnToPool(arrow); m_active_arrows.Remove(arrow); arrow = null; --i; continue; } } // update arrows transform if (arrow.state == Arrow.STATES.GO) { arrow.prevPosition = arrow.position; const float FLYMAXTIME = 6; arrow.fly_time += Time.deltaTime; if (arrow.fly_time > FLYMAXTIME) { arrow.state = Arrow.STATES.HIT; } else { float GlerpAmt = arrow.fly_time / FLYMAXTIME; Vector3 addedPosition = arrow.direction * arrow.speed; addedPosition = Vector3.Lerp(addedPosition, Physics.gravity, GlerpAmt); addedPosition *= Time.deltaTime; arrow.position += addedPosition; if (Time.deltaTime > 0) { arrow.velocity = arrow.position - arrow.prevPosition; arrow.velocity /= Time.deltaTime; } #if DEBUG_ARROW_PATH arrow_debug_paths[arrow].Add(arrow.position); #endif Vector3 difference = arrow.position - arrow.prevPosition; arrow.direction = difference.normalized; float maxDistance = (arrow.position - arrow.prevPosition).magnitude; arrow.gobject.transform.position = arrow.prevPosition; arrow.gobject.transform.LookAt(arrow.position); Ray ray = new Ray(arrow.prevPosition, arrow.direction); RaycastHit[] rayHits = Physics.RaycastAll(ray, maxDistance, arrow.layers, QueryTriggerInteraction.Ignore); // sort the collisions by distance System.Array.Sort(rayHits, m_RayHitComparer); for (int j = 0; j < rayHits.Length; ++j) { RaycastHit hit = rayHits[j]; // EXLUDE COLLISIONS WITH OWNER CHARACTER if (LayerMask.LayerToName(hit.collider.gameObject.layer) == "ColliderInactiveLayer") { BodyColliderScript bcs = hit.collider.GetComponent <BodyColliderScript>(); if (bcs) { if (bcs.ParentObject /*ownerGameCharacter*/ == arrow.owner.transform.gameObject) { continue; } } } checkMaterialImpact(ref arrow, ref hit); break; } arrow.prevPosition = arrow.position; } } } #if DEBUG_ARROW_PATH foreach (KeyValuePair <Arrow, List <Vector3> > pair in arrow_debug_paths) { List <Vector3> path = pair.Value; for (int i = 0; i < path.Count - 1; i++) { if (i % 2 == 0) { Debug.DrawLine(path[i], path[i + 1], Color.yellow); } else { Debug.DrawLine(path[i], path[i + 1], Color.blue); } } } #endif }
/// <summary> /// update projectile /// </summary> protected virtual void updateSpheremarch() { Vector3 transformPosition = transform.position; // advance lifetime starting from time when fired onwards if (m_State != ProjectileStates.Ready) { m_CurrentLifetime += Time.deltaTime; if (m_CurrentLifetime > lifetime) { if (m_OnLifetimeExpire != null) { m_OnLifetimeExpire(this); } else { Destroy(this.gameObject); } return; } } #if DEBUG_DRAW positionList.Add(transformPosition); radiusList.Add(m_SphereCollider.radius * this.transform.localScale.x); #endif // check for collision only when fired if (m_State == ProjectileStates.Fired && m_LastPosition.HasValue) { // shoot sphere from last position to current // and check if we have a hit int mask = collidingLayers; #if DEBUG_INFO if (!m_SphereCollider) { Debug.LogError("SphereCollider missing." + " < " + this.ToString() + ">"); return; } #endif float radius = m_SphereCollider.radius * this.transform.localScale.x; Vector3 difference = transformPosition - m_LastPosition.Value; Vector3 direction = difference.normalized; float length = difference.magnitude; Vector3 rayPos = m_LastPosition.Value; Ray ray = new Ray(rayPos, direction); RaycastHit[] hits = Physics.SphereCastAll(ray, radius, length, mask); List <int> chosenHits = new List <int>(); RagdollManager ragMan = null; RaycastHit?rayhit = null; for (int i = 0; i < hits.Length; i++) { RaycastHit rhit = hits[i]; BodyColliderScript bcs = rhit.collider.GetComponent <BodyColliderScript>(); if (!bcs) { #if DEBUG_INFO Debug.LogError("BodyColliderScript missing on " + rhit.collider.name); #endif continue; } if (!bcs.ParentObject) { #if DEBUG_INFO Debug.LogError("BodyColliderScript.ParentObject missing on " + rhit.collider.name); #endif continue; } if (bcs.ParentObject == this.m_Owner) { continue; } if (!ragMan) { ragMan = bcs.ParentRagdollManager; m_HitInfo.hitObject = bcs.ParentObject; m_HitInfo.collider = rhit.collider; m_HitInfo.hitDirection = direction; m_HitInfo.hitStrength = m_CurrentHitStrength; rayhit = rhit; } chosenHits.Add(bcs.index); } if (hits.Length > 0) { if (ragMan) { if (!rayhit.HasValue) { #if DEBUG_INFO Debug.LogError("object cannot be null." + " < " + this.ToString() + ">"); #endif return; } Vector3 n = rayhit.Value.normal; Vector3 r = Vector3.Reflect(direction, n); this.transform.position = rayPos + ray.direction * (rayhit.Value.distance - radius); Vector3 vel = r; this.m_Rigidbody.velocity = vel; m_HitInfo.bodyPartIndices = chosenHits.ToArray(); m_State = ProjectileStates.Done; m_CurrentHitStrength = vel.magnitude; m_CurrentHitStrength += m_HitStrength; if (m_OnHit != null) { m_OnHit(); } else { Vector3 force = direction * m_CurrentHitStrength; ragMan.startHitReaction(m_HitInfo.bodyPartIndices, force); } if (m_OnAfterHit != null) { m_OnAfterHit(); } } #if DEBUG_INFO else { BodyColliderScript bcs = hits[0].collider.GetComponent <BodyColliderScript>(); if (!bcs) { return; } if (!bcs.ParentObject) { return; } if (bcs.ParentObject == this.m_Owner) { return; } Debug.LogWarning("RagdollUser interface not implemented. " + bcs.ParentObject.name); } #endif } } m_LastPosition = transformPosition; }