using System;
using System.Threading;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;

namespace Test
{
    struct ScoreData
    {
        int id;

        public int ID
        {
            get => id;
            set
            {
                id = value;
            }
        }

        int kor;
        int math;
        int eng;

        public ScoreData(int Id, int Kor = 0, int Math = 0, int Eng = 0)
        {
            id = Id;
            kor = Kor;
            math = Math;
            eng = Eng;
        }

        public void Print()
        {
            Console.WriteLine("ID : {0}, 국어 : {1}, 수학 : {2}, 영어 : {3} 입니다.", id, kor, math, eng);
        }
    }

    class ScoreSystem
    {
        public List<ScoreData> dataList = new List<ScoreData>();

        public ScoreSystem()
        {
            for(int i = 0; i < 3; ++i)
            {
                Console.WriteLine("{0} 번 째 데이터를 입력 받겠습니다. 먼저, ID, 국어, 수학, 영어 성적을 차례 대로 입력해 주세요.", i + 1);

                int tempID   = int.Parse(Console.ReadLine());
                int tempKor  = int.Parse(Console.ReadLine());
                int tempMath = int.Parse(Console.ReadLine());
                int tempEng  = int.Parse(Console.ReadLine());

                dataList.Add(new ScoreData(tempID, tempKor, tempMath, tempEng));
            }
        }

        public void PrintData(int Id)
        {
            for(int i = 0; i < dataList.Count(); ++i)
            {
                if(Id == dataList[i].ID)
                {
                    dataList[i].Print();
                }
            }
        }
    }



    class Program
    {
        static void Main(string[] args)
        {
            ScoreSystem system = new ScoreSystem();

            while(true)
            {
                Console.WriteLine("보고 싶은 학생의 ID를 입력하세요. 단, 0은 프로그램 종료");

                int inputData = int.Parse(Console.ReadLine());

                if(inputData == 0)
                {
                    break;
                }
                else
                {
                    system.PrintData(inputData);
                }
            }
        }
    }
}

'프로그래밍 > 코드 정리' 카테고리의 다른 글

