예제 #1
0
        /// <summary>
        /// Trigger the defined Cast/Overlap.
        /// </summary>
        /// <param name="showDebugWidgets">Show 3d visuals for hitscans. Disabled in Release Builds.</param>
        /// <returns></returns>
        public static int GenericHitscanNonAlloc(this HitscanDefinition hd, Transform origin, ref Collider[] hits, ref RaycastHit[] rayhits, ref int nearestIndex, Realm realm, bool showDebugWidgets = false)
        {
//#if (UNITY_EDITOR || DEVELOPMENT_BUILD)
            if (showDebugWidgets)
            {
                VisualizeHitscan(hd, origin, 0.5f);
            }
//#endif

            if (ReferenceEquals(hits, null))
            {
                hits = reusableColliderArray;
            }

            if (ReferenceEquals(rayhits, null))
            {
                rayhits = reusableRayHitArray;
            }

            var hitscanType = hd.hitscanType;

            int     hitcount;
            Vector3 srcPos = (hd.useOffset) ? origin.TransformPoint(hd.offset1) : origin.position;

#if !UNITY_2019_1_OR_NEWER
            LayerMask layerMask = (realm == Realm.Primary) ?
                                  (LayerMask)(hd.layerMask & ~GhostWorld.GHOST_WORLD_LAYERMASK) :
                                  (LayerMask)(GhostWorld.GHOST_WORLD_LAYERMASK);

            switch (hitscanType)
            {
            case HitscanType.Raycast:
                hitcount = Physics.RaycastNonAlloc(/*srcPos*/ origin.position, origin.forward, rayhits, hd.distance, layerMask);
                break;

            case HitscanType.SphereCast:
                hitcount = Physics.SphereCastNonAlloc(new Ray(srcPos, origin.forward), hd.radius, rayhits, hd.distance, layerMask);
                break;

            case HitscanType.BoxCast:
                hitcount = Physics.BoxCastNonAlloc(srcPos, hd.halfExtents, origin.forward, rayhits, Quaternion.Euler(origin.eulerAngles + hd.orientation), hd.distance, layerMask);
                break;

            case HitscanType.CapsuleCast:
                hitcount = Physics.CapsuleCastNonAlloc(origin.TransformPoint(hd.offset1), origin.TransformPoint(hd.offset2), hd.radius, origin.forward, rayhits, hd.distance, layerMask);
                break;

            case HitscanType.OverlapSphere:
                hitcount = Physics.OverlapSphereNonAlloc(srcPos, hd.radius, hits, layerMask);
                break;

            case HitscanType.OverlapBox:
                hitcount = Physics.OverlapBoxNonAlloc(srcPos, hd.halfExtents, hits, Quaternion.Euler(origin.eulerAngles + hd.orientation), layerMask);
                break;

            case HitscanType.OverlapCapsule:
                hitcount = Physics.OverlapCapsuleNonAlloc(origin.TransformPoint(hd.offset1), origin.TransformPoint(hd.offset2), hd.radius, hits, layerMask);
                break;

            default:
                hitcount = 0;
                break;
            }
#else
            var       phys      = (realm == Realm.Primary) ? Physics.defaultPhysicsScene : GhostWorld.ghostPhysics;
            LayerMask layerMask = hd.layerMask;

            switch (hitscanType)
            {
            case HitscanType.Raycast:
                hitcount = phys.Raycast(srcPos, origin.forward, rayhits, hd.distance, layerMask);
                break;

            case HitscanType.SphereCast:
                hitcount = phys.SphereCast(srcPos, hd.radius, origin.forward, rayhits, hd.distance, layerMask);
                break;

            case HitscanType.BoxCast:
                hitcount = phys.BoxCast(srcPos, hd.halfExtents, origin.forward, rayhits, Quaternion.Euler(origin.eulerAngles + hd.orientation), hd.distance, layerMask);
                break;

            case HitscanType.CapsuleCast:
                hitcount = phys.CapsuleCast(origin.TransformPoint(hd.offset1), origin.TransformPoint(hd.offset2), hd.radius, origin.forward, rayhits, hd.distance, layerMask);
                break;

            case HitscanType.OverlapSphere:
                hitcount = phys.OverlapSphere(srcPos, hd.radius, hits, layerMask, QueryTriggerInteraction.UseGlobal);
                break;

            case HitscanType.OverlapBox:
                hitcount = phys.OverlapBox(srcPos, hd.halfExtents, hits, Quaternion.Euler(origin.eulerAngles + hd.orientation), layerMask);
                break;

            case HitscanType.OverlapCapsule:
                hitcount = phys.OverlapCapsule(origin.TransformPoint(hd.offset1), origin.TransformPoint(hd.offset2), hd.radius, hits, layerMask);
                break;

            default:
                hitcount = 0;
                break;
            }
#endif
            nearestIndex = -1;

            if (hitcount == 0)
            {
                return(hitcount);
            }

            bool  nearestOnly   = hd.nearestOnly;
            float distToNearest = float.PositiveInfinity;


            /// Overlaps have no rayhit info, so we are done.
            if (hitscanType.IsOverlap())
            {
                nearestIndex = -1;
                return(hitcount);
            }
            ///Cast Nearest Only
            if (nearestOnly)
            {
                for (int i = 0; i < hitcount; i++)
                {
                    RaycastHit rayhit = rayhits[i];

                    /// Get Nearest
                    float dist = rayhit.distance;

                    if (dist < distToNearest)
                    {
                        distToNearest = dist;
                        nearestIndex  = i;
                    }
                }

                hits[0] = rayhits[nearestIndex].collider;
                return(1);
            }
            /// Cast All
            // Convert the raycasthits to colliders[] if this was a cast and not an overlap
            else             /*if (hitscanType.IsCast())*/
            {
                for (int i = 0; i < hitcount; i++)
                {
                    RaycastHit rayhit = rayhits[i];

                    /// Get Nearest
                    float dist = rayhit.distance;

                    if (dist < distToNearest)
                    {
                        distToNearest = dist;
                        nearestIndex  = i;
                    }

                    if (!nearestOnly)
                    {
                        hits[i] = rayhits[i].collider;
                    }
                }
                if (nearestOnly)
                {
                    hits[0] = rayhits[nearestIndex].collider;
                    return(1);
                }
                return(hitcount);
            }
        }
