예제 #1
0
        // 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);
        }
예제 #2
0
        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));
            }
        }
예제 #3
0
        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);
        }
예제 #4
0
        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);
        }
예제 #5
0
        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);
            }
        }
예제 #6
0
        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);
        }
예제 #7
0
        /*
         *  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);
        }
예제 #8
0
        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);
        }
예제 #9
0
        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);
            }
        }