// 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 GrabbedBody(PhysicsHit physicsHit, Quaternion rotation) { this.physicsHit = physicsHit; grabPoint = GrabPoint.GetGrabPoint(); grabPoint.transform.position = physicsHit.averagePosition; grabPoint.transform.rotation = rotation; for (int x = 0; x < physicsHit.hitElements.Count; x++) { connectedJoints.Add(RagdollPhysics.GrabRigidbody(physicsHit.hitElements[x].rigidbody, grabPoint.childRigidbody, false)); } }
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); }
public static PhysicsHit SphereCast(Ray ray, float radius, LayerMask shootMask, float maxDist) { RaycastHit hit; if (Physics.SphereCast(ray, radius, out hit, maxDist, shootMask, QueryTriggerInteraction.Ignore)) { PhysicsHit r = new PhysicsHit(new List <PhysicsHitElement>() { new PhysicsHitElement(hit) }); r.InitializeHit(ray.origin); return(r); } return(null); }
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); } }
public PhysicsHit Launch(float velocity, Ray ray, float maxDistance, float radiusCheck, LayerMask layerMask, float lifeTime, float hitObjectVelocityMultiplier, bool simulateArc, System.Action <PhysicsHit> onReachHitObject) { this.simulateArc = simulateArc; this.onReachHitObject = onReachHitObject; InitializeLaunch(ray, velocity, lifeTime, hitObjectVelocityMultiplier); if (!simulateArc) { transform.rotation = Quaternion.Euler(Random.Range(0, 360), Random.Range(0, 360), Random.Range(0, 360)); } physicsHit = RagdollPhysics.SphereCast(ray, radiusCheck, layerMask, maxDistance); if (physicsHit != null) { Collider hitCollider = physicsHit.hitElements[0].collider; transform.SetParent(hitCollider.transform); localHitPoint = hitCollider.transform.InverseTransformPoint(physicsHit.averagePosition); startLocalPosition = transform.localPosition; endPointDistance = physicsHit.hitDistance; StartCollisionIgnoreWithMyCollider(new List <PhysicsHit>() { physicsHit }); DynamicRagdoll.Demo.GameTime.SetTimeDilation(.5f, .1f, 10, .1f); } else { EnablePhysics(true); rb.velocity = ray.direction * velocity; collidedDuringPhysicsFly = false; reachedDestination = true; } return(physicsHit); }
/* * raycasts through until a static collider hit (or kinematic rigidbody) * * and "grabs" all the rigidbodies in between */ public static Vector3 ShootMultiGrabRay(Ray ray, float radius, LayerMask shootMask, float maxDist, List <GrabbedBody> grabbedBodies, List <PhysicsHit> physicsHits, out float endPointDistance, out bool hitStatic) { grabbedBodies.Clear(); physicsHits.Clear(); hitStatic = false; Quaternion lookRotation = Quaternion.LookRotation(ray.direction); List <PhysicsHit> hits = SphereCastAll(ray, radius, shootMask, maxDist); Vector3 endPoint = ray.origin + ray.direction * maxDist; endPointDistance = maxDist; // each ragdoll has it's own hit group, to avoid having multiple moving joints attached to // ragdolls (this improves stability) for (int i = 0; i < hits.Count; i++) { PhysicsHit hit = hits[i]; hitStatic = hit.hitStatic; if (!hitStatic) { grabbedBodies.Add(new GrabbedBody(hit, lookRotation)); physicsHits.Add(hit); } // hit static, we're done else { endPoint = hit.averagePosition; endPointDistance = hit.hitDistance; break; } } return(endPoint); }
public List <PhysicsHit> ShootSpear(float velocity, Ray ray, float maxDistance, LayerMask skewerMask, float lifeTime, float skewerSeperation, float minSpaceFromWall, float hitObjectVelocityMultiplier, System.Action <PhysicsHit, bool> onReachHitObject) { this.onReachHitObject = onReachHitObject; collidedDuringPhysicsFly = false; InitializeLaunch(ray, velocity, lifeTime, hitObjectVelocityMultiplier); reachedIndicies.Clear(); //grab any rigidbodies along a ray, until a static collider Vector3 endPoint = RagdollPhysics.ShootMultiGrabRay(ray, spearRadius, skewerMask, maxDistance, grabbedBodies, physicsHits, out endPointDistance, out stickToEnd); int hitCount = grabbedBodies.Count; // if we have no wall to stick to if (!stickToEnd) { //if we have some rigidbodies to impale, recalculate an end point after the last one if (hitCount > 0) { PhysicsHit furthestHit = physicsHits[hitCount - 1]; endPoint = furthestHit.hitElements[furthestHit.hitElements.Count - 1].hitPoint + ray.direction * spearLength; endPointDistance = Vector3.Distance(ray.origin, endPoint); } else { // turn on physics and just use our velocity to "fly" ReachDestination(1); } } // this is true already if we didnt hit anything if (!reachedDestination) { // if we have any impaled rigidbodies if (hitCount > 0) { // where each grabbed rigidbody will end up skewerTargets = new Vector3[hitCount]; skewerOffsets = new float[hitCount]; // the first index that is being skewered startIndexForSkewered = hitCount; // calculate where each grabbed rigidbody will end up: float lastEndPoint = minSpaceFromWall; for (int i = hitCount - 1; i >= 0; i--) { float skewerOffset; skewerTargets[i] = CalculateSkewerTargetPosition(endPoint, ray.direction, skewerSeperation, DetermineHitPointsSize(physicsHits[i], ray.direction, skewerMask), ref lastEndPoint, out skewerOffset); skewerOffsets[i] = skewerOffset; // if we have enough space on teh spear, skewer this index if (skewerOffset < spearLength) { startIndexForSkewered = i; } // if not we'll just add force to it (or dismember it) when the spear reaches it } StartCollisionIgnoreWithMyCollider(physicsHits); DynamicRagdoll.Demo.GameTime.SetTimeDilation(.5f, .1f, 10, .1f); } // randomly offset the amount the spear model sticks out of the end point randomOffset = Random.Range(-tipLength * .5f, 0); modelEndTarget = endPoint + ray.direction * randomOffset; } return(physicsHits); }
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); } }