
유니티 프로젝트를 위해 2D로 뭘 만들까하다가 오목을 만들어보려고한다.
오목을 만들기위해 공부해야하는 것은 생각보다 많았다.
근데 그냥 오목만 만들면 재미없어서 추억삼아 메이플로 만들어보려고한다.
먼저 오목 UI를 위해 포토샵으로 전부 작업을 진행했다.
Texture 폴더를 만들고, 기능에따라 Quick png 시스템을 이용해 나눠놨다.





버튼형식의 리소스들 , 공통적으로 사용하는 부분 ,오목판을 나타낼 판과, 배경인 Background를 넣었다.
이제 나중에 Resources를 불러올때나, 폴더에서 관리할때 편하겠지?


빈 게임오브젝트 Board를 생성했다. SpriteRenderer로 그렸음.
GameManager에 보드판 작성을 위해 코드를 작성하려고한다. 어떻게 할거냐면, 메이플 보드판 ui 격자선에 맞춰 격자를 생성하는 방식을 채택했다.
public GameManager : Monobehaviour
{
//바둑판 SpriteRenderer 참조
public SpriteRenderer boardRenderer;
//격자 위치를 저장할 배열
private Vector2[,] gridPositions;
}
먼저 보드판을 참조할 SpriteRenderer를 불러왔다. 이곳을 기준으로 그리드 점을 찍을 것이기 때문.
그리고, 격자 생성을 위해 Vector2 배열을 사용했다. 주로 int형식을 사용하는 것 같았는데, 벡터를 채택한 이유는 부동 소수점으로 좌표 표현이 가능해서 정밀하게 위치 설정을 할수있어서라고는 하는데. 차이가 과연 클까?
private void Awake()
{
//그리드 초기화
InitalizeGrid();
}
private void InitializeGrid()
{
//오목은 15x15게임입니다!
int gridSize = 15;
//격자를 15, 15로 설정
gridPosition = new Vector2[gridSize, gridSize]
//바둑판 이미지 측정
flaot boardWidth = boardRenderer.bounds.size.x;
float boardHeight = boardRenderer.bounds.size.y;
//각 격자 사이의 간격 계산
float cellWidth = boardWidth / gridSize;
float cellHeight = boardHeight / gridSize;
}
Init으로 초기화 메서드를 생성해준뒤에 오목판 생성을 위해 gridSize를 15로 선언했다. 그리고 스프라이트 이미지 사이즈를 측정하기위해 bounds.size를 해서 x, y값을 구해놨고, x y값의 길이를 15로 나눠서 한칸 한칸의 값을 구했다.

참고로 SpriteRenderer에 들어가있는 오브젝트는 바로 빨간 네모 부분이다. 이 부분에 투명한 Square를 넣어서 맞춰줬다.
이제 for문으로 격자만 찍어주면 되는데... 이게 은근 헷갈린다.
private void InitializeGrid()
{
int gridSize = 15;
gridPosition = new Vector2[gridSize, gridSize]
//바둑판 이미지 측정
flaot boardWidth = boardRenderer.bounds.size.x;
float boardHeight = boardRenderer.bounds.size.y;
//각 격자 사이의 간격 계산
float cellWidth = boardWidth / gridSize;
float cellHeight = boardHeight / gridSize;
//
Vector3 boardPosition = boardRenderer.transform.position
for (int i = 0; i < gridSize; i++)
{
for (int j = 0; j < gridSize; j++)
{
float posX = boardPosition.x + (i * cellWidth) - (boardWidth / 2) + (cellWidth / 2);
float posY = boardPosition.y + (j * cellHeight) - (boardHeight / 2) + (cellHeight / 2);
gridPosition[i,j] = new Vector2(posX, posY);
}
}
}
for문으로 15x15를 위해 i, j를 쓰는건 알겠는데, (i * cellWIdth)와 (boardWidth / 2), (cellWidth / 2)는 뭘까?
먼저, boardPosition은 SpriteRenderer는 localPosition이므로 globalPosition로 바꿔주기 위해 Vector3 boardPosition로 선언했다. 그리고 i * cellWidth와 j * cellHeight는 각각 증가하는 i번째 열과 j번째 행의 위치를 계산했다.
boardWidth, Height / 2 = 는 바둑판의 중앙을 원점으로 삼기위해 전체 너비와 높이의 절반을 빼서 (0, 0)에 위치하도록했다. + (cell Width / 2)와 + (cellHeight / 2)는 격자 셀의 중심점을 찾기위한 조정이죠. 각 셀의 시작점에서 셀의 너비와 높이 절반을 더해 정확한 격자점을 계산했습니다.
//눈으로 확인하자
private void OnDrawGizmos()
{
if (gridPosition != null)
{
Gizoms.color = Color.red;
int gridSize = gridPosition.GetLength(0);
for (int i = 0; i < gridSize; i++)
{
for (int j = 0; j < gridSize; j++)
Gizmos.DrawSphere(new Vector3(gridPosition[i, j].x, gridPosition[i, j].y, 0f), 0.1f);
}
}
}

격자에 돌을 생성해보자.
private GameObject[,] stoneObejects //바둑알 추적
private void Update()
{
//클릭!
if (Input.GetMouseButtonDown(0))
{
PlaceStoneAtMousePosition();
}
}
private void PlaceStoneAtMousePosition()
{
//마우스 포인터의 스크린 좌표를 월드 좌표로 변환
Vector2 mouseWorldPosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
//가장 가까운 격자 위치의 x, y 인덱스를 저장
int closetX = -1;
int closetY = -1;
float closetDistance = Mathf.Infinity;
for (int i = 0; i < 15; i++)
{
for (int j = 0; j < 15; j++)
{
float distance = Vector2.Distance(mouseWorldPosition, gridPosition[i, j])
if (distance < closetDistance)
{
closestX = i;
closestY = j;
closetDistance = distance;
}
}
}
}
if (placedStones[closestX, closestY] == 0)
{
string stonePath = playerNumber == 1 ? "Prefabs/Ingame_Slime" : "Prefabs/Ingame_Yeti";
GameObject stonePrefab = Resources.Load<GameObject>(stonePath);
GameObject newStone = Instantiate(stonePrefab, gridPosition[x, y], Queternion.identity);
stoneObjects[x, y] = newStone;
}
리소스 폴더에서 슬라임모양의 바둑알, 예티모먕의 바둑알을 놓았다. 참고로 여기서 나온 stoneObjects[,]는 격자에 놓은 바둑알을 추적하는 용도이다. 나중에 게임판을 초기화할때도 쓰려고 만들었다. 이러면 바둑알이 놔진다~

'Unity Engine > Unity 2D.' 카테고리의 다른 글
| [유니티] 8시간만에 버그를 잡아서 기분이 너무 좋은 (0) | 2023.12.02 |
|---|---|
| [유니티 2D] 경고 메세지 출력 (1) | 2023.11.12 |
| [유니티 2D] 사운드 매니저 (0) | 2023.11.12 |
| [유니티 2D] 무한 스크롤 (0) | 2023.11.12 |
| Unity 2D) A*(Astar) 알고리즘 (0) | 2023.08.23 |