부트캠프

[멋쟁이사자처럼 유니티 TIL] 에셋을 이용한 보석 먹기 게임 구현 ( + 파일 경로, 링큐 등)

맛난과자 2024. 6. 4. 20:58

파일 경로

- 상대적 파일 경로 지정

string filePath = "yammySnack.txt";

 

- 절대적 파일 경로 지정

   /(슬래시), \\(백슬래시), @\ 를 이용한다

string filePath = "C:/yammySnack.txt";
string filePath = "C:\\yammySnack.txt";
string filePath = @"C:\yammySnack.txt";

 

 

파일 쓰기

 

배열을 이용하여 파일에 쓸 문자열 저장하고,

File.WriteAllLines 를 이용하여 작성한 배열을 파일에 작성한다.

// 파일 생성 경로 정의
string filePath = "yammySnack.txt";

// 파일에 쓰여질 문자열 배열 정의
string[] lines = { "First line", "Second line", "Third line" };

// 문자열 배열을 "yammySnack.txt"라는 새 파일에 씀.
// 파일이 이미 존재하는 경우 덮어씀
File.WriteAllLines(filePath, lines);

Console.WriteLine("File written successfully.");

 

 

파일 읽기

 

1) ReadAllLines 사용

File.Exists() 로 파일의 유무를 판단한다.

File.ReadAllLines() 로 문자열 모두 읽는다.

string filePath = "yammySnack.txt";

// 파일이 있는지 확인
if (File.Exists(filePath))
{
    // 파일의 모든 줄을 문자열 배열로 읽어들임
    string[] lines = File.ReadAllLines(filePath);
    
    // 배열의 각 줄을 순회하며 콘솔에 출력
    foreach (string line in lines)
    {
        // 읽어 온 파일 출력
        Console.WriteLine(line);
    }               
}
else
{
    Console.WriteLine("File not Found");
}

 

2) StreamReader 클래스 사용

using을 이용하여 StreamReader를 인스턴스화 하고

StreamReader의 함수 ReadLine()를 이용하여 한 줄씩 읽어온다.

 

● using: 괄호 내에서만 사용할 수 있겠끔 하는 키워드. 일회성으로 사용할 때 쓰인다.

● StreamReader: 파일을 읽는데 최적화 된 클래스

string filePath = "yummySnack.txt";

// 파일이 있는지 확인
if (File.Exists(filePath))
{
    // 파일 한 줄씩 Read
    using (StreamReader streamReader = new StreamReader(filePath))
    {
        // 파일 한 줄을 읽어옴
        string line = streamReader.ReadLine();
        while (line != null)
        {
            // 읽어 온 파일 출력
            Console.WriteLine(line);
            // 그 다음 라인 읽어옴
            line = streamReader.ReadLine();
        }
    }
}
else
{
    Console.WriteLine();
}

 

 

파일 추가 쓰기

 

1) 단일 텍스트 추가

AppendAllText(파일, 추가할 글) 함수를 사용하여 텍스트를 추가한다.

string filePath = "yammySnack.txt";

string newLine = "Fourth line";

// filePath에다가 newLine 데이터를 넣어라.
File.AppendAllText(filePath, newLine);

Console.WriteLine("Success sppend Line");

 

2) 여러 문자열 추가

AppendAllLines(파일, 추가할 글) 함수를 사용하여 문자열을 추가한다.

string filePath = "example.txt";

string[] newLine = { "Fourth line", "5", "6" };

// filePath에다가 newLine 데이터를 넣어라.
File.AppendAllLines(filePath, newLine);

Console.WriteLine("Success sppend Line");

 

 

 

++변수 와 변수++ 의 차이

● 변수++ : 함수의 argument에 넣은 후 1만큼 증가시키겠다.

++변수 : 1만큼 증가시킨 다음에 함수의 argument에 전달하겠다.

int idx1 = 0, idx2 = 0;

Console.WriteLine(idx1);
Console.WriteLine(idx2);
Console.WriteLine(idx1++);  // 0
Console.WriteLine(++idx2);  // 1

int idx1Result = 0, idx2Result = 0;

idx1Result = idx1++;
idx2Result = ++idx2;

Console.WriteLine(idx1Result.ToString() + " " + idx1.ToString());  // 1 2
Console.WriteLine(idx2Result.ToString() + " " + idx2.ToString());  // 2 2

 

위와 같이 ++이 뒤에 있는 경우, 원래의 변수와 같은 값을 가지고

++이 앞에 있는 경우, 원래의 변수에 1이 커진 값을 가진다.

 


