Carrot
본문 바로가기
Unity/멋쟁이사자처럼 부트캠프

[멋쟁이사자처럼부트캠프] 유니티 게임 개발 5기(17일차) - C# 기초(9)

by 독기품은토끼 2025. 6. 9.
✅ 오늘의 학습 목표
1. C# 기초 (9) - 반복문, Coroutine 활용

 

1. C# - 반복문(2)

1. Switch

using UnityEngine;

public class StudySwitch : MonoBehaviour
{
    // 열거형 생성
    public enum CalculationType { Plus, Minus, Multiply, Divide };

    public CalculationType CalculationVal = CalculationType.Plus;

    public int input1, input2, result;

    void Start()
    {
        result = Calculation();
        Debug.Log($"계산 결과 : {result}");
    }

    // void는 return 값이 없기 때문에 int 자료형 사용
    private int Calculation()
    {
        switch (CalculationVal) // Alt + Enter : 케이스문 자동 완성
        {
            case CalculationType.Plus:
                result = input1 + input2;
                break;

            case CalculationType.Minus:
                result = input1 - input2;
                break;

            case CalculationType.Multiply:
                result = input1 * input2;
                break;

            case CalculationType.Divide:
                result = input1 / input2;
                break;
        }

        return result;
    }
}

 

▶ enum

enum은 관련된 상수들을 하나의 타입으로 묶어주는 타입으로 해당 타입이 가질 수 있는 값을 제한한다.

위 코드에서는 CalculationTpye 이라는 자료형을 만들고 해당 자료형은 Plus, Minus, Multiply, Divide 4개의 값만 가질 수 있도록 선언하였다.

 

2. For

  • 반복 횟수가 명확할 때 유용
  • 인덱스(i)를 이용해 현재 반복 위치를 제어 가능
  • 배열, 리스트 등 순차 자료구조에 적합
using System.Collections.Generic;
using UnityEngine;

public class StudyFor : MonoBehaviour
{
    // public int[] arrayInt = new int[5];
    public List<int> listInt = new List<int>();

    void Start()
    {
        for (int i = 0; i < listInt.Count; i++)
        {
            Debug.Log(listInt[i]);
        }

        // 다중 포문
        for (int i = 0; i < 3; i++)
        {
            for (int j = 0; j < 3; j++)
            {
                Debug.Log($"{i} / {j}");
            }
        }
    }
}

 

3. Foreach

  • 모든 요소를 순서대로 탐색할 때 유용
  • 인덱스가 필요 없는 상황에 적합
  • 내부에서 요소 수정 불가
using System.Runtime.CompilerServices;
using UnityEditor.Build;
using UnityEngine;

public class StudyForeach : MonoBehaviour
{
    public string[] persons = new string[5] { "철수", "짱구", "훈이", "맹구", "유리" };

    public string findName;

    void Start()
    {
        FindPerson(findName);
    }

    private void FindPerson(string name)
    {
        bool isFind = false;

        foreach (var person in persons)
        {
            if (person == name)
            {
                isFind = true;
                Debug.Log($"인원 중에 {name}이/가 존재합니다.");
            }
        }

        if(!isFind) Debug.Log($"{name}을/를 찾지 못했습니다.");
    }
}

 

 

▶ For와 Foreach의 차이점

항목 for foreach
인덱스 사용 가능 (i로 접근) 불가능
요소 수정 가능 읽기 전용 (수정 불가)
구조 단순성 복잡할 수 있음 더 간결하고 읽기 쉬움
using UnityEngine;

public class StudyForeach : MonoBehaviour
{
    public string[] persons = new string[5] { "철수", "짱구", "훈이", "맹구", "유리" };
    void Start()
    {
    	// foreach 사용법
        foreach (string person in persons)
        {
            Debug.Log(person);
        }

	// for 사용법
        for (int i = 0; i < persons.Length; i++)
        {
            Debug.Log(persons[i]);
        }
    }
}

 

 

 

2. C# - 메서드

1. Invoke

일정 시간 후 메서드를 실행(지연 실행)하는 기능

using UnityEngine;

public class StudyInvoke : MonoBehaviour
{
    public int count = 10;

    void Start()
    {
        // 반복 Invoke ("함수명", 첫 지연, 주기)
        InvokeRepeating("Bomb", 0f, 1f);
    }

    private void Bomb()
    {
        Debug.Log($"현재 남은 시간 : {count}초");
        count--;

        if (count == 0)
        {
            Debug.Log("펑~~");
            CancelInvoke("Bomb");
        }
    }

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            CancelInvoke("Bomb");
            Debug.Log("폭탄이 해제되었습니다.");
        }
    }
}

 

2. Coroutine

함수 실행 흐름을 제어하는 기능

using System.Collections;
using UnityEngine;

public class StudyCoroutine : MonoBehaviour
{
    private bool isStop = false;

    void Start()
    {
        StartCoroutine(BombRoutine());
    }

    IEnumerator BombRoutine()
    {
        int t = 10;

        while (t > 0)
        {
            Debug.Log($"{t}초 남았습니다.");
            yield return new WaitForSeconds(1f);
            t--;

            if (isStop)
            {
                Debug.Log("폭탄이 해제 되었습니다.");
                yield break;
            }
        }
        
        Debug.Log("폭탄이 터졌습니다.");
    }

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        { 
            isStop = true;
        }
    }
}

 

