본문 바로가기

유니티(게임 다시하기, 빌드하기, RenderTexture 이용해 CCTV, 미니맵 만들기, Lotto 구현) _ 멋쟁이사자처럼 유니티 부트캠프 후기 20회차

@salmu2025. 6. 13. 16:15
반응형

[20회차 수업내용] 250612

 

1. Outro 만들기

2. 다시하기 기능 만들기

3. 게임 빌드하기

4. CCTV 만들기

5. MiniMap 만들기

6. Lotto 구현

 

 

 

1.1 Cat 초기화 기능

// cat controller 스크립트


void Awake() // 1번만 실행
{
    catRb = GetComponent<Rigidbody2D>();  // 고양이 오브젝트의 Rigidbody2D 컴포넌트 가져옴
    catAnim = GetComponent<Animator>();   // 고양이 오브젝트의 Animator 컴포넌트 가져옴
}

void OnEnable() // 오브젝트가 활성화될 때마다 실행
{
    transform.localPosition = Vector3.zero; // 고양이 위치 초기화 (0,0,0)
    GetComponent<CircleCollider2D>().enabled = true; // 고양이 충돌 판정 켜기
    soundManager.audioSource.mute = false; // 소리 켜기
}

 

 

1.1.1 Vector3 상수 (3D좌표)

Vector3.zero (0, 0, 0) — 원점 (0, 0, 0)
Vector3.one (1, 1, 1) — 모든 축 값이 1 (1, 1, 1)
Vector3.up (0, 1, 0) — 월드 좌표 기준 위쪽 (0, 1, 0)
Vector3.down (0, -1, 0) — 아래쪽 (0, -1, 0)
Vector3.right (1, 0, 0) — 오른쪽 (1, 0, 0)
Vector3.left (-1, 0, 0) — 왼쪽 (-1, 0, 0)
Vector3.forward (0, 0, 1) — 앞쪽 (Z+) (3D 기준) (0, 0, 1)
Vector3.back (0, 0, -1) — 뒤쪽 (0, 0, -1)

 

 

 

 

1.2 Item 초기화

using UnityEngine;

public class ItemEvent : MonoBehaviour
{

 // ...
 
    private Vector3 initPos;  // 아이템의 초기 위치 저장 변수

    void Awake()
    {
        // 게임 시작 시 1번 실행
        // 아이템의 초기 위치를 저장해둔다 (다시 활성화 시 기준점으로 사용)
        initPos = transform.localPosition;
    }

    void OnEnable()
    {
        // 오브젝트가 활성화될 때마다 실행됨
        // 초기 위치를 기준으로 랜덤하게 위치나 상태를 설정하는 함수 호출
        SetRandomSetting(initPos.x);
    }
    
    // ...
}

 

 

2.1  버튼 생성 

public void OnRestartButton()
{
    GameManager.ResetPlayUI();  // 게임 상태 초기화
    playObj.SetActive(true);    // 플레이 화면 켜기
    videoPanel.SetActive(false);// 영상 패널 끄기
}

 

 

 

2.2 fadeUI  / 영상 재생

using System.Collections;
using UnityEngine;
using UnityEngine.UI;

public class FadeRoutine : MonoBehaviour
{
    public Image fadePanel;  // 페이드 처리할 UI Image (흑색 또는 원하는 색상의 패널)

    // 페이드 코루틴 호출 함수
    // fadeTime : 페이드에 걸리는 시간 (초)
    // color : 페이드할 색상 (투명도 포함)
    // isFadeStart : true면 페이드 인(점점 나타남), false면 페이드 아웃(점점 사라짐)
    public void OnFade(float fadeTime, Color color, bool isFadeStart)
    {
        StartCoroutine(Fade(fadeTime, color, isFadeStart));
    }

    // 페이드 효과 코루틴
    IEnumerator Fade(float fadeTime, Color color, bool isFadeStart)
    {
        float timer = 0f;     // 경과 시간
        float percent = 0f;   // 진행률 (0~1)

        while (percent < 1f)
        {
            // isFadeStart가 true면 알파가 0->1 증가, false면 1->0 감소
            float value = isFadeStart ? percent : 1 - percent;

            timer += Time.deltaTime;
            percent = timer / fadeTime;

            // 페이드 패널 색상 변경 (알파 값만 조절)
            fadePanel.color = new Color(color.r, color.g, color.b, value);

            yield return null; // 다음 프레임까지 대기
        }
    }
}

 

//catcontroller script

