void Test() { C05_Knight knight = new C05_Knight(); //새로 생성하지 않고 null로 남겨두면, 대상이 없어 접근할 수 없다. //게임에서 에러의 70% 이상은 이런 Null Reference Exception 에러(참조할 대상이 비어 있는 상태)에 해당한다. knight.hp = 100; knight.power = 10; knight.Move(); knight.Attack(); }
void KillObjectTest() { //기사와 마법사를 생성하고, 생성한 기사와 마법사를 새로운 변수에 대입하여 하나 더 만든 뒤, 이름만 달리해 준다. C05_Knight knight = new C05_Knight(); knight.name = "기사 1"; knight.hp = 100; knight.power = 10; C05_Knight knight2 = knight; knight2.name = "기사 2"; C05_Mage mage = new C05_Mage(); mage.name = "마법사 1"; mage.hp = 50; mage.power = 20; C05_Mage mage2 = mage; mage2.name = "마법사 2"; //첫 번째 기사와 마법사를 죽인다. KillKnight(knight); KillMage(mage); //그 후 출력해보면, 기사는 두 번째 기사가 죽어있고 첫번째와 두번째 기사의 정보가 동일하다. //Class는 대입할 때 메모리 주소(포인터)를 대입하므로, 기사2는 기존에 생성된 기사1을 가리키는 값일 뿐이다. 따라서 기사1과 기사2는 하나의 객체를 가리킨다. //KillKnight에서 Class 변수를 가져가 변경했으니, 이는 기사1과 기사2가 가리키는 주소에 위치한 값을 실제로 변경했다. 따라서 hp도 0이 되었다. Debug.Log($"죽은 기사는 {knight.name} (체력: {knight.hp})이며, 살아있는 기사는 {knight2.name} (체력: {knight2.hp}) 입니다."); //반면 마법사는 mage와 mgae2가 선언될 때 각각 별개의 메모리 공간을 갖는다. //둘은 다른 객체이므로 마법사 1의 정보 변경(사망)은 마법사 2에게 영향을 주지 않을 뿐더러, mage의 값을 복사해서 가져간 KillMage의 영향도 받지 않아서 원본의 hp도 그대로다. Debug.Log($"죽은 마법사는 {mage.name} (체력: {mage.hp})이며, 살아있는 마법사는 {mage2.name} (체력: {mage2.hp}) 입니다."); }
//---------------------------------------------------------------------------- //2.복사와 참조 // E01에서 사용한 struct는 구조체로 복사 형식이며, Class는 참조 형식이라는 차이가 있다. // struct를 대입하면 해당 객체가 가진 값을 변수에 저장하지만, Class를 대입하면 해당 객체가 저장된 메모리 주소값(포인터)을 변수로 갖는다. // struct는 값으로 불러오면 원래의 값을 복사한 별개의 값을 가져오지만, Class는 메모리 주소를 복사해 가져오므로 원래의 객체 그대로를 참조한다. // 함수에서 ref를 사용하지 않아도 Class가 변수로 들어 있다면 ref를 사용한 변수처럼 원본을 참조하게 된다. //struct로 만든 Mage와 Class로 만든 Knight를 비교해보자. //객체를 매개변수로 넣으면 hp를 0으로 만드는 함수를 만든다. void KillKnight(C05_Knight knight) { knight.hp = 0; Debug.Log($"{knight.name} 사망 (체력: {knight.hp})"); }