예제 #2
0
 public static int GenericHitscanNonAlloc(this HitscanDefinition hd, Transform origin, out RaycastHit[] rayhits, out Collider[] hits, ref int nearestIndex, Realm realm = Realm.Primary, bool showDebugWidgets = false)
 {
     hits    = reusableColliderArray;
     rayhits = reusableRayHitArray;
     return(GenericHitscanNonAlloc(hd, origin, ref reusableColliderArray, ref reusableRayHitArray, ref nearestIndex, realm, showDebugWidgets));
 }
예제 #3
0
        public static int GenericHitscanNonAlloc(this HitscanDefinition hd, Transform origin, ref List <NetworkHit> hitscanHits, ref int nearestIndex, Realm realm, bool showDebugWidgets = false)
        {
            if (hitscanHits == null)
            {
                hitscanHits = reusableHitscanHitList;
            }

            int nearestRayHit = -1;

            nearestIndex = -1;
            int count = GenericHitscanNonAlloc(hd, origin, ref reusableColliderArray, ref reusableRayHitArray, ref nearestRayHit, realm, showDebugWidgets);

            reusableGameObjIntDict.Clear();
            hitscanHits.Clear();

            if (count > 0)
            {
                /// Check each collider hit for its hitgroup and its rootgameobject/netid - add to our outgoing List<HitscanHit>
                for (int i = 0; i < count; ++i)
                {
                    var hit = reusableColliderArray[i];

                    /// We are only interested in objects with IDs
                    /// TODO: this assumes root only PhotonViews - which may not always be the case
                    var netObj = hit.GetComponentInParent <emotitron.Networking.NetObject>();
                    if (ReferenceEquals(netObj, null))
                    {
                        continue;
                    }

                    var netId = netObj.NetObjId;

                    var hitgroupassign = hit.GetComponent <IHitGroupAssign>();
                    var mask           = (ReferenceEquals(hitgroupassign, null)) ? 0 : hitgroupassign.Mask;

                    int  existingIndex;
                    bool exists = reusableGameObjIntDict.TryGetValue(netId, out existingIndex);

                    int colliderId = netObj.colliderLookup[hit];

                    if (exists)
                    {
                        var hitscanHit = hitscanHits[existingIndex];
                        //Debug.Log("EXIST Hitscan hit on " + origin.name + "/" + hit.name + " m: " + mask + "->" + (hitscanHit.hitMask | mask));
                        hitscanHits[existingIndex] = new NetworkHit(hitscanHit.netObjId, hitscanHit.hitMask | mask, colliderId);

                        /// If we are adding the nearest raycast, log it.
                        if (i == nearestRayHit)
                        {
                            nearestIndex = existingIndex;
                        }
                    }
                    else
                    {
                        //Debug.Log("NEW Hitscan hit on " + rootGO.name + "/" + hit.name + " " + mask);

                        /// If we are adding the nearest raycast, log it.
                        if (i == nearestRayHit)
                        {
                            nearestIndex = hitscanHits.Count;
                        }

                        hitscanHits.Add(new NetworkHit(netId, mask, colliderId));

                        reusableGameObjIntDict.Add(netId, hitscanHits.Count - 1);
                    }
                }
            }
            return(reusableGameObjIntDict.Count);
        }
