2026-01-09 08:45:22 +03:00

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();
}
}
}