HuePuzzle/Assets/Scripts/GameManager.cs
2025-11-21 16:12:41 +09:00

242 lines
7.9 KiB
C#

using UnityEngine;
using System.Collections;
using UnityEngine.EventSystems;
public class GameManager : MonoBehaviour
{
public static GameManager Instance;
public LevelGenerator levelGenerator;
public UIManager uiManager; // UI 매니저 연결
public bool isAnimating = false;
// 현재 진행 중인 레벨 인덱스
private int currentLevelIndex = 1;
private const int MAX_LEVEL = 100; // 최대 레벨
// 드래그 관련 변수
private TileController currentDraggedTile;
private Vector3 dragStartPos; // 드래그 시작 전 원래 위치
public LevelData testLevelData;
public bool isGameOver = false;
void Awake() { Instance = this; }
void Start()
{
LoadLevel(currentLevelIndex);
}
public void LoadLevel(int index)
{
currentLevelIndex = index;
// Resources 폴더에서 데이터 로드 (경로: Assets/Resources/Levels/Level_001...)
string path = $"Levels/Level_{index:D3}";
LevelData data = Resources.Load<LevelData>(path);
if (data != null)
{
levelGenerator.SpawnLevel(data);
// 약간의 딜레이 후 셔플 (연출 효과)
StartCoroutine(ShuffleRoutine());
}
else
{
Debug.LogError($"레벨 데이터를 찾을 수 없습니다: {path}");
}
}
public void LoadNextLevel()
{
currentLevelIndex++;
if (currentLevelIndex > MAX_LEVEL) currentLevelIndex = 1; // 루프 혹은 엔딩
LoadLevel(currentLevelIndex);
}
IEnumerator ShuffleRoutine()
{
yield return new WaitForSeconds(0.5f); // 타일 생성 감상 시간
ShuffleGrid();
isGameOver = false;
}
void ShuffleGrid()
{
// 간단하게 무작위로 N번 스왑
int shuffleCount = 20;
int width = levelGenerator.tileGrid.GetLength(0);
int height = levelGenerator.tileGrid.GetLength(1);
for(int i=0; i<shuffleCount; i++)
{
int x1 = Random.Range(1, width-1); // 모서리(고정타일) 제외
int y1 = Random.Range(0, height);
int x2 = Random.Range(1, width-1);
int y2 = Random.Range(0, height);
TileController t1 = levelGenerator.tileGrid[x1, y1];
TileController t2 = levelGenerator.tileGrid[x2, y2];
if(!t1.isFixed && !t2.isFixed)
{
// 셔플은 애니메이션 없이 즉시 데이터/위치 변경
Vector3 tempPos = t1.transform.position;
t1.transform.position = t2.transform.position;
t2.transform.position = tempPos;
Vector2Int tempCoord = t1.currentCoord;
t1.currentCoord = t2.currentCoord;
t2.currentCoord = tempCoord;
levelGenerator.tileGrid[x1, y1] = t1;
levelGenerator.tileGrid[x2, y2] = t2;
}
}
}
public void StartGame(LevelData data)
{
isGameOver = false;
uiManager.HideWinUI();
levelGenerator.SpawnLevel(data);
}
void Update()
{
if (isAnimating) return; // 애니메이션 중에는 조작 불가
if (isGameOver || isAnimating) return;
// 2. [중요] UI를 클릭 중이라면 게임 입력 무시 (PC/Mobile 통합)
if (IsPointerOverUI()) return;
HandleInput();
}
private bool IsPointerOverUI()
{
// PC or Unity Editor
if (EventSystem.current.IsPointerOverGameObject()) return true;
// Mobile (Touch)
if (Input.touchCount > 0 && EventSystem.current.IsPointerOverGameObject(Input.GetTouch(0).fingerId)) return true;
return false;
}
void HandleInput()
{
// 1. 터치/클릭 시작 (Pick Up)
if (Input.GetMouseButtonDown(0))
{
TileController hitTile = GetTileUnderMouse();
// 고정 타일이 아니고 유효한 타일이면 잡기
if (hitTile != null && !hitTile.isFixed)
{
currentDraggedTile = hitTile;
dragStartPos = currentDraggedTile.transform.position; // 원래 위치 기억
currentDraggedTile.SetDraggingState(true); // 시각적 효과 ON & 콜라이더 OFF
}
}
// 2. 드래그 중 (Dragging)
if (Input.GetMouseButton(0) && currentDraggedTile != null)
{
Vector3 mousePos = GetWorldMousePosition();
// 타일이 마우스 따라다니기 (Z값은 유지하거나 0으로)
currentDraggedTile.transform.position = new Vector3(mousePos.x, mousePos.y, 0);
}
// 3. 터치/클릭 뗌 (Drop)
if (Input.GetMouseButtonUp(0) && currentDraggedTile != null)
{
// 놓는 순간 마우스 밑에 뭐가 있는지 확인
// (currentDraggedTile의 콜라이더가 꺼져 있으므로 밑에 있는 타일이 잡힘)
TileController targetTile = GetTileUnderMouse();
currentDraggedTile.SetDraggingState(false); // 상태 복구 (콜라이더 켜짐)
if (targetTile != null && targetTile != currentDraggedTile && !targetTile.isFixed)
{
// 교체 대상이 있고, 고정 타일이 아니면 -> 스왑
StartCoroutine(SwapTiles(currentDraggedTile, targetTile));
}
else
{
// 대상이 없거나 고정 타일이면 -> 원래 자리로 복귀
StartCoroutine(currentDraggedTile.MoveToPosition(dragStartPos, 0.2f));
}
currentDraggedTile = null;
}
}
// 마우스 위치의 타일 가져오는 헬퍼 함수
TileController GetTileUnderMouse()
{
Vector2 mousePos = GetWorldMousePosition();
RaycastHit2D hit = Physics2D.Raycast(mousePos, Vector2.zero);
if (hit.collider != null)
{
return hit.collider.GetComponent<TileController>();
}
return null;
}
Vector3 GetWorldMousePosition()
{
Vector3 mousePos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
mousePos.z = 0;
return mousePos;
}
// 기존 스왑 로직 (약간 수정: StartPos가 꼬이지 않게 위치 강제 할당)
IEnumerator SwapTiles(TileController tileA, TileController tileB)
{
isAnimating = true;
// 중요: 드래그 했던 타일(A)은 현재 마우스 위치에 있음.
// 타일 B의 위치로 부드럽게 이동
Vector3 posB = tileB.transform.position;
// 타일 B는 타일 A의 원래 위치(dragStartPos)로 이동해야 함
Vector3 posA = dragStartPos; // A의 현재 위치가 아니라 원래 위치!
StartCoroutine(tileA.MoveToPosition(posB, 0.2f));
yield return StartCoroutine(tileB.MoveToPosition(posA, 0.2f));
// 데이터 교체
Vector2Int tempCoord = tileA.currentCoord;
tileA.currentCoord = tileB.currentCoord;
tileB.currentCoord = tempCoord;
levelGenerator.tileGrid[tileA.currentCoord.x, tileA.currentCoord.y] = tileA;
levelGenerator.tileGrid[tileB.currentCoord.x, tileB.currentCoord.y] = tileB;
isAnimating = false;
CheckWinCondition();
}
// 승리 체크 로직은 그대로 유지
void CheckWinCondition()
{
int width = levelGenerator.tileGrid.GetLength(0);
int height = levelGenerator.tileGrid.GetLength(1);
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
TileController tile = levelGenerator.tileGrid[x, y];
if (tile.currentCoord != tile.correctCoord) return;
}
}
// 승리 확정!
Debug.Log("Level Cleared!");
isGameOver = true; // [중요] 이제부터 타일 클릭 금지!
uiManager.ShowWinUI(); // UI 띄우기
}
}