유니티 기초 강좌: 반복문 – foreach

안녕하세요! 이번 강좌에서는 유니티에서 매우 중요한 프로그래밍 개념 중 하나인 반복문, 특히 foreach 문에 대해 자세히 알아보도록 하겠습니다. 반복문은 일을 반복적으로 처리할 수 있는 기능을 제공하여 코드의 유용성을 높이고, 반복적인 작업을 효율적으로 수행할 수 있게 합니다. foreach 문은 컬렉션(배열, 리스트 등)과 같이 반복할 수 있는 데이터를 다룰 때 매우 유용합니다.

1. 반복문의 개념

반복문은 지정된 조건이 참인 동안 특정 코드를 반복 실행하는 구조입니다. 일반적인 반복문에는 for, while, 그리고 foreach가 있습니다. 이 중 foreach 문은 컬렉션의 각 요소에 직접 접근할 수 있도록 해주어, 코드의 가독성을 높이고 오류를 줄이는 데 도움이 됩니다.

2. foreach 문 기본 구조

foreach 문은 다음과 같은 기본 구조를 가지고 있습니다.

foreach (자료형 변수명 in 컬렉션) {
        // 반복 실행할 코드
    }

2.1 예제: 배열 사용하기

간단한 예제로, foreach 문을 사용하여 배열의 모든 요소를 출력해 보겠습니다.

using UnityEngine;

public class ForEachExample : MonoBehaviour
{
    void Start()
    {
        int[] numbers = { 1, 2, 3, 4, 5 };

        foreach (int number in numbers)
        {
            Debug.Log(number);
        }
    }
}

위 코드에서 numbers 배열의 요소를 하나씩 number라는 변수에 할당하고, 그 값을 콘솔에 출력합니다.

3. foreach 문과 컬렉션

foreach 문은 배열뿐만 아니라 리스트, 해시셋, 딕셔너리 등 다양한 컬렉션에서도 사용할 수 있습니다. 각 컬렉션 유형에 따른 사용 예제를 살펴보겠습니다.

3.1 리스트 사용하기

리스트는 동적인 배열 구조로, 요소를 추가하거나 삭제할 수 있습니다. 다음은 리스트를 사용하여 foreach 문을 적용하는 예제입니다.

using System.Collections.Generic;
using UnityEngine;

public class ForEachListExample : MonoBehaviour
{
    void Start()
    {
        List fruits = new List { "사과", "바나나", "체리", "두리안" };

        foreach (string fruit in fruits)
        {
            Debug.Log(fruit);
        }
    }
}

위 예제에서 fruits 리스트의 각 요소가 fruit 변수에 대입되어 콘솔에 출력됩니다.

3.2 해시셋 사용하기

해시셋은 유일한 값을 저장하는 구조로, 주로 중복을 피하고자 할 때 사용됩니다. 다음은 해시셋을 사용한 예제입니다.

using System.Collections.Generic;
using UnityEngine;

public class ForEachHashSetExample : MonoBehaviour
{
    void Start()
    {
        HashSet uniqueNumbers = new HashSet { 1, 2, 3, 4, 5, 1, 2 };

        foreach (int number in uniqueNumbers)
        {
            Debug.Log(number);
        }
    }
}

여기서 uniqueNumbers 해시셋에 중복된 숫자가 포함되어 있어도 출력되는 값은 유일합니다.

3.3 딕셔너리 사용하기

딕셔너리는 키와 값의 쌍으로 이루어진 컬렉션입니다. 다음은 딕셔너리를 사용한 예제입니다.

using System.Collections.Generic;
using UnityEngine;

public class ForEachDictionaryExample : MonoBehaviour
{
    void Start()
    {
        Dictionary ageMap = new Dictionary
        {
            { "홍길동", 25 },
            { "김철수", 30 },
            { "이영희", 28 }
        };

        foreach (KeyValuePair entry in ageMap)
        {
            Debug.Log($"이름: {entry.Key}, 나이: {entry.Value}");
        }
    }
}

딕셔너리의 KeyValuePair를 사용하여 각 이름과 나이를 출력할 수 있습니다.

4. foreach 문과 성능 고려사항

foreach 문은 매우 유용하지만, 때때로 성능 측면에서 고려해야 할 사항이 있습니다. 특히 큰 컬렉션을 반복할 경우, 성능이 중요해질 수 있습니다. 다음은 foreach 문 사용 시 알아두어야 할 성능 관련 사항입니다.

4.1 메모리 할당

어떤 경우에는 foreach 문이 컬렉션의 복사본을 생성하여 메모리를 추가로 할당할 수 있습니다. 이는 주로 배열이 아닌 컬렉션에서 발생합니다. 성능이 중요한 게임에서는 직접 인덱스를 사용하는 for 문이 더 빠를 수 있습니다.

4.2 컬렉션 타입

메모리 할당 문제는 사용 중인 컬렉션의 유형에 따라 다릅니다. 예를 들어, List는 메모리를 효율적으로 관리하지만, LinkedList는 노드 간의 연결 때문에 상대적으로 느릴 수 있습니다.

5. foreach 문을 통한 실용적인 예제

foreach 문을 활용하여 좀 더 실용적인 예제를 살펴보도록 하겠습니다.

5.1 적 아이템 생성하기

다음은 적(Enemy) 캐릭터를 배열로 만들고 foreach 문을 사용하여 해당 캐릭터의 상태를 출력하는 예제입니다.

using UnityEngine;

public class Enemy
{
    public string Name;
    public int Health;

    public Enemy(string name, int health)
    {
        Name = name;
        Health = health;
    }
}

public class EnemyManager : MonoBehaviour
{
    void Start()
    {
        Enemy[] enemies = {
            new Enemy("슬라임", 100),
            new Enemy("고블린", 150),
            new Enemy("드래곤", 300)
        };

        foreach (Enemy enemy in enemies)
        {
            Debug.Log($"{enemy.Name}의 체력: {enemy.Health}");
        }
    }
}

5.2 나만의 오브젝트 풀링 예제

오브젝트 풀링(Object Pooling)은 자주 생성 및 소멸되는 게임 오브젝트를 효율적으로 관리하기 위한 패턴입니다. 다음은 간단한 오브젝트 풀링을 위한 클래스 예제입니다.

using System.Collections.Generic;
using UnityEngine;

public class Bullet
{
    public GameObject bulletObject;
}

public class ObjectPool : MonoBehaviour
{
    private List bulletPool;

    void Start()
    {
        bulletPool = new List();
        for (int i = 0; i < 10; i++)
        {
            Bullet bullet = new Bullet();
            bullet.bulletObject = CreateBullet();
            bulletPool.Add(bullet);
        }

        foreach (Bullet bullet in bulletPool)
        {
            Debug.Log("Bullet created: " + bullet.bulletObject.name);
        }
    }

    GameObject CreateBullet()
    {
        GameObject bullet = new GameObject("Bullet");
        // Bullet의 초기화 코드
        return bullet;
    }
}

6. 결론

이번 강좌에서는 유니티에서의 반복문, 특히 foreach 문에 대해 알아보았습니다. foreach 문은 여러 컬렉션 타입을 순회하며 코드를 더욱 간결하고 가독성이 높게 만들어줍니다. 그러나 성능 고려사항 또한 잊지 말아야 하며, 적절히 다른 반복문과 함께 사용하는 것이 중요합니다. 이를 통해 게임 개발 시 반복적인 작업을 효율적으로 처리할 수 있습니다.

유니티의 다양한 요소를 활용하여 멋진 게임을 만들어 보세요! 감사합니다.