sea-battle/Assets/Scripts/GamePole.cs

624 lines
18 KiB
C#

using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;
public class GamePole : MonoBehaviour
{
public GameManager gameManager;
public GameObject eLiters, eNums, ePole;
public GameObject[] ShipMass;
private List<GameObject> placedShips = new List<GameObject>();
public bool IsReady { get; private set; } = false;
GameObject[] Liters;
GameObject[] Nums;
public GameObject[,] Pole;
public int LengPole = 10;
public int[,] PoleShot; // 0 - íå ñòðåëÿë 1 - ïðîìàõ 2 - ðàíèë 3 - óíè÷òîæåí
public int[,] FreePole; // ïîëå äëÿ ðàñòîíîâêè êîðàáëåé
public Material hitMaterial;
private GameObject ghostShip = null;
private int ghostShipIndex = -1;
private int currentShipIndex = 0;
private int shipCaunt = 10;
public GameObject[] missEffectPrefabs; // ïðîìàõ
void Awake()
{
PoleShot = new int[LengPole, LengPole];
FreePole = new int[LengPole, LengPole];
if (gameManager == null)
gameManager = GetComponentInParent<GameManager>();
}
void Start()
{
CreatePole();
}
public Cell GetCell(int x, int y)
{
// Ïðîâåðÿåì, ÷òî ïîëå óæå ñîçäàíî
if (Pole == null) return null;
// Ïðîâåðÿåì êîððåêòíîñòü êîîðäèíàò
if (x < 0 || x >= LengPole || y < 0 || y >= LengPole) return null;
GameObject cellObject = Pole[x, y];
if (cellObject == null) return null;
return cellObject.GetComponent<Cell>();
}
public List<GameObject> GetPlacedShips()
{
return placedShips;
}
void CreatePole()
{
Vector3 StartPoze = transform.position;
float XX = 1; // òåïåðü áóäåì èñïîëüçîâàòü ëîêàëüíûå êîîðäèíàòû
float ZZ = -1;
Liters = new GameObject[LengPole];
Nums = new GameObject[LengPole];
for (int Nadpis = 0; Nadpis < LengPole; Nadpis++)
{
// --- Áóêâû ---
Liters[Nadpis] = Instantiate(eLiters, transform); // äåëàåì äî÷åðíèì
Liters[Nadpis].transform.localPosition = new Vector3(XX, 0, 0);
Liters[Nadpis].GetComponent<Chanks>().Index = Nadpis;
XX++;
// --- Öèôðû ---
Nums[Nadpis] = Instantiate(eNums, transform); // äåëàåì äî÷åðíèì
Nums[Nadpis].transform.localPosition = new Vector3(0, 0, ZZ);
Nums[Nadpis].GetComponent<Chanks>().Index = Nadpis;
ZZ--;
}
XX = 1;
ZZ = -1;
Pole = new GameObject[LengPole, LengPole];
for (int Z = 0; Z < LengPole; Z++)
{
for (int X = 0; X < LengPole; X++)
{
Pole[X, Z] = Instantiate(ePole, transform); // äåëàåì äî÷åðíèì
Pole[X, Z].transform.localPosition = new Vector3(XX, 0, ZZ);
XX++;
}
XX = 1;
ZZ--;
}
}
public List<(int x, int y)> GetAvailableShots() // ïîëó÷àåì äîñòóïíûå äëÿ âûñòðåëà ïîëÿ
{
var available = new List<(int, int)>();
for (int x = 0; x < LengPole; x++)
{
for (int y = 0; y < LengPole; y++)
{
if (PoleShot[x, y] == 0)
available.Add((x, y));
}
}
return available;
}
public int[] SearchWreckedShip() // èùåì êîðàáëè âàîêðóã
{
for (int x = 0; x < LengPole; x++)
{
for (int y = 0; y < LengPole; y++)
{
if (PoleShot[x, y] == 2)
{
// Ïðîâåðÿåì êëåòêè âîêðóã
if (HasFreeAdjacent( x, y))
return new int[] { x, y };
}
}
}
return null;
}
private bool HasFreeAdjacent( int x, int y)
{
int[,] dirs = { { -1, 0 }, { 1, 0 }, { 0, -1 }, { 0, 1 } };
foreach (var i in new int[] { 0, 1, 2, 3 })
{
int dx = x + dirs[i, 0];
int dy = y + dirs[i, 1];
if (dx >= 0 && dx < LengPole && dy >= 0 && dy < LengPole)
{
if (PoleShot[dx, dy] == 0)
return true;
}
}
return false;
}
public bool Shot(int x, int y)
{
if (PoleShot[x, y] != 0) return true; // çàòû÷êà
bool hit = Pole[x, y].GetComponent<Cell>().hit();
if (hit)
{
var cell = Pole[x, y].GetComponent<Cell>();
if (cell != null && cell.deck != null)
{
PoleShot[x, y] = 2;
gameManager.playerCamera.GetComponent<CameraShake>().Shake(0.3f, 0.2f);
var ship = cell.deck.GetComponentInParent<Ship>();
if (ship != null && ship.IsDestroyed())
{
HitAroundShip(ship);
ship.Destroy();
bool isPlayer = this == gameManager.playerField;
// gameManager.ShipDestroyed(isPlayer);
}
}
}
else
{
PoleShot[x, y] = 1;
if (missEffectPrefabs != null && missEffectPrefabs.Length > 0)
{
Vector3 spawnPos = Pole[x, y].transform.position;
// âûáèðàåì ñëó÷àéíûé ýëåìåíò
GameObject prefab = missEffectPrefabs[Random.Range(0, missEffectPrefabs.Length)];
if (prefab != null)
{
GameObject effect = Instantiate(prefab, spawnPos, Quaternion.identity);
// Àâòîìàòè÷åñêè óíè÷òîæàåì ÷åðåç 2 ñåêóíäû
Destroy(effect, 2f);
}
}
if (EffectManager.Instance != null)
{
Vector3 basePos = Pole[x, y].transform.position;
// Ñëó÷àéíîå ñìåùåíèå: ïî Y îò 5 äî 10, ïî X îò -1 äî 1
float randomY = Random.Range(7f, 14f);
float randomX = Random.Range(-2f, 2f);
Vector3 spawnPos = basePos + new Vector3(randomX, randomY, 0f);
GameObject textFx = EffectManager.Instance.PlayMissText(spawnPos);
if (textFx != null)
{
// Ñëó÷àéíûé ìàñøòàá äëÿ ðàçíîîáðàçèÿ
float scale = Random.Range(3f, 4f);
textFx.transform.localScale *= scale;
}
}
}
return hit;
}
// îáâäèì êîðàáëü
void HitAroundShip(Ship ship)
{
foreach (var coord in ship.deckCoords)
{
for (int dx = -1; dx <= 1; dx++)
{
for (int dy = -1; dy <= 1; dy++)
{
int nx = coord.x + dx;
int ny = coord.y + dy;
if (nx >= 0 && nx < LengPole && ny >= 0 && ny < LengPole)
{
if (dx == 0 && dy == 0)
{
PoleShot[nx, ny] = 3; // êîðàáëü óáèò
continue;
}
var cell = Pole[nx, ny].GetComponent<Cell>();
if (cell != null)
{
PoleShot[nx, ny] = 1;
cell.hit();
}
}
}
}
}
}
public void ClearPole()
{
ClearGhost();
foreach (var ship in placedShips)
{
if (ship != null)
Destroy(ship);
}
placedShips.Clear();
currentShipIndex = 0;
IsReady = false;
for (int x = 0; x < LengPole; x++)
{
for (int y = 0; y < LengPole; y++)
{
if (Pole[x, y] != null)
{
var cell = Pole[x, y].GetComponent<Cell>();
if (cell != null)
{
cell.deck = null;
cell.HideAll();
}
}
FreePole[x, y] = 0;
PoleShot[x, y] = 0;
}
}
}
// ïðîâåðÿåìñ ñâîáîäíû ëè êëåòêè
bool CanPlaceShip(int[,] field, int start_x, int start_y, int length, Direction dir)
{
int dx = 0, dy = 0;
switch (dir)
{
case Direction.Left: dx = -1; break;
case Direction.Right: dx = 1; break;
case Direction.Up: dy = -1; break;
case Direction.Down: dy = 1; break;
}
for (int i = 0; i < length; i++)
{
int x = start_x + dx * i;
int y = start_y + dy * i;
if (x < 0 || x >= LengPole || y < 0 || y >= LengPole) return false;
if (field[x, y] != 0) return false;
}
return true;
}
public bool PlaceShipManual(int x, int y, Direction direction)
{
if (currentShipIndex >= shipCaunt)
return false;
GameObject shipPrefab = ShipMass[currentShipIndex];
int size = shipPrefab.GetComponent<Ship>().decks.Count;
if (!CanPlaceShip(FreePole, x, y, size, direction))
return false;
GameObject ship = Instantiate(shipPrefab, transform);
ship.SetActive(true);
// Ïîâîðîò
switch (direction)
{
case Direction.Left: ship.transform.localRotation = Quaternion.Euler(0, 0, 0); break;
case Direction.Right: ship.transform.localRotation = Quaternion.Euler(0, 180, 0); break;
case Direction.Up: ship.transform.localRotation = Quaternion.Euler(0, 90, 0); break;
case Direction.Down: ship.transform.localRotation = Quaternion.Euler(0, 270, 0); break;
}
Vector3 basePos = Pole[x, y].transform.localPosition;
ship.transform.localPosition = new Vector3(basePos.x, basePos.y - 0.1f, basePos.z);
int end_x = x + (direction == Direction.Left ? -size + 1 :
direction == Direction.Right ? size - 1 : 0);
int end_y = y + (direction == Direction.Up ? -size + 1 :
direction == Direction.Down ? size - 1 : 0);
PlaceShip(FreePole, ship, x, y, end_x, end_y);
placedShips.Add(ship);
ClearGhost(); // óáèðàåì ïðèçðàê
currentShipIndex++;
return true;
}
public void ShowShipGhost(int x, int y, Direction direction)
{
if(currentShipIndex >= shipCaunt) return;
int size = ShipMass[currentShipIndex].GetComponent<Ship>().decks.Count;
if (!CanPlaceShip(FreePole, x, y, size, direction))
{
if (ghostShip != null) ghostShip.SetActive(false); // ïðîñòî ñêðûâàåì
return;
}
// Åñëè óæå ñîçäàí ïðèçðàê íóæíîãî òèïà — ïðîñòî îáíîâëÿåì ïîçèöèþ
if (ghostShip != null && ghostShipIndex == currentShipIndex)
{
ghostShip.SetActive(true); // âäðóã áûë ñêðûò
}
else
{
if (ghostShip != null)
Destroy(ghostShip);
ghostShip = Instantiate(ShipMass[currentShipIndex], transform);
ghostShipIndex = currentShipIndex;
foreach (Collider col in ghostShip.GetComponentsInChildren<Collider>())
col.enabled = false;
foreach (Renderer renderer in ghostShip.GetComponentsInChildren<Renderer>())
renderer.material.color = new Color(1f, 1f, 1f, 0.3f); // ïîëóïðîçðà÷íûé
}
// Ïîâîðîò
switch (direction)
{
case Direction.Left: ghostShip.transform.localRotation = Quaternion.Euler(0, 0, 0); break;
case Direction.Right: ghostShip.transform.localRotation = Quaternion.Euler(0, 180, 0); break;
case Direction.Up: ghostShip.transform.localRotation = Quaternion.Euler(0, 90, 0); break;
case Direction.Down: ghostShip.transform.localRotation = Quaternion.Euler(0, 270, 0); break;
}
Vector3 basePos = Pole[x, y].transform.localPosition;
ghostShip.transform.localPosition = new Vector3(basePos.x, basePos.y - 0.1f, basePos.z);
}
public void ClearGhost()
{
if (ghostShip != null)
{
Destroy(ghostShip);
ghostShip = null;
ghostShipIndex = -1;
}
}
// ðàñòàâëÿåì êîðàáëè
public void ArrangeShip(bool hideShips = false)
{
ClearPole();
foreach (GameObject shipPrefab in ShipMass)
{
GameObject ship = Instantiate(shipPrefab);
ship.transform.SetParent(this.transform, false);
ship.SetActive(true);
placedShips.Add(ship);
if (hideShips)
{
foreach (Renderer r in ship.GetComponentsInChildren<Renderer>())
r.enabled = false;
}
int quantity = ship.GetComponent<Ship>().decks.Count;
// Ãåíåðèðóåì ñïèñîê âñåõ âîçìîæíûõ ïîçèöèé
List<(int x, int y, Direction dir)> possiblePlacements = new();
for (int x = 0; x < LengPole; x++)
{
for (int y = 0; y < LengPole; y++)
{
foreach (Direction direction in System.Enum.GetValues(typeof(Direction)))
{
if (CanPlaceShip(FreePole, x, y, quantity, direction))
possiblePlacements.Add((x, y, direction));
}
}
}
// Åñëè íåò íè îäíîãî ïîäõîäÿùåãî ìåñòà
if (possiblePlacements.Count == 0)
{
Debug.LogWarning("Íå óäàëîñü ðàçìåñòèòü êîðàáëü, ïåðåçàïóñêàåì ðàññòàíîâêó.");
ArrangeShip(hideShips);
continue;
}
// Ïåðåìåøèâàåì âîçìîæíûå ïîçèöèè
Shuffle(possiblePlacements);
// Áåðåì ïåðâóþ ïîäõîäÿùóþ
var (start_x, start_y, dir) = possiblePlacements[0];
switch (dir)
{
case Direction.Left: ship.transform.localRotation = Quaternion.Euler(0, 0, 0); break;
case Direction.Right: ship.transform.localRotation = Quaternion.Euler(0, 180, 0); break;
case Direction.Up: ship.transform.localRotation = Quaternion.Euler(0, 90, 0); break;
case Direction.Down: ship.transform.localRotation = Quaternion.Euler(0, 270, 0); break;
}
Vector3 basePos = Pole[start_x, start_y].transform.localPosition;
ship.transform.localPosition = new Vector3(basePos.x, basePos.y - 0.1f, basePos.z);
int end_x = start_x + (dir == Direction.Left ? -quantity + 1 :
dir == Direction.Right ? quantity - 1 : 0);
int end_y = start_y + (dir == Direction.Up ? -quantity + 1 :
dir == Direction.Down ? quantity - 1 : 0);
PlaceShip(FreePole, ship, start_x, start_y, end_x, end_y);
}
IsReady = true;
}
void Shuffle<T>(List<T> list)
{
for (int i = list.Count - 1; i > 0; i--)
{
int j = Random.Range(0, i + 1);
(list[i], list[j]) = (list[j], list[i]);
}
}
// òóò ðàñòàâëÿþòñÿ êîðàáëè
void PlaceShip(int[,] FreePole, GameObject ship, int start_x, int start_y, int end_x, int end_y)
{
var decks = ship.GetComponent<Ship>().decks;
int deckIndex = 0;
if (start_x != end_x)
{
int step = start_x < end_x ? 1 : -1;
for (; start_x != end_x + step; start_x += step)
{
SetDeckAndAround(FreePole, start_x, start_y, decks[deckIndex]);
ship.GetComponent<Ship>().AddDeckCoord(start_x, start_y);
deckIndex++;
}
}
else
{
int step = start_y < end_y ? 1 : -1;
for (; start_y != end_y + step; start_y += step)
{
SetDeckAndAround(FreePole, start_x, start_y, decks[deckIndex]);
ship.GetComponent<Ship>().AddDeckCoord(start_x, start_y);
deckIndex++;
}
}
}
// òóò óñòàíàâëèâàåì ïàëóáû è ñâîáîäíîå ïîëå äåëàåì íå ñâîáîäíûì
void SetDeckAndAround(int[,] FreePole, int x, int y, GameObject deck)
{
FreePole[x, y] = 1;
// Ïðèâÿçêà ïàëóáû ê êëåòêå
Pole[x, y].GetComponent<Cell>().deck = deck; // TODU íàäî ïðèäóìàòü ÷òî-òî ïîóìíåå
deck.SetActive(true);
for (int dx = -1; dx <= 1; dx++)
{
for (int dy = -1; dy <= 1; dy++)
{
int nx = x + dx;
int ny = y + dy;
if (nx >= 0 && nx < LengPole && ny >= 0 && ny < LengPole && FreePole[nx, ny] == 0)
{
FreePole[nx, ny] = 2;
}
}
}
}
// òóò êîïèðóåì êîðàáëè
public void CopyShipsFrom(GamePole sourceField, bool hideShips = true)
{
ClearPole();
foreach (var originalShip in sourceField.placedShips)
{
GameObject copy = Instantiate(originalShip);
// Äåëàåì êîïèþ äî÷åðíèì îáúåêòîì òåêóùåãî ïîëÿ
copy.transform.SetParent(this.transform, false);
// Êîïèðóåì ËÎÊÀËÜÍÛÅ êîîðäèíàòû, ÷òîáû êîðàáëè âñòàëè íà ñåòêó ïîëÿ
copy.transform.localPosition = originalShip.transform.localPosition;
copy.transform.localRotation = originalShip.transform.localRotation;
if (hideShips)
{
foreach (Renderer r in copy.GetComponentsInChildren<Renderer>())
r.enabled = false;
}
placedShips.Add(copy);
var ship = copy.GetComponent<Ship>();
var sourceShip = originalShip.GetComponent<Ship>();
for (int i = 0; i < sourceShip.deckCoords.Count; i++)
{
var coord = sourceShip.deckCoords[i];
Pole[coord.x, coord.y].GetComponent<Cell>().deck = ship.decks[i];
ship.AddDeckCoord(coord.x, coord.y);
}
}
IsReady = true;
}
}