hellbound/Assets/Sources/Lean/Touch+/Scripts/LeanSpawnWithFinger.cs

237 lines
7.6 KiB
C#

using UnityEngine;
using System.Collections.Generic;
using Lean.Common;
using FSA = UnityEngine.Serialization.FormerlySerializedAsAttribute;
namespace Lean.Touch
{
/// <summary>This component allows you to spawn a prefab at a point relative to a finger and the specified ScreenDepth.
/// NOTE: To trigger the prefab spawn you must call the Spawn method on this component from somewhere.</summary>
[HelpURL(LeanTouch.HelpUrlPrefix + "LeanSpawnWithFinger")]
[AddComponentMenu(LeanTouch.ComponentPathPrefix + "Spawn With Finger")]
public class LeanSpawnWithFinger : MonoBehaviour
{
public enum RotateType
{
ThisTransform,
ScreenDepthNormal
}
[System.Serializable]
public class FingerData : LeanFingerData
{
public Transform Clone;
}
/// <summary>The prefab that this component can spawn.</summary>
public Transform Prefab { set { prefab = value; } get { return prefab; } } [FSA("Prefab")] [SerializeField] private Transform prefab;
/// <summary>How should the spawned prefab be rotated?</summary>
public RotateType RotateTo { set { rotateTo = value; } get { return rotateTo; } } [FSA("RotateTo")] [SerializeField] private RotateType rotateTo;
/// <summary>Hold on to the spawned clone while the spawning finger is still being held?</summary>
public bool DragAfterSpawn { set { dragAfterSpawn = value; } get { return dragAfterSpawn; } } [FSA("DragAfterSpawn")] [SerializeField] private bool dragAfterSpawn;
/// <summary>If the specified prefab is selectable, select it when spawned?</summary>
public bool SelectOnSpawn { set { selectOnSpawn = value; } get { return selectOnSpawn; } } [SerializeField] private bool selectOnSpawn;
/// <summary>If you want the spawned component to be a selected with a specific select component, you can specify it here.
/// None/null = It will be self selected.</summary>
public LeanSelect SelectWith { set { selectWith = value; } get { return selectWith; } } [SerializeField] private LeanSelect selectWith;
/// <summary>The conversion method used to find a world point from a screen point.</summary>
public LeanScreenDepth ScreenDepth = new LeanScreenDepth(LeanScreenDepth.ConversionType.FixedDistance, Physics.DefaultRaycastLayers, 10.0f);
/// <summary>This allows you to offset the finger position.</summary>
public Vector2 PixelOffset { set { pixelOffset = value; } get { return pixelOffset; } } [FSA("PixelOffset")] [SerializeField] private Vector2 pixelOffset;
/// <summary>If you want the pixels to scale based on device resolution, then specify the canvas whose scale you want to use here.</summary>
public Canvas PixelScale { set { pixelScale = value; } get { return pixelScale; } } [FSA("PixelScale")] [SerializeField] private Canvas pixelScale;
/// <summary>This allows you to offset the spawned object position.</summary>
public Vector3 WorldOffset { set { worldOffset = value; } get { return worldOffset; } } [FSA("WorldOffset")] [SerializeField] private Vector3 worldOffset;
/// <summary>This allows you transform the WorldOffset to be relative to the specified Transform.</summary>
public Transform WorldRelativeTo { set { worldRelativeTo = value; } get { return worldRelativeTo; } } [FSA("WorldRelativeTo")] [SerializeField] private Transform worldRelativeTo;
[SerializeField]
private List<FingerData> fingerDatas;
private static Stack<FingerData> fingerDataPool = new Stack<FingerData>();
/// <summary>This will spawn Prefab at the specified finger based on the ScreenDepth setting.</summary>
public void Spawn(LeanFinger finger)
{
if (prefab != null && finger != null)
{
// Spawn and position
var clone = Instantiate(prefab);
UpdateSpawnedTransform(finger, clone);
clone.gameObject.SetActive(true);
if (dragAfterSpawn == true)
{
var fingerData = LeanFingerData.FindOrCreate(ref fingerDatas, finger);
fingerData.Clone = clone;
}
// Select?
if (selectOnSpawn == true)
{
var selectable = clone.GetComponent<LeanSelectable>();
var selectableByFinger = selectable as LeanSelectableByFinger;
var selectWithByFinger = selectWith as LeanSelectByFinger;
if (selectableByFinger != null)
{
if (selectWithByFinger != null)
{
selectWithByFinger.Select(selectableByFinger, finger);
}
else if (selectWith != null)
{
selectWith.Select(selectableByFinger);
}
else
{
selectableByFinger.SelectSelf(finger);
}
}
else if (selectable != null)
{
if (selectWithByFinger != null)
{
selectWithByFinger.Select(selectable, finger);
}
else if (selectWith != null)
{
selectWith.Select(selectable);
}
else
{
selectable.SelfSelected = true;
}
}
}
}
}
protected virtual void OnEnable()
{
LeanTouch.OnFingerUp += HandleFingerUp;
}
protected virtual void OnDisable()
{
LeanTouch.OnFingerUp -= HandleFingerUp;
}
protected virtual void Update()
{
for (var i = fingerDatas.Count - 1; i >= 0; i--)
{
var fingerData = fingerDatas[i];
if (fingerData.Clone != null)
{
UpdateSpawnedTransform(fingerData.Finger, fingerData.Clone);
}
}
}
private void UpdateSpawnedTransform(LeanFinger finger, Transform instance)
{
// Grab screen position of finger, and optionally offset it
var screenPoint = finger.ScreenPosition;
if (pixelScale != null)
{
screenPoint += pixelOffset * pixelScale.scaleFactor;
}
else
{
screenPoint += pixelOffset;
}
// Converted screen position to world position, and optionally offset it
var worldPoint = ScreenDepth.Convert(screenPoint, gameObject, instance);
if (worldRelativeTo != null)
{
worldPoint += worldRelativeTo.TransformPoint(worldOffset);
}
else
{
worldPoint += worldOffset;
}
// Write position
instance.position = worldPoint;
// Write rotation
switch (rotateTo)
{
case RotateType.ThisTransform:
{
instance.rotation = transform.rotation;
}
break;
case RotateType.ScreenDepthNormal:
{
instance.up = LeanScreenDepth.LastWorldNormal;
}
break;
}
}
private void HandleFingerUp(LeanFinger finger)
{
LeanFingerData.Remove(fingerDatas, finger, fingerDataPool);
}
}
}
#if UNITY_EDITOR
namespace Lean.Touch.Editor
{
using TARGET = LeanSpawnWithFinger;
[UnityEditor.CanEditMultipleObjects]
[UnityEditor.CustomEditor(typeof(TARGET), true)]
public class LeanSpawnWithFinger_Editor : LeanEditor
{
protected override void OnInspector()
{
TARGET tgt; TARGET[] tgts; GetTargets(out tgt, out tgts);
BeginError(Any(tgts, t => t.Prefab == null));
Draw("prefab");
EndError();
Draw("rotateTo", "How should the spawned prefab be rotated?");
Draw("dragAfterSpawn", "Hold on to the spawned clone while the spawning finger is still being held?");
Draw("selectOnSpawn", "If the specified prefab is selectable, select it when spawned?");
if (Any(tgts, t => t.SelectOnSpawn == true))
{
BeginIndent();
Draw("selectWith", "If you want the spawned component to be a selected with a specific select component, you can specify it here.\n\nNone/null = It will be self selected.");
EndIndent();
}
Draw("ScreenDepth");
Separator();
Draw("pixelOffset", "This allows you to offset the finger position.");
Draw("pixelScale", "If you want the pixels to scale based on device resolution, then specify the canvas whose scale you want to use here.");
Separator();
Draw("worldOffset", "This allows you to offset the spawned object position.");
Draw("worldRelativeTo", "This allows you transform the WorldOffset to be relative to the specified Transform.");
}
}
}
#endif