619 lines
19 KiB
C#
619 lines
19 KiB
C#
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
using UnityEngine.Events;
|
|
using UnityEngine.UIElements;
|
|
|
|
public class matchPlayerToTargetSystem : MonoBehaviour
|
|
{
|
|
[Header ("Main Settings")]
|
|
[Space]
|
|
|
|
public bool matchSystemEnabled = true;
|
|
|
|
public float matchSpeed = 10;
|
|
|
|
public float positionOffset;
|
|
|
|
public bool ignoreCustomPositionOffset;
|
|
|
|
public bool useDistancePercentageAsOffset;
|
|
[Range (0, 1)] public float positionOffsetPercentage;
|
|
|
|
[Space]
|
|
[Space]
|
|
|
|
public float minDistanceToMatchPosition;
|
|
public float maxDistanceToMatchPosition;
|
|
|
|
[Space]
|
|
|
|
public float minAngleToMatchRotation;
|
|
|
|
public float maxAngleToMatchRotation;
|
|
|
|
public bool adjustRotationEvenIfNotMoved;
|
|
|
|
public float minDistanceToMatchRotation;
|
|
public float maxDistanceToMatchRotation;
|
|
|
|
[Space]
|
|
|
|
public bool useMaxDistanceToCameraCenter;
|
|
public float maxDistanceToCameraCenter;
|
|
|
|
public bool useMoveInputAsDirectionToClosestTarget;
|
|
|
|
[Space]
|
|
[Header ("Vertical Distance Settings")]
|
|
[Space]
|
|
|
|
public bool adjustVerticalPositionEnabled;
|
|
public float raycastDistanceForVerticalPosition;
|
|
public LayerMask layerMaskForVerticalPosition;
|
|
|
|
[Space]
|
|
|
|
public bool checkMaxVerticalDistanceWithTarget;
|
|
public float maxVerticalDistanceWithTarget;
|
|
|
|
[Space]
|
|
|
|
public bool checkIfObstaclesToTarget;
|
|
public LayerMask layerToCheckTarget;
|
|
|
|
[Space]
|
|
[Header ("Front Position Settings")]
|
|
[Space]
|
|
|
|
public bool useFrontPositionAsPositionToMatch;
|
|
public Vector3 frontPositionAsPositionToMatchOffset;
|
|
|
|
[Space]
|
|
[Header ("Other Settings")]
|
|
[Space]
|
|
|
|
public bool addMainPlayerOnListForAI;
|
|
|
|
[Space]
|
|
[Header ("Debug")]
|
|
[Space]
|
|
|
|
public bool showDebugPrint;
|
|
|
|
public bool movementActive;
|
|
|
|
public bool matchPositionPaused;
|
|
|
|
public bool getClosestTargetWithoutConditionsActive;
|
|
|
|
public List<Transform> charactersAround = new List<Transform> ();
|
|
|
|
[Space]
|
|
[Header ("Events")]
|
|
[Space]
|
|
|
|
public bool useEventsOnTargetsChange;
|
|
public UnityEvent eventOnTargetsDetected;
|
|
public UnityEvent eventOnTargetsRemoved;
|
|
|
|
public bool useEventOnFirstTargetDetected;
|
|
public UnityEvent eventOnFirstTargetDetected;
|
|
|
|
public bool useEventOnLastTargetRemoved;
|
|
public UnityEvent eventOnLastTargetRemoved;
|
|
|
|
[Space]
|
|
[Header ("Components")]
|
|
[Space]
|
|
|
|
public Transform playerTransform;
|
|
|
|
public Transform debugTargetToMatchTransform;
|
|
|
|
public Camera mainCamera;
|
|
|
|
public playerCamera mainPlayerCamera;
|
|
|
|
public playerController mainPlayerController;
|
|
|
|
public playerInputManager mainPlayerInputManager;
|
|
|
|
Coroutine movementCoroutine;
|
|
|
|
Vector3 screenPoint;
|
|
|
|
Vector3 characterPosition;
|
|
|
|
Vector3 centerScreen;
|
|
|
|
Vector3 currentPlayerPosition;
|
|
|
|
bool playerCheckInitialized;
|
|
|
|
|
|
public void findPlayerOnScene ()
|
|
{
|
|
addCharacterAround (GKC_Utils.findMainPlayerTransformOnScene ());
|
|
}
|
|
|
|
public void addCharacterAround (Transform newCharacter)
|
|
{
|
|
if (newCharacter == null) {
|
|
return;
|
|
}
|
|
|
|
if (!charactersAround.Contains (newCharacter)) {
|
|
charactersAround.Add (newCharacter);
|
|
|
|
checkRemoveEmptyObjects ();
|
|
|
|
if (charactersAround.Count == 1) {
|
|
checkEventOnFirstTargetDetected ();
|
|
}
|
|
|
|
checkEventsOnTargetsChange (true);
|
|
|
|
if (showDebugPrint) {
|
|
print ("Adding target " + newCharacter.name);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void removeCharacterAround (Transform newCharacter)
|
|
{
|
|
if (charactersAround.Contains (newCharacter)) {
|
|
charactersAround.Remove (newCharacter);
|
|
|
|
checkRemoveEmptyObjects ();
|
|
|
|
if (showDebugPrint) {
|
|
print ("Removing target " + newCharacter.name);
|
|
}
|
|
}
|
|
|
|
if (charactersAround.Count == 0) {
|
|
checkEventsOnTargetsChange (false);
|
|
|
|
checkEventOnLastTargetRemoved ();
|
|
}
|
|
}
|
|
|
|
public void clearAllCharactersAround ()
|
|
{
|
|
if (charactersAround.Count > 0) {
|
|
charactersAround.Clear ();
|
|
}
|
|
|
|
checkEventsOnTargetsChange (false);
|
|
|
|
checkEventOnLastTargetRemoved ();
|
|
}
|
|
|
|
public void setMatchPositionPausedState (bool state)
|
|
{
|
|
matchPositionPaused = state;
|
|
}
|
|
|
|
public void setMatchSystemEnabledstate (bool state)
|
|
{
|
|
matchSystemEnabled = state;
|
|
}
|
|
|
|
public void setAddMainPlayerOnListForAIState (bool state)
|
|
{
|
|
addMainPlayerOnListForAI = state;
|
|
}
|
|
|
|
public void activateMatchPosition (float customOffset)
|
|
{
|
|
if (!matchSystemEnabled) {
|
|
return;
|
|
}
|
|
|
|
if (matchPositionPaused) {
|
|
return;
|
|
}
|
|
|
|
if (!playerCheckInitialized) {
|
|
if (matchSystemEnabled && addMainPlayerOnListForAI) {
|
|
findPlayerOnScene ();
|
|
}
|
|
|
|
playerCheckInitialized = true;
|
|
}
|
|
|
|
if (debugTargetToMatchTransform != null) {
|
|
activateMatchPosition (debugTargetToMatchTransform, customOffset);
|
|
|
|
return;
|
|
}
|
|
|
|
Transform transformToMatchPosition = getCurrentTargetToMatchPosition ();
|
|
|
|
if (transformToMatchPosition != null) {
|
|
activateMatchPosition (transformToMatchPosition, customOffset);
|
|
|
|
if (showDebugPrint) {
|
|
print ("activating match position for " + transformToMatchPosition.name);
|
|
}
|
|
} else {
|
|
if (showDebugPrint) {
|
|
print ("no target to match found");
|
|
}
|
|
}
|
|
|
|
if (charactersAround.Count == 0) {
|
|
checkEventsOnTargetsChange (false);
|
|
|
|
checkEventOnLastTargetRemoved ();
|
|
}
|
|
}
|
|
|
|
public void activateMatchPosition (Transform targetToUse, float customOffset)
|
|
{
|
|
stopMovement ();
|
|
|
|
if (targetToUse == null) {
|
|
return;
|
|
}
|
|
|
|
movementCoroutine = StartCoroutine (activateMatchPositionCoroutine (targetToUse, customOffset));
|
|
}
|
|
|
|
public void stopMovement ()
|
|
{
|
|
if (movementCoroutine != null) {
|
|
StopCoroutine (movementCoroutine);
|
|
}
|
|
|
|
movementActive = false;
|
|
}
|
|
|
|
public void setUseFrontPositionAsPositionToMatchState (bool state)
|
|
{
|
|
useFrontPositionAsPositionToMatch = state;
|
|
}
|
|
|
|
IEnumerator activateMatchPositionCoroutine (Transform targetToUse, float customOffset)
|
|
{
|
|
movementActive = true;
|
|
|
|
Vector3 targetToUsePosition = targetToUse.position;
|
|
|
|
if (useFrontPositionAsPositionToMatch) {
|
|
targetToUsePosition += targetToUse.right * frontPositionAsPositionToMatchOffset.x +
|
|
targetToUse.up * frontPositionAsPositionToMatchOffset.y +
|
|
targetToUse.forward * frontPositionAsPositionToMatchOffset.z;
|
|
}
|
|
|
|
Vector3 currentPosition = playerTransform.position;
|
|
|
|
Vector3 direction = new Vector3 (targetToUsePosition.x, currentPosition.y, targetToUsePosition.z) - currentPosition;
|
|
|
|
direction = direction / direction.magnitude;
|
|
|
|
float angle = Vector3.SignedAngle (playerTransform.forward, direction, playerTransform.up);
|
|
|
|
if (useFrontPositionAsPositionToMatch) {
|
|
angle = Vector3.SignedAngle (playerTransform.forward, -targetToUse.forward, playerTransform.up);
|
|
}
|
|
|
|
float distanceToTarget = GKC_Utils.distance (targetToUsePosition, currentPosition);
|
|
|
|
float currentPositionOffset = positionOffset;
|
|
|
|
if (useFrontPositionAsPositionToMatch) {
|
|
currentPositionOffset = customOffset;
|
|
} else {
|
|
if (customOffset != 0 && !ignoreCustomPositionOffset) {
|
|
currentPositionOffset = customOffset;
|
|
} else {
|
|
if (useDistancePercentageAsOffset) {
|
|
currentPositionOffset = distanceToTarget * positionOffsetPercentage;
|
|
}
|
|
}
|
|
|
|
float targetToUseRadius = GKC_Utils.getCharacterRadius (targetToUse);
|
|
|
|
currentPositionOffset += mainPlayerController.getCharacterRadius () + targetToUseRadius;
|
|
}
|
|
|
|
if (adjustVerticalPositionEnabled) {
|
|
direction = targetToUsePosition - currentPosition;
|
|
|
|
direction = direction / direction.magnitude;
|
|
}
|
|
|
|
Vector3 targetPosition = currentPosition + direction * (distanceToTarget - currentPositionOffset);
|
|
|
|
if (showDebugPrint) {
|
|
print (targetPosition + " " + currentPosition + " " + currentPositionOffset);
|
|
}
|
|
|
|
if (adjustVerticalPositionEnabled) {
|
|
|
|
RaycastHit hit;
|
|
|
|
if (Physics.Raycast (targetPosition + playerTransform.up * 1.2f, -playerTransform.up, out hit, raycastDistanceForVerticalPosition, layerMaskForVerticalPosition)) {
|
|
targetPosition = hit.point;
|
|
}
|
|
}
|
|
|
|
Quaternion targetRotation = Quaternion.Euler (playerTransform.eulerAngles + playerTransform.up * angle);
|
|
|
|
bool targetReached = false;
|
|
|
|
float angleDifference = 0;
|
|
|
|
float positionDifference = 0;
|
|
|
|
float t = 0;
|
|
|
|
float movementTimer = 0;
|
|
|
|
float dist = GKC_Utils.distance (targetPosition, currentPosition);
|
|
|
|
float duration = dist / matchSpeed;
|
|
|
|
bool positionChangeActive = false;
|
|
|
|
bool rotationChangeActive = false;
|
|
|
|
if (distanceToTarget > minDistanceToMatchPosition && distanceToTarget < maxDistanceToMatchPosition) {
|
|
positionChangeActive = true;
|
|
}
|
|
|
|
if (positionChangeActive ||
|
|
(adjustRotationEvenIfNotMoved && distanceToTarget > minDistanceToMatchRotation && distanceToTarget < maxDistanceToMatchRotation)) {
|
|
|
|
if (Mathf.Abs (angle) > minAngleToMatchRotation && Mathf.Abs (angle) < maxAngleToMatchRotation) {
|
|
rotationChangeActive = true;
|
|
}
|
|
}
|
|
|
|
while (!targetReached) {
|
|
t += Time.deltaTime / duration;
|
|
|
|
if (positionChangeActive) {
|
|
playerTransform.position = Vector3.Lerp (playerTransform.position, targetPosition, t);
|
|
}
|
|
|
|
if (rotationChangeActive) {
|
|
playerTransform.rotation = Quaternion.Lerp (playerTransform.rotation, targetRotation, t);
|
|
}
|
|
|
|
angleDifference = Quaternion.Angle (playerTransform.rotation, targetRotation);
|
|
|
|
positionDifference = GKC_Utils.distance (playerTransform.position, targetPosition);
|
|
|
|
movementTimer += Time.deltaTime;
|
|
|
|
if (positionChangeActive && rotationChangeActive) {
|
|
if (positionDifference < 0.01f && angleDifference < 0.2f) {
|
|
targetReached = true;
|
|
}
|
|
} else {
|
|
if (rotationChangeActive) {
|
|
if (angleDifference < 0.2f) {
|
|
targetReached = true;
|
|
}
|
|
}
|
|
|
|
if (positionChangeActive) {
|
|
if (positionDifference < 0.01f) {
|
|
targetReached = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (movementTimer > (duration + 1)) {
|
|
targetReached = true;
|
|
}
|
|
|
|
if (!positionChangeActive && !rotationChangeActive) {
|
|
targetReached = true;
|
|
}
|
|
|
|
yield return null;
|
|
}
|
|
|
|
movementActive = false;
|
|
}
|
|
|
|
public Transform getCurrentTargetToMatchPosition ()
|
|
{
|
|
if (!matchSystemEnabled) {
|
|
return null;
|
|
}
|
|
|
|
if (matchPositionPaused) {
|
|
return null;
|
|
}
|
|
|
|
if (!playerCheckInitialized) {
|
|
if (matchSystemEnabled && addMainPlayerOnListForAI) {
|
|
findPlayerOnScene ();
|
|
}
|
|
|
|
playerCheckInitialized = true;
|
|
}
|
|
|
|
float maxDistanceToTarget = Mathf.Infinity;
|
|
|
|
Transform transformToMatchPosition = null;
|
|
|
|
float currentDistance = 0;
|
|
|
|
float currentDistanceToScreenCenter = 0;
|
|
|
|
centerScreen = mainPlayerCamera.getScreenCenter ();
|
|
|
|
bool ignoreRestOfChecks = false;
|
|
|
|
float maxAngleWithTarget = Mathf.Infinity;
|
|
|
|
currentPlayerPosition = playerTransform.position;
|
|
|
|
Transform currentLockedCameraTransform = mainPlayerCamera.getCurrentLockedCameraTransform ();
|
|
|
|
if (mainCamera == null) {
|
|
mainCamera = mainPlayerCamera.getMainCamera ();
|
|
}
|
|
|
|
for (int i = charactersAround.Count - 1; i >= 0; i--) {
|
|
if (charactersAround [i] != null) {
|
|
if (!applyDamage.checkIfDead (charactersAround [i].gameObject)) {
|
|
|
|
characterPosition = charactersAround [i].position;
|
|
|
|
if (getClosestTargetWithoutConditionsActive) {
|
|
currentDistance = GKC_Utils.distance (characterPosition, currentPlayerPosition);
|
|
|
|
if (currentDistance < maxDistanceToTarget) {
|
|
maxDistanceToTarget = currentDistance;
|
|
|
|
transformToMatchPosition = charactersAround [i];
|
|
}
|
|
} else {
|
|
screenPoint = mainCamera.WorldToScreenPoint (characterPosition);
|
|
currentDistanceToScreenCenter = GKC_Utils.distance (screenPoint, centerScreen);
|
|
|
|
bool canBeChecked = false;
|
|
|
|
if (useMoveInputAsDirectionToClosestTarget) {
|
|
Vector2 rawAxisvalues = mainPlayerInputManager.rawMovementAxis;
|
|
|
|
if (rawAxisvalues != Vector2.zero) {
|
|
Vector3 direction = new Vector3 (characterPosition.x, currentPlayerPosition.y, characterPosition.z) - currentPlayerPosition;
|
|
|
|
direction = direction / direction.magnitude;
|
|
|
|
Vector3 inputDirection = Vector3.zero;
|
|
|
|
if (mainPlayerCamera.isCameraTypeFree ()) {
|
|
inputDirection = (rawAxisvalues.y * mainPlayerCamera.transform.forward + rawAxisvalues.x * mainPlayerCamera.transform.right);
|
|
} else {
|
|
inputDirection = (rawAxisvalues.y * currentLockedCameraTransform.forward + rawAxisvalues.x * currentLockedCameraTransform.right);
|
|
}
|
|
|
|
inputDirection.Normalize ();
|
|
|
|
float angle = Vector3.SignedAngle (inputDirection, direction, playerTransform.up);
|
|
|
|
ignoreRestOfChecks = true;
|
|
|
|
if (Mathf.Abs (angle) < maxAngleWithTarget) {
|
|
maxAngleWithTarget = Mathf.Abs (angle);
|
|
|
|
transformToMatchPosition = charactersAround [i];
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!ignoreRestOfChecks) {
|
|
//unity takes the resolution of the main screen if the press or input is done on
|
|
//the editor it self, instead of taking the resolution of the game window
|
|
|
|
if (useMaxDistanceToCameraCenter && mainPlayerCamera.isCameraTypeFree ()) {
|
|
if (currentDistanceToScreenCenter < maxDistanceToCameraCenter) {
|
|
canBeChecked = true;
|
|
}
|
|
} else {
|
|
canBeChecked = true;
|
|
}
|
|
|
|
if (checkMaxVerticalDistanceWithTarget) {
|
|
float verticalDistance = Mathf.Abs (characterPosition.y - currentPlayerPosition.y);
|
|
|
|
if (verticalDistance > maxVerticalDistanceWithTarget) {
|
|
canBeChecked = false;
|
|
|
|
if (showDebugPrint) {
|
|
print ("vertical distance too long " + verticalDistance);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (checkIfObstaclesToTarget) {
|
|
RaycastHit hit;
|
|
|
|
Vector3 raycastPosition = currentPlayerPosition + playerTransform.up;
|
|
|
|
Vector3 targetPosition = charactersAround [i].position + charactersAround [i].up;
|
|
|
|
Vector3 raycastDirection = raycastPosition - targetPosition;
|
|
raycastDirection = raycastDirection / raycastDirection.magnitude;
|
|
|
|
float raycastDistance = GKC_Utils.distance (raycastPosition, targetPosition);
|
|
|
|
if (Physics.Raycast (raycastPosition, raycastDirection, out hit, raycastDistance, layerToCheckTarget)) {
|
|
canBeChecked = false;
|
|
|
|
if (showDebugPrint) {
|
|
print ("obstacle detected " + hit.collider.name);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (canBeChecked) {
|
|
currentDistance = GKC_Utils.distance (characterPosition, currentPlayerPosition);
|
|
|
|
if (currentDistance < maxDistanceToTarget) {
|
|
maxDistanceToTarget = currentDistance;
|
|
|
|
transformToMatchPosition = charactersAround [i];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
charactersAround.RemoveAt (i);
|
|
}
|
|
} else {
|
|
charactersAround.RemoveAt (i);
|
|
}
|
|
}
|
|
|
|
return transformToMatchPosition;
|
|
}
|
|
|
|
void checkEventsOnTargetsChange (bool state)
|
|
{
|
|
if (useEventsOnTargetsChange) {
|
|
if (state) {
|
|
eventOnTargetsDetected.Invoke ();
|
|
} else {
|
|
eventOnTargetsRemoved.Invoke ();
|
|
}
|
|
}
|
|
}
|
|
|
|
void checkEventOnFirstTargetDetected ()
|
|
{
|
|
if (useEventOnFirstTargetDetected) {
|
|
eventOnFirstTargetDetected.Invoke ();
|
|
}
|
|
}
|
|
|
|
void checkEventOnLastTargetRemoved ()
|
|
{
|
|
if (useEventOnLastTargetRemoved) {
|
|
eventOnLastTargetRemoved.Invoke ();
|
|
}
|
|
}
|
|
|
|
void checkRemoveEmptyObjects ()
|
|
{
|
|
for (int i = charactersAround.Count - 1; i >= 0; i--) {
|
|
if (charactersAround [i] == null) {
|
|
charactersAround.RemoveAt (i);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void setGetClosestTargetWithoutConditionsActiveState (bool state)
|
|
{
|
|
getClosestTargetWithoutConditionsActive = state;
|
|
}
|
|
} |