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

223 lines
7.9 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.Events;
using UnityEngine.EventSystems;
using System.Collections;
// This class is an implementation of Basetile in which the image on each tile
// zooms inward and scrolls along with the controller retical as it is hovering
// over the tile. The edges of the image are masked off if they go beyond the
// bounding rectangle of the tile.
public class MaskedTile : BaseTile {
#if UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
private const string OBJ_NAME_MASKED_IMAGE = "MaskedImage";
private const float PARENT_CHANGE_THRESHOLD_PERCENT = 0.33f;
private Image maskedImage;
private GameObject maskedImageObject;
private Vector3 originalMaskedPosition; // Start position when pointer is not on tile.
private Vector3 maskedScrollOffset;
private Vector2 originalImageSize;
private Vector2 enlargedImageSize;
private float desiredPositionZ;
[Range(0.1f, 0.5f)]
[Tooltip("Image scroll amount when the pointer over the tile.")]
public float movementWeight = 0.15f;
[Range(1.1f, 2.0f)]
[Tooltip("Image scale amount when the pointer over the tile.")]
public float scaleWeight = 1.4f;
[Range(0.01f, 0.2f)]
[Tooltip("Tile forward distance when the pointer over the tile.")]
public float hoverPositionZMeters = 0.125f;
[Range(0.1f, 10.0f)]
[Tooltip("Speed used for lerping the rotation/scale/position of the tile.")]
public float interpolationSpeed = 8.0f;
protected override void Awake() {
base.Awake();
// Get current image.
Image image = GetComponent<Image>();
// Create mask.
gameObject.AddComponent<RectMask2D>();
// Save size data.
originalImageSize = image.rectTransform.sizeDelta;
enlargedImageSize = originalImageSize;
enlargedImageSize.x *= scaleWeight;
enlargedImageSize.y *= scaleWeight;
// Save position data.
originalMaskedPosition = new Vector3(originalImageSize.x / 2.0f, -originalImageSize.y / 2.0f, 0);
// Set data that varies.
maskedScrollOffset = Vector3.zero;
// Create game object for masked image.
maskedImageObject = new GameObject(OBJ_NAME_MASKED_IMAGE);
RectTransform maskedTransform = maskedImageObject.AddComponent<RectTransform>();
maskedTransform.SetParent(transform); // Set as child of this game object.
// Create maskedImage as component of child game object and initialize to base image.
maskedImage = maskedImageObject.AddComponent<Image>();
maskedImage.sprite = image.sprite;
maskedImage.color = image.color;
maskedImage.material = image.material;
image.sprite = null;
// If this object has a selectable referencing the original image,
// then we set the selectable to the masked image.
Selectable selectable = GetComponent<Selectable>();
if (selectable != null && selectable.image == image) {
selectable.image = maskedImage;
}
// Set size, scale, rotation and position.
maskedImage.rectTransform.sizeDelta = originalImageSize;
maskedImage.rectTransform.localScale = Vector3.one;
maskedImage.rectTransform.localRotation = Quaternion.identity;
maskedImage.rectTransform.anchoredPosition3D = originalMaskedPosition;
// Set masked image alignment to top-left.
Vector2 anchor = new Vector2(0, 1);
maskedImage.rectTransform.anchorMin = anchor;
maskedImage.rectTransform.anchorMax = anchor;
maskedImage.rectTransform.pivot = new Vector2(0.5f, 0.5f);
}
void Update() {
// Make sure to always ignore raycasts.
// This may be set back to true by BaseTile when the Tile becomes interactable.
maskedImage.raycastTarget = false;
UpdateScrollPosition();
UpdateFloatPosition();
UpdateScale();
}
#endif // UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
public override void OnPointerEnter(PointerEventData eventData) {
#if UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
isHovering = true;
desiredPositionZ = -hoverPositionZMeters / GetMetersToCanvasScale();
#endif // UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
}
public override void OnPointerExit(PointerEventData eventData) {
#if UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
isHovering = false;
maskedScrollOffset = Vector3.zero;
desiredPositionZ = 0.0f;
#endif // UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
}
public override void OnGvrPointerHover(PointerEventData eventData) {
#if UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
isHovering = true;
Vector3 pos = eventData.pointerCurrentRaycast.worldPosition;
RectTransform rectTransform = null;
if (maskedImageObject) {
rectTransform = maskedImageObject.GetComponent<RectTransform>();
}
if (!rectTransform || !isInteractable) {
return;
}
Rect rect = rectTransform.rect;
Vector3 localCenter = rect.center;
Vector3 worldCenter = maskedImageObject.transform.TransformPoint(localCenter);
Vector3 localMin = new Vector3(rect.min.x, rect.min.y, 0.0f);
Vector3 worldMin = maskedImageObject.transform.TransformPoint(localMin);
worldCenter -= worldMin;
pos -= worldMin;
Vector3 direction = pos - worldCenter;
maskedScrollOffset.x = movementWeight * enlargedImageSize.x * direction.x;
maskedScrollOffset.y = movementWeight * enlargedImageSize.y * direction.y;
#endif // UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
}
#if UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
private void UpdateScrollPosition() {
Vector3 desiredPosition = originalMaskedPosition;
if (isInteractable && isHovering) {
desiredPosition.x += maskedScrollOffset.x;
desiredPosition.y += maskedScrollOffset.y;
}
Vector3 position = maskedImage.rectTransform.anchoredPosition3D;
position = Vector3.Lerp(position, desiredPosition, Time.deltaTime * interpolationSpeed);
maskedImage.rectTransform.anchoredPosition3D = position;
}
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() {
Vector2 currentSize = maskedImage.rectTransform.sizeDelta;
Vector2 desiredSize;
if (IsInteractable && isHovering) {
desiredSize = enlargedImageSize;
} else {
desiredSize = originalImageSize;
}
currentSize = Vector2.Lerp(currentSize, desiredSize, Time.deltaTime * interpolationSpeed);
maskedImage.rectTransform.sizeDelta = currentSize;
}
#endif // UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
}