//public Enum Preset { Weapon, Grabber } public void UsePreset(Preset preset) { switch (preset) { case Preset.WeaponScan: triggerKey = KeyCode.R; grab = false; break; case Preset.ContactScan: { triggerKey = KeyCode.Alpha4; hitscanDefinition = new HitscanDefinition() { hitscanType = HitscanType.OverlapSphere, radius = 2 }; break; } case Preset.VitalsScan: { triggerKey = KeyCode.Alpha4; hitscanDefinition = new HitscanDefinition() { hitscanType = HitscanType.OverlapSphere, radius = 2 }; break; } case Preset.InventorysScan: { triggerKey = KeyCode.Alpha4; hitscanDefinition = new HitscanDefinition() { hitscanType = HitscanType.OverlapSphere, radius = 2 }; break; } default: { triggerKey = KeyCode.Alpha4; // If either the poke or grab bits are set, use both for settings. Otherwise just leave defaults. bool isPoke = (preset & Preset.Poke) != 0; bool isGrab = (preset & Preset.Grab) != 0; if (isPoke || isGrab) { poke = isPoke; grab = isGrab; } break; } } }
/// <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, bool showDebugWidgets = false, bool useSecondaryRealm = 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 #if GHOST_WORLD LayerMask layerMask = (useSecondaryRealm) ? (LayerMask)(GhostWorld.GHOST_WORLD_LAYERMASK) : (LayerMask)(hd.layerMask & ~GhostWorld.GHOST_WORLD_LAYERMASK); #else LayerMask layerMask = hd.layerMask; #endif 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 #if GHOST_WORLD var phys = (realm == Realm.Primary) ? Physics.defaultPhysicsScene : GhostWorld.ghostPhysics; #else var phys = Physics.defaultPhysicsScene; #endif 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); } }
public static int GenericHitscanNonAlloc(this HitscanDefinition hd, Transform origin, NetObject ownerNetObj, ref List <NetworkHit> hitscanHits, ref int nearestIndex, bool showDebugWidgets = false, bool useSecondaryRealm = false) { if (hitscanHits == null) { hitscanHits = reusableHitscanHitList; } int nearestRayHit = -1; nearestIndex = -1; int count = GenericHitscanNonAlloc(hd, origin, ref reusableColliderArray, ref reusableRayHitArray, ref nearestRayHit, showDebugWidgets, useSecondaryRealm); reusableGameObjIntDict.Clear(); hitscanHits.Clear(); if (count > 0) { /// Check each collider hit for its contactGroup and its rootgameobject/viewID - add to our outgoing List<HitscanHit> for (int i = 0; i < count; ++i) { var hit = reusableColliderArray[i]; var netObjs = reusableNetObjectsList; #if PUN_2_OR_NEWER /// Collect all nested NetObjects - child to parent in order hit.transform.GetNestedComponentsInParents(netObjs); #endif /// We are only interested in objects with IDs int noCount = netObjs.Count; if (noCount == 0) { continue; } /// Determine if any of the nested NetObjs is the owner. bool selfHit = false; for (int c = 0; c < noCount; ++c) { if (ReferenceEquals(netObjs[c], ownerNetObj)) { selfHit = true; break; } } if (selfHit) { continue; } var netObj = netObjs[0]; var viewID = netObj.ViewID; var contactGroupassign = hit.GetComponent <IContactGroupsAssign>(); var mask = (ReferenceEquals(contactGroupassign, null)) ? 0 : contactGroupassign.Mask; int existingIndex; bool exists = reusableGameObjIntDict.TryGetValue(viewID, 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(viewID, mask, colliderId)); reusableGameObjIntDict.Add(viewID, hitscanHits.Count - 1); } } } return(reusableGameObjIntDict.Count); }
public static int GenericHitscanNonAlloc(this HitscanDefinition hd, Transform origin, out RaycastHit[] rayhits, out Collider[] hits, ref int nearestIndex, bool showDebugWidgets = false, bool useSecondaryRealm = false) { hits = reusableColliderArray; rayhits = reusableRayHitArray; return(GenericHitscanNonAlloc(hd, origin, ref reusableColliderArray, ref reusableRayHitArray, ref nearestIndex, showDebugWidgets, useSecondaryRealm)); }
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; } }