Files
beyond/Assets/Scripts/Effects/WonderingShadow.cs
2024-11-20 15:21:28 +01:00

332 lines
11 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using Invector.vCharacterController.AI;
using PixelCrushers.DialogueSystem;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
using Random = UnityEngine.Random;
namespace Beyond
{
public class WonderingShadow : MonoBehaviour
{
public enum Mode
{
DESTROY_ON_TARGET,
DESTROY_WHEN_NEAR,
WONDER
}
public enum State
{
STARTING,
MOVING,
STOPPING,
IDLE,
GONE
};
[Serializable]
public class ShadowData
{
public GameObject objectToSpawn;
public float spawnedObjectYOffset = 0.1f;
public Mode mode = Mode.DESTROY_WHEN_NEAR;
public float distanceToDestroy = 7f;
public LayerMask spawnedObjectRayMask = ~0;
public Vector3 targetPosition;
public UnityEvent<GameObject> OnDead;
}
public ShadowData m_shadowData = new ShadowData();
public UnityEvent<State> m_OnStateChanged = new UnityEvent<State>();
public GameObject m_endEffect;
public float m_endEffectDestroyDelay = 7f;
private State m_state;
private const float MinDistance = 0.15f;
// public float Distance = 30;
public float Speed = 1;
public float TimeDelay = 0;
public float m_StartStopDelay = 1f;
public float RandomMoveRadius = 0;
public float RandomMoveSpeedScale = 0;
private Vector3 startPosition;
private Vector3 startPositionLocal;
private Transform t;
private Vector3 oldPos;
private Quaternion startQuaternion;
//private float currentSpeed;
private float currentDelay;
private bool isInitialized;
private int dropFirstFrameForFixUnityBugWithParticles = 3;
private Vector3 randomTimeOffset;
private float m_timer;
public ParticleSystem[] m_particlesToReset;
private ShadowArea m_shadowArea;
public void ResetParticles()
{
foreach (ParticleSystem p in m_particlesToReset)
{
p.Clear();
p.time = 0;
p.Simulate(0, true, true);
p.Play();
}
}
private void Start()
{
t = transform;
SetState(State.STARTING);
m_shadowArea = gameObject.FindComponentUpHierarchy<ShadowArea>();
Initialize(false);
}
private void Initialize(bool setTarget)
{
if (setTarget)
{
if (m_shadowArea != null)
{
m_shadowData.targetPosition = m_shadowArea.GetRandomPosition();
}
else
{
//if there is no area, just come back to starting location
m_shadowData.targetPosition = startPosition;
}
}
startQuaternion = t.rotation;
startPositionLocal = t.localPosition;
startPosition = t.position;
oldPos = startPosition;
//currentSpeed = Speed;
currentDelay = 0;
//dropFirstFrameForFixUnityBugWithParticles = 3;
randomTimeOffset = Random.insideUnitSphere * 10;
//isInitialized = true;
}
public void SpawnEndEffect()
{
if (m_endEffect == null)
return;
var instance = Instantiate(m_endEffect, transform.position, transform.rotation);
Destroy(instance, m_endEffectDestroyDelay);
}
public void SpawnEndObject()
{
if (m_shadowData.objectToSpawn == null)
return;
Vector3 pos = transform.position;
RaycastHit hit = new RaycastHit();
if (Physics.Raycast(pos, Vector3.down, out hit, 100f, m_shadowData.spawnedObjectRayMask))
{
pos.y = hit.point.y + m_shadowData.spawnedObjectYOffset;
}
var rotation = Quaternion.LookRotation(transform.rotation * Vector3.forward, Vector3.up);
var instance = Instantiate(m_shadowData.objectToSpawn, pos, rotation);
var spawnedAI = instance.GetComponent<vControlAI>();
if (spawnedAI)
{
spawnedAI.onDead.AddListener(OnKilled);
}
if (Player.Instance != null)
{
Vector3 toPlayer = Player.Instance.transform.position - pos;
toPlayer.y = 0f;
rotation = Quaternion.LookRotation(transform.rotation * toPlayer, Vector3.up);
instance.transform.rotation = rotation;
}
}
public void OnKilled(GameObject go)
{
m_shadowData.OnDead?.Invoke(go);
}
private void SetState(State state)
{
switch (state)
{
case State.IDLE:
break;
case State.STARTING:
//t.position = m_area.GetRandomPosition();
//m_targetPosition = m_area.GetRandomPosition();
//ResetParticles();
//ActivateEffects(true);
// Initialize();
//Initialize();
//SetState(State.MOVING);
break;
case State.STOPPING:
// SetState(State.STARTING);
break;
case State.MOVING:
break;
case State.GONE:
SpawnEndEffect();
SpawnEndObject();
// Destroy(gameObject);
gameObject.SetActive(false);
break;
}
m_state = state;
m_timer = 0f;
m_OnStateChanged?.Invoke(state);
}
private void Update()
{
switch (m_state)
{
case State.MOVING:
if (dropFirstFrameForFixUnityBugWithParticles <= 0)
{
UpdateWorldPosition();
}
else
{
dropFirstFrameForFixUnityBugWithParticles--;
}
break;
case State.STARTING:
if (m_timer > m_StartStopDelay)
{
SetState(State.MOVING);
}
break;
case State.STOPPING:
if (m_timer > m_StartStopDelay)
{
//ResetParticles();
//ActivateEffects(false);
if (m_shadowData.mode != Mode.DESTROY_ON_TARGET)
{
Initialize(true);
SetState(State.STARTING);
}
else
{
SetState(State.GONE);
}
}
break;
case State.IDLE:
break;
}
m_timer += Time.deltaTime;
}
/*
private void LateUpdate()
{
if (dropFirstFrameForFixUnityBugWithParticles > 0)
{
Initialize();
}
}
*/
private void UpdateWorldPosition()
{
currentDelay += Time.deltaTime;
if (currentDelay < TimeDelay)
return;
Vector3 randomOffset = Vector3.zero;
if (RandomMoveRadius > 0)
{
randomOffset = GetRadiusRandomVector() * RandomMoveRadius;
var fade = Vector3.Distance(t.position, m_shadowData.targetPosition) /
Vector3.Distance(startPosition, m_shadowData.targetPosition);
randomOffset *= fade;
}
var frameMoveOffset = Vector3.zero;
var frameMoveOffsetWorld = Vector3.zero;
//if (!isCollided && !isOutDistance)
{
//currentSpeed = Mathf.Clamp(currentSpeed - Speed*Dampeen*Time.deltaTime, MinSpeed, Speed);
if (m_shadowData.targetPosition == null)
{
var currentForwardVector = (Vector3.forward + randomOffset) * Speed * Time.deltaTime;
frameMoveOffset = t.localRotation * currentForwardVector;
frameMoveOffsetWorld = startQuaternion * currentForwardVector;
}
else
{
var forwardVec = (m_shadowData.targetPosition - t.position).normalized;
var currentForwardVector = (forwardVec + randomOffset) * Speed * Time.deltaTime;
frameMoveOffset = currentForwardVector;
frameMoveOffsetWorld = currentForwardVector;
}
}
var currentDistance = (t.localPosition + frameMoveOffset - startPositionLocal).magnitude;
var targetDistance = (t.position + frameMoveOffset - m_shadowData.targetPosition).magnitude;
Debug.DrawRay(t.position, frameMoveOffsetWorld.normalized * (currentDistance));
if (targetDistance < MinDistance + frameMoveOffset.magnitude)
{
SetState((State.STOPPING));
}
else if (m_shadowData.mode == Mode.DESTROY_WHEN_NEAR)
{
if (Player.Instance == null)
return;
var dist = Vector3.Distance(Player.Instance.transform.position, t.position);
if (dist < m_shadowData.distanceToDestroy)
{
SetState(State.GONE);
}
}
t.position = oldPos + frameMoveOffsetWorld;
oldPos = t.position;
}
private Vector3 GetRadiusRandomVector()
{
var x = Time.time * RandomMoveSpeedScale + randomTimeOffset.x;
var vecX = Mathf.Sin(x / 7 + Mathf.Cos(x / 2)) * Mathf.Cos(x / 5 + Mathf.Sin(x));
x = Time.time * RandomMoveSpeedScale + randomTimeOffset.y;
var vecY = Mathf.Cos(x / 8 + Mathf.Sin(x / 2)) * Mathf.Sin(Mathf.Sin(x / 1.2f) + x * 1.2f);
x = Time.time * RandomMoveSpeedScale + randomTimeOffset.z;
var vecZ = Mathf.Cos(x * 0.7f + Mathf.Cos(x * 0.5f)) * Mathf.Cos(Mathf.Sin(x * 0.8f) + x * 0.3f);
return new Vector3(vecX, vecY, vecZ);
}
}
}