// determing the full size of a series of hit colliders static float DetermineHitPointsSize(PhysicsHit hitGroup, Vector3 direction, LayerMask mask) { int hitGroupHitsCount = hitGroup.hitElements.Count; if (!hitGroup.isRagdoll || hitGroupHitsCount == 1) { PhysicsHitElement h = hitGroup.hitElements[0]; if (h.box != null) { return(DetermineBoxSize(h.box)); } if (h.sphere != null) { return(DetermindSphereSize(h.sphere)); } if (h.capsule != null) { return(DetermineCapsuleSize(h.capsule)); } } // determine size for multiple grabbed ragdolls / mesh colliders // start ray from the last hit (furthest from origin) Vector3 startRayPoint = hitGroup.hitElements[hitGroupHitsCount - 1].hitPoint; Rigidbody furthestHitRB = hitGroup.hitElements[hitGroupHitsCount - 1].rigidbody; // keep trying until we've searched too far float trySize = determineSizeTrySize; while (trySize < maxTrySize) { RaycastHit hit; // go forward and then raycast back towards our last hit point, to find the "other" side of the collider if (Physics.Raycast(new Ray(startRayPoint + direction * trySize, -direction), out hit, determineSizeTrySize, mask, QueryTriggerInteraction.Ignore)) { // if it's our collider we hit, then we found the other side if (hit.rigidbody == furthestHitRB) { Vector3 lastCollidersOtherSide = hit.point; // distance start calculated from the first hit point (nearest to ray origin) return(Vector3.Distance(hitGroup.hitElements[0].hitPoint, lastCollidersOtherSide)); } } // didnt find end trySize += determineSizeTrySize; } // Debug.LogError("Couldnt find end " + hitGroup.hitElements[0].rigidbody.name); return(1); }
public static List <PhysicsHit> SphereCastAll(Ray ray, float radius, LayerMask shootMask, float maxDist) { // shoot ray grabRayHits = Physics.SphereCastAll(ray, radius, maxDist, shootMask, QueryTriggerInteraction.Ignore); // sort from nearest to farthest System.Array.Sort(grabRayHits, (x, y) => x.distance.CompareTo(y.distance)); List <PhysicsHit> allHits = new List <PhysicsHit>(); // each ragdoll has it's own hit group, to avoid having multiple moving joints attached to // ragdolls (this improves stability) Dictionary <Ragdoll, PhysicsHit> ragdoll2HitGroup = new Dictionary <Ragdoll, PhysicsHit>(); for (int i = 0; i < grabRayHits.Length; i++) { RaycastHit hit = grabRayHits[i]; PhysicsHitElement hitElement = new PhysicsHitElement(hit); if (hitElement.ragdollBone != null) { if (ragdoll2HitGroup.ContainsKey(hitElement.ragdollBone.ragdoll)) { ragdoll2HitGroup[hitElement.ragdollBone.ragdoll].hitElements.Add(hitElement); } else { PhysicsHit newGroup = new PhysicsHit(new List <PhysicsHitElement>() { hitElement }); allHits.Add(newGroup); ragdoll2HitGroup[hitElement.ragdollBone.ragdoll] = newGroup; } } else { allHits.Add(new PhysicsHit(new List <PhysicsHitElement>() { hitElement })); } } // initialize the groups, (must be done after loop, so ragdoll groups are complete) for (int i = 0; i < allHits.Count; i++) { allHits[i].InitializeHit(ray.origin); } return(allHits); }
protected override void UpdateProjectile(float deltaTime) { if (reachedDestination) { return; } UpdateTravelZ(deltaTime, 0); for (int i = physicsHits.Count - 1; i >= 0; i--) { PhysicsHit hit = physicsHits[i]; // if we've reached the hitgroup average position if (travelZ >= hit.hitDistance) { // make sure this only happens for a frame if (!reachedIndicies.Contains(i)) { if (onReachHitObject != null) { onReachHitObject(hit); } // foreach rigidbody in the hit group // simulate as if the impaler passed through it // add force to the rigidbodies for (int x = 0; x < hit.hitElements.Count; x++) { PhysicsHitElement hitElement = hit.hitElements[x]; hitElement.rigidbody.velocity = impaleDirection * velocity * hitObjectVelocityMultiplier; // hitElement.rigidbody.AddForceAtPosition( impaleDirection * velocity * hitObjectVelocityMultiplier, hitElement.hitPoint, ForceMode.VelocityChange); } reachedIndicies.Add(i); } } } if (reachedDestination) { SetKinematic(kinematicOnReach); EnableCollider(!kinematicOnReach || useColliderOnReach); } }
protected override void UpdateProjectile(float deltaTime) { UpdateArcSimulation(); if (reachedDestination) { return; } UpdateTravelZ(deltaTime, randomOffset); /* * update backwards for stability, so we set our furthest rigidbody first * this way A doesnt bump into B accidentally * -Spear-->>>> A B */ for (int i = physicsHits.Count - 1; i >= 0; i--) { bool isSkewered = i >= startIndexForSkewered; PhysicsHit hit = physicsHits[i]; // out offset with regard to all the other impaled entities (local position on spear) // 0 if we're not skewering float skewerOffset = isSkewered ? skewerOffsets[i] : 0; // where out imalement "slot" is on the spear thats travelling float z = travelZ - skewerOffset; // our target z (where we'll wind up) float end = endPointDistance - skewerOffset; // stay at 0 until the "spear" reaches our destination float t = Mathf.Clamp01((z - hit.hitDistance) / (end - hit.hitDistance)); // if we've reached the hitgroup average position if (t > 0) { // make sure this only happens for a frame if (!reachedIndicies.Contains(i)) { if (onReachHitObject != null) { onReachHitObject(hit, isSkewered); } // if we're not skewering this hit group // simulate as if the spear passed through it if (!isSkewered) { // ungrab the group (disables created joints) grabbedBodies[i].Detach(); // foreach rigidbody in the hit group for (int x = 0; x < hit.hitElements.Count; x++) { PhysicsHitElement physicsHitElement = hit.hitElements[x]; // add force to the rigidbodies // physicsHitElement.rigidbody.velocity = launchRay.direction * velocity; physicsHitElement.rigidbody.AddForceAtPosition(launchRay.direction * velocity, physicsHitElement.hitPoint, ForceMode.VelocityChange); // if its a ragdoll, attempt to dismember the bone if (physicsHitElement.ragdoll != null) { physicsHitElement.ragdoll.DismemberBone("Spear", physicsHitElement.ragdollBone.bone); } } } reachedIndicies.Add(i); } } if (isSkewered) { /* * update each attachment point so that it starts moving when * the point on the spear it's going to wind up impaled on reaches the point itself * * set the target position as the spot it's going to wind up at the end of the * movement */ grabbedBodies[i].grabPoint.baseRigidbody.MovePosition(Vector3.Lerp(hit.averagePosition, skewerTargets[i], t)); // if we're pinned up against a wall, allow joint movement along teh z axis, // so rigidbodies can slide along the spear (helps stability) if (reachedDestination && stickToEnd) { ConfigurableJoint j = grabbedBodies[i].grabPoint.baseJoint; j.zMotion = ConfigurableJointMotion.Limited; var l = j.linearLimit; l.limit = spearLength - skewerOffset; j.linearLimit = l; } } } // move model transform.position = Vector3.Lerp(launchRay.origin, modelEndTarget, Mathf.Clamp01(travelZ / endPointDistance)); if (reachedDestination) { ReachDestination(skeweredCount > 0 ? hitObjectVelocityMultiplier : 1); } }