242 lines
7.9 KiB
C#
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 띄우기
|
|
}
|
|
} |