296 lines
8.9 KiB
C#
296 lines
8.9 KiB
C#
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
|
|
public class Ship : MonoBehaviour
|
|
{
|
|
public Material hitMaterial;
|
|
public List<GameObject> decks;
|
|
|
|
[Header("Ýôôåêòû âçðûâà")]
|
|
public ParticleSystem[] explosionPrefabs;
|
|
|
|
public float explosionScale = 1f;
|
|
|
|
public List<Vector2Int> deckCoords = new List<Vector2Int>();
|
|
|
|
[Header("Îáëîìêè")]
|
|
public GameObject[] debrisPrefabs;
|
|
public int debrisCount = 3;
|
|
public float spawnRadius = 0.2f;
|
|
public float minExplosionForce = 5f;
|
|
public float maxExplosionForce = 60f;
|
|
|
|
[Header("Ìà÷òû")]
|
|
public Transform mastsContainer;
|
|
public int mastThrowChance = 20; // % øàíñ âûáðîñà
|
|
|
|
[SerializeField] private float mastMass = 30f;
|
|
[SerializeField] private float mastDrag = 0.5f;
|
|
[SerializeField] private float mastAngularDrag = 0.05f;
|
|
|
|
[SerializeField] private float partsLifetime = 5f; // ñåê
|
|
|
|
|
|
[Header("Îðóæèå è ïðî÷åå")]
|
|
public Transform weaponsContainer;
|
|
public Transform otherContainer;
|
|
|
|
public int otherPartsCount = 10;
|
|
|
|
private HashSet<Transform> usedMasts = new HashSet<Transform>();
|
|
|
|
private int playerId = 1;
|
|
|
|
|
|
void Start()
|
|
{
|
|
var wobble = GetComponent<ShipsMuved>();
|
|
if (wobble != null)
|
|
wobble.OnSunk += ExtinguishAllDecks;
|
|
|
|
var player = transform.root.GetComponent<Player>();
|
|
if (player != null)
|
|
playerId = player.PlayerId;
|
|
}
|
|
|
|
private void ExtinguishAllDecks()
|
|
{
|
|
foreach (var deckObj in decks)
|
|
{
|
|
Deck deck = deckObj.GetComponent<Deck>();
|
|
if (deck != null) deck.Extinguish();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
public void AddDeckCoord(int x, int y)
|
|
{
|
|
deckCoords.Add(new Vector2Int(x, y));
|
|
}
|
|
|
|
public void Destroy()
|
|
{
|
|
foreach (Renderer r in GetComponentsInChildren<Renderer>())
|
|
r.enabled = true;
|
|
|
|
ShipsMuved wobble = GetComponent<ShipsMuved>();
|
|
if (wobble != null) wobble.Sink();
|
|
else
|
|
{
|
|
Vector3 newPos = transform.localPosition;
|
|
newPos.y -= 0.2f;
|
|
transform.localPosition = newPos;
|
|
}
|
|
// ìåñòî äëÿ âûçîâà ëåíòû
|
|
|
|
}
|
|
|
|
|
|
public bool IsDestroyed()
|
|
{
|
|
foreach (GameObject deckObj in decks)
|
|
{
|
|
Deck deck = deckObj.GetComponent<Deck>();
|
|
if (deck != null && !deck.isHit) return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public ParticleSystem GetRandomExplosion()
|
|
{
|
|
if (explosionPrefabs != null && explosionPrefabs.Length > 0)
|
|
return explosionPrefabs[Random.Range(0, explosionPrefabs.Length)];
|
|
return null;
|
|
}
|
|
|
|
// =========================
|
|
// ÎÁËÎÌÊÈ
|
|
// =========================
|
|
public void SpawnDebrisAt(Vector3 origin)
|
|
{
|
|
if (debrisPrefabs == null || debrisPrefabs.Length == 0) return;
|
|
|
|
for (int i = 0; i < debrisCount; i++)
|
|
{
|
|
GameObject prefab = debrisPrefabs[Random.Range(0, debrisPrefabs.Length)];
|
|
Vector3 spawnPos = origin + Random.insideUnitSphere * spawnRadius;
|
|
Quaternion spawnRot = Random.rotation;
|
|
|
|
GameObject debris = Instantiate(prefab, spawnPos, spawnRot);
|
|
|
|
Rigidbody rb = debris.GetComponent<Rigidbody>();
|
|
if (rb == null) rb = debris.AddComponent<Rigidbody>();
|
|
rb.isKinematic = false;
|
|
rb.useGravity = true;
|
|
|
|
Vector3 dir = (spawnPos - origin).normalized + Random.insideUnitSphere * 0.5f;
|
|
float force = Random.Range(minExplosionForce, maxExplosionForce);
|
|
rb.AddForce(dir * force, ForceMode.Impulse);
|
|
|
|
Destroy(debris, 5f);
|
|
}
|
|
}
|
|
|
|
// =========================
|
|
// ÌÀ×ÒÛ
|
|
// =========================
|
|
|
|
|
|
|
|
|
|
public void ThrowRandomMast()
|
|
{
|
|
if (mastsContainer == null || mastsContainer.childCount == 0) return;
|
|
|
|
if (Random.Range(0, 100) > mastThrowChance) return;
|
|
|
|
Transform mast = mastsContainer.GetChild(Random.Range(0, mastsContainer.childCount));
|
|
|
|
// Åñëè ìà÷òà óæå îòðûâàëàñü/ïàäàëà — ïðîïóñêàåì
|
|
if (usedMasts.Contains(mast)) return;
|
|
usedMasts.Add(mast);
|
|
|
|
int mode = Random.Range(0, 2); // 0 - õàîòè÷íî óëåòàåò, 1 - ïàäåíèå ïî XZ
|
|
|
|
switch (mode)
|
|
{
|
|
case 0:
|
|
// Õàîòè÷íî îòðûâàåì è óëåòàåì
|
|
Rigidbody rb = mast.GetComponent<Rigidbody>();
|
|
if (rb == null)
|
|
{
|
|
rb = mast.gameObject.AddComponent<Rigidbody>();
|
|
rb.mass = mastMass;
|
|
rb.drag = mastDrag;
|
|
rb.angularDrag = mastAngularDrag;
|
|
}
|
|
|
|
rb.isKinematic = false;
|
|
rb.useGravity = true;
|
|
rb.constraints = RigidbodyConstraints.None;
|
|
|
|
rb.AddForce(Vector3.up * Random.Range(15f, 55f) + Random.insideUnitSphere * 0.5f, ForceMode.Impulse);
|
|
rb.AddTorque(Random.insideUnitSphere * Random.Range(1f, 3f), ForceMode.Impulse);
|
|
break;
|
|
|
|
case 1:
|
|
// Ïàäåíèå â ñëó÷àéíóþ ñòîðîíó â ïëîñêîñòè XZ, íî íå ñòðîãî ïî X
|
|
Vector3 dirXZ;
|
|
do
|
|
{
|
|
dirXZ = new Vector3(Random.Range(-1f, 1f), 0f, Random.Range(-1f, 1f)).normalized;
|
|
}
|
|
while (Vector3.Angle(dirXZ, Vector3.right) < 30f || Vector3.Angle(dirXZ, Vector3.left) < 20f);
|
|
|
|
dirXZ.Normalize();
|
|
|
|
Vector3 fallAxis = Vector3.Cross(Vector3.up, dirXZ).normalized; // îñü âðàùåíèÿ ïåðïåíäèêóëÿðíà íàïðàâëåíèþ ïàäåíèÿ
|
|
StartCoroutine(RotateMastToAngle(mast, Quaternion.AngleAxis(90f, fallAxis), 1f));
|
|
break;
|
|
}
|
|
}
|
|
|
|
private IEnumerator RotateMastToAngle(Transform mast, Quaternion localTargetRotation, float duration)
|
|
{
|
|
Quaternion startRot = mast.rotation;
|
|
Quaternion targetRot = localTargetRotation * startRot;
|
|
float t = 0f;
|
|
|
|
while (t < duration)
|
|
{
|
|
t += Time.deltaTime;
|
|
mast.rotation = Quaternion.Slerp(startRot, targetRot, t / duration);
|
|
yield return null;
|
|
}
|
|
mast.rotation = targetRot; // ÷òîáû òî÷íî âñòàëà íà ìåñòî
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// =========================
|
|
// ÎÐÓÆÈÅ È ÏÐÎ×ÅÅ
|
|
// =========================
|
|
private void ThrowParts(Transform container, int count, Vector3 explosionPos)
|
|
{
|
|
if (container == null || container.childCount == 0) return;
|
|
|
|
List<Transform> parts = new List<Transform>();
|
|
foreach (Transform child in container) parts.Add(child);
|
|
|
|
for (int i = 0; i < count && parts.Count > 0; i++)
|
|
{
|
|
int index = Random.Range(0, parts.Count);
|
|
Transform part = parts[index];
|
|
parts.RemoveAt(index);
|
|
|
|
part.SetParent(null, true);
|
|
|
|
// âèäèìîñòü
|
|
var rend = part.GetComponent<Renderer>();
|
|
if (rend != null) rend.enabled = true;
|
|
|
|
// ôèçèêà
|
|
var rb = part.GetComponent<Rigidbody>();
|
|
if (rb == null) rb = part.gameObject.AddComponent<Rigidbody>();
|
|
rb.isKinematic = false;
|
|
rb.useGravity = true;
|
|
|
|
Vector3 dir = (part.position - explosionPos).normalized + Random.insideUnitSphere * 0.5f;
|
|
rb.AddForce(dir * Random.Range(minExplosionForce, maxExplosionForce), ForceMode.Impulse);
|
|
|
|
Destroy(part.gameObject, partsLifetime);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
public void ThrowWeapons(Vector3 explosionPos, int count) => ThrowParts(weaponsContainer, count, explosionPos);
|
|
public void ThrowOtherParts(Vector3 explosionPos, int count) => ThrowParts(otherContainer, count, explosionPos);
|
|
|
|
// =========================
|
|
// ÂÇÐÛÂ ÏÀËÓÁÛ
|
|
// =========================
|
|
public void ExplodeDeck(Vector3 deckPos)
|
|
{
|
|
GetComponent<ShipsMuved>()?.Shake();
|
|
SpawnDebrisAt(deckPos);
|
|
ThrowWeapons(deckPos, 2);
|
|
ThrowOtherParts(deckPos, 10);
|
|
ThrowRandomMast();
|
|
// Ýôôåêò ïîïàäàíèÿ (íàä ïàëóáîé, ÷óòü âûøå è ñ ðàíäîìíûì ñìåùåíèåì)
|
|
if (EffectManager.Instance != null)
|
|
{
|
|
Vector3 basePos = deckPos;
|
|
|
|
// Ñëó÷àéíîå ñìåùåíèå: ïî Y îò 15 äî 25, ïî X è Z îò -1 äî 1
|
|
float randomY = Random.Range(15f, 25f);
|
|
float randomX = Random.Range(-1f, 1f);
|
|
float randomZ = Random.Range(-1f, 1f);
|
|
|
|
Vector3 hitPos = basePos + new Vector3(randomX, randomY, randomZ);
|
|
GameObject textFx = EffectManager.Instance.PlayHitText(hitPos);
|
|
|
|
if (textFx != null)
|
|
{
|
|
// Ìàñøòàáèðóåì òåêñò ïðîïîðöèîíàëüíî âçðûâó
|
|
textFx.transform.localScale *= explosionScale;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
ParticleSystem prefab = GetRandomExplosion();
|
|
if (prefab != null)
|
|
{
|
|
ParticleSystem ps = Instantiate(prefab, deckPos, Quaternion.identity);
|
|
ps.transform.localScale *= explosionScale; // ìàñøòàáèðóåì òóò
|
|
ps.Play();
|
|
}
|
|
}
|
|
}
|