You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

158 lines
5.7 KiB
C#

6 months ago
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
namespace Autohand{
[HelpURL("https://app.gitbook.com/s/5zKO0EvOjzUDeT2aiFk3/auto-hand/teleportation")]
public class Teleporter : MonoBehaviour{
[Header("Teleport")]
[Tooltip("The object to teleport")]
public GameObject teleportObject;
[Tooltip("Can be left empty - Used for if there is a container that should be teleported in addition to the main teleport object")]
public Transform[] additionalTeleports;
[Header("Aim Settings")]
[Tooltip("The Object to Shoot the Beam From")]
public Transform aimer;
[Tooltip("Layers You Can Teleport On")]
public LayerMask layer;
[Tooltip("The Maximum Slope You Can Teleport On")]
public float maxSurfaceAngle = 45;
[Min(0)]
public float distanceMultiplyer = 1;
[Min(0)]
public float curveStrength = 1;
[Tooltip("Use Worldspace Must be True")]
public LineRenderer line;
[Tooltip("Maximum Length of The Teleport Line")]
public int lineSegments = 50;
[Header("Line Settings")]
public Gradient canTeleportColor = new Gradient(){ colorKeys = new GradientColorKey[] { new GradientColorKey(){ color = Color.green, time = 0 } } };
public Gradient cantTeleportColor = new Gradient(){ colorKeys = new GradientColorKey[] { new GradientColorKey(){ color = Color.red, time = 0 } } };
[Tooltip("This gameobject will match the position of the teleport point when aiming")]
public GameObject indicator;
[Header("Unity Events")]
public UnityEvent OnStartTeleport;
public UnityEvent OnStopTeleport;
public UnityEvent OnTeleport;
Vector3[] lineArr;
bool aiming;
bool hitting;
RaycastHit aimHit;
HandTeleportGuard[] teleportGuards;
AutoHandPlayer playerBody;
private void Awake() {
line.enabled = false;
}
private void Start() {
playerBody = AutoHandExtensions.CanFindObjectOfType<AutoHandPlayer>();
if (playerBody != null && playerBody.transform.gameObject == teleportObject)
teleportObject = null;
lineArr = new Vector3[lineSegments];
teleportGuards = AutoHandExtensions.CanFindObjectsOfType<HandTeleportGuard>();
}
void Update(){
if(aiming)
CalculateTeleport();
else
line.positionCount = 0;
DrawIndicator();
}
void CalculateTeleport() {
line.colorGradient = cantTeleportColor;
var lineList = new List<Vector3>();
int i;
hitting = false;
for(i = 0; i < lineSegments; i++) {
var time = i/60f;
lineArr[i] = aimer.transform.position;
lineArr[i] += transform.forward*time*distanceMultiplyer*15;
lineArr[i].y += curveStrength * (time - Mathf.Pow(9.8f*0.5f*time, 2));
lineList.Add(lineArr[i]);
if(i != 0) {
if(Physics.Raycast(lineArr[i-1], lineArr[i]-lineArr[i-1], out aimHit, Vector3.Distance(lineArr[i], lineArr[i-1]), ~Hand.GetHandsLayerMask(), QueryTriggerInteraction.Ignore)) {
//Makes sure the angle isnt too steep
if(Vector3.Angle(aimHit.normal, Vector3.up) <= maxSurfaceAngle && layer == (layer | (1 << aimHit.collider.gameObject.layer))) {
line.colorGradient = canTeleportColor;
lineList.Add(aimHit.point);
hitting = true;
break;
}
break;
}
}
}
line.enabled = true;
line.positionCount = i;
line.SetPositions(lineArr);
}
void DrawIndicator(){
if(indicator != null){
if(hitting){
indicator.gameObject.SetActive(true);
indicator.transform.position = aimHit.point;
indicator.transform.up = aimHit.normal;
}
else
indicator.gameObject.SetActive(false);
}
}
public void StartTeleport(){
aiming = true;
OnStartTeleport?.Invoke();
}
public void CancelTeleport(){
line.positionCount = 0;
line.enabled = false;
hitting = false;
aiming = false;
OnStopTeleport?.Invoke();
}
public void Teleport(){
Queue<Vector3> fromPos = new Queue<Vector3>();
foreach(var guard in teleportGuards) {
if(guard.gameObject.activeInHierarchy)
fromPos.Enqueue(guard.transform.position);
}
if(hitting) {
if (teleportObject != null){
var diff = aimHit.point - teleportObject.transform.position;
teleportObject.transform.position = aimHit.point;
foreach (var teleport in additionalTeleports){
teleport.position += diff;
}
}
playerBody?.SetPosition(aimHit.point);
OnTeleport?.Invoke();
foreach(var guard in teleportGuards) {
if(guard.gameObject.activeInHierarchy) {
guard.TeleportProtection(fromPos.Dequeue(), guard.transform.position);
}
}
}
CancelTeleport();
}
}
}