예제 #4
0
        public static void VisualizeHitscan(this HitscanDefinition hd, Transform origin, float duration = .5f)
        {
            if (DebugSpherePrefab == null)
            {
                CreateDebugPrimitives();
            }

            //Transform tr = hd.sourceObject.transform;

            switch (hd.hitscanType)
            {
            case HitscanType.Raycast:
            {
                Vector3 pos = hd.useOffset ?
                              origin.position + origin.TransformDirection(hd.offset1) + (origin.forward * hd.distance * .5f):
                              origin.position + (origin.forward * hd.distance * .5f);

                Pool.Spawn(DebugCylinderPrefab, pos, origin.rotation, new Vector3(.1f, .1f, hd.distance * .5f), duration);
            }
            break;

            case HitscanType.BoxCast:
            {
                Vector3 pos = (hd.useOffset) ?
                              origin.position + origin.TransformDirection(hd.offset1) :
                              origin.position;

                Vector3 pos2 = hd.useOffset ?
                               origin.position + origin.TransformDirection(hd.offset1) + (origin.forward * hd.distance) :
                               origin.position + (origin.forward * hd.distance);

                Vector3 midpos = pos + (pos2 - pos) * .5f;

                var     rot = Quaternion.Euler(origin.eulerAngles + hd.orientation);
                Vector3 scl = hd.halfExtents * 2;

                Pool.Spawn(DebugCubePrefab, pos2, rot, scl, duration);
                //DebugCylinder.Set(midpos, Quaternion.LookRotation(Vector3.up, tr.forward), new Vector3(.1f, cd.distance * .5f, .1f), duration);
                Pool.Spawn(DebugCylinderPrefab, midpos, Quaternion.LookRotation(pos2 - pos, Vector3.up), new Vector3(.1f, .1f, hd.distance * .5f), duration);
            }
            break;

            case HitscanType.SphereCast:
            {
                Vector3 spos = hd.useOffset ?
                               origin.position + origin.TransformDirection(hd.offset1) :
                               origin.position;

                Vector3 mpos = hd.useOffset ?
                               origin.position + origin.TransformDirection(hd.offset1) + (origin.forward * hd.distance * .5f) :
                               origin.position + (origin.forward * hd.distance * .5f);

                Vector3 epos = hd.useOffset ?
                               origin.position + origin.TransformDirection(hd.offset1) + (origin.forward * hd.distance) :
                               origin.position + (origin.forward * hd.distance);

                //Vector3 dir = (epos - spos);
                float scl = hd.radius * 2;
                Pool.Spawn(DebugSpherePrefab, spos, Quaternion.identity, new Vector3(scl, scl, scl), duration);
                Pool.Spawn(DebugSpherePrefab, epos, Quaternion.identity, new Vector3(scl, scl, scl), duration);
                Pool.Spawn(DebugCylinderPrefab, mpos, origin.rotation, new Vector3(scl, scl, hd.distance * .5f), duration);
            }
            break;

            case HitscanType.CapsuleCast:
            {
                Vector3 spos1 = origin.position + origin.TransformDirection(hd.offset1);
                Vector3 spos2 = origin.position + origin.TransformDirection(hd.offset2);

                var originFwd     = origin.forward * hd.distance;
                var halfOriginFwd = originFwd * .5f;

                Vector3 mpos1 = spos1 + halfOriginFwd;
                Vector3 mpos2 = spos2 + halfOriginFwd;


                Vector3 epos1 = spos1 + originFwd;
                Vector3 epos2 = spos2 + originFwd;

                Vector3 mposStr = spos1 + (spos2 - spos1) * .5f;
                Vector3 mposEnd = epos1 + (epos2 - epos1) * .5f;

                float scl = hd.radius * 2;
                Pool.Spawn(DebugSpherePrefab, spos1, Quaternion.identity, new Vector3(scl, scl, scl), duration);
                Pool.Spawn(DebugSpherePrefab, epos1, Quaternion.identity, new Vector3(scl, scl, scl), duration);
                Pool.Spawn(DebugSpherePrefab, spos2, Quaternion.identity, new Vector3(scl, scl, scl), duration);
                Pool.Spawn(DebugSpherePrefab, epos2, Quaternion.identity, new Vector3(scl, scl, scl), duration);
                Pool.Spawn(DebugCylinderPrefab, mpos1, origin.rotation, new Vector3(scl, scl, hd.distance * .5f), duration);
                Pool.Spawn(DebugCylinderPrefab, mpos2, origin.rotation, new Vector3(scl, scl, hd.distance * .5f), duration);
                float mag = Vector3.Magnitude(spos2 - spos1) * .5f;
                Pool.Spawn(DebugCylinderPrefab, mposStr, Quaternion.LookRotation(spos2 - spos1, Vector3.up), new Vector3(scl, scl, mag), duration);
                Pool.Spawn(DebugCylinderPrefab, mposEnd, Quaternion.LookRotation(epos2 - epos1, Vector3.up), new Vector3(scl, scl, mag), duration);
            }
            break;

            case HitscanType.OverlapSphere:
            {
                Vector3    pos = (hd.useOffset) ? origin.position + hd.offset1 : origin.position;
                Quaternion rot = origin.rotation;
                float      scl = hd.radius * 2;
                Pool.Spawn(DebugSpherePrefab, pos, rot, new Vector3(scl, scl, scl), duration);
            }
            break;

            case HitscanType.OverlapBox:
            {
                Vector3 pos = (hd.useOffset) ? origin.position + hd.offset1 : origin.position;
                var     rot = Quaternion.Euler(origin.eulerAngles + hd.orientation);
                Vector3 scl = hd.halfExtents * 2;

                Pool.Spawn(DebugCubePrefab, pos, rot, scl, duration);
            }
            break;

            case HitscanType.OverlapCapsule:
            {
                Quaternion rot  = origin.rotation;
                float      scl  = hd.radius * 2;
                Vector3    pos1 = origin.TransformPoint(hd.offset1);
                Vector3    pos2 = origin.TransformPoint(hd.offset2);
                Vector3    dir  = pos2 - pos1;
                Vector3    mid  = pos1 + dir * .5f;
                Pool.Spawn(DebugSpherePrefab, pos1, rot, new Vector3(scl, scl, scl), duration);
                Pool.Spawn(DebugSpherePrefab, pos2, rot, new Vector3(scl, scl, scl), duration);
                Pool.Spawn(DebugCylinderPrefab, mid, Quaternion.LookRotation(dir, Vector3.up), new Vector3(scl, scl, dir.magnitude * .5f), duration);
            }
            break;
            }
        }