[C#] StreamWriter, StreamReader  (0) 2021.04.02
[C#] BitConverter 테스트  (0) 2021.04.02
[C#] 성적 정렬 프로그램  (0) 2021.03.29
[C#] 우승할 달리기 선수 맞추기  (0) 2021.03.21
[C#] 성적 프로그램  (0) 2021.03.20
블로그 이미지

NIA1995

,
using System;
using System.Threading;
using System.Linq;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;

namespace Test
{
    class Program
    {
        static int choosedPlayer;
        static int arrivalPlayer;

        const int MAP_X = 7;
        const int MAP_Y = 22;

        static int[,] initMapData =

            {
              /* 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 */
                {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
                {3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0},
                {4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0},
                {5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0},
                {6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0},
                {7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0},
                {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
            };

        static int[] InitarrCharacterIndex = { 0, 0, 0, 0, 0 };

        static int ChoicePlayer()
        {
            Console.Write("원하는 달리기 선수를 선택하세요 ! (1~5) : ");
            int targetPlayer = int.Parse(Console.ReadLine());

            if(targetPlayer > 5 || targetPlayer < 1)
            {
                Console.WriteLine("1번 부터 5번 선수 중에 선택하세요 ! ");
                return ChoicePlayer();
            }

            return targetPlayer;
        }

        static void ClearScreen()
        {            
            Thread.Sleep(300);
            Console.Clear();
        }

        static void RunPlayer(int[,] mapData, int[] playerData)
        {
            for(int i = 1; i < MAP_X - 1; ++i)
            {
                SwapTile(mapData, i, playerData[i-1]++);
            }
        }

        static void RandomRunPlayer(int[,] mapData, int[] playerData)
        {
            Random rnd = new Random();

            int boosterPlayer = rnd.Next(1, 6);

            SwapTile(mapData, boosterPlayer, playerData[boosterPlayer-1]++);
        }

        static void SwapTile(int [,] map, int x, int y)
        {
            int tempTile = map[x, y];
            map[x, y] = 0;
            map[x, y + 1] = tempTile;
        }

        static void DrawMap(int[,] mapData, char[] tileData)
        {
            for (int i = 0; i < MAP_X; ++i)
            {
                for (int j = 0; j < MAP_Y; ++j)
                {
                    int maptile = mapData[i, j];

                    Console.Write(tileData[maptile]);

                    if (j == MAP_Y - 1)
                    {
                        Console.WriteLine();
                    }
                }
            }
        }

        static bool IsArrival(int[] playerData)
        {
            for(int i = 0; i < playerData.Length; ++i)
            {
                if(playerData[i] >= 20)
                {
                    arrivalPlayer = i;
                    return true;
                }
            }

            return false;
        }

        static void Main()
        {
            /*               0    1    2    3    4    5    6    7     타일 데이터 */
            char[] tile = { ' ', '-', '|', '1', '2', '3', '4', '5' };

            /* 실제 맵 데이터 */
            int[,] mapData = (int[,])initMapData.Clone();

            /* 달리기 선수의 위치 */
            int[] arrCharacterIndex = (int[])InitarrCharacterIndex.Clone();

            while(true)
            {
                Console.WriteLine(" Runner Game ! ");

                choosedPlayer = ChoicePlayer();

                Console.WriteLine("잠시 후 게임을 시작합니다 !");

                while (true)
                {
                    if (IsArrival(arrCharacterIndex))
                    {
                        Console.WriteLine("{0} 번 째 선수가 먼저 도착했습니다 !", arrivalPlayer + 1);

                        if (choosedPlayer == arrivalPlayer + 1)
                        {
                            Console.WriteLine("선택한 플레이어가 우승했습니다 ! 축하합니다 !");
                        }
                        else
                        {
                            Console.WriteLine("아쉽게도 우승자를 맞히지 못했습니다.");
                        }

                        Thread.Sleep(2000);

                        break;
                    }

                    ClearScreen();

                    RunPlayer(mapData, arrCharacterIndex);

                    DrawMap(mapData, tile);

                    ClearScreen();

                    RandomRunPlayer(mapData, arrCharacterIndex);

                    DrawMap(mapData, tile);                    
                }

                ClearScreen();

                Console.Write("다시 하시겠습니까? (YES -> 1 , 그 외 종료 : ");

                int reStart = int.Parse(Console.ReadLine());

                if (reStart == 1)
                {
                    mapData = initMapData;
                    arrCharacterIndex = InitarrCharacterIndex;
                }
                else
                {
                    break;
                }
            }
        }         
    }
}

'프로그래밍 > 코드 정리' 카테고리의 다른 글

[C#] StreamWriter, StreamReader  (0) 2021.04.02
[C#] BitConverter 테스트  (0) 2021.04.02
[C#] 성적 정렬 프로그램  (0) 2021.03.29
[C#] 성적 입력 프로그램  (0) 2021.03.25
[C#] 성적 프로그램  (0) 2021.03.20
블로그 이미지

NIA1995

,
using System;
using System.Threading;
using System.Linq;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Test
{
    class Program
    {
        int[] arrweek = new int[7]{1,2,3,4,5,6,7};

        /* 성적 프로그램 시작 */
        static void Start()
        {
            Console.WriteLine("성적 프로그램 - Method");
        }

        /* 성적 입력 */
        static void Input(ref int kor, ref int mat, ref int eng)
        {
            Console.Write("국어 성적 입력 : ");
            kor = Int32.Parse(Console.ReadLine());

            Console.Write("수학 성적 입력 : ");
            mat = Int32.Parse(Console.ReadLine());

            Console.Write("영어 성적 입력 : ");
            eng = Int32.Parse(Console.ReadLine());
        }

        /* 입력한 성적의 합 */
        static int Total(int kor, int mat, int eng)
        {
            return kor + mat + eng;
        }

        /* 성적의 평균 */
        static void Average(int total, out float average)
        {
            average = (float)total / 3;
        }

        static void Main(string[] args)
        {
            int kor = 0;
            int eng = 0;
            int mat = 0;
            int total;
            float average;

            Start();
            Input(ref kor, ref eng, ref mat);
            total = Total(kor, mat, eng);
            Average(total, out average);

            Console.WriteLine("Total : {0} / Average : {1}", total, average);
        }
    }
}

 

'프로그래밍 > 코드 정리' 카테고리의 다른 글

[C#] StreamWriter, StreamReader  (0) 2021.04.02
[C#] BitConverter 테스트  (0) 2021.04.02
[C#] 성적 정렬 프로그램  (0) 2021.03.29
[C#] 성적 입력 프로그램  (0) 2021.03.25
[C#] 우승할 달리기 선수 맞추기  (0) 2021.03.21
블로그 이미지

NIA1995

,

C# 프로그래밍에서는 Boxing과 Unboxing의 개념이 존재합니다. 닷넷 프레임워크에서 모든 타입은 Object 타입을 상속받게 됩니다. Boxing의 경우 값 형식의 데이터를 더 큰 영역인 Object 형식 또는 이 값 형식에서 구현된 임의의 인터페이스 형식으로 변환하는 과정을 의미합니다. 이때 Boxing하게 되는 값은 System.Object 인스턴스 내부에 래핑이 되고 에 저장되어 관리되게 됩니다.

 

int i = 123;
object o = i; // Boxing
int j = (int)o; // unboxing

https://docs.microsoft.com/ko-kr/dotnet/csharp/programming-guide/types/boxing-and-unboxing

 

Unboxing의 과정은 이와 반대로 암시적인 값을 다시 명확하게 Object 형식에서 값 형식으로 변환하는 목적의 과정입니다. 두 과정 모두 상당한 성능 소모가 필요합니다. Boxing의 경우 새로운 개체를 할당하고 생성해야 하며, Unboxing의 경우 캐스트 계산 과정이 필요합니다. 따라서 꼭 필요한 경우를 제외하고는 사용을 자제하는 편이 성능에 좋습니다.

 

 

블로그 이미지

NIA1995

,

- 값형식(Value) : 숫자, char, bool, enum 등

- 참조형식(Reference) : string, 배열, class, interface, delegate 등

'프로그래밍 > C#' 카테고리의 다른 글

[C#, LINQ] 내부 조인과 외부 조인  (0) 2021.03.31
[C#] Boxing과 Unboxing  (0) 2021.03.15
[C#] var 데이터 형식  (0) 2021.03.15
[C#] SerializableAttribute 클래스  (0) 2021.01.01
[C#] Null 조건 부 연산자  (1) 2020.12.26
블로그 이미지

NIA1995

,

C#에서는 함수 범위 내에서 선언되는 변수에 암시적 형식인 var 형식을 사용할 수 있습니다. 암시적 형식의 지역 변수는 직접 선언한 것처럼 강력한 형식이지만 컴파일러가 직접적인 형식을 결정합니다. 

 

var i = 10; // 암시적 형식의 지역 변수
int i = 10; // 분명한 형식의 지역 변수
https://docs.microsoft.com/ko-kr/dotnet/csharp/language-reference/keywords/var

 

위와 같은 방법으로 사용하면 되며 아래와 같은 특징들을 가지고 있습니다.

 

1. 암시적 형식의 지역 변수

2. 지역 변수로만 사용 가능

3. 선언과 동시에 초기화가 필요

'프로그래밍 > C#' 카테고리의 다른 글

[C#] Boxing과 Unboxing  (0) 2021.03.15
[C#] 값형식과 참조형식의 예시  (1) 2021.03.15
[C#] SerializableAttribute 클래스  (0) 2021.01.01
[C#] Null 조건 부 연산자  (1) 2020.12.26
[C#] out, ref 키워드 살펴보기  (0) 2020.09.24
블로그 이미지

NIA1995

,

유니티에서는 변수를 선언할 때 public, private와 같은 다양한 접근 제한을 설정할 수 있습니다. public의 경우 인스펙터 창과, 다른 스크립트에서 접근 가능하다는 특징을 가지고 있습니다. 반대로 private의 경우 양 쪽 모두 접근이 불가능합니다.

 

그런데 외부 스크립트에서 수정, 참조를 불가능하게 하면서 동시에 인스펙터 창에서는 자주 사용되는 변수가 있을 수 있습니다. 이때 private 변수에 SerializeField를 사용하여 인스펙터 상에서 접근이 가능하도록 만들어 줍니다. 사용법도 간단한데, 원하는 변수 윗 라인에 [SerializeField]를 붙여주면 됩니다.

 

[SerializeField]
private LayerMask targetMask;

 

블로그 이미지

NIA1995

,

Scriptable Object는 클래스의 인스턴스와는 별개로 자료를 저장할 수 있는 데이터 컨테이너입니다. Scrpitable Object는 주로 값의 사본이 생성되는 것을 방지하여 메모리 사용을 줄여줍니다. 예를 들어서 MonoBehaviour 스크립트에 변경되지 않는 데이터를 저장하는 프리팹이 있는 프로젝트의 경우 유용하게 사용됩니다. 프리팹을 인스턴스화 할 때마다 프리팹에 이 데이터 자체의 사본이 생성되는데, 이와 같은 방법을 사용하여 중복 데이터를 저장하는 대신에 Scriptable Object를 이용하여 데이터를 저장한 다음 모든 프리팹을 참조하여 접근할 수 있습니다. 즉, 메모리에 데이터 사본을 하나만 저장하게 되는 것입니다.

 

Scriptable Object는 유니티 오브젝트에서 파생되지만 MonoBehavior와 달리 게임 오브젝트에 연결할 수 없고 프로젝트의 에셋으로 사용하게 됩니다.

 

에디터 사용 시, Scriptable Object에 데이터를 저장하는 작업은 편집할 때나 런타임에 가능합니다. 이는 Scriptable Object가 에디터 스크립팅을 사용하기 때문입니다. 빌드 단계에서는 Scriptable Object를 사용하여 데이터를 저장할 수 없고 사용만 가능합니다. 에디터 툴에서 에셋 형태로 저장한 Scirptable Object 데이터는 디스크에 저장되서 세션 간에도 유지됩니다.

 

이제 간단한 예제로 이해를 해보겠습니다.

 

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

[CreateAssetMenu(fileName = "Data", menuName = "ScriptableObject/SpawnManagerScriptableObject", order = 1)]
public class SpawnManagerScriptableObject : ScriptableObject
{
    public string prefabName;

    public int numberOfPrefabsToCreate;
    public Vector3[] spawnPoints;
}

 

우선 데이터 컨테이너를 만들어주기 위해 MonoBehaviour 대신 Scirptable Object를 상속합니다. 이후 간편한 데이터 편집을 위해서 Create Asset Menu 속성을 사용해 Assets > Create > ScriptableObjects > SpawnManagerScriptableObject 경로로 인스턴스를 생성할 수 있게 만들어줍니다.

 

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

public class Spawner : MonoBehaviour
{
    public GameObject entityToSpawn;

    public SpawnManagerScriptableObject spawnManagerValues;

    int instanceNumber = 1;

    private void Start()
    {
        SpawnEntities();
    }

    private void SpawnEntities()
    {
        int currentSpawnPointIndex = 0;

        for (int i = 0; i < spawnManagerValues.numberOfPrefabsToCreate; i++)
        {       
            GameObject currentEntity = Instantiate(
            entityToSpawn, 
            spawnManagerValues.spawnPoints[currentSpawnPointIndex], 
            Quaternion.identity);

            currentEntity.GetComponentInChildren<Text>().text = spawnManagerValues.prefabName;

            currentEntity.name = spawnManagerValues.prefabName + instanceNumber;	

				/* Scriptable Object의 데이터 수정 환경 테스트 */
            spawnManagerValues.prefabName = "TEST";

            currentSpawnPointIndex = (currentSpawnPointIndex + 1) % spawnManagerValues.spawnPoints.Length;

            instanceNumber++;
        }
    }
}

 

이제 만들어둔 Scriptable Object 데이터를 사용할 수 있는 스크립트를 만들어 줍니다. SpawnManagerScriptableObject 인스턴스에서 설정해둔 Prefab을 설정한 위치에서 원하는 개수만큼 생성하는 스크립트입니다. 중간에 Scriptable Object의 수정 환경 테스트를 위해서 spawnManagerValues.prefabName = "TEST"; 의 코드를 삽입했습니다.

 

Scriptable Object 인스턴스 생성

이제 실제로 Scriptable Object 인스턴스를 생성하고 테스트를 진행하겠습니다. 처음은 Scriptable Object의 인스턴스를 생성하고 원하는 대로 데이터를 저장하면 됩니다. (에디터 상의 데이터 저장)

 

에디터 상의 데이터 수정 및 저장

 

이후 플레이 버튼을 눌러 테스트를 진행하면  아래와 같은 형태로 오브젝트들이 구성됩니다.

 

런타임 상의 데이터 수정
런타임 상의 데이터 저장
데이터 수정 후의 테스트

위에서 코드 중간에 Scriptable Object의 변수인 prefabName을 런타임 도중 수정하도록 코드를 삽입했었습니다. 실제로 테스트를 해보면 런타임 도중 수정이 가능하고 저장 또한 가능하다는 것을 알 수 있습니다.

 

마지막으로 빌드 단계에서는 데이터의 사용만 가능하고 수정이 불가능한데 실제로 그렇습니다. 테스트를 해보시면 게임 실행 중에는 Cube - Test - Test로 데이터의 일시적인 변경이 가능하나, 다시 게임을 시작하면 Test - Test - Test가 아닌 Cube - Test - Test의 형태로 출력됩니다. 즉, 빌드 단계에서의 데이터의 수정이 불가능합니다.

 

지금까지 Scirptable Obejct 클래스에 대해서 간단하게 알아보았습니다.

블로그 이미지

NIA1995

,