// for human agents bool ApplyDamage(AgentHuman inAgent, Vector3 inExplosionPos, float inDmgMultiplier) { Vector3 tmp = ClosestPoint.PointBounds(inExplosionPos, inAgent.CharacterController.bounds); float dist = (inExplosionPos - tmp).sqrMagnitude; if (dist > damageRadius * damageRadius) { return(false); } #if DEBUG DebugDraw.Diamond(Color.grey, 0.02f, tmp); DebugDraw.LineOriented(Color.grey, inExplosionPos, tmp, 0.04f); #endif int idx = inAgent.ExplosionHitTargets != null ? inAgent.ExplosionHitTargets.Length : 0; while (idx-- > 0) { if (CheckHit(inAgent.ExplosionHitTargets[idx], inExplosionPos, ref tmp)) { float coef = 1.0f - Mathf.Clamp01(Mathf.Sqrt(dist) / damageRadius); Damage = BaseDamage * coef * inDmgMultiplier; Impulse = tmp; inAgent.SendMessage("OnExplosionHit", this, SendMessageOptions.DontRequireReceiver); return(true); } } return(false); }
internal void SpawnExplosion() { if (m_Explosion != null) { //Debug.Log("ProjectileRocket.SpawnExplosion " + name); float dot = -Vector3.Dot(HitNormal, Transform.forward); float offNormal = 0.1f + 0.6f * (dot / 2.0f); float offDir = 0.0f + 0.3f * (1.0f - dot); Vector3 pos = Transform.position + m_ExplosionOffset - offDir * Transform.forward + offNormal * HitNormal; // Explosion explosion = Object.Instantiate(m_Explosion, transform.position, transform.rotation) as Explosion; // Explosion explosion = Mission.Instance.ExplosionCache.Get(m_Explosion, Transform.position + m_ExplosionOffset, Transform.rotation); Explosion explosion = Mission.Instance.ExplosionCache.Get(m_Explosion, pos, Transform.rotation); if (null != explosion && Agent != null) { explosion.Agent = Agent; explosion.BaseDamage = Damage; explosion.m_WeaponID = WeaponID; explosion.m_WeaponImpulse = Settings.Impulse; #if DEBUG DebugDraw.DepthTest = true; DebugDraw.DisplayTime = 10.0f; DebugDraw.Diamond(Color.yellow, 0.04f, explosion.Position); #endif } } // destroy projectile ... // Destroy(gameObject); - !!! Don't do it. This object is cached now. }
private static float ProceedOneCoverDistanceCast(Vector3 fromPos, Vector3 forward, float distance, ref MinMaxPair minMax, float invertDistance = -1) { RaycastHit hit; int Default = 1 << LayerMask.NameToLayer("Default"); int PhysicsMetal = 1 << LayerMask.NameToLayer("PhysicsMetal"); if (true == Physics.Raycast(fromPos, forward, out hit, distance, Default | PhysicsMetal)) { DebugDraw.LineOriented(Color.red, fromPos, fromPos + forward * distance, 0.05f); distance = (fromPos - hit.point).magnitude; if (Vector3.Dot(hit.normal, forward) > -0.1f) { if (invertDistance < 0) { distance = 0; } else { distance = invertDistance; } } else { if (true == VisualizeTests) { DebugDraw.DisplayTime = 0.00f; DebugDraw.Diamond(Color.green, 0.03f, hit.point); DebugDraw.LineOriented(VisualizationColor, hit.point, hit.point + hit.normal * 0.25f, 0.05f); } } } else { if (invertDistance < 0) { Debug.LogWarning("CoverUtils : Expected collision hit not found, position :" + fromPos); } return(distance); } if (invertDistance > 0) { minMax.Absorb(invertDistance - distance); } else { minMax.Absorb(distance); } return(distance); }
bool IsCollisionBetween(Vector3 inFrom, Vector3 inTo, Collider inVictim) { Vector3 dir = inTo - inFrom; float lng = dir.magnitude; dir /= lng; inFrom -= dir * 0.04f; int mask = ~(ObjectLayerMask.IgnoreRayCast | ObjectLayerMask.Ragdoll | ObjectLayerMask.PhysicBody | ObjectLayerMask.Hat); RaycastHit[] hits = Physics.RaycastAll(inFrom, dir, lng, mask); if (hits.Length > 1) { System.Array.Sort(hits, CollisionUtils.CompareHits); } foreach (RaycastHit hit in hits) { if ((hit.collider.isTrigger == true) || (hit.collider == inVictim)) { continue; } if (noBlocking != null && IgnoreInBlockingTest(hit.collider.transform) == true) { continue; } m_ObstacleNormalAccum += hit.normal; #if DEBUG DebugDraw.LineOriented(ColMiss, inFrom, inTo); DebugDraw.Collider(ColMiss, inVictim, 0.96f); DebugDraw.Diamond(ColMiss, 0.02f, hit.point); #endif return(true); } #if DEBUG DebugDraw.LineOriented(ColHit, inFrom, inTo); DebugDraw.Collider(ColHit, inVictim, 0.96f); #endif return(false); }
void ApplyDamage() { if (uLink.Network.isServer == false) { return; } // enumerate victims... Vector3 tmp; Vector3 pos = Position; int mask = ~(ObjectLayerMask.IgnoreRayCast | ObjectLayerMask.Ragdoll | ObjectLayerMask.Hat); Collider[] colliders = Physics.OverlapSphere(Position, damageRadius, mask); #if DEBUG DebugDraw.DepthTest = true; DebugDraw.DisplayTime = 8.0f; DebugDraw.Diamond(ColExp, 0.04f, pos); #endif // categorize victims... foreach (Collider c in colliders) { AgentHuman a = c.gameObject.GetFirstComponentUpward <AgentHuman>(); if (a == null) { m_Others.Add(c); } else if (m_Agents.Contains(a) == false) { m_Agents.Add(a); } } // process human-agents... foreach (AgentHuman a in m_Agents) { m_ObstacleNormalAccum = Vector3.zero; a.SampleDominantAnim(); if (ApplyDamage(a, pos, 1.0f) == false) { if ((m_ObstacleDamageReduction > 0.0f) && (m_ObstacleNormalAccum.sqrMagnitude > 0.0f)) { Vector3 u = Vector3.up; Vector3 v = Vector3.zero; Vector3 n = m_ObstacleNormalAccum; Vector3.OrthoNormalize(ref n, ref u, ref v); tmp = pos; tmp += 0.5f * n; // tmp += 1.0f * u; Vector3 diff = a.Position - pos; float dot = Vector3.Dot(diff, v); // if (Mathf.Abs(dot) > 0.3f) { tmp += 0.5f * Mathf.Sign(dot) * v; } #if DEBUG DebugDraw.LineOriented(ColExp, pos, tmp, 0.04f); #endif ApplyDamage(a, tmp, m_ObstacleDamageReduction); } } } // process other objects... foreach (Collider c in m_Others) { ApplyDamage(c, pos); } // clean-up... m_Agents.Clear(); m_Others.Clear(); }
//collide camera and place it to the best position void CollideCamera5() { // #if CAMERA_DEBUG_DRAW Color col; #endif Transform desiredTransform = CameraBehaviour.GetDesiredCameraTransform(); if (desiredTransform) { Vector3 desiredPosition = desiredTransform.position; Quaternion desiredRotation = desiredTransform.rotation; float dif = (desiredPosition - PrevPos).sqrMagnitude; #if !CAMERA_DEBUG_DRAW //disable the optimization when Debug Draw is on //exit if the camera didn't move or rotate if (dif < 0.0001f && Mathf.Approximately(PrevRot.x, desiredRotation.x) && Mathf.Approximately(PrevRot.y, desiredRotation.y) && Mathf.Approximately(PrevRot.z, desiredRotation.z) && Mathf.Approximately(PrevRot.w, desiredRotation.w)) { return; } #endif //blend the transform (this is useful especially when the CameraState changes or when the camera moves very fast) if (dif > 0.1f) { desiredPosition = Vector3.Lerp(PrevPos, desiredPosition, Time.deltaTime * 20); desiredRotation = Quaternion.Slerp(PrevRot, desiredRotation, Time.deltaTime * 20); } PrevPos = desiredPosition; PrevRot = desiredRotation; Vector3 FinalPos; //pokud je jiny CameraState nez CameraState3RD, tak muzeme nasledujici testy preskocit a jen nastavit CameraTransform.position a CameraTransform.rotation a zavolat UpdateLocalPlayerInstance(); // if ( (CameraBehaviour.State is CameraState3RD) || (CameraBehaviour.State is CameraStateCover) || (CameraBehaviour.State is CameraStateDeath) ) { LayerMask mask = ObjectLayerMask.Default | ObjectLayerMask.PhysicsMetal; //~( ObjectLayerMask.Ragdoll | ObjectLayerMask.IgnoreRayCast | ObjectLayerMask.PhysicBody ); const float minNear = 0.02f; //0.05f still penetrates walls while rolling const float minRadius = 0.12f; //0.1f const float maxRadius = 0.3f; //with 0.5f the camera collides too often when player runs close to obstacles bool IsRolling = CameraBehaviour.Owner.PlayerComponent.IsRolling; bool IsAlive = CameraBehaviour.Owner.IsAlive; float radius = IsRolling ? minRadius : maxRadius; //in dodge, use minRadius for collisions //for testing collision between Head and TargetPos ("CameraTargetDir" node) Vector3 HeadPos = CameraBehaviour.Owner.EyePosition; Vector3 TargetPos = CameraBehaviour.CameraOrigin.position; Vector3 headDir = TargetPos - HeadPos; //shift the HeadPos to not allow the camera to move into player's head HeadPos += headDir * 0.5f; //middle point between head and target headDir = TargetPos - HeadPos; float headLength = headDir.magnitude; RaycastHit headHit; #if CAMERA_DEBUG_DRAW DebugDraw.Line(Color.magenta, HeadPos, TargetPos + headDir.normalized * radius); //c DebugDraw.Diamond(Color.magenta, 0.03f, TargetPos); DebugDraw.Diamond(Color.green, 0.03f, desiredPosition); #endif //check whether the TargetPos is behind collision or not (it is controlled by animation and usually is outside the player's capsule collider) //this happens when players 'shoulder' (i.e. the "CameraTargetDir") gets behind a wall if (Physics.Raycast(HeadPos, headDir, out headHit, headLength + radius, mask)) { float m = Mathf.Max(0, headHit.distance - radius); TargetPos = HeadPos + headDir.normalized * m; //move the TargetPos along the line to a safe place if (headHit.distance < radius) { radius = Mathf.Max(minRadius, headHit.distance - 0.001f); //change the radius based on the collision distance } #if CAMERA_DEBUG_DRAW DebugDraw.Diamond(Color.cyan, 0.03f, headHit.point); DebugDraw.Diamond(Color.white, 0.03f, TargetPos); //new TargetPos DebugDraw.Line(Color.green, headHit.point, headHit.point + headHit.normal * (radius + 0.01f)); //b DebugDraw.Line(Color.yellow, headHit.point + headHit.normal * (radius + 0.01f), TargetPos); #endif } // Vector3 dir = desiredPosition - TargetPos; Vector3 dirN = dir.normalized; float length = dir.magnitude; float q, dist; const float safeDist = maxRadius + 0.1f; //shift the capsule in front of the TargetPos a little //do the sphere (capsule) collision with scene RaycastHit[] hits = Physics.SphereCastAll(TargetPos - dirN * safeDist, radius, dirN, length + safeDist, mask); //sort by distance if (hits.Length > 1) { System.Array.Sort(hits, CollisionUtils.CompareHits); } // FinalPos = desiredPosition; dist = length; //default position at the desiredPosition if we will not collide MainCamera.nearClipPlane = Mathf.Max(0.2f, radius * 0.5f); //radius * 0.5f; //was 0.3f; foreach (RaycastHit hit in hits) { if (hit.collider.gameObject.layer == InteractionObject.UseLayer) { continue; } if (hit.collider.isTrigger) { continue; } if (hit.collider == IgnoredCollider) { continue; } // FinalPos = hit.point + hit.normal * minRadius; //was 0.3f; changed to 0.1f to help fix the camera-player intersection (when player was running backwards against wall) dist = Mathf.Min(length, hit.distance + radius - safeDist - minRadius); if (dist < 0) //can become < 0 due to safeDist { dist = 0; } // FinalPos = TargetPos + dirN * q; MainCamera.nearClipPlane = (IsRolling || !IsAlive) ? minNear : 0.2f; //0.02f; //was 0.05f; the new value needs testing on devices (check z-fight) #if CAMERA_DEBUG_DRAW col = Color.grey; col.a = 0.5f; Debug.DrawLine(desiredPosition, TargetPos, col, 0.5f); DebugDraw.Diamond(Color.red, 0.03f, hit.point); col = Color.gray; col.a = 0.5f; DebugDraw.Capsule(col, radius, TargetPos - dirN * safeDist, TargetPos + dirN * length); #endif break; //need to care just about the nearest valid hit } // float ratio = (Mathf.Abs(PrevDist - dist) / length) + (1 - (radius - minRadius) / maxRadius); if (PrevDist < dist) //we're returning back - do it slower { ratio *= 0.5f; } float speed = Mathf.Clamp(ratio, 0.2f, 1.0f) * 25; //change the blend speed based on the distance between actual and computed distance (position) q = Mathf.Lerp(PrevDist, dist, Time.deltaTime * speed); //smoothly blend between previous and current position // if ( Mathf.Abs(PrevDist - dist) > 0.01f ) // Debug.Log ("radius=" + radius + ", dist=" + dist + ", PrevDist=" + PrevDist + ", ratio=" + ratio + ", q=" + q + ", speed=" + speed); PrevDist = q; #if CAMERA_DEBUG_DRAW DebugDraw.Diamond(Color.yellow, 0.03f, TargetPos + dirN * dist); //where we need to be (we're interpolating to this pos) #endif //set Final Position FinalPos = TargetPos + dirN * q; } // else // { // FinalPos = desiredPosition; // } //set Final Position CameraTransform.position = FinalPos; //CameraTransform.rotation = Quaternion.Lerp(CameraTransform.rotation, desiredRotation, 15.0f * Time.deltaTime); CameraTransform.rotation = desiredRotation; // #if CAMERA_DEBUG_DRAW col = Color.yellow; col.a = 0.5f; DebugDraw.Diamond(col, 0.03f, FinalPos); #endif UpdateLocalPlayerInstance(); } }
void ProceedHits(RaycastHit[] hits, bool softInit, Vector3 newPos) { // launched from cover (fast dirty solution) Cover cover = null; bool hitIsValid = false; if ((Agent != null) && (Agent.IsInCover == true) && (Agent.BlackBoard.Cover != null)) { cover = Agent.BlackBoard.Cover; } // sort hits by distance if (hits.Length > 1) { System.Array.Sort(hits, CollisionUtils.CompareHits); } // process hits foreach (RaycastHit hit in hits) { //Debug.Log("ProjectileUpdate Hit" + hit.transform.name); if (hit.transform == Settings.IgnoreTransform) { continue; } //skip the Owner of this shot when his HitZone got hit HitZone zone = hit.transform.GetComponent <HitZone>(); if (zone && (zone.HitZoneOwner is AgentHuman) && (zone.HitZoneOwner as AgentHuman).transform == Settings.IgnoreTransform) { continue; } //HACK The projectile belongs to the "Default" collision layer. //This is probably bug but we do not want to modify the data at the moment. //The only chance now is to ignore such hits if (hit.transform.gameObject.name.StartsWith("Projectile")) { continue; } //skip friends when the projectile should explode near the player (this solves the unwanted suicide when a friend suddenly enters the area in front of me) AgentHuman hitAgent = hit.transform.gameObject.GetFirstComponentUpward <AgentHuman>(); if (Agent != null && hitAgent != null) { float dist = Vector3.Distance(Agent.Position, hitAgent.Position); if (dist < 3) //ignore only if the projectile is still within X m radius { if (Agent.IsFriend(hitAgent)) { continue; } } } Transform.position = hit.point; if (hit.collider.isTrigger) { if (!softInit) { hit.transform.SendMessage("OnProjectileHit", this, SendMessageOptions.DontRequireReceiver); continue; } } if ((cover != null) && (cover.IsPartOfCover(hit.collider.gameObject) == true)) { continue; } newPos = hit.point; #if DEBUG DebugDraw.DepthTest = true; DebugDraw.DisplayTime = 10.0f; DebugDraw.Diamond(Color.red, 0.02f, newPos); #endif Hit = true; HitNormal = hit.normal; hitIsValid = ValidateHit(hit); break; } if (false == softInit) { Transform.position = newPos; } if (Hit) { if (hitIsValid) { HitReaction(); } else { //This function probably has no effect here but I want to be sure that I did not miss anything important //This code is triggered on the server side and only in the case when attacker is cheating InvalidHitReaction(); } } }