메인 기능을 기획하고 흐름도를 작성한 후 코드를 작성했다.
먼저 다른 2048게임을 참고하여 메인 기능을 구성한다.
게임 규칙
1. 같은 수의 블럭 2개가 맞닿아 있다면 합성한다.
2. 2개면 다음 단계의 블럭으로 3개면 2단계 위 블럭, 4개면 3단계 위 블럭으로 변한다.
3. 이때 합성의 주체가 되는 위치의 기준은 새로 떨어진 블록 기준이다.
예를 들어
빨간 블럭이 새로 떨어진 블럭이라면 그 위치에 새로운 블럭이 생성된다.
이 규칙을 바탕으로 흐름도를 작성한다.
대략적인 흐름도를 작성한 후 이를 바탕으로 코드를 작성했다.
구현을 최우선으로 하여 작성한 코드로 효율성은 낮을 수 있다.
이후 테스팅 과정에서 리펙토링하기로 한다.
큐브 생성 함수
public void SpawnCube(int nowLine)
{
// 현재 줄이 다 찼는지 확인
bool nowLineFull = true;
// 현재 큐브 레벨 설정
nowCubeLevel = nextCubeLevel[nowLine];
// 스폰 제한 - 아직 로직 진행중일 시 새로 생성 불가능
if (!canSpawn)
{
return;
}
canSpawn = false;
SaveUndoData();
// 빈 칸에 생성 할당 이동 후 머지 체크
for (int i = 0; i < Y_COUNT; i++)
{
// 빈 곳이 있을 시
if (square[nowLine, i] == null)
{
// 빈 곳 있음 표시
nowLineFull = false;
// 다음 큐브 정보 갱신
AddNewCubeData();
ShowNextCube();
// 생성 후 하강 애니메이션
square[nowLine, i] = Instantiate(cubes[nowCubeLevel]); // 판 변화
SoundManager.instance.PlaySound("spawn");
square[nowLine, i].transform.position = new Vector3(position_x[nowLine], 3.4f, 0);
square[nowLine, i].transform.DOMoveY(position_y[i], 0.5f).OnComplete(() =>
{
UpdateScore(nowCubeLevel);
// 머지 가능한지 확인
if (CheckMerge(nowLine, i))
{
// 머지 실행
StartCoroutine(Merge(nowLine, i));
}
else
{
// 새로 생성 가능
if (!EndCheck())
{
canSpawn = true;
}
}
});
break;
}
}
// 빈 곳이 없을 시 마지막 큐브 머지가능한지 확인
if (nowLineFull)
{
// 마지막 칸에서 머지할 경우
if (square[nowLine, Y_COUNT - 1].GetComponent<Cube>().myLevel == nowCubeLevel)
{
Except1(nowLine, nowCubeLevel);
}
else
{
if (!EndCheck())
{
canSpawn = true;
}
}
}
}
상하좌우 확인 함수
private bool CheckMerge(int x, int y)
{
// 메인 위치 기준으로 머지 체크
int nowLevel = square[x, y].GetComponent<Cube>().myLevel;
bool canMerge = false;
if (x > 0)
{
if (square[x - 1, y] != null && nowLevel == square[x - 1, y].GetComponent<Cube>().myLevel)
{
deleteList.Add(new Vector2Int(x-1,y));
canMerge = true;
}
}
if (y > 0)
{
if (square[x, y - 1] != null && nowLevel == square[x, y - 1].GetComponent<Cube>().myLevel)
{
deleteList.Add(new Vector2Int(x, y - 1));
canMerge = true;
}
}
if (x < X_COUNT-1)
{
if (square[x + 1, y] != null && nowLevel == square[x + 1, y].GetComponent<Cube>().myLevel)
{
deleteList.Add(new Vector2Int(x + 1, y));
canMerge = true;
}
}
if (y < Y_COUNT - 1)
{
if (square[x, y + 1] != null && nowLevel == square[x, y + 1].GetComponent<Cube>().myLevel)
{
deleteList.Add(new Vector2Int(x, y + 1));
canMerge = true;
}
}
return canMerge;
}
큐브 합성 함수
private IEnumerator Merge(int x, int y)
{
// 삭제할 리스트에 본인 추가
deleteList.Add(new Vector2Int(x, y));
int tempNowLevel = square[x, y].GetComponent<Cube>().myLevel;
if (deleteList.Count == 2)
{
tempNowLevel += 1;
}
else if (deleteList.Count == 3)
{
tempNowLevel += 2;
}
else if (deleteList.Count == 4)
{
tempNowLevel += 3;
}
// 제거 이펙트
for (int i = 0; i < deleteList.Count; i++)
{
square[deleteList[i].x, deleteList[i].y].GetComponent<Animator>().SetBool("Delete", true);
}
SoundManager.instance.PlaySound("merge");
yield return new WaitForSeconds(0.3f);
// 제거
for (int i = 0; i < deleteList.Count; i++)
{
Destroy(square[deleteList[i].x, deleteList[i].y]); // 판 변화
}
deleteList.Clear();
yield return new WaitForSeconds(0.1f);
// 상위 큐브 생성
if (cubes[tempNowLevel] == null)
{
yield break;
}
square[x, y] = Instantiate(cubes[tempNowLevel]); // 판 변화
square[x, y].GetComponent<Animator>().SetTrigger("Spawn");
if (tempNowLevel > nowStageLevel + 9)
{
yield return StartCoroutine(LevelUp());
}
UpdateScore(tempNowLevel);
square[x, y].transform.position = new Vector3(position_x[x], position_y[y], 0);
// 현재 정보 다른 함수에게 넘길 수 있도록 프레임 넘기기
yield return new WaitForEndOfFrame();
// 자기자신이 하강하는지 안하는지 확인
if (CheckMeDown(x, y))
{
SetDownList();
}
else
{
if (CheckMerge(x, y))
{
yield return new WaitForSeconds(0.2f);
StartCoroutine(Merge(x, y));
}
else
{
SetDownList();
}
}
}
자신이 하강하는지 확인하는 함수
private bool CheckMeDown(int x, int y)
{
for (int i = 0; i < y; i++)
{
if (square[x, i] == null)
{
return true;
}
}
return false;
}
하강하는 큐브가 있는지 확인하는 함수
private void SetDownList()
{
downList.Clear();
// 전체 큐브 중 하강하는 위치 정보 저장
for (int i = 1; i < Y_COUNT; i++) // 세로
{
for (int j = 0; j < X_COUNT; j++) // 가로
{
// 자기 자신보다 낮은 층에 원소가 비어 있으면 하강목록에 저장
for (int k = 0; k < i; k++)
{
if (square[j, i] != null && square[j, k] == null)
{
downList.Add(new Vector2Int(j, i));
break;
}
}
}
}
if (downList.Count > 0)
{
StartCoroutine(DownOne());
return;
}
else
{
if (!EndCheck())
{
canSpawn = true;
}
}
}
선택한 큐브 하강 동작 함수
private IEnumerator DownOne()
{
// 1개 하강
for (int i = 0; i < downList[0].y; i++)
{
if (square[downList[0].x, i] == null)
{
square[downList[0].x, i] = square[downList[0].x, downList[0].y];
square[downList[0].x, downList[0].y] = null;
square[downList[0].x, i].transform.DOMoveY(position_y[i], 0.1f);
yield return new WaitForSeconds(0.1f);
// 머지 체크
if (CheckMerge(downList[0].x, i))
{
yield return new WaitForSeconds(0.2f);
// 머지 실행
StartCoroutine(Merge(downList[0].x, i));
}
else
{
SetDownList();
}
yield break;
}
}
}
이를 바탕으로 개발하여 현재 진행 상황이다.
2048 - choice 1(기획) (0) | 2023.08.17 |
---|---|
unity -> cloud once + playfab login 구현 오류 unity GetServerAuthCode null (0) | 2023.05.12 |
메타버스 경진대회 참가 (0) | 2022.08.16 |
오아시스 해커톤 후기 (0) | 2022.08.16 |
이노베이션 해커톤 후기 (0) | 2021.08.28 |