본문 바로가기
Development/C#

[멋쟁이사자처럼 부트캠프 TIL 회고] Unity 게임 개발 3기 10일차

by Mobics 2024. 12. 2.

 

목차


    자료구조

    정의

    : 데이터 요소들을 체계적으로 구조화하는 방식

     

    목적

    • 데이터의 효율적인 저장과 검색
    • 메모리 사용 최적화
    • 알고리즘의 성능 향상

    주요 자료구조

    • 배열(Array)
    • 연결 리스트(Linked List)
    • 스택(Stack)
    • 큐(Queue)
    • 트리(Tree)
    • 그래프(Graph)
    • 해시 테이블(Hash Table)

    배열(Array)

    : 동일한 데이터 타입의 요소들을 연속된 메모리 공간에 저장

     

    장점

    • 빠른 요소 접근 : Index를 통한 O(1) 시간 복잡도 --> Random Access 가능
    • 메모리 효율성 : 연속된 메모리 할당으로 캐시 효율 높음
    • 간단한 구현 : 기본적인 프로그래밍 구조로 쉽게 사용 가능
    • 다차원 데이터 표현 : 행렬, 이미지 등의 데이터 표현에 적합

    ※ 임의 접근(Random Access)

    : 무작위로 뽑아서 출력하는 것을 의미하는 것이 아니라 임의의 Index를 뽑고자 할 때, Access가 즉시 가능하느냐의 의미

    단점

    • 고정된 크기 : 동적 크기 조절 불가
    • 삽입과 삭제의 비효율성 : 요소 이동 필요 --> O(n) 시간 복잡도
    • 메모리 낭비 가능성 : 선언된 크기만큼 항상 메모리 차지
    • 연관 데이터 저장의 어려움 : 다른 자료구조에 비해 복잡한 데이터 구조 표현이 어려움
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Linq;
    using UnityEngine;
    using Random = UnityEngine.Random;
    
    public class ArrayExample : MonoBehaviour
    {
        #region Values
    
        private const int ARRAY_SIZE = 10;
        // 플레이어 점수를 저장하는 배열
        private int[] playerScores = new int[ARRAY_SIZE];
        
        // 아이템 이름을 저장하는 배열
        private string[] itemNames = { "검", "방패", "포션", "활", "마법서" };
        
        // 적 프리팹을 저장하는 배열
        public GameObject[] enemyPrefabs;
        
        // 맵의 타일 타입을 저장하는 2D 배열
        private int[,] mapTiles = new int[10, 10];
    
        public GameObject Cube;
        public GameObject Sphere;
    
        private GameObject[,] CubeTiles = new GameObject[10, 10];
    
        #endregion
        
        void Start()
        {
            PlayerScoresExample();
            ItemInventoryExample();
            EnemySpawnExample();
            MapGenerationExample();
        }
    
        void PlayerScoresExample()
        {
            // 플레이어 점수 할당
            for (int i = 0; i < playerScores.Length; i++)
            {
                playerScores[i] = Random.Range(100, 1000);
            }
    		
            // Max를 linq를 사용하지 않고 구하는 방법
            //this.highestScore();
    
            // 최고 점수 찾기
            int highestScore = playerScores.Max();
            Debug.Log($"최고 점수: {highestScore}");
    		
            // Average를 linq를 사용하지 않고 구하는 방법
            //Average();
    
            // 평균 점수 계산
            double averageScore = playerScores.Average();
            Debug.Log($"평균 점수: {averageScore:F2}");
        }
        
        void ItemInventoryExample()
        {
            // 랜덤 아이템 선택
            int randomIndex = Random.Range(0, itemNames.Length);
            string selectedItem = itemNames[randomIndex];
            Debug.Log($"선택된 아이템: {selectedItem}");
            
            // 특정 아이템 검색
            string searchItem = "포션";
            bool hasPosition = itemNames.Contains(searchItem);
            Debug.Log($"포션 보유 여부: {hasPosition}");
        }
    	
        // Contains 직접 구현해보기
        private bool Contains(string itemName)
        {
            for (var i = 0; i < itemNames.Length; i++)
            {
                if (itemNames[i] == itemName)
                {
                    return true;
                }
            }
    
            return false;
        }
        
        void EnemySpawnExample()
        {
            if (enemyPrefabs != null && enemyPrefabs.Length > 0)
            {
                // 랜덤 위치에 랜덤 적 생성
                Vector3 spawnPosition = new Vector3(Random.Range(-10f, 10f), 0, Random.Range(-10f, 10f));
                int randomEnemyIndex = Random.Range(0, enemyPrefabs.Length);
                Instantiate(enemyPrefabs[randomEnemyIndex], spawnPosition, Quaternion.identity);
                Debug.Log($"적 생성됨: {enemyPrefabs[randomEnemyIndex].name}");
            }
            else
            {
                Debug.LogWarning("적 프리팹이 할당되지 않았습니다.");
            }
        }
    
        void MapGenerationExample()
        {
            // 간단한 맵 생성 (0 : 빈 공간, 1 : 벽)
            for (int x = 0; x < mapTiles.GetLength(0); x++)
            {
                for (int y = 0; y < mapTiles.GetLength(1); y++)
                {
                    mapTiles[x, y] = Random.value > 0.8f ? 1 : 0;
                }
            }
            
            // Unity에 맵 출력
            for (int x = 0; x < mapTiles.GetLength(0); x++)
            {
                for (int y = 0; y < mapTiles.GetLength(1); y++)
                {
                    // 방법 1. 삼항 연산자를 사용하고 그 객체를 관리하기 위해 배열에 넣기
                    CubeTiles[x, y] = mapTiles[x, y] == 1 ? Instantiate(Cube, new Vector3(x-5, y-5, 0), Quaternion.identity) : Instantiate(Sphere, new Vector3(x-5, y-5, 0), Quaternion.identity);
                    
                    // 방법 2. 조건문을 통해 그 객체를 관리하기 위해 배열에 넣기
                    //if (mapTiles[x, y] == 1)
                    //    CubeTiles[x, y] = Instantiate(Cube, new Vector3(x-5, y-5, 0), Quaternion.identity);
                    //else
                    //    CubeTiles[x, y] = Instantiate(Sphere, new Vector3(x-5, y-5, 0), Quaternion.identity);
                }
            }
    
            // 콘솔에 맵 출력
            // string mapString = "생성된 맵:\n";
            // for (int x = 0; x < mapTiles.GetLength(0); x++)
            // {
            //     for (int y = 0; y < mapTiles.GetLength(1); y++)
            //     {
            //         mapString += mapTiles[x, y] == 1 ? "■" : "□";
            //     }
            //     mapString += "\n";
            // }
            // Debug.Log(mapString);
        }
    
        #region 주석 처리
    
        // private void highestScore()
        // {
        //     int maxValue = 0;
        //     for (int i = 0; i < playerScores.Length; i++)
        //     {
        //         if (playerScores[i] > maxValue)
        //             maxValue = playerScores[i];
        //     }
        //     
        //     Debug.Log($"최고 점수1: {maxValue}");
        // }
        //
        // private void Average()
        // {
        //     int totalValue = 0;
        //     float averageValue = 0;
        //
        //     for (int i = 0; i < playerScores.Length; i++)
        //     {
        //         totalValue += playerScores[i];
        //     }
        //
        //     averageValue = totalValue / (float)playerScores.Length;
        //     Debug.Log($"평균 점수1: {averageValue:F2}");
        // }
    
        #endregion
    }

     

    ※ Average 직접 구현 부분

    : int형끼리 나누면 딱 떨어지게만 나오기 때문에, player.Scores.Lengthfloat으로 형변환 시켜서 나누면 Average()와 똑같이 나옴

     

    삼항연산자

    : if else 구문을 한 줄로 작성하게 해준다.

    >> Condition(bool) ? true : false;

     

    Instantiate

    : 게임을 실행하는 도중에 Game Object를 생성하는 기능

    >> Instantiate(GameObject original, Vector3(x, y, z), Quaternion rotation)

    • GameObject : 생성하고자 하는 Game Object명
    • Vector3 : Vector3로 생성될 위치를 설정
    • Quaternion : 생성될 Game Object의 회전값 --> 굳이 회전을 줘야할 상황이 아니라면 기본값으로 설정 (Quaternion.identity)

    Rider 기능

    원하는 부분 편하게 함수로 만들기

     

    반복문 편하게 만들기