Files
beyond/Assets/Scripts/Characters/EnemySpawner.cs

171 lines
3.8 KiB
C#

using System.Collections;
using System.Collections.Generic;
using Invector;
using Invector.vCharacterController.AI;
using PixelCrushers;
using UnityEngine;
using UnityEngine.Events;
namespace Beyond
{
public class EnemySpawner : Saver
{
public GameObject m_prefab;
public Transform m_distanceFrom;
//public bool m_distanceFromMainCam;
public float m_spawnCheckInterval = .5f;
public float m_distance = 20f;
public int m_numToSpawn = -1;
public bool m_respawnOnPlayersDeath = true;
public LayerMask raycastMask = 1; //default
private SaveData m_spawnData;
//private bool m_spawned;
private vControlAI m_spawnedAI;
public UnityEvent<EnemySpawner> m_OnDead;
public UnityEvent<EnemySpawner> m_onReceivedDamage;
class SaveData
{
public int numSpawned;
public bool spawned;
}
public override void Awake()
{
#if ENEMIES_DISABLED && UNITY_EDITOR
enabled = false;
return;
#endif
base.Awake();
//m_spawned = false;
m_spawnData = new SaveData();
m_spawnData.numSpawned = 0;
m_spawnData.spawned = false;
}
void OnDestroy()
{
if (m_respawnOnPlayersDeath && Player.Instance != null)
{
var respawner = Player.Instance.GetComponent<Respawner>();
respawner.m_onRespawned.RemoveListener(OnPlayerRespawned);
}
if (m_spawnedAI)
{
m_spawnedAI.onDead.RemoveListener(OnDead);
}
}
public override void Start()
{
base.Start();
if (Player.Instance != null)
m_distanceFrom = Player.Instance.transform;
else
{
m_distanceFrom = Camera.main.transform;
}
if (m_respawnOnPlayersDeath)
{
var respawner = Player.Instance.GetComponent<Respawner>();
respawner.m_onRespawned.AddListener(OnPlayerRespawned);
}
InvokeRepeating("CheckSpawn", m_spawnCheckInterval + (Random.value * m_spawnCheckInterval), m_spawnCheckInterval);
}
void CheckRespawnCondition()
{
if ((m_numToSpawn < 0 || m_numToSpawn > m_spawnData.numSpawned) && m_spawnedAI == null )
m_spawnData.spawned = false;
}
private void OnPlayerRespawned()
{
CheckRespawnCondition();
}
public override string RecordData()
{
return SaveSystem.Serialize(m_spawnData);
}
public override void ApplyData(string s)
{
var data = SaveSystem.Deserialize<SaveData>(s);
if (data != null)
{
m_spawnData = data;
//m_spawned = true;
CheckRespawnCondition();
}
}
public bool SpawnedAndLive()
{
return m_spawnedAI != null;
}
public bool SpawnedAndDead()
{
return m_spawnData.spawned && m_spawnedAI == null;
}
public void Spawn()
{
if (m_prefab == null)
return;
Vector3 pos;
const float RAY_OFFSET = 30f;
const float Y_OFFSET = .1f;
pos = transform.position;
pos.y += RAY_OFFSET;
RaycastHit hit = new RaycastHit();
if (Physics.Raycast(pos, Vector3.down, out hit, 100f, raycastMask))
{
pos.y -= RAY_OFFSET;
if (pos.y < hit.point.y + Y_OFFSET)
{
pos.y = hit.point.y + Y_OFFSET;
}
}
else
{
Debug.LogError("EnemySpawner error: raycast failed");
return;
}
//m_spawned = true;
m_spawnData.spawned = true;
m_spawnData.numSpawned++;
var enemy = Instantiate(m_prefab, pos, transform.rotation, transform);
m_spawnedAI = enemy.GetComponent<vControlAI>();
if (m_spawnedAI)
{
m_spawnedAI.onDead.AddListener(OnDead);
m_spawnedAI.onReceiveDamage.AddListener(OnReceiveDamage);
}
}
private void OnReceiveDamage(vDamage arg0)
{
m_onReceivedDamage?.Invoke(this);
}
private void OnDead(GameObject arg0)
{
m_spawnedAI = null;
m_OnDead?.Invoke(this);
}
public void CheckSpawn(){
if (!m_spawnData.spawned && gameObject.activeInHierarchy && (transform.position - m_distanceFrom.position).sqrMagnitude < m_distance * m_distance){
Spawn();
}
}
}
}