보석 먹기 게임 구현

① 에셋 스토어에서 마음에 드는 보석, 오디오, 이펙트 에셋을 다운받는다.

② 보석의 프리팹을 복사하여 Hierarchy에 드래그 앤 드롭 한다.

③ 보석 오브젝트에 Sphere Collider를 추가 후 Is Trigger를 체크한다.

 

Trigger란?

: 콜라이더와 콜라이더끼리 부딪혔을 때 물리작용은 일어나지 않지만, 상호작용은 하는 충돌체를 말한다.

 

④ 앞 시간에 했던 것처럼 Tag에 Jewelry 태그를 추가한 후 보석 오브젝트에 등록한다.

⑤ PlayerController 스크립트에서 OnTriggerEnter() 함수를 선언한 후,

    "Jewlry" 태그를 가진 오브젝트와 충돌할 시 로그를 띄우게 한다.

// 충돌체가 본인 콜라이더에 들어왔을 때
private void OnTriggerEnter(Collider other)
{
	// 충돌체가 "Jewelry" 태그를 가지고 있으면
    if (other.gameObject.CompareTag("Jewelry"))
    {
        Debug.Log("보석 먹음");
    }
}

 

=> 플레이어가 보석에 닿을 경우, 로그가 나타난다.

 

⑥ 사용할 이펙트 프리팹에 Audio Source 컴포넌트를 추가하고, AudioClip에 원하는 오디오 소스를 드래그 앤 드롭한다.

 

⑦ 이펙트 스크립트를 만들어 보석 오브젝트에 컴포넌트로 추가한다.

⑧ 이펙트 스크립트에서 GameObject 타입의 변수 'HitEffect'를 public으로 선언한다.

⑨ 함수를 선언하여 보석 오브젝트의 위치에 이펙트가 나타나게 하기 위해 'HitEffect'를 인스턴스화하고,

    Destroy() 함수로 현재 본인의 오브젝트를 삭제한다.

// 내 오브젝트가 사라질 때 나타날 효과
public GameObject HitEffect;
  
public void OnHit() 
{ 
    // 내 오브젝트가 있는 곳에 HitEffect 게임 오브젝트를 스폰
    GameObject.Instantiate(HitEffect, this.transform.position, Quaternion.identity);

    // 내 오브젝트 삭제
    GameObject.Destroy(this.gameObject);
}


Instantiate
란?

: 유니티식 메모리 할당. 프리팹을 복제할 때 주로 쓰인다.

 

⑩ 유니티 창에서 주얼리의 이펙트 스크립트 컴포넌트의 "Hit Effect"에 해당 이펙트 프리팹을 드래그 앤 드롭한다.

 

 

결과

 

캐릭터가 보석을 먹으면 이펙트와 함께 소리가 나는 것을 확인할 수 있다.

 


LINQ(링큐)

Language Integrated Query

: C#에서 데이터를 쿼리하고 조작할 수 있게 해주는 문법

한 마디로, 데이터를 정리하는 기능이다.

 

중요 메서드

From : 원하는 데이터에서 요소 추출

Where : 조건을  만족하는 요소 필터링

Select : 컬렉션의 각 요소를 특정 형식으로 변환

OrderBy, OrderByDescending : 컬렉션 정렬

GroupBy : 컬렉션의 요소를 그룹화

Sum, Max, Min, Average : 집계 함수

등등이 있다.

 

예시

짝수를 골라내는 코드

● 일반적인 방식

// 데이터 모음집
List<int> nums = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
var oddNumbers = new List<int>();

foreach (var num in oddNumbers)
{
    if (num % 2 != 0)
    {
        Console.WriteLine(num);
    }
}

 

● 링큐 적용 방식

foreach문보다 직관적이다.

데이터 생성이 많아서 foreach문보다 조금 느리다.

// 데이터 모음집
List<int> nums = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
var oddNumbers = new List<int>();

// 짝수만 골라내고 싶을 때
var evenNumbers = from num in nums     // nums에서 요소들 뽑아와
                  where num % 2 == 0   // 짝수인 애들 
                  select num;          // 반환해

Console.WriteLine("Even numbers : ");
foreach (var num in evenNumbers) Console.WriteLine(num);

 

● 링큐 함수 적용 방식

일반 링큐와 기능상의 차이는 없다.

가독성의 차이

// 데이터 모음집
List<int> nums = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

var evenNumbers = nums.Where(e => e % 2 == 0).Select(e => e);
// 기능상 같음. 가독성의 차이

Console.WriteLine("Even numbers : ");
foreach (var num in evenNumbers) Console.WriteLine(num);

 

