1
This repository has been archived on 2025-03-15. You can view files and clone it, but cannot push or open issues or pull requests.
2025-03-15 20:02:21 +01:00

210 lines
7.5 KiB
C#

// Copyright 2016 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using UnityEngine.Events;
// This class is an implementation of Basetile in which tiles float forward along
// the z-axis and tilt towards the camera when the gvr controller pointer is
// hovering over them.
public class FloatTile : BaseTile {
#if UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
private const float PARENT_CHANGE_THRESHOLD_PERCENT = 0.33f;
private const float _360_DEGREES = 360.0f;
private const float _180_DEGREES = 180.0f;
private Quaternion desiredRotation = Quaternion.identity;
private float desiredPositionZ;
private Vector3 desiredScale = Vector3.one;
[Range(1.0f, 2.0f)]
[Tooltip("Tile scale when the pointer over the tile.")]
public float hoverScale = 1.2f;
[Range(0.01f, 0.5f)]
[Tooltip("Tile forward distance when the pointer over the tile.")]
public float hoverPositionZMeters = 0.225f;
[Range(0.0f, 30.0f)]
[Tooltip("Maximum tile rotation towards the camera.")]
public float maximumRotationDegreesCamera = 15.0f;
[Range(0.0f, 5.0f)]
[Tooltip("Maximum tile rotation towards the pointer.")]
public float maximumRotationDegreesPointer = 3.0f;
[Range(1.0f, 10.0f)]
[Tooltip("Speed used for lerping the rotation/scale/position of the tile.")]
public float interpolationSpeed = 8.0f;
public override void Reset() {
base.Reset();
Transform myTransform = transform;
myTransform.SetParent(originalParent, true);
myTransform.SetAsLastSibling();
}
#endif // UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
public override void OnPointerEnter(PointerEventData eventData) {
#if UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
isHovering = true;
// Since canvas graphics render facing the negative Z direction,
// negative z is the forward direction for a canvas element.
desiredPositionZ = -hoverPositionZMeters / GetMetersToCanvasScale();
desiredScale = new Vector3(hoverScale, hoverScale, hoverScale);
#endif // UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
}
public override void OnPointerExit(PointerEventData eventData) {
#if UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
isHovering = false;
desiredRotation = Quaternion.identity;
desiredPositionZ = 0.0f;
desiredScale = Vector3.one;
#endif // UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
}
public override void OnGvrPointerHover(PointerEventData eventData) {
#if UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
isHovering = true;
UpdateDesiredRotation(eventData.pointerCurrentRaycast.worldPosition);
#endif // UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
}
#if UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
void Update() {
UpdateRotation();
UpdateFloatPosition();
UpdateScale();
}
private void UpdateRotation() {
Quaternion finalDesiredRotation = desiredRotation;
if (!isInteractable) {
finalDesiredRotation = Quaternion.identity;
}
if (finalDesiredRotation != transform.localRotation) {
Quaternion localRotation = transform.localRotation;
localRotation = Quaternion.Lerp(localRotation, finalDesiredRotation, Time.deltaTime * interpolationSpeed);
transform.localRotation = localRotation;
}
}
private void UpdateFloatPosition() {
float finalDesiredPositionZ = desiredPositionZ;
if (!isInteractable) {
finalDesiredPositionZ = 0.0f;
}
if (finalDesiredPositionZ != transform.localPosition.z) {
Vector3 localPosition = transform.localPosition;
Vector3 desiredPosition = localPosition;
desiredPosition.z = finalDesiredPositionZ;
localPosition = Vector3.Lerp(localPosition, desiredPosition, Time.deltaTime * interpolationSpeed);
transform.localPosition = localPosition;
TiledPage page = GetPage();
if (page != null) {
float diff = Mathf.Abs(localPosition.z);
if (diff < ((PARENT_CHANGE_THRESHOLD_PERCENT * hoverPositionZMeters) / GetMetersToCanvasScale()) &&
transform.parent == page.transform) {
transform.SetParent(originalParent, true);
transform.SetAsLastSibling();
} else if (isHovering && diff >= 0 && transform.parent == originalParent) {
transform.SetParent(page.transform, true);
}
}
}
}
private void UpdateScale() {
Vector3 finalDesiredScale = desiredScale;
if (!isInteractable) {
finalDesiredScale = Vector3.one;
}
if (finalDesiredScale != transform.localScale) {
Vector3 localScale = transform.localScale;
localScale = Vector3.Lerp(localScale, finalDesiredScale, Time.deltaTime * interpolationSpeed);
transform.localScale = localScale;
}
}
private void UpdateDesiredRotation(Vector3 pointerIntersectionWorldPosition) {
Vector3 localCenter = CalculateLocalCenter();
Vector3 worldCenter = transform.TransformPoint(localCenter);
Vector2 localSize = CalculateLocalSize();
Vector3 pointerLocalPositionOnTile = transform.InverseTransformPoint(pointerIntersectionWorldPosition);
Vector3 pointerDiffFromCenter = pointerLocalPositionOnTile - localCenter;
float pointerRatioX = pointerDiffFromCenter.x / localSize.x;
float pointerRatioY = pointerDiffFromCenter.y / localSize.y;
Vector2 pointerRatioFromCenter = new Vector2(pointerRatioX, pointerRatioY);
float axisCoeff = maximumRotationDegreesPointer * 2.0f;
Vector3 worldDirection = worldCenter - Camera.main.transform.position;
Vector3 localDirection = transform.parent.InverseTransformDirection(worldDirection);
Quaternion lookRotation = Quaternion.LookRotation(localDirection, Vector3.up);
Vector3 lookEuler = clampEuler(lookRotation.eulerAngles, maximumRotationDegreesCamera);
float eulerX = lookEuler.x - pointerRatioFromCenter.y * axisCoeff;
float eulerY = lookEuler.y + pointerRatioFromCenter.x * axisCoeff;
desiredRotation = Quaternion.Euler(eulerX, eulerY, lookEuler.z);
}
private Vector2 CalculateLocalSize() {
RectTransform rectTransform = GetComponent<RectTransform>();
if (rectTransform) {
Vector3 localMax = rectTransform.rect.max;
Vector3 localMin = rectTransform.rect.min;
return localMax - localMin;
}
return Vector2.zero;
}
protected Vector3 CalculateLocalCenter() {
RectTransform rectTransform = GetComponent<RectTransform>();
if (rectTransform) {
Vector3 localCenter = rectTransform.rect.center;
return localCenter;
}
return Vector3.zero;
}
private Vector3 clampEuler(Vector3 rotation, float maxDegrees) {
rotation.x = clampDegrees(rotation.x, maxDegrees);
rotation.y = clampDegrees(rotation.y, maxDegrees);
rotation.z = clampDegrees(rotation.z, maxDegrees);
return rotation;
}
private float clampDegrees(float degrees, float maxDegrees) {
if (degrees > _180_DEGREES) {
degrees -= _360_DEGREES;
}
return Mathf.Clamp(degrees, -maxDegrees, maxDegrees);
}
#endif // UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
}