원래는 체스 게임을 만들려고 했었는데 배열 관리가 이렇게 어려운건줄 몰랐다
프로그래밍 처음 배울때도 배열이 참 어려웠었는데...그런 의미에서!
게임개발에 사용되는 배열개념을 배우기 딱 좋은 스도쿠를 제작해보도록 하겠다
가장 먼저 시작화면부터 만들어보려 했는데

좋은 아이디어가 생각나서 시작화면에서 스도쿠 판을 하나 깔아서 만들려고 했다
그래서 이걸 어떻게 하냐로 별 방법을 다 썻던것 같은데...
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class MenuSudoku : MonoBehaviour
{
private int[,] board;
void Start()
{
CreateBoard();
DrawGridOnCanvas();
}
private void CreateBoard()
{
board = new int[9, 9];
for (int y = 0; y < 9; y++)
{
for (int x = 0; x < 9; x++)
{
board[y, x] = (x + y) % 2 == 0 ? 1 : 0;
}
}
board[0, 0] = 9;
board[4, 4] = 5;
board[8, 8] = 7;
}
private void DrawGridOnCanvas()
{
int cellSize = 60;
int width = cellSize * 9;
int height = cellSize * 9;
// Canvas에 UI Image 생성
GameObject canvas = GameObject.Find("Canvas");
if (canvas == null)
{
Debug.LogError("Canvas not found!");
return;
}
GameObject gridImage = new GameObject("GridImage");
gridImage.transform.SetParent(canvas.transform, false);
Image image = gridImage.AddComponent<Image>();
image.color = new Color(1, 1, 1, 0); // 투명 배경
image.rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, width);
image.rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, height);
image.rectTransform.anchoredPosition = Vector2.zero;
// 선을 그릴 GameObject 생성
for (int y = 0; y < 9; y++)
{
for (int x = 0; x < 9; x++)
{
// 셀의 중심 위치 계산
float cellX = x * cellSize + cellSize / 2;
float cellY = y * cellSize + cellSize / 2;
// 셀의 중심에 텍스트 추가
GameObject cellText = new GameObject("CellText");
cellText.transform.SetParent(gridImage.transform, false);
Text text = cellText.AddComponent<Text>();
text.text = board[y, x].ToString();
text.fontSize = 24;
text.color = Color.black;
text.rectTransform.anchoredPosition = new Vector2(cellX, cellY);
}
}
// 선을 그릴 GameObject 생성
for (int i = 0; i < 9; i++)
{
// 세로선
GameObject verticalLine = new GameObject("VerticalLine");
verticalLine.transform.SetParent(gridImage.transform, false);
LineRenderer lineRenderer = verticalLine.AddComponent<LineRenderer>();
lineRenderer.positionCount = 2;
lineRenderer.SetPosition(0, new Vector3(i * cellSize, 0));
lineRenderer.SetPosition(1, new Vector3(i * cellSize, height));
// 가로선
GameObject horizontalLine = new GameObject("HorizontalLine");
horizontalLine.transform.SetParent(gridImage.transform, false);
LineRenderer lineRenderer2 = horizontalLine.AddComponent<LineRenderer>();
lineRenderer2.positionCount = 2;
lineRenderer2.SetPosition(0, new Vector3(0, i * cellSize));
lineRenderer2.SetPosition(1, new Vector3(width, i * cellSize));
}
// 두꺼운 선 추가 (3x3 격자 구분)
for (int i = 0; i < 3; i++)
{
// 세로선
GameObject verticalLine = new GameObject("VerticalLine");
verticalLine.transform.SetParent(gridImage.transform, false);
LineRenderer lineRenderer = verticalLine.AddComponent<LineRenderer>();
lineRenderer.positionCount = 2;
lineRenderer.SetPosition(0, new Vector3(i * 3 * cellSize, 0));
lineRenderer.SetPosition(1, new Vector3(i * 3 * cellSize, height));
// 가로선
GameObject horizontalLine = new GameObject("HorizontalLine");
horizontalLine.transform.SetParent(gridImage.transform, false);
LineRenderer lineRenderer2 = horizontalLine.AddComponent<LineRenderer>();
lineRenderer2.positionCount = 2;
lineRenderer2.SetPosition(0, new Vector3(0, i * 3 * cellSize));
lineRenderer2.SetPosition(1, new Vector3(width, i * 3 * cellSize));
}
// 크기 조정
transform.localScale = new Vector3(1.05f, 1.05f, 1f);
transform.position = Vector3.zero;
}
}
결국 코드로 그리는 방법을 선택했다
이미 완성된 이미지를 가져오기 > 불투명해서 숫자가 안채워짐
직접 선을 그리기 > 최적화 최악, 불편함 고트
이런건 코드로 그리는게 투명함에 최적화도 좋다

