332 lines
11 KiB
C#
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);
|
|
}
|
|
}
|
|
} |