/// <summary>
/// 랜덤 스테이지 생성 후 층수에 맞는 강함을 지닌 몬스터를 소환하는 함수 입니다.
/// </summary>
/// <param name="floor">탑 층수</param>
public void CreateStage(int floor = 1)
{
StageType stageType = RandomStageType(floor);
int stageID = 0;
Debug.Log(stageType);
// 스테이지 특성에 맞는 몬스터 생성
switch (stageType)
{
case StageType.Boss:
stageID = RandomStageID<BossStageData>(Managers.Data.GameDataBase.BossStageDatas);
BossStageData bossStage = Managers.Data.GameDataBase.BossStageDatas[stageID];
CreateMonster(bossStage._name, bossStage._monsterIDs, bossStage._monsterQuantity);
break;
case StageType.Normal:
stageID = RandomStageID<NormalStageData>(Managers.Data.GameDataBase.NormalStageDatas);
NormalStageData normalStage = Managers.Data.GameDataBase.NormalStageDatas[stageID];
CreateMonster(normalStage._name, normalStage._monsterIDs, normalStage._monsterQuantity);
break;
case StageType.Event:
// 얘는 빼도 될듯. 그라운드 생성 고려 하여 일단 두기로 결정
break;
}
}
/// <summary>
/// 리스트에 저장된 스테이지타입을 랜덤으로 선택하여 ID(인덱스) 값을 반환하는 함수 입니다.
/// </summary>
/// <returns>랜덤 스테이지타입 ID</returns>
private StageType RandomStageType(int floor)
{
int stageType;
if (floor % 10 == 0)
{
stageType = 0; // 보스타입 고정
}
else
{
int stageCount = Managers.Data.GameDataBase.StageTypeDatas.Count; // 스테이지 종류 갯수 반환
stageType = Random.Range(1, stageCount); // 보스방 빼고 랜덤 선택
}
return (StageType)stageType; // 이넘으로 변환
}
/// <summary>
/// 랜덤 스테이지 ID를 반환하는 함수 입니다.
/// </summary>
/// <typeparam name="T">해당 스테이지 데이터테이블</typeparam>
/// <param name="stageMonster">스테이지 딕셔너리</param>
/// <returns>스테이지 ID</returns>
private int RandomStageID<T>(Dictionary<int, T> stageMonster)
{
List<int> keys = new List<int>(stageMonster.Keys);
// 딕셔너리에서 키 추출하여 리스트 만듬
int randomIndex = Random.Range(0, keys.Count);
// 키 리스트 카운트 범위내에서 랜덤 인덱스
return (int)keys[randomIndex];
}
/// <summary>
/// 몬스터를 생성해주는 함수 입니다.
/// </summary>
/// <param name="stageName">스테이지 이름</param>
/// <param name="monsterIDs">몬스터 ID 리스트</param>
/// <param name="monsterQuantity">몬스터 수 리스트</param>
private void CreateMonster(string stageName, List<int> monsterIDs, List<int> monsterQuantity)
{
Debug.Log(stageName);
GameObject monsterPrefab;
int listCount = monsterIDs.Count;
for(int i = 0; i < listCount; i++)
{
monsterPrefab = Resources.Load<GameObject>(Managers.Data.GameDataBase.MonsterDatas[monsterIDs[i]]._prefabPath + Managers.Data.GameDataBase.MonsterDatas[monsterIDs[i]]._ID);
if (monsterPrefab != null)
Debug.Log("프리펩이 없습니다.");
for (int j = 0; j < monsterQuantity[i]; j++)
{
Debug.Log(Managers.Data.GameDataBase.MonsterDatas[monsterIDs[i]]._name);
Debug.Log(Managers.Data.GameDataBase.MonsterDatas[monsterIDs[i]]._prefabPath + Managers.Data.GameDataBase.MonsterDatas[monsterIDs[i]]._ID);
//Managers.Pool.GetPool(monsterPrefab, monsterQuantity[i]);
}
}
}
using System;
class Program
{
static void Main()
{
// 변수 선언만 하고 초기화하지 않음
int result;
// out 매개변수로 메서드 호출
Calculate(5, 3, out result);
Console.WriteLine($"결과: {result}"); // 출력: 결과: 8
}
static void Calculate(int a, int b, out int sum)
{
// 반드시 값을 설정해야 함
sum = a + b;
}
}
static void Example(out int value, ref int refValue)
{
value = 10; // out 매개변수는 초기화 필수
refValue += 10; // ref 매개변수는 초기화되어 있음
}
static (int sum, int product) CalculateValues(int a, int b)
{
return (a + b, a * b);
}
var (sum, product) = CalculateValues(5, 3);
Console.WriteLine($"합: {sum}, 곱: {product}");
Unity에서는 여전히 out 키워드가 특정 상황에서 유용하게 사용됨
특히 Unity는 C# 7.0 이후의 최신 기능을 점진적으로 받아들이고 있지만, Unity API 자체가 out을 사용하는 경우가 많아서 이 키워드를 접할 일이 있음
Unity에서는 여전히 많이 쓰이는 이유
호환성과 성능
Unity는 최신 C# 기능을 점진적으로 도입하지만, 여전히 기존 API와의 호환성을 유지하기 위해 out을 사용하는 경우가 많음. 특히 Unity의 네이티브 엔진 코드와의 상호작용에서 out은 효율적인 데이터 반환 방법
간결함
out을 사용하면 필요하지 않은 객체나 데이터 구조를 추가로 생성하지 않고도 값을 반환할 수 있음. 이는 메모리 할당을 줄이는 데 도움이 됨
직관적 API 설계
Unity API는 사용하기 쉽도록 설계되어 있습니다. out은 초보자도 간단히 이해할 수 있으며, 명확하게 값이 반환됨을 나타내므로 직관적임
out RaycastHit hit
: 충돌된 객체와 관련된 정보를 반환하기 위해 사용됨hit
객체를 통해 충돌 위치, 충돌된 객체, 노멀 벡터 등의 정보를 얻을 수 있음using UnityEngine;
public class RaycastExample : MonoBehaviour
{
void Update()
{
if (Input.GetMouseButtonDown(0)) // 마우스 클릭 시
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out RaycastHit hit, 100f))
{
Debug.Log($"Hit Object: {hit.collider.gameObject.name}");
}
}
}
}
using UnityEngine;
public class ParseExample : MonoBehaviour
{
void Start()
{
string input = "123";
if (int.TryParse(input, out int result))
{
Debug.Log($"Parsed number: {result}");
}
else
{
Debug.Log("Parsing failed.");
}
}
}
1. 기본예제
using System;
class Program
{
static void Main()
{
int number = 10; // 초기화 필수
Console.WriteLine($"Before: {number}");
// ref를 사용하여 변수 전달
ModifyValue(ref number);
Console.WriteLine($"After: {number}");
}
static void ModifyValue(ref int value)
{
value *= 2; // 원본 변수 수정
}
}
Before: 10
After: 20
2. 여러 값 수정
using System;
class Program
{
static void Main()
{
int a = 5, b = 3;
Swap(ref a, ref b);
Console.WriteLine($"After Swap: a = {a}, b = {b}");
}
static void Swap(ref int x, ref int y)
{
int temp = x;
x = y;
y = temp;
}
}
After Swap: a = 3, b = 5
3. 배열과 ref
using System;
class Program
{
static void Main()
{
int[] numbers = { 1, 2, 3 };
Console.WriteLine($"Before: {string.Join(", ", numbers)}");
ModifyArray(ref numbers);
Console.WriteLine($"After: {string.Join(", ", numbers)}");
}
static void ModifyArray(ref int[] arr)
{
arr = new int[] { 10, 20, 30 }; // 배열 자체를 새로운 것으로 변경
}
}
Before: 1, 2, 3
After: 10, 20, 30