원래는 완성된 스도쿠 판 위에 숫자 박스를 떨어뜨리고 싶었는데 위 이미지처럼 만들고 싶다는 아이디어가 떠올랐다
가장 윗줄은 박스가 떨어지는 충격을 흡수해서 받아내는? 지붕 역할을 하게 만들고 싶었다
그래서 코드를 수정하여 맨 윗줄만 지우고

사전에 이렇게 미리 윗줄 부분만 만들어놓았다. 일자로 보이지만 사실 6개의 긴 직사각형을 이어붙인것
그리고 내가 원하는 조건은 3가지였는데 이걸 다 만족시키는 방법을 찾느라 시간이 좀 걸렸다
1. 사각형의 한쪽 축은 고정이 될것
2. 다른 물체와 충돌이 있을때 부드럽게 일정 각도 이상으로 넘어가지 않고 돌아갈 것
3. 돌아가더라도 자연스럽게 처음 상태였던 제자리를 찾아 돌아올 것
이럴땐 어떤게 가장 좋다고 알려줄 사람이 없으니 이것 역시 별 방법을 다 써보고 폐기했었다
그렇게 찾은 가장 좋은 방법은!
Hinge Joint 2D

사실 딱 이럴때 쓰는 전용 기능인데 이제서야 찾았다
말 그대로 오브젝트에 축을 꽂아주는 컴포넌트

이렇게 위치를 조절하여 내가 원하는곳에 축을 정해준다. 이러면 x,y,z축 고정을 다 풀어놔도 상관없다. 축이 고정해주니까!
using UnityEngine;
[RequireComponent(typeof(Rigidbody2D))]
[RequireComponent(typeof(HingeJoint2D))]
public class BarController : MonoBehaviour
{
[Header("Spring Return Settings")]
[Tooltip("원래 각도로 돌아가려는 복원 힘 (토크)")]
public float returnStrength = 50f;
[Tooltip("돌아올 때 흔들림을 잡아주는 저항(감쇠)")]
public float damping = 5f;
private Rigidbody2D rb;
private HingeJoint2D hinge;
private float initialAngle;
void Start()
{
rb = GetComponent<Rigidbody2D>();
hinge = GetComponent<HingeJoint2D>();
// 게임 시작 시점의 Z축 회전값을 원래 각도로 기억
initialAngle = transform.eulerAngles.z;
}
void FixedUpdate()
{
// 현재 각도와 원래 각도의 차이(오차) 계산
float currentAngle = transform.eulerAngles.z;
float angleDifference = Mathf.DeltaAngle(currentAngle, initialAngle);
// 오차가 존재할 때 원래 자리로 되돌아가려는 회전력(토크)을 계산하여 적용
// (현재 회전 속도에 저항(damping)을 주어 무한정 핑글돌지 않고 멈추게 함)
float restoringTorque = (angleDifference * returnStrength) - (rb.angularVelocity * damping);
rb.AddTorque(restoringTorque * Mathf.Deg2Rad, ForceMode2D.Force);
}
}
하지만 충돌한 뒤 다시 원상태로 돌아오는건 코드가 필요하다
그에 맞는 코드만 간단하게 짜주면 된다

그리고 위에서 떨어질 프리펩 만들고 랜덤으로 떨궈주면 된다

그럼 이제 이런식의 연출이 가능한 것이다
'3. Sudoku' 카테고리의 다른 글
| #2 스도쿠 문제 제작 & 활성화 (Grid Layout Group) (0) | 2026.08.04 |
|---|