space-shmup/Assets/__Scripts/Enemy_4.cs

160 lines
5.1 KiB
C#
Raw Normal View History

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
2024-03-14 11:56:10 -05:00
/// <summary>
/// Enemy_4 will start offscreen and then pick a random point on screen to
/// move to. Once it has arrived, it will pick another random point and
/// continue until the player has shot it down.
/// </summary>
[System.Serializable]
public class Part {
// These three fields need to be defined in the Inspector pane
public string name;
public float health;
public string[] protectedBy;
[HideInInspector]
public GameObject go;
[HideInInspector]
public Material mat;
}
public class Enemy_4 : Enemy
{
2024-03-14 11:56:10 -05:00
[Header("Set in Inspector: Enemy_4")]
public Part[] parts;
private Vector3 p0, p1; // The two points to interpolate
private float timeStart; // Birth time for this Enemy_4
private float duration = 4; // Duration of movement
void Start()
{
2024-03-14 11:56:10 -05:00
// There is already an initial position chosen by Main.SpawnEnemy()
// so add it to points as the initial p0 & p1
p0 = p1 = pos;
InitMovement();
Transform t;
foreach(Part prt in parts) {
t = transform.Find(prt.name);
if (t != null) {
prt.go = t.gameObject;
prt.mat = prt.go.GetComponent<Renderer>().material;
}
}
}
2024-03-14 11:56:10 -05:00
void InitMovement() {
p0 = p1; // Set p0 to the old p1
// Assign a new on-screen location to p1
float widMinRad = bndCheck.camWidth - bndCheck.radius;
float hgtMinRad = bndCheck.camHeight - bndCheck.radius;
p1.x = Random.Range(-widMinRad, widMinRad);
p1.y = Random.Range(-hgtMinRad, hgtMinRad);
// Reset the time
timeStart = Time.time;
}
public override void Move() {
// This completely overrides Enemy.Move() with a linear interpolation
float u = (Time.time - timeStart) / duration;
if (u >= 1) {
InitMovement();
u = 0;
}
u = 1 - Mathf.Pow(1 - u, 2); // Apply East Out easing to u
pos = (1 - u) * p0 + u*p1; // Simple linear interpolation
}
2024-03-14 18:40:19 -05:00
// These two functions find a Part in parts based on name or GameObject
Part FindPart(string n) {
foreach(Part prt in parts) {
if (prt.name == n) {
return prt;
}
}
return null;
}
Part FindPart(GameObject go) {
foreach(Part prt in parts) {
if (prt.go == go) {
return prt;
}
}
return null;
}
// These functions return true if the Part has been destroyed
bool Destroyed(GameObject go) {
return Destroyed(FindPart(go));
}
bool Destroyed(string n) {
return Destroyed(FindPart(n));
}
bool Destroyed(Part prt) {
if (prt == null) {
return true;
}
return prt.health <= 0;
}
// This changes the color of just one Part to red instead of the whole ship
void ShowLocalizedDamage(Material m) {
m.color = Color.red;
damageDoneTime = Time.time + showDamageDuration;
showingDamage = true;
}
// This will override the OnCollisionEnter that is part of Enemy.cs
void OnCollisionEnter(Collision coll) {
GameObject other = coll.gameObject;
switch (other.tag) {
case "ProjectileHero":
Projectile p = other.GetComponent<Projectile>();
// If this Enemy is off screen, don't damage it.
if (!bndCheck.isOnScreen) {
Destroy(other);
break;
}
// Hurt this Enemy
GameObject goHit = coll.contacts[0].thisCollider.gameObject;
Part prtHit = FindPart(goHit);
if (prtHit == null) {
goHit = coll.contacts[0].otherCollider.gameObject;
prtHit = FindPart(goHit);
}
// Check whether this part is still protected
if (prtHit.protectedBy != null) {
foreach(string s in prtHit.protectedBy) {
// If one of the protecting parts hasn't been destroyed...
if (!Destroyed(s)) {
// ...then don't damage this part yet
Destroy(other);
return;
}
}
}
prtHit.health -= 1;
ShowLocalizedDamage(prtHit.mat);
if (prtHit.health <= 0) {
prtHit.go.SetActive(false);
}
bool allDestroyed = true;
foreach (Part prt in parts) {
if (!Destroyed(prt)) {
allDestroyed = false;
break;
}
}
if (allDestroyed) {
Main.S.ShipDestroyed(this);
Destroy(this.gameObject);
}
Destroy(other);
break;
}
}
}