▶ Invoke와 Coroutine의 차이

Invoke는 함수 이름을 문자열(string)로 호출하기 때문에 오타 발생 시 컴파일 오류가 발생하지 않아 디버깅이 어렵다.

Coroutine은 함수 자체를 직접 호출하므로 실수 방지와 유지보수 측면에서 인보크보다 더 많이 사용된다.

 

[실습]

2.1. 캔버스/이미지 생성 후 이미지 크기 및 색상 적용

 

2.2. FadePanel 스크립트 생성 후 아래와 같이 Coroutine 오브젝트에 적용

 

2.3. 코드

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

public class FadePanel : MonoBehaviour
{
    public Image fadePanel; // 페이드 이미지

    void Start()
    {
        // 3초동안 페이드 인
        StartCoroutine(FadeRoutineA(3, true));

        // 3초동안 페이드 아웃
        StartCoroutine(FadeRoutineA(3, true));
    }

    // 이렇게 모듈화 하였기 때문에 다른 씬/프로젝트에서도 사용 가능
      IEnumerator FadeRoutineA(float fadeTime, bool isFadeIn)
    {
        float timer = 0f;
        float percent = 0f;
        float value = 0f;

        while (percent < 1f)
        {
            timer += Time.deltaTime;
            percent = timer / fadeTime; // Fade 퍼센트
            value = isFadeIn ? percent : 1 - percent;

            fadePanel.color = new Color(fadePanel.color.r, fadePanel.color.g, fadePanel.color.b, value);
            yield return null;
        }
    }
}

 

2.4. 결과

코루틴으로 간단한 애니메이션을 만들어 사용할 수 있다 (모듈화)

 

3. Random

🥕 예행 작업
1. Scene 생성 (StudyRandom)
2. Script 생성 (StudyRandom)
굳이 안 해도 상관없음..... 한 게 없어서...
using UnityEngine;

public class StudyRandom : MonoBehaviour
{
    void OnEnable()
    {
        int ranNumber = Random.Range(0, 100);

        Debug.Log(ranNumber);
    }
}

 

3. Cat

위에서 배운 것들을 활용해서 Cat 횡스크롤 게임을 업그레이드 해보자

 

1. Pipe 추가

1.1. Pipe 2개 추가 생성

 

1.2. Pipe 모두 랜덤한 Y 위치에 나타나도록 설정

using UnityEngine;

public class Transform_LoopMap : MonoBehaviour
{
    public float moveSpeed = 0.3f;
    public float returnPosX = 15f;
    public float randomPosY;

    void Start()
    {
        randomPosY = Random.Range(-4f, -0.5f);
        transform.position = new Vector3(transform.position.x, randomPosY, 0.1f);
    }

    void Update()
    {
        transform.position += Vector3.left * moveSpeed * Time.fixedDeltaTime;

        if (transform.position.x <= -returnPosX)
        {
            // Pipe가 랜덤한 높이에 나타나도록 설정
            randomPosY = Random.Range(-4f, -0.5f);
            transform.position = new Vector3(returnPosX, randomPosY, 0.1f);
        }
    }
}

 

2. 고양이 회전

고양이가 움직임에 따라 회전되도록 구현 (고양이의 z값을 기준으로 회전됨)

   // CatController 스크립트
   void Update()
    {
        // 고양이 회전 구현
        var catRotation = transform.eulerAngles;
        catRotation.z = catRb.linearVelocity.y * 5f;
        transform.eulerAngles = catRotation;
    }

 

고양이 오브젝트 안에 고양이 이름표가 자식 오브젝트로 있기 때문에

해당 코드를 적용하면 이름표도 같이 회전됨

 

따라서 이름표를 고양이의 자식 오브젝트로 두지 않고 분리하는 작업을 진행

 

using UnityEngine;

public class CatFollow : MonoBehaviour
{
    public Transform cat;

    public Vector3 offset; // 기준점을 맞추기 위하 변수

    void Update()
    {
        transform.position = cat.transform.position + offset;
    }
}

 

CatFollow 라는 스크립트 생성 후 Canvas에 적용하면

이름표가 고양이 오브젝트의 움직임에 따라 이동한다.

 

 

이렇게 모두 적용하고 나면 고양이의 이름표가 고양이와 같이 회전되지 않고 고양이 머리 위에 잘 따라다닌다

 

중간에 다시 코루틴 실습을 진행하게 되면서 Cat 게임은 잠시 중단되었다.

이틀 내로 마무리될 예정이라고 하니 좀만 더 힘내보자 🙌

 

 


 

 

수업 진도를 나갈 때 씬이랑 스크립트를 자주 왔다갔다 하다 보니까 따라가기 어렵진 않은데 이걸 어떻게 블로그에 적어야하지? 싶을 때가 많다.. 나름 잘 적었다고는 생각하는데 무언가 찜찜한 느낌! 내가 알아보면 됐지 뭐.. 허허

얼른 더 재밌는 수업.. 나가고싶돠... 그래도 많은 기능들을 배워서 활용만 하면 될 것 같은데~~ 흠.. 잘 써먹을 수 있을지는 지켜봐야 할 것 같다. 내가 지금 뭘 모르는지도 잘 모르겠음! 이게 잘 따라간다 해서 내가 100% 이해한 게 아닐 텐데.. 흠 뭐 어떻게든 되겠지!