본문 바로가기
Development/멋쟁이사자처럼 게임개발 부트캠프

[멋쟁이사자처럼 Unity 게임 부트캠프 4기] 10일차 - 네임스페이스 & 필드 & 생성자, 소멸자 & ref, out & 추상 클래스

by jjeondeuk1008 2025. 3. 13.

 

[ 목차 ]

     

     

     


     

    오늘은 10일차다 !

     

    오늘은 상속과 관련된 것, 클래스와 관련된 것

     

    앞에 내용에서 복습을 같이 하는 겸,

    응용해 어떤 방식으로 활용하는 지에 대한 내용이 많다.

     

    이미 아는 내용도 있을 수 있고, 저번에 배운 내용이 다시 언급되는 일도 허다하다.

     

    오늘도 집중하면서 힘내자!

     

    파이팅! 😊

     

     

     

     

     


     

     

     

     

    1. 네임스페이스 (namespace)

     

    기존에 파일을 생성할 때 주어지는 namespace 외에도 새로운 namespace를 만들 수 있다.

    namespace Hello
    {
        public class Say
        {
            public void SayHello()
            {
                Console.WriteLine("안녕하세요!");
            }
        }
    }
    
    namespace lionstudy57
    {
        class Program
        {
            static void Main(string[] args)
            {
                Hello.Say sa = new Hello.Say();
                sa.SayHello();
            }
        }
    }
    

     

     

    코드를 보면 알 수 있듯이 반복적인 namespace가 있을 것이다.

     

    Main 에서 namespace를 붙이기엔 귀찮고 번거로워요!

    하면 여기에 추가를 하면 된다.

     

     

    전)

    static void Main(string[] args)
    {
    		Hello.Say sa = new Hello.Say();
    		sa.SayHello();
    }
    

     

    후)

    static void Main(string[] args)
    {
        Say sa = new Say();
        sa.SayHello();
    }
    

     

     

     


     

     

    2. 필드

     

    필드는 클래스나 구조체의 데이터를 저장하는데 사용되는 멤버이다.

     

    간단한 예시로 아래의 코드가 필드인 것이다.

    public string name;

     

     

    아래의 예제로는 필드를 정의하고,

     

    Main에서 변수 p를 선언하고

    클래스 Person을 불러내

    필드에 값을 넣어 호출할 수 있다.

    class Person
    {
        public string name;  //필드 클래스의 데이터를 저장한는 멤버
    }
    
    class Program
    {
        static void Main(string[] args)
        {
            Person p = new Person();
            p.name = "Alice"; //필드에 값 넣기
            Console.WriteLine(p.name);
        }
    }
    

     

     

     

    외부에서 쓰지 못하게 코드를 보호하는 방법이 있다.

     

    그건 바로 public을 쓰지 않고 private를 쓰는 것이다.

    이렇게 되면 메인에서 오류가 난다. (외부에서 못 쓰기 때문)

    class Person
    {
        private string name;  //필드 클래스의 데이터를 저장한는 멤버
        //private : 외부에서 못 쓰게 막기
    }
    

     

     

    private를 활용하고,

    return을 통해 외부에서 name 필드의 값을 읽을 수 있게 된다.

    class Person
    {
        private string name;  //필드 클래스의 데이터를 저장한는 멤버
        //private : 외부에서 못 쓰게 막기
    
        public void SetName(string n)
        {
            name = n;
        }
        public string GetName()
        {
            return name;
        }
    }
    
    class Program
    {
        static void Main(string[] args)
        {
            Person p = new Person();
            p.SetName("Bob");
            Console.WriteLine(p.GetName());
        }
    }

     

     

     


     

     

    3. 생성자

     

    생성자는 클래스의 객체를 생성할 때 호출되는 특수한 메서드이다.

    생성자는 클래스의 이름과 동일해야한다. 반환 타입이 없어 void를 포함하지 않는다.

     

    생성자를 만들어 선언을 하고 Person 클래스의 인스턴스를 생성한다.

    class Person
    {
        public string Name;
        public Person()
        {
            Name = "Unknown";
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            Person p = new Person();
            Console.WriteLine(p.Name); //Unknown
        }
    }

     

     

     

    하나의 클래스에 여러 개의 생성자를 정의할 수 있다.

    이 경우에는 매개변수의 개수나 타입에 따라 생성자를 구분할 수 있다.

     

    매개변수가 없는 생성자를 기본 생성자라고 한다.

    매개변수를 통해 객체 생성 시에 초기 값을 설정할 수 있다.

    class Person
    {
        public string Name;
        public Person() //생성자
        {
            Name = "Unknown";
        }
    
        public Person(string name) //매개변수가 다른 생성자
        {
            Name = name;
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            Person p = new Person("앨리스"); //생성자 호출
            Console.WriteLine(p.Name);
        }
    }

     

     

    생성자를 이용해서 호출하는 응용 예제를 실습하였다.

    Name과 Age 변수명으로 필드를 선언하고,

    생성자로 초기값을 정한다.

     

    매개변수가 다른 생성자로 1개가 있는 매개변수, 2개가 있는 매개변수를 생성한다.

    Main에서 호출할 때 여러 생성자를 호출할 수 있다.

    class Person
    {
        public string Name;
        public int Age;
        public Person() //생성자
        {
            Name = "Unknown";
            Age = 0;
        }
    
        public Person(string name) //매개변수가 다른 생성자
        {
            Name = name;
            Age = 0;
        }
    
        public Person(string name, int age)
        {
            Name = name;
            Age = age;
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            Person p = new Person(); //생성자 호출
            Person p1 = new Person("Bob"); //1개의 매개변수 있는 생성자
            Person p2 = new Person("카타리나", 20); //2개의 매개변수 (name, age)
    
            Console.WriteLine(p.Name + ", " + p.Age);
            Console.WriteLine(p1.Name + ", " + p1.Age);
            Console.WriteLine(p2.Name + ", " + p2.Age);
        }
    }
    

     

     

     


     

    4. 소멸자

     

    메서드 앞에 물결표(~)가 존재한다.

    클래스의 객체가 소멸될 때 실행된다.

     

    이 소멸자는 객체가 더 이상 사용되지 않을 때

    (가비지 컬렉션에 의해 메모리에서 해제될 때)

    자동으로 호출된다.

     

    가비지 컬렉션(GC)는 더 이상 참조되지 않은 객체를 정리한다.

    class MyResource
    {
        ~MyResource()
        {
            Console.WriteLine("삭제될 때 호출");
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            MyResource r = new MyResource();
            // GC에 의해 나중에 소멸자 호출
            
            //가비지 컬렉션(GC)는 더이상 참조되지 않은 객체를 정리한다.
        }
    }

     

     

     


     

    5. 메서드 매개변수 ref out

     

    (1) ref

    ref 키워드를 사용하면 메서드에 전달된 변수를 참조로 전달한다.

    메서드 내에서 변수의 값을 수정하면 호출한 쪽도 같이 수정된다.

    class Program
    {
        //ref 포인터개념 참조
        //메서드 매개변수 ref, out
        static void Increase(ref int x)
        {
            x++;
        }
    
        static void Main(string[] args)
        {
            int a = 10;
            Increase(ref a);
    
            Console.WriteLine("A의 값: " + a);
        }
    }

     

    처음 보았을 때

    코드의 흐름을 알기 쉽지 않아서 따로 정리해보았다.

     

    int a = 10; 의 값을

    Increase(ref a);에 입력이 되고 a를 매개변수로 전달한다.

     

    그로 인해 a 값이 x 값과 함께 영향을 받게 된다.

    x++ 연산자로 인해

     

    값이 1이 증가했으므로, 결과는 11이 되는 것이다.

     

     

     

    (2) out

     

    out 키워드는 메서드에 변수를 참조로 전달하지만, 메서드 내에서 반드시 값을 할당해야 한다.

    ref와 달리 메서드 호출 전에 초기화할 필요가 없다.

     

    아래의 메서드는 두 개의 정수 매개변수 a와 b를 받고,

    두 개의 out 매개변수 x와 y를 받는다.

     

    그 out 매개변수는 a 와 b 값으로 초기화한다.

     

    Main 메서드에서 a 는 10, b 는 20

     

    OutFunc(a, b, out x, out y);

    코드로 인해 x와 y는 out으로 전달한다.

     

    x와 a는 같고, y는 b와 같다.

    고로 x는 10, y는 20 이다.

    //out은 반환이 여러개일때 유용하다
    static void OutFunc(int a, int b, out int x, out int y)
    {
        x = a;
        y = b;
    }
    
    static void Main(string[] args)
    {
        int a = 10;
        int b = 20;
        int x, y;
        OutFunc(a, b, out x, out y);
    
        Console.WriteLine("x : " + x + " y : " + y);
    
    }

     

     

     


     

    6. 추상 클래스 (abstract class)

     

    추상 클래스는 객체를 생성할 수 없는 클래스이다.

    상속을 통해서만 사용할 수 있다.

     

    공통적인 기능을 정의하고, 상속받은 클래스가 구현하도록 강제할 때 사용된다.

    선언만 하고, 구현은 하지 않는다.

     

    상속 받은 클래스는 반드시 구현해야 한다.

    abstract class Animal
    {
        //추상 메서드 (구현 x, 상속받은 클래스가 구현)
        public abstract void MakeSound();
    
        //일반 메서드(공통 기능 제공)
        public void Sleep()
        {
            Console.WriteLine("동물이 잠을 잡니다.");
        }
    }
    
    class Dog : Animal
    {
        public override void MakeSound()
        {
            Console.WriteLine("멍멍!");
        }
    }
    
    class Cat : Animal
    {
        public override void MakeSound()
        {
            Console.WriteLine("야옹~");
        }
    }
    
    class Program
    {
    
        static void Main(string[] args)
        {
            Animal myDog = new Dog();
            myDog.MakeSound(); //멍멍
            myDog.Sleep();
    
            Animal myCat = new Cat();
            myCat.MakeSound();
            myCat.Sleep();
        }
    }

     

     

     


     

    7. 메서드 오버라이드

     

     

    상속을 사용하여 부모 클래스의 메서드를 자식 클래스에서 재정의(구현)하는 기능이다.

     class Parent
     {
         protected string name; //부모 자식이 같이 쓸 수 있음
    
         public Parent(string name)
         {
             this.name = name;
             Console.WriteLine($"부모 생성자: {name}");
         }
     }
    
     class Child : Parent
     {
         private int age;
    
         //부모 생성자를 호출하면서 name 전달 + 추가로 age 초기화
         public Child(string name, int age):base(name)
         {
             this.age = age;
             Console.WriteLine($"자식 생성자: 나이 = {age}");
         }
    
         public void ShowInfo()
         {
             Console.WriteLine($"이름: {name}, 나이 {age}");
         }
     }
     class Program
     {
         static void Main(string[] args)
         {
             Child child = new Child("홍길동", 25);
             child.ShowInfo();
         }
     }
    

     

     

     

     


     

    8. 실습

     

    (1) 클래스를 새로 생성하는 방법 (같은 파일로 연결이 되지만, 가독성 좋게 분할)

     

    솔루션 탐색기 - 추가 - 새항목

     

     

     

    (2) 간단한 TextRPG 실습

     

    GameCharacter 클래스

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace lionstudy64_Parent_class_test
    {
        public abstract class GameCharacter
        {
            //필드 생성
            public string Name { get; set; }
            public int Health { get; set; }
            public int Attack { get; set; }
            public int Defense { get; set; }
    
            protected GameCharacter(string name, int health, int attack, int defense)
            {
                Name = name;
                Health = health;
                Attack = attack;
                Defense = defense;
            }
    
            //추상메서드: 모든 캐릭터가 구현해야 하는 기본 공격
            public abstract void BasicAttack(GameCharacter target);
    
            //추상메서드 : 모든 캐릭터가 구현해야 하는 특수 공격
            public abstract void SpecialAttack(GameCharacter target);
    
            //일반메서드: 모든 캐릭터가 공유하는 기능
            public void TakeDamage(int damage)
            {
                int actualDamage = Math.Max(1, damage - Defense);
    
                Health = Math.Max(0, Health - actualDamage);
    
                Console.WriteLine($"{Name}가 {actualDamage}의 피해를 받았습니다. 남은체력: {Health}");
    
            }
    
        }
    }
    
    

     

     

    Mage 클래스

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace lionstudy64_Parent_class_test
    {
        public class Mage : GameCharacter
        {
    
            public Mage(string name) : base(name, 80, 20, 5) //(이름, 체력, 공격력, 방어력)
            {
    
            }
            public override void BasicAttack(GameCharacter target)
            {
                Console.WriteLine($"{Name}가 {target.Name}에게 마법 구체를 던집니다.");
                target.TakeDamage(Attack);
            }
    
            public override void SpecialAttack(GameCharacter target)
            {
                Console.WriteLine($"{Name}가 {target.Name}에게 화염 폭발을 시전합니다.");
                target.TakeDamage(Attack * 2);
    
            }
        }
    }
    
    

     

     

    Warrior 클래스

    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Xml.Linq;
    
    namespace lionstudy64_Parent_class_test
    {
        class Warrior : GameCharacter
        {
            public Warrior(string name) : base(name, 100, 15, 10) //(이름, 체력, 공격력, 방어력)
            {
    
            }
            public override void BasicAttack(GameCharacter target)
            {
                Console.WriteLine($"{Name}가 {target.Name}에게 기본 공격을 시도합니다!");
                target.TakeDamage(Attack);
            }
    
            public override void SpecialAttack(GameCharacter target)
            {
                Console.WriteLine($"{Name}가 {target.Name}에게 필살기를 시전합니다.");
                target.TakeDamage(Attack * 2);
    
            }
        }
    }
    
    

     

     

    Main 클래스

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace lionstudy64_Parent_class_test
    {
    
        class Program
        {
            static void Main(string[] args)
            {
                Console.WriteLine("RPG 게임을 시작합니다.");
    
                //캐릭터 생성
                GameCharacter warrior = new Warrior("전사");
                GameCharacter mage = new Warrior("마법사");
    
                //전투 시뮬
                Console.WriteLine("========전투 시작!=========");
    
                //전사의 공격
                warrior.BasicAttack(mage);
                warrior.SpecialAttack(mage);
    
                //마법사의 반격
                mage.BasicAttack(warrior);
                mage.SpecialAttack(warrior);
    
                Console.WriteLine("========전투 종료=========");
                Console.WriteLine($"전사 남은 체력: {warrior.Health}");
                Console.WriteLine($"마법사 남은 체력: {mage.Health}");
            }
        }
    }
    
    

     

     

     


     

    시작한지 10일차까지 왔다.. 현재 체감상

    하루에 오래 공부하다보니 한 달은 공부한 느낌이다.

     

    벼락치기를 엄청나게 많이 한 느낌!?

     

    매일 매일이 뜻 깊게 보내는 듯 해서

    이러한 공부할 계기가 되는 부트캠프는 나의 좋은 선택인 것 같다.

     

    이제 C#의 끝이 보인다.

     

    며칠 내로 유니티에 들어가니!

    본격적인 게임 제작을 시작할 테니 많은 기대 부탁!

     


    목차