319 lines
13 KiB
C#
319 lines
13 KiB
C#
using System.Collections;
|
|
using UnityEngine;
|
|
|
|
namespace RPGTALK.Snippets
|
|
{
|
|
[AddComponentMenu("Seize Studios/RPGTalk/Snippets/Follow Character")]
|
|
public class RPGTalkFollowCharacter : MonoBehaviour
|
|
{
|
|
[Header("Set ups")]
|
|
public Canvas canvas;
|
|
public RectTransform dialogWindow;
|
|
|
|
[Header("Camera Specs")]
|
|
public bool rotateToTarget;
|
|
public bool cameraBillboard;
|
|
public Camera basedOnWhatCamera;
|
|
|
|
[Header("Limits")]
|
|
public bool containInsideScreen;
|
|
public float unitsToMoveWhenOutside = 1;
|
|
public bool maximumIsInitialPoint = true;
|
|
public bool mantainZ = true;
|
|
|
|
[Header("Pointer")]
|
|
public RectTransform pointer;
|
|
public Vector3 pointerInitialOffset;
|
|
public bool mantainXDistanceFromClosestCorner;
|
|
int closestCorner;
|
|
|
|
RPGTalk rpgTalk;
|
|
|
|
Vector3 initialPoint;
|
|
bool doneFirst;
|
|
|
|
RPGTalkSmartPointer smartPointer;
|
|
Vector3 pointerPos;
|
|
|
|
|
|
bool following;
|
|
|
|
// Start is called before the first frame update
|
|
void Awake()
|
|
{
|
|
rpgTalk = GetComponent<RPGTalk>();
|
|
rpgTalk.OnNewTalk += BeginMove;
|
|
rpgTalk.OnEndTalk += EndMove;
|
|
if (pointer != null)
|
|
{
|
|
smartPointer = pointer.GetComponent<RPGTalkSmartPointer>();
|
|
}
|
|
}
|
|
|
|
void BeginMove()
|
|
{
|
|
following = true;
|
|
}
|
|
|
|
void EndMove()
|
|
{
|
|
following = false;
|
|
doneFirst = false;
|
|
}
|
|
|
|
private void Update()
|
|
{
|
|
if (!following || rpgTalk.following == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//Make sure that anything that should follow is following and is billboarding
|
|
Vector3 newPos = rpgTalk.following.position + rpgTalk.followingOffset;
|
|
//If we mantain the z, we will keep the previous Z of the dialogWindow. Perfect for 2D projects.
|
|
if (mantainZ)
|
|
{
|
|
newPos.z = dialogWindow.transform.position.z;
|
|
}
|
|
|
|
//If our canvas was overlay, we want the pos to be screen based
|
|
if (canvas != null && canvas.renderMode == RenderMode.ScreenSpaceOverlay)
|
|
{
|
|
newPos = basedOnWhatCamera.WorldToScreenPoint(newPos);
|
|
//If it is behind the camera, we don't want to display it
|
|
dialogWindow.gameObject.SetActive(newPos.z > 0);
|
|
}
|
|
|
|
|
|
Quaternion newRotation = Quaternion.identity;
|
|
if (rotateToTarget)
|
|
{
|
|
newRotation = rpgTalk.following.rotation;
|
|
}
|
|
if (cameraBillboard)
|
|
{
|
|
newRotation = basedOnWhatCamera.transform.rotation;
|
|
}
|
|
|
|
dialogWindow.transform.position = newPos;
|
|
dialogWindow.transform.rotation = newRotation;
|
|
|
|
//If the pointer was a smart pointer, we want to set the end of it to our following obj.
|
|
if (smartPointer != null)
|
|
{
|
|
//If our canvas was overlay, we want the pos to be screen based
|
|
if (canvas == null || canvas.renderMode == RenderMode.WorldSpace)
|
|
{
|
|
smartPointer.endPoint = rpgTalk.following.position;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//Get the corners of the recttransform
|
|
Vector3[] corners = new Vector3[4];
|
|
dialogWindow.GetWorldCorners(corners);
|
|
|
|
//Settings for the first time we run
|
|
if (!doneFirst)
|
|
{
|
|
//doneFirst = true;
|
|
initialPoint = dialogWindow.transform.position;
|
|
//If we got a pointer, let's teleport it to the initial position
|
|
if (pointer != null)
|
|
{
|
|
pointerPos = initialPoint;
|
|
pointerPos.y = corners[0].y;
|
|
//If we want to mantain X distance, let's find out what is the closest corner
|
|
if (mantainXDistanceFromClosestCorner)
|
|
{
|
|
closestCorner = -1;
|
|
for (int i = 0; i < corners.Length; i++)
|
|
{
|
|
|
|
//Vector3.distance is heavy. Changing it to sqrMagnitude
|
|
if (closestCorner == -1 || (pointer.position - corners[i]).sqrMagnitude < (pointer.position - corners[closestCorner]).sqrMagnitude)
|
|
{
|
|
closestCorner = i;
|
|
}
|
|
|
|
}
|
|
pointerPos.x = corners[closestCorner].x;
|
|
}
|
|
//If our canvas was overlay, we want the pos to be screen based
|
|
if (canvas != null && canvas.renderMode == RenderMode.ScreenSpaceOverlay)
|
|
{
|
|
pointerPos = basedOnWhatCamera.ScreenToWorldPoint(pointerPos);
|
|
}
|
|
pointer.position = pointerPos + pointerInitialOffset;
|
|
|
|
|
|
|
|
}
|
|
//If our canvas was overlay, we want the pos to be screen based
|
|
if (canvas != null && canvas.renderMode == RenderMode.ScreenSpaceOverlay)
|
|
{
|
|
pointerPos = basedOnWhatCamera.ScreenToWorldPoint(pointerPos);
|
|
initialPoint = basedOnWhatCamera.ScreenToWorldPoint(initialPoint);
|
|
}
|
|
}
|
|
|
|
|
|
//If our canvas was overlay, we want the pos to be screen based
|
|
if (canvas != null && canvas.renderMode == RenderMode.ScreenSpaceOverlay)
|
|
{
|
|
|
|
if (smartPointer != null && pointer.parent == dialogWindow.transform)
|
|
{
|
|
|
|
pointerPos = dialogWindow.transform.position;
|
|
pointerPos.y = corners[0].y;
|
|
|
|
if (mantainXDistanceFromClosestCorner)
|
|
{
|
|
pointerPos.x = corners[closestCorner].x;
|
|
}
|
|
|
|
|
|
Vector3 followingPoint = rpgTalk.following.position + rpgTalk.followingOffset;
|
|
Vector3 followingPointScreen = basedOnWhatCamera.WorldToScreenPoint(followingPoint);
|
|
|
|
Vector3 directionBetweenPoints = (pointerPos - dialogWindow.position).normalized;
|
|
|
|
Vector3 appliedOffset = pointerInitialOffset;
|
|
appliedOffset.x *= directionBetweenPoints.x;
|
|
appliedOffset.y *= directionBetweenPoints.y;
|
|
appliedOffset.z *= directionBetweenPoints.z;
|
|
|
|
|
|
Vector3 cornerOnWorld = basedOnWhatCamera.ScreenToWorldPoint(pointerPos + appliedOffset);
|
|
Vector3 followOnWorld = basedOnWhatCamera.ScreenToWorldPoint(followingPointScreen);
|
|
|
|
|
|
pointer.position = cornerOnWorld;
|
|
smartPointer.endPoint = followOnWorld;
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
if (containInsideScreen)
|
|
{
|
|
|
|
|
|
//If our canvas was overlay, we want the pos to be screen based
|
|
if (canvas != null && canvas.renderMode == RenderMode.ScreenSpaceOverlay)
|
|
{
|
|
|
|
|
|
if (basedOnWhatCamera.ScreenToViewportPoint(corners[2]).x > 1 && basedOnWhatCamera.ScreenToViewportPoint(corners[0]).x < 0)
|
|
{
|
|
Debug.LogError("Your Canvas was out left and right at the same time! I don't know what to do!");
|
|
return;
|
|
}
|
|
if (basedOnWhatCamera.ScreenToViewportPoint(corners[1]).y > 1 && basedOnWhatCamera.ScreenToViewportPoint(corners[0]).y < 0)
|
|
{
|
|
Debug.LogError("Your Canvas was out top and bottom at the same time! I don't know what to do!");
|
|
return;
|
|
}
|
|
|
|
|
|
//if the left corners passed the view
|
|
while (basedOnWhatCamera.ScreenToViewportPoint(corners[0]).x < 0 &&
|
|
(!maximumIsInitialPoint || basedOnWhatCamera.ScreenToViewportPoint(corners[0]).x < basedOnWhatCamera.WorldToViewportPoint(initialPoint).x))
|
|
{
|
|
Vector3 newpos = dialogWindow.localPosition;
|
|
newpos.x += unitsToMoveWhenOutside;
|
|
dialogWindow.localPosition = newpos;
|
|
dialogWindow.GetWorldCorners(corners);
|
|
}
|
|
//if the right corners passed the view
|
|
while (basedOnWhatCamera.ScreenToViewportPoint(corners[2]).x > 1 &&
|
|
(!maximumIsInitialPoint || basedOnWhatCamera.ScreenToViewportPoint(corners[2]).x > basedOnWhatCamera.WorldToViewportPoint(initialPoint).x))
|
|
{
|
|
Vector3 newpos = dialogWindow.localPosition;
|
|
newpos.x -= unitsToMoveWhenOutside;
|
|
dialogWindow.localPosition = newpos;
|
|
dialogWindow.GetWorldCorners(corners);
|
|
}
|
|
|
|
//if the bottom corners passed the view
|
|
while (basedOnWhatCamera.ScreenToViewportPoint(corners[0]).y < 0 &&
|
|
(!maximumIsInitialPoint || basedOnWhatCamera.ScreenToViewportPoint(corners[0]).y < basedOnWhatCamera.WorldToViewportPoint(initialPoint).y))
|
|
{
|
|
Vector3 newpos = dialogWindow.localPosition;
|
|
newpos.y += unitsToMoveWhenOutside;
|
|
dialogWindow.localPosition = newpos;
|
|
dialogWindow.GetWorldCorners(corners);
|
|
}
|
|
//if the top corners passed the view
|
|
while (basedOnWhatCamera.ScreenToViewportPoint(corners[1]).y > 1 &&
|
|
(!maximumIsInitialPoint || basedOnWhatCamera.ScreenToViewportPoint(corners[1]).y > basedOnWhatCamera.WorldToViewportPoint(initialPoint).y))
|
|
{
|
|
Vector3 newpos = dialogWindow.localPosition;
|
|
newpos.y -= unitsToMoveWhenOutside;
|
|
dialogWindow.localPosition = newpos;
|
|
dialogWindow.GetWorldCorners(corners);
|
|
}
|
|
|
|
|
|
}
|
|
else
|
|
{
|
|
|
|
|
|
if (basedOnWhatCamera.WorldToViewportPoint(corners[2]).x > 1 && basedOnWhatCamera.WorldToViewportPoint(corners[0]).x < 0)
|
|
{
|
|
Debug.LogError("Your Canvas was out left and right at the same time! I don't know what to do!");
|
|
return;
|
|
}
|
|
if (basedOnWhatCamera.WorldToViewportPoint(corners[1]).y > 1 && basedOnWhatCamera.WorldToViewportPoint(corners[0]).y < 0)
|
|
{
|
|
Debug.LogError("Your Canvas was out top and bottom at the same time! I don't know what to do!");
|
|
return;
|
|
}
|
|
//if the left corners passed the view
|
|
while (basedOnWhatCamera.WorldToViewportPoint(corners[0]).x < 0 &&
|
|
(!maximumIsInitialPoint || basedOnWhatCamera.WorldToViewportPoint(corners[0]).x < basedOnWhatCamera.WorldToViewportPoint(initialPoint).x))
|
|
{
|
|
Vector3 newpos = dialogWindow.localPosition;
|
|
newpos.x += unitsToMoveWhenOutside;
|
|
dialogWindow.localPosition = newpos;
|
|
dialogWindow.GetWorldCorners(corners);
|
|
}
|
|
//if the right corners passed the view
|
|
while (basedOnWhatCamera.WorldToViewportPoint(corners[2]).x > 1 &&
|
|
(!maximumIsInitialPoint || basedOnWhatCamera.WorldToViewportPoint(corners[2]).x > basedOnWhatCamera.WorldToViewportPoint(initialPoint).x))
|
|
{
|
|
Vector3 newpos = dialogWindow.localPosition;
|
|
newpos.x -= unitsToMoveWhenOutside;
|
|
dialogWindow.localPosition = newpos;
|
|
dialogWindow.GetWorldCorners(corners);
|
|
}
|
|
|
|
//if the bottom corners passed the view
|
|
while (basedOnWhatCamera.WorldToViewportPoint(corners[0]).y < 0 &&
|
|
(!maximumIsInitialPoint || basedOnWhatCamera.WorldToViewportPoint(corners[0]).y < basedOnWhatCamera.WorldToViewportPoint(initialPoint).y))
|
|
{
|
|
Vector3 newpos = dialogWindow.localPosition;
|
|
newpos.y += unitsToMoveWhenOutside;
|
|
dialogWindow.localPosition = newpos;
|
|
dialogWindow.GetWorldCorners(corners);
|
|
}
|
|
//if the top corners passed the view
|
|
while (basedOnWhatCamera.WorldToViewportPoint(corners[1]).y > 1 &&
|
|
(!maximumIsInitialPoint || basedOnWhatCamera.WorldToViewportPoint(corners[1]).y > basedOnWhatCamera.WorldToViewportPoint(initialPoint).y))
|
|
{
|
|
Vector3 newpos = dialogWindow.localPosition;
|
|
newpos.y -= unitsToMoveWhenOutside;
|
|
dialogWindow.localPosition = newpos;
|
|
dialogWindow.GetWorldCorners(corners);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
} |