IEnumerator EndingRoutine(bool isHappy)
{
    yield return new WaitForSeconds(3.5f); // 3.5초 대기 (게임 오버 또는 성공 후 잠시 멈춤)
    
    videoManager.VideoPlay(isHappy); // 성공/실패에 따라 영상 재생 시작
    yield return new WaitForSeconds(1f); // 영상 시작 후 1초 대기

    // 성공이면 흰색, 실패면 검은색으로 페이드 아웃 색상 설정
    var newColor = isHappy ? Color.white : Color.black;
    fadeUI.GetComponent<FadeRoutine>().OnFade(3f, newColor, false); // 3초 동안 페이드 아웃 실행
    
    yield return new WaitForSeconds(3f); // 페이드 아웃이 끝날 때까지 3초 대기
    fadeUI.SetActive(false); // 페이드 UI 비활성화
    gameOverUI.SetActive(false); // 게임 오버 UI 비활성화
    soundManager.audioSource.Stop(); // 배경음악 및 효과음 정지
    
    transform.parent.gameObject.SetActive(false); // 플레이 오브젝트 전체 비활성화 (게임 플레이 종료)
}

 

 

  • 게임 종료 시 EndingRoutine 코루틴이 실행
  • 3.5초 대기 후 성공 여부에 따라 영상 재생 시작 (videoManager.VideoPlay(isHappy))
  • 1초 대기 성공 시 흰색, 실패 시 검은색으로 3초간 페이드 아웃 실행 (fadeUI.GetComponent<FadeRoutine>().OnFade)
  • 페이드 완료 후 fadeUIgameOverUI 비활성화
  • 사운드 정지 (soundManager.audioSource.Stop())
  • 최종적으로 플레이 오브젝트(부모 오브젝트)를 비활성화하여 게임 화면 종료

 

3. 게임 빌드하기

3.1 Pixel Perfect Camera (픽셀 퍼펙트 카메라)

Pixel Perfect Camera2D 픽셀 아트 게임에서 픽셀이 깨지지 않고 또렷하게 보이도록 만들어주는 Unity 전용 컴포넌트

Assets Pixels Per Unit 스프라이트 1 유닛당 몇 픽셀인지 설정함. (보통 16, 32, 64 추천)
Reference Resolution 기준으로 삼을 해상도. 화면 비율 유지 기준 (예시: 320x180, 640x360)
Crop Frame X / Y 화면 비율이 기준 해상도와 다를 때 잘라낼 방향 선택 (X: 좌우 잘림 / Y: 상하 잘림)
Stretch Fill 남는 공간을 강제로 채워서 화면을 꽉 채움 (화면 왜곡 발생 가능, 주의해서 사용)

 

 

3.2  Resolution and Presentation 옵션

      • 기능: PC 게임 실행 시 플레이어가 마우스로 창 크기를 조절할 수 있게 함
      • 설정 위치: Unity → Edit → Project Settings → Player → Resolution and Presentation → Resizable Window
      • 픽셀 아트 게임에서는 꺼두는 게 좋다 (비활성화 추천)
      • Default Screen Width / Height: 원하는 기본 해상도 입력 (예: 1920 / 1080 or 1280 / 720)
      • Fullscreen Mode: 원하는 방식
      • Assets → Pixel Per Unit 값 맞추기 (보통 16, 32, 64 중 선택 → 스프라이트 기준

3.3 빌드 실행하기

  1. Build Settings 창Add Open Scenes → 현재 씬 추가
  2. Build Folder 선택 (예: Builds/Windows/)
  3. Build 클릭 → exe 파일 생성됨
  • exe와 함께 Data 폴더가 생성됨 → 반드시 exe와 함께 있어야 정상 실행됨

 

 

 

 

 

4. CCTV 만들기

4.1 Render Texture

    • 카메라가 찍는 화면을 실시간으로 Texture로 만들어주는 기능
    • TV 화면, CCTV, 거울, 미니맵 등에서 사용
    • 일반 텍스처처럼 UI나 오브젝트에 표시 가능

4.2 CCTV 만들기

            • Render Texture 만들기( Assets → Create → Render Texture)
            • Hierarchy → Camera 추가 (ex: CCTV_Camera)
            • Camera → Output Texture → CCTV_RenderTexture 연결
            • 카메라 위치 조정 → CCTV가 보여줄 화면 위치로
            • UI에 출력 :  Canvas → RawImage → Texture에 CCTV_RenderTexture 연결

 

* CCTV 흐릿하게 보이기 -> Render Texture의 해상도 낮추기

 

 

5. 미니맵 만들기

        • Render Texture 만들기( Assets → Create → Render Texture)
        • Hierarchy → Camera 추가
        • 카메라 위치 조정 위쪽에서 아래로 보는 시점 (Top-Down View) 예) (x, y+높이, z)Rotation X = 90
        • Projection → Orthographic 설정_ 미니맵엔 직교가 좋음 (원근 왜곡 X)
        • Orthographic Size 조절 → 보여줄 영역 설정
        • Camera → Output Texture → MiniMap_RenderTexture 연결
        • UI에 출력 :  Canvas → RawImage → Texture에 MiniMap_RenderTexture 연결

 

 

 

6.1 Swap

:두 개의 값을 서로 바꾸는 것

int a = 5;
int b = 10;

// 스왑
int temp = a;
a = b;
b = temp;

// 결과: a = 10, b = 5

 

ex

using UnityEngine;