GroupBy

1) group by 쿼리 구문

List<Student> students = new List<Student>();

// List에 키 넣음
students.Add(new Student { Id = 1, Name = "Sumi", Age = 23 });
students.Add(new Student { Id = 1, Name = "Suman", Age = 23 });
students.Add(new Student { Id = 2, Name = "Sumi2", Age = 18 });
students.Add(new Student { Id = 2, Name = "Suman2", Age = 18 });
students.Add(new Student { Id = 3, Name = "Sumi3", Age = 50 });

// 'group by' 쿼리 구문
var result = from student in students
             // student.Id 를 기준으로 students 컬렉션 그룹화
             group student by student.Id;

foreach (var item in result)
{
    Console.Write(item.Key);
    foreach (var item1 in item)
    {
    	// \t 탭 문자
        Console.WriteLine("\t {0}", item1.Name);
    }
}

 

2) GroupBy 함수 구문

List<Student> students = new List<Student>();

// List에 키 넣음
students.Add(new Student { Id = 1, Name = "Sumi", Age = 23 });
students.Add(new Student { Id = 1, Name = "Suman", Age = 23 });
students.Add(new Student { Id = 2, Name = "Sumi2", Age = 18 });
students.Add(new Student { Id = 2, Name = "Suman2", Age = 18 });
students.Add(new Student { Id = 3, Name = "Sumi3", Age = 50 });

var groups = students.GroupBy(e => e.Id);

foreach (var group in groups)
{
    Console.WriteLine(group.Key);
    foreach (var item in group)
    {
        // \t : 탭 문자
        Console.WriteLine("\t {0}", item.Name);
    }
}

 

 

 

Collection(컬렉션)

데이터를 그룹으로 관리한 것

 

Array(배열)

- 추가 삽입 삭제 불가능

- 수정 콜렉션 중 제일 빠름

- '수정하면 안되는 그룹' 이라고 명시할 때 쓰임

int[] arr = { 1, 2, 3 };

// 수정 가능
arr[1] = 5;

// 추가 삽입 삭제 불가능
// arr.Append(5); (X)

Console.WriteLine(arr);

 

List(리스트)

- 배열의 확장판

- 추가 삽입 삭제 가능

List<int> nums = new List<int> { 1, 2, 3 };

// 삭제 가능
nums.RemoveAt(2);
foreach (var num in nums) Console.WriteLine();

// 추가 가능
nums.Add(4);
foreach (var num in nums) Console.WriteLine();

 

ArrayList

- 고정되지 않음

- 추가 삭제 가능

- 여러 타입의 데이터 저장 가능

- 다른 언어끼리 메모리 교환할 때 나타나는 박싱, 언박싱 발생 => 메모리에 부담 많이 준다

 

Dictionary(딕셔너리)

- 인덱스 번호를 대신해 사용하는 Key와 키가 가지는 값 Value를 세트로 다루는 배열

Dictionary<string, int> dic = new Dictionary<string, int>();

// 키와 키에 대한 밸류를 가짐
dic["단검"] = 1;
dic["장검"] = 2;
dic["도끼"] = 3;
dic["채찍"] = 4;

foreach (var item in dic) Console.WriteLine(item);

// 원하는 값을 찾을 수 있는 key 값을 이용하여
// 순차적으로 탐색하지 않고 원하는 value값을 바로 찾을 수 있음.
string keyToFind = "단검";

// TryGetValue 사용
if (dic.TryGetValue(keyToFind, out int value))
    Console.WriteLine($"키 {keyToFind}에 해당하는 값 : {value}");
else
    Console.WriteLine($"키 {keyToFind}가 딕셔너리에 없음.");

// 키 직접 접근
if (dic.ContainsKey(keyToFind))
{
    int valueDirect = dic[keyToFind];
    Console.WriteLine($"키 {keyToFind}에 해당하는 값 : {valueDirect}");
}
else
    Console.WriteLine($"키 {keyToFind}가 딕셔너리에 없음.");

 

=> 강사님은 List와 Dictionary 를 추천하셨다!

 


아이템에 이펙트는 처음 붙여보았는데, 이펙트 내에 소리를 넣고

아이템에 이펙트 스크립트를 넣어 본인을 Distroy 한다는 것이 새로웠다.

이 방식을 익혀놓아야겠다.

 

링큐를 접하면서 개발자들이 상당히 많이 쓰는 문법이라는 것을 알았다.

아직 익숙지 않고 어렵지만, 반복해서 나의 것으로 만들어야겠다.