bool SnapToSurface(Ray ray, ref Vector3 position, ref Quaternion rotation, SnappingState state, Vector3 boundsOffset, Vector3 targetPosition, Quaternion targetRotation, Quaternion rotationOffset, Vector3 upVector, float breakDistance, float raycastDistance) { RaycastHit hit; GameObject go; if (raycast(ray, out hit, out go, raycastDistance, m_CombinedIgnoreList)) { var snappedRotation = Quaternion.LookRotation(hit.normal, upVector) * rotationOffset; var hitPoint = hit.point; m_CurrentSurfaceSnappingHit = hitPoint; var snappedPosition = pivotSnappingEnabled ? hitPoint : hitPoint + rotation * boundsOffset; if (localOnly && Vector3.Distance(snappedPosition, targetPosition) > breakDistance) { return(false); } state.surfaceSnapping = true; state.groundSnapping = false; position = snappedPosition; rotation = rotationSnappingEnabled ? snappedRotation : targetRotation; m_CurrentSurfaceSnappingPosition = position; m_CurrentSurfaceSnappingRotation = snappedRotation; return(true); } return(false); }
// The tile has 3 states: idle, wrapping and moving // If it's on idle and userSwipe transition is fired, it changes to moving // If it's on moving and reachedGoal transition is fired, it returns to idle // If it's on moving and offGrid is fired, it changes to wrapping // If it's on wrapping and finished wrap is fired, it changes to idle private void MakeFSM() { IdleState idle = new IdleState(this); idle.AddTransition(Transition.UserSwiped, StateID.Follow); FollowState follow = new FollowState(this); follow.AddTransition(Transition.FinishedFollow, StateID.Snapping); SnappingState snap = new SnappingState(this); snap.AddTransition(Transition.FinishedSnapping, StateID.Idle); snap.AddTransition(Transition.OffGrid, StateID.Wrapping); WrapState wrap = new WrapState(this); wrap.AddTransition(Transition.FinishedWrap, StateID.Idle); SetupState setup = new SetupState(this); setup.AddTransition(Transition.FinishedSetup, StateID.Idle); fsm = new FSMSystem(); fsm.AddState(setup); fsm.AddState(idle); fsm.AddState(follow); fsm.AddState(snap); fsm.AddState(wrap); }
void Update() { if (snappingEnabled) { SnappingState surfaceSnapping = null; var shouldActivateGroundPlane = false; foreach (var statesForRay in m_SnappingStates.Values) { foreach (var state in statesForRay.Values) { if (state.groundSnapping) { shouldActivateGroundPlane = true; } if (state.surfaceSnapping) { surfaceSnapping = state; } } } m_GroundPlane.SetActive(shouldActivateGroundPlane); if (widgetEnabled) { var shouldActivateWidget = surfaceSnapping != null; m_Widget.SetActive(shouldActivateWidget); if (shouldActivateWidget) { var camera = CameraUtils.GetMainCamera(); var distanceToCamera = Vector3.Distance(camera.transform.position, m_CurrentSurfaceSnappingPosition); m_Widget.transform.position = m_CurrentSurfaceSnappingHit; m_Widget.transform.rotation = m_CurrentSurfaceSnappingRotation; m_Widget.transform.localScale = Vector3.one * k_WidgetScale * distanceToCamera; } } } else { m_GroundPlane.SetActive(false); m_Widget.SetActive(false); } }
SnappingState GetSnappingState(Transform rayOrigin, GameObject[] objects, Vector3 position, Quaternion rotation) { Dictionary <GameObject, SnappingState> states; if (!m_SnappingStates.TryGetValue(rayOrigin, out states)) { states = new Dictionary <GameObject, SnappingState>(); m_SnappingStates[rayOrigin] = states; } var firstObject = objects[0]; SnappingState state; if (!states.TryGetValue(firstObject, out state)) { state = new SnappingState(objects, position, rotation); states[firstObject] = state; } return(state); }
bool SnapToSurface(Ray ray, ref Vector3 position, ref Quaternion rotation, SnappingState state, Vector3 boundsOffset, Quaternion targetRotation, Quaternion rotationOffset, Vector3 upVector, float raycastDistance, float maxRayDot = Mathf.Infinity, bool constrained = false) { RaycastHit hit; GameObject go; if (this.Raycast(ray, out hit, out go, raycastDistance, m_CombinedIgnoreList)) { if (Vector3.Dot(ray.direction, hit.normal) > maxRayDot) { return(false); } if (!state.surfaceSnapping && hit.distance > raycastDistance * k_SnapDistanceScale) { return(false); } var snappedRotation = Quaternion.LookRotation(hit.normal, upVector) * rotationOffset; state.snappingNormal = hit.normal; var hitPoint = hit.point; var snappedPosition = pivotSnappingEnabled ? hitPoint : hitPoint + boundsOffset; state.surfaceSnapping = true; state.groundSnapping = false; position = snappedPosition; rotation = !constrained && rotationSnappingEnabled ? snappedRotation : targetRotation; state.snappingPosition = hitPoint; state.snappingRotation = snappedRotation; return(true); } return(false); }
bool SnapToGround(ref Vector3 position, ref Quaternion rotation, Vector3 targetPosition, Quaternion targetRotation, SnappingState state, float groundSnapMin, float groundSnapMax) { if (groundSnappingEnabled) { var diffGround = Mathf.Abs(targetPosition.y - k_GroundHeight); var bounds = state.rotatedBounds; if (rotationSnappingEnabled) { bounds = state.identityBounds; } var offset = bounds.center.y - bounds.extents.y; if (!pivotSnappingEnabled) { diffGround = Mathf.Abs(targetPosition.y + offset - k_GroundHeight); } if (diffGround < groundSnapMin) { state.groundSnapping = true; } if (diffGround > groundSnapMax) { state.groundSnapping = false; position = targetPosition; rotation = targetRotation; } if (state.groundSnapping) { if (pivotSnappingEnabled) { targetPosition.y = k_GroundHeight; } else { targetPosition.y = k_GroundHeight - offset; } position = targetPosition; if (rotationSnappingEnabled) { rotation = Quaternion.LookRotation(Vector3.up, targetRotation * Vector3.back) * Quaternion.AngleAxis(90, Vector3.right); } return(true); } } return(false); }
static bool TryBreakSurfaceSnap(ref Vector3 position, ref Quaternion rotation, Vector3 targetPosition, Quaternion targetRotation, SnappingState state, float breakDistance) { if (state.surfaceSnapping) { if (Vector3.Distance(position, targetPosition) > breakDistance) { position = targetPosition; rotation = targetRotation; state.surfaceSnapping = false; } return(true); } return(false); }
bool DirectSnapToSurface(ref Vector3 position, ref Quaternion rotation, Vector3 targetPosition, SnappingState state, Quaternion targetRotation, float breakDistance) { var bounds = state.identityBounds; var boundsCenter = bounds.center; for (int i = 0; i < k_Directions.Length; i++) { var direction = k_Directions[i]; var upVector = targetRotation * direction.upVector; var directionVector = direction.direction; var rotationOffset = direction.rotationOffset; var boundsRay = new Ray(targetPosition + targetRotation * boundsCenter, targetRotation * directionVector); var boundsExtents = bounds.extents; var projectedExtents = Vector3.Project(boundsExtents, directionVector); var raycastDistance = projectedExtents.magnitude * k_DirectSurfaceSearchScale; var offset = -boundsCenter; if (i > 2) { offset -= projectedExtents; } else { offset += projectedExtents; } if (SnapToSurface(boundsRay, ref position, ref rotation, state, offset, targetPosition, targetRotation, rotationOffset, upVector, breakDistance, raycastDistance)) { return(true); } } if (TryBreakSurfaceSnap(ref position, ref rotation, targetPosition, targetRotation, state, breakDistance)) { return(true); } return(false); }
bool ManipulatorSnapToSurface(Transform rayOrigin, ref Vector3 position, ref Quaternion rotation, Vector3 targetPosition, SnappingState state, Quaternion targetRotation, float breakDistance) { var bounds = state.identityBounds; var boundsExtents = bounds.extents; var projectedExtents = Vector3.Project(boundsExtents, Vector3.down); var offset = projectedExtents - bounds.center; var rotationOffset = Quaternion.AngleAxis(90, Vector3.right); var startRotation = state.startRotation; var upVector = startRotation * Vector3.back; var maxRayLength = k_SurfaceSnappingMaxRayLength * this.GetViewerScale(); var pointerRay = new Ray(rayOrigin.position, rayOrigin.forward); return(SnapToSurface(pointerRay, ref position, ref rotation, state, offset, targetPosition, targetRotation, rotationOffset, upVector, breakDistance, maxRayLength) || TryBreakSurfaceSnap(ref position, ref rotation, targetPosition, startRotation, state, breakDistance)); }
bool SnapToGround(Ray ray, ref Vector3 position, ref Quaternion rotation, Vector3 targetPosition, Quaternion targetRotation, SnappingState state, float raycastDistance, Vector3 boundsOffset = default(Vector3), bool constrained = false) { if (Mathf.Approximately(Vector3.Dot(ray.direction, Vector3.up), 0)) { return(false); } var groundPlane = new Plane(Vector3.up, k_GroundHeight); float distance; if (groundPlane.Raycast(ray, out distance) && distance <= raycastDistance) { state.groundSnapping = true; state.snappingNormal = -Vector3.Project(ray.direction, Vector3.up).normalized; var hitPoint = ray.origin + ray.direction * distance; var snappedPosition = pivotSnappingEnabled ? hitPoint : hitPoint + boundsOffset; position = snappedPosition; if (!constrained && rotationSnappingEnabled) { rotation = Quaternion.LookRotation(Vector3.up, targetRotation * Vector3.back) * Quaternion.AngleAxis(90, Vector3.right); } else { rotation = targetRotation; } return(true); } state.groundSnapping = false; position = targetPosition; rotation = targetRotation; return(false); }
bool LocalSnapToSurface(ref Vector3 position, ref Quaternion rotation, Vector3 targetPosition, Quaternion targetRotation, SnappingState state) { var bounds = state.identityBounds; var boundsCenter = bounds.center; var boundsExtents = bounds.extents; var viewerScale = this.GetViewerScale(); var breakDistance = viewerScale * k_BreakDistance; if (state.snapping) { var directionIndex = state.directionIndex; var direction = k_Directions[directionIndex]; var upVector = targetRotation * direction.upVector; var directionVector = direction.direction; var rotationOffset = direction.rotationOffset; var projectedExtents = Vector3.Project(boundsExtents, directionVector); var offset = -boundsCenter; if (directionIndex > 2) { offset -= projectedExtents; } else { offset += projectedExtents; } offset = rotation * offset; var snappingNormal = state.snappingNormal; var breakVector = targetPosition - position; if (Vector3.Dot(snappingNormal, breakVector) < 0) { var boundsBreakDist = breakDistance * k_BlockedBreakScale; var raycastDistance = projectedExtents.magnitude + breakVector.magnitude; directionVector = targetRotation * directionVector; var boundsRay = new Ray(targetPosition - Vector3.Project(breakVector, directionVector), directionVector); if (pivotSnappingEnabled) { var extra = k_RayExtra * viewerScale; raycastDistance += extra; boundsRay.origin -= directionVector * extra; } else { boundsRay.origin += targetRotation * boundsCenter; } if (TryBreakSnap(ref position, ref rotation, targetPosition, targetRotation, state, boundsBreakDist)) { return(true); } if (surfaceSnappingEnabled && SnapToSurface(boundsRay, ref position, ref rotation, state, offset, targetRotation, rotationOffset, upVector, raycastDistance)) { return(true); } if (groundSnappingEnabled && SnapToGround(boundsRay, ref position, ref rotation, targetPosition, targetRotation, state, raycastDistance, offset)) { return(true); } return(true); } if (TryBreakSnap(ref position, ref rotation, targetPosition, targetRotation, state, breakDistance)) { return(true); } } for (var i = 0; i < k_Directions.Length; i++) { var direction = k_Directions[i]; var upVector = targetRotation * direction.upVector; var directionVector = direction.direction; var rotationOffset = direction.rotationOffset; var offset = Vector3.zero; if (!pivotSnappingEnabled) { var projectedExtents = Vector3.Project(boundsExtents, directionVector); offset = -boundsCenter; if (i > 2) { offset -= projectedExtents; } else { offset += projectedExtents; } offset = rotation * offset; } var raycastDistance = breakDistance * 2; directionVector = targetRotation * directionVector; var boundsRay = new Ray(targetPosition - offset - directionVector * breakDistance, directionVector); if (surfaceSnappingEnabled && SnapToSurface(boundsRay, ref position, ref rotation, state, offset, targetRotation, rotationOffset, upVector, raycastDistance, k_MaxRayDot)) { state.directionIndex = i; return(true); } if (groundSnappingEnabled && SnapToGround(boundsRay, ref position, ref rotation, targetPosition, targetRotation, state, raycastDistance, offset)) { state.directionIndex = i; return(true); } } if (TryBreakSnap(ref position, ref rotation, targetPosition, targetRotation, state, breakDistance)) { return(true); } if (TryBreakSnap(ref position, ref rotation, state.snappingPosition, targetRotation, state, breakDistance)) { return(true); } return(false); }
bool ManipulatorSnapConstrained(ref Vector3 position, ref Quaternion rotation, Vector3 delta, Vector3 targetPosition, Quaternion targetRotation, SnappingState state, float raycastDistance, AxisFlags constraints, PivotMode pivotMode) { var rotationOffset = Quaternion.AngleAxis(90, Vector3.right); var startRotation = state.startRotation; var upVector = startRotation * Vector3.back; var direction = delta.normalized; var bounds = state.identityBounds; var projectedExtents = Vector3.Project(rotation * bounds.extents, direction); var axisRay = new Ray(targetPosition, direction); var objectCenter = Vector3.zero; var offset = Vector3.zero; if (!pivotSnappingEnabled) { objectCenter = targetPosition; if (pivotMode != PivotMode.Center) { objectCenter += targetRotation * state.identityBounds.center; } switch (constraints) { case AxisFlags.X: if (Vector3.Dot(rotation * Vector3.right, direction) > 0) { projectedExtents *= -1; } break; case AxisFlags.Y: if (Vector3.Dot(rotation * Vector3.up, direction) > 0) { projectedExtents *= -1; } break; case AxisFlags.Z: if (Vector3.Dot(rotation * Vector3.forward, direction) > 0) { projectedExtents *= -1; } break; } axisRay.origin = objectCenter - projectedExtents; offset = targetPosition - axisRay.origin; } if (state.snapping) { var breakDistance = raycastDistance; if (Vector3.Dot(targetPosition - position, state.snappingNormal) < 0) { breakDistance *= k_BlockedBreakScale; } TryBreakSnap(ref position, ref rotation, targetPosition, startRotation, state, breakDistance); return(true); } if (surfaceSnappingEnabled && SnapToSurface(axisRay, ref position, ref rotation, state, offset, targetRotation, rotationOffset, upVector, raycastDistance, constrained: true)) { return(true); } if (groundSnappingEnabled && SnapToGround(axisRay, ref position, ref rotation, targetPosition, targetRotation, state, raycastDistance, offset, true)) { return(true); } // Check other direction axisRay.direction *= -1; if (!pivotSnappingEnabled) { axisRay.origin = objectCenter + projectedExtents; offset = targetPosition - axisRay.origin; } if (surfaceSnappingEnabled && SnapToSurface(axisRay, ref position, ref rotation, state, offset, targetRotation, rotationOffset, upVector, raycastDistance, constrained: true)) { return(true); } if (groundSnappingEnabled && SnapToGround(axisRay, ref position, ref rotation, targetPosition, targetRotation, state, raycastDistance, offset, true)) { return(true); } if (TryBreakSnap(ref position, ref rotation, targetPosition, startRotation, state, raycastDistance)) { return(true); } return(false); }