public void UpdatePositionAndRotation(VR_Controller controller, AimRaycastInfo info) { if (!marker.activeInHierarchy) { marker.SetActive(true); } marker.transform.position = info.hitPoint; marker.transform.up = info.normal; Vector2 controllerInput = controller.Input.GetJoystickInput().normalized; Vector3 controllerDirection = new Vector3(controllerInput.x, 0.0f, controllerInput.y); //get controller pointing direction in world space controllerDirection = controller.transform.TransformDirection(controllerDirection); //get marker forward in local space Vector3 forward = marker.transform.InverseTransformDirection(marker.transform.forward); //find the angle diference betwen the controller pointing direction and marker current forward float angle = Vector2.SignedAngle(new Vector2(controllerDirection.x, controllerDirection.z), new Vector2(forward.x, forward.z)); //rotate marker in local space to match controller pointing direction marker.transform.Rotate(Vector3.up, angle, Space.Self); }
private void PostTeleportUpdate() { teleportMarker.Hide(); lastActiveController = null; lastRaycastInfo = null; currentTeleportState = TeleporState.WaitingInput; }
private AimRaycastInfo ProcessHitInfo(RaycastHit hitInfo, List <Vector3> validPoints) { Vector3 start = hitInfo.point + (hitInfo.normal * characterController.radius * characterRadiusOffset) + hitInfo.normal; Vector3 end = start + (hitInfo.normal * characterController.height); AimRaycastInfo info = new AimRaycastInfo(); info.hitPoint = hitInfo.point; info.normal = hitInfo.normal; info.validPoints = validPoints; //check if the character can fit in this place info.suitableForTeleporting = GetSlopeAngle(info.normal) < slopeLimit && !Physics.CheckCapsule(start, end, characterController.radius * characterRadiusOffset, validLayerMask.value, QueryTriggerInteraction.Ignore); return(info); }
//wait for the player to decide where to teleport private void PreTeleportUpdate() { UpdateActiveController(); //there is no active controller try to do a teleport if (activeController == null) { //if we can teleport to the last AimRaycast if (IsAimRaycastInfoSuitableForTeleporting(lastRaycastInfo)) { DoTeleport(lastRaycastInfo); } //clean the line inmediatly teleportLineRender.CleanRender(); //go to post teleport currentTeleportState = TeleporState.PostTeleport; return; } Ray controllerRay = new Ray(activeController.transform.position, activeController.transform.forward); //use the aimhandler to generate all the line points List <Vector3> points = aimHandler.GetAllPoints(controllerRay); //use the raycaster AimRaycastInfo info = aimRaycaster.Raycast(points, activeController.transform); if (info != null) { teleportLineRender.Render(info.validPoints, info.suitableForTeleporting); } else { teleportLineRender.Render(points, false); } if (IsAimRaycastInfoSuitableForTeleporting(info)) { teleportMarker.UpdatePositionAndRotation(activeController, info); } else { teleportMarker.Hide(); } lastRaycastInfo = info; }
public virtual AimRaycastInfo Raycast(List <Vector3> points, Transform rayController) { //get rayController angle Vector3 rayControllerForward = rayController.forward; Vector3 unalteredForward = new Vector3(rayController.forward.x, 0.0f, rayController.forward.z).normalized; float angle = Vector3.Angle(rayController.forward, unalteredForward); //check if we are on a valid angle if (angle > validAngle) { AimRaycastInfo info = new AimRaycastInfo(); info.hitPoint = Vector3.zero; info.normal = Vector3.zero; //clamp ray to a distance info.validPoints = ClampToDistance(points, invalidRayDistance); info.suitableForTeleporting = false; return(info); } //the points are valid? if (points.Count <= 1) { return(null); } RaycastHit hitInfo; if (points.Count == 2) { if (Physics.Linecast(points[0], points[1], out hitInfo, validLayerMask.value, QueryTriggerInteraction.Ignore)) { return(ProcessHitInfo(hitInfo, new List <Vector3> { points[0], hitInfo.point })); } return(null); } List <Vector3> validPoints = new List <Vector3>(); int subdivision = Mathf.CeilToInt(points.Count / collisionAccuracy); int currentIndex = 0; int nextIndex = subdivision; for (int n = 0; n < subdivision; n++) { //check for collision in this segment if (Physics.Linecast(points[currentIndex], points[nextIndex], validLayerMask.value, QueryTriggerInteraction.Ignore)) { //found a collision in this segment //find collision in all points inside this segment for (int j = currentIndex; j < nextIndex; j++) { validPoints.Add(points[j]); if (Physics.Linecast(points[j], points[j + 1], out hitInfo, validLayerMask.value, QueryTriggerInteraction.Ignore)) { validPoints.Add(hitInfo.point); return(ProcessHitInfo(hitInfo, validPoints)); } } } else { //this segment dont has a collision, addall as valid points for (int j = currentIndex; j <= nextIndex; j++) { validPoints.Add(points[j]); } } //move to the next subdivision if we have one currentIndex += subdivision; nextIndex += subdivision; //we found the end if (currentIndex >= points.Count) { return(null); } if (nextIndex >= points.Count) { nextIndex = points.Count - 1; } } return(null); }
private void DoTeleport(AimRaycastInfo info) { isTeleporting = true; teleportHandler.DoTeleport(characterController, teleportMarker.Marker.transform, delegate { isTeleporting = false; }); }
private bool IsAimRaycastInfoSuitableForTeleporting(AimRaycastInfo info) { return(info != null && info.suitableForTeleporting); }