public class LottoGenerator : MonoBehaviour
{
    public int[] intArray = new int[10];

    void Start()
    {
        int ranInt1 = Random.Range(0, intArray.Length);
        int ranInt2 = Random.Range(0, intArray.Length);

        var temp = intArray[ranInt1];
        intArray[ranInt1] = intArray[ranInt2];
        intArray[ranInt2] = temp;
    }
}

 

 

 

6.2 Shuffle 

: 배열이나 리스트의 요소들을 랜덤하게 섞는 것

: 보통 여러 번 swap을 이용해서 구현함.

void Shuffle<T>(T[] array)
{

    // 배열의 끝에서부터 시작해 앞쪽으로 이동
    for (int i = array.Length - 1; i > 0; i--)
    {
     // 0부터 i까지 범위 내에서 무작위 인덱스 선택
        int randomIndex = Random.Range(0, i + 1);
        
        // 선택한 인덱스의 요소와 현재 인덱스 요소를 교환 (swap)
        T temp = array[i];
        array[i] = array[randomIndex];
        array[randomIndex] = temp;
    }
}


* Fisher-Yates Shuffle 

  • 배열의 마지막부터 시작해서 앞쪽으로 이동
  • 현재 위치(i)와 0부터 i 사이의 임의 위치(j)를 선택해 두 요소를 교환(swap)
  • 이렇게 하면 균등한 확률로 모든 요소가 섞임

 

Ex)

using System.Collections;
using UnityEngine;

public class LottoGenerator : MonoBehaviour
{
    public int[] intArray = new int[10];

    public int shakeCount = 1000;

    IEnumerator Start()
    {
        for (int i = 0; i < shakeCount; i++)
        {
            int ranInt1 = Random.Range(0, intArray.Length);
            int ranInt2 = Random.Range(0, intArray.Length);

            var temp = intArray[ranInt1];
            intArray[ranInt1] = intArray[ranInt2];
            intArray[ranInt2] = temp;

            yield return new WaitForSeconds(0.1f);
        }
    }
}

 

 

 

5.3 List (삽입/추가 가능) 를 활용한 셔플 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class LottoGenerator : MonoBehaviour
{
    // 1~45 숫자를 저장하는 리스트 (필요 시 추가, 삭제, 삽입 가능)
    public List<int> intList = new List<int>();

    // 셔플 반복 횟수 설정
    public int shakeCount = 1000;

    void Awake()
    {
        // 1부터 45까지 숫자를 리스트에 추가 (로또 번호 후보 초기화)
        for (int i = 1; i < 46; i++) 
            intList.Add(i);
    }
    
    IEnumerator Start()
    {
        // shakeCount 횟수만큼 리스트 내 숫자를 무작위로 섞음 (셔플)
        for (int i = 0; i < shakeCount; i++)
        {
            // 리스트 내 두 개의 랜덤 인덱스 선택
            int ranInt1 = Random.Range(0, intList.Count);
            int ranInt2 = Random.Range(0, intList.Count);

            // 두 위치의 숫자 서로 교환 (swap)
            var temp = intList[ranInt1];
            intList[ranInt1] = intList[ranInt2];
            intList[ranInt2] = temp;

            yield return null; // 한 프레임 대기 후 다음 셔플 진행
        }

        // 셔플된 리스트에서 앞 6개 숫자를 뽑아 결과 그룹 생성
        List<int> resultGroup = new List<int>();

        for (int i = 0; i < 6; i++)
            resultGroup.Add(intList[i]);
        
        resultGroup.Sort(); // 결과 번호를 오름차순 정렬
        // resultGroup.Reverse(); // 필요시 번호를 내림차순으로 뒤집기

        // 6개 번호와 7번째 숫자를 보너스 번호로 출력할 문자열 생성
        string resultNumber = $"이번 주 로또 번호 : {resultGroup[0]} / {resultGroup[1]} / {resultGroup[2]}" +
                                              $"/ {resultGroup[3]} / {resultGroup[4]} / {resultGroup[5]} " +
                                              $"/ 보너스 넘버 : {intList[6]}";
        
        Debug.Log(resultNumber); // 콘솔에 결과 출력
    }
}

 

*리마인드

Sort() 리스트나 배열을 오름차순으로 정렬 list.Sort();
Reverse() 리스트나 배열의 순서를 반대로 뒤집음 list.Reverse(); (정렬 후 내림차순 만들 때 주로 사용)

 

 

오늘은 유니티 코루틴을 활용한 페이드 효과와 게임 오브젝트 제어, 빌드 해상도 설정 방법을 익혔다. Fisher-Yates 셔플 알고리즘을 직접 구현하며 무작위 리스트 섞기와 정렬도 실습했다. 알고리즘을 간단히 체험해보았는데 앞으로 더 다양한 알고리즘을 배우고 싶고, 클론 코딩으로 게임 하나를 완성한 경험이 큰 도움이 될 것 같다.

반응형
salmu
@salmu :: SMU 각종 기록

목차