141 lines
5.8 KiB
C#
141 lines
5.8 KiB
C#
using UnityEngine;
|
|||
|
|
|
||
|
|
namespace Ironspore
|
||
|
|
{
|
||
|
|
public sealed class EnemyUnit : MonoBehaviour
|
||
|
|
{
|
||
|
|
GameSession game;
|
||
|
|
float health, cooldown, age;
|
||
|
|
int type;
|
||
|
|
public void Initialize(GameSession session, int enemyType, GameObject mech, Transform world)
|
||
|
|
{
|
||
|
|
game = session;
|
||
|
|
type = enemyType;
|
||
|
|
health = type == 3 ? 650 : type == 2 ? 140 : 60;
|
||
|
|
var model = Instantiate(mech, transform);
|
||
|
|
model.transform.localScale = Vector3.one * (type == 3 ? 1.7f : type == 0 ? .65f : 1);
|
||
|
|
foreach (var renderer in model.GetComponentsInChildren<Renderer>())
|
||
|
|
renderer.sharedMaterial = WorldFactory.Material(new Color(.5f, .2f, .12f));
|
||
|
|
foreach (var node in model.GetComponentsInChildren<Transform>())
|
||
|
|
node.gameObject.layer = 9;
|
||
|
|
var capsule = gameObject.AddComponent<CapsuleCollider>();
|
||
|
|
capsule.height = type == 3 ? 5.2f : 3;
|
||
|
|
capsule.radius = type == 3 ? 1.5f : .8f;
|
||
|
|
capsule.center = Vector3.up * capsule.height * .5f;
|
||
|
|
WorldFactory.Label(type == 3 ? "world.overseer" : type == 2 ? "world.bulwark" : type == 0 ? "world.skimmer" : "world.sentinel", transform.position + Vector3.up * (capsule.height + 1), new Color(1, .5f, .25f), transform);
|
||
|
|
cooldown = 1 + Random.value;
|
||
|
|
}
|
||
|
|
void Update()
|
||
|
|
{
|
||
|
|
if (!game.InField || game.Paused || game.Trial || !game.World.Player)
|
||
|
|
return;
|
||
|
|
age += Time.deltaTime;
|
||
|
|
Vector3 target = game.World.Player.transform.position + Vector3.up * 1.5f;
|
||
|
|
if (game.World.Escort && game.World.Escort.Health > 0 && Vector3.Distance(transform.position, game.World.Escort.transform.position) < 15)
|
||
|
|
target = game.World.Escort.transform.position;
|
||
|
|
Vector3 flat = target - transform.position;
|
||
|
|
flat.y = 0;
|
||
|
|
if (flat.sqrMagnitude > .1f)
|
||
|
|
transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(flat), Time.deltaTime * 2);
|
||
|
|
float distance = flat.magnitude;
|
||
|
|
if (type != 1 && distance > 10)
|
||
|
|
{
|
||
|
|
Vector3 step = flat.normalized * Time.deltaTime * (type == 3 ? 1.4f : type == 0 ? 2.5f : 1.2f);
|
||
|
|
if (!Physics.Raycast(transform.position + Vector3.up, step.normalized, 1.1f, 1, QueryTriggerInteraction.Ignore))
|
||
|
|
transform.position += step;
|
||
|
|
}
|
||
|
|
if (type == 0)
|
||
|
|
{
|
||
|
|
Vector3 p = transform.position;
|
||
|
|
p.y = 1.8f + Mathf.Sin(age) * .4f;
|
||
|
|
transform.position = p;
|
||
|
|
}
|
||
|
|
cooldown -= Time.deltaTime;
|
||
|
|
if (cooldown <= 0 && distance < 42)
|
||
|
|
{
|
||
|
|
Vector3 origin = transform.position + Vector3.up * (type == 3 ? 3.5f : 2);
|
||
|
|
if (!Physics.Linecast(origin, target, 1, QueryTriggerInteraction.Ignore))
|
||
|
|
{
|
||
|
|
var bolt = WorldFactory.Primitive(PrimitiveType.Sphere, "EnemyBolt", origin, Vector3.one * .3f, new Color(1, .35f, .08f), null, false, true);
|
||
|
|
bolt.AddComponent<EnemyBolt>().Initialize((target - origin).normalized, type == 3 ? 23 : 12);
|
||
|
|
}
|
||
|
|
cooldown = type == 3 ? .7f : type == 1 ? 1.7f : 2.5f;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
public void Damage(float damage)
|
||
|
|
{
|
||
|
|
health -= damage;
|
||
|
|
if (health > 0)
|
||
|
|
return;
|
||
|
|
if (type == 3)
|
||
|
|
game.CompleteTerminal();
|
||
|
|
GameAudio.Cue(95, .15f);
|
||
|
|
Destroy(gameObject);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
public sealed class EnemyBolt : MonoBehaviour
|
||
|
|
{
|
||
|
|
Vector3 direction;
|
||
|
|
float damage, life;
|
||
|
|
public void Initialize(Vector3 travel, float amount)
|
||
|
|
{
|
||
|
|
direction = travel;
|
||
|
|
damage = amount;
|
||
|
|
}
|
||
|
|
void Update()
|
||
|
|
{
|
||
|
|
if (!GameSession.Active || !GameSession.Active.InField)
|
||
|
|
{
|
||
|
|
Destroy(gameObject);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
float distance = Time.deltaTime * 17;
|
||
|
|
if (Physics.SphereCast(transform.position, .12f, direction, out var hit, distance, ~(1 << 9), QueryTriggerInteraction.Ignore))
|
||
|
|
{
|
||
|
|
var pilot = hit.collider.GetComponentInParent<MechPilot>();
|
||
|
|
if (pilot)
|
||
|
|
pilot.Damage(damage);
|
||
|
|
var escort = hit.collider.GetComponentInParent<EscortUnit>();
|
||
|
|
if (escort)
|
||
|
|
escort.Damage(damage);
|
||
|
|
Destroy(gameObject);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
transform.position += direction * distance;
|
||
|
|
life += Time.deltaTime;
|
||
|
|
if (life > 5)
|
||
|
|
Destroy(gameObject);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
public sealed class EscortUnit : MonoBehaviour
|
||
|
|
{
|
||
|
|
GameSession game;
|
||
|
|
public float Health { get; private set; } = 250;
|
||
|
|
public void Initialize(GameSession session)
|
||
|
|
{
|
||
|
|
game = session;
|
||
|
|
Health = game.Run.escortArmor;
|
||
|
|
WorldFactory.Label("world.escort", transform.position + Vector3.up * 3, Color.cyan, transform);
|
||
|
|
}
|
||
|
|
void Update()
|
||
|
|
{
|
||
|
|
if (!game.InField || game.Paused || Health <= 0 || game.Run.routeCompleted)
|
||
|
|
return;
|
||
|
|
if (Vector3.Distance(game.World.Player.transform.position, transform.position) < 14)
|
||
|
|
transform.position += Vector3.forward * Time.deltaTime * 1.5f;
|
||
|
|
if (transform.position.z >= 33)
|
||
|
|
game.CompleteTerminal();
|
||
|
|
}
|
||
|
|
public void Damage(float amount)
|
||
|
|
{
|
||
|
|
Health = Mathf.Max(0, Health - amount);
|
||
|
|
game.Run.escortArmor = Health;
|
||
|
|
if (Health <= 0)
|
||
|
|
{
|
||
|
|
game.Store.Commit(s => true);
|
||
|
|
game.Notify("notice.escortLost");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|