티스토리 뷰

스타크래프트.

1990년대 후반에 나온 이 게임은 인기가 정말 대단했습니다. 필자는 새로운 게임을 배우는 것이 귀찮은 나머지 원래부터 좋아하던 축구 게임만 즐기고 있었는데 PC방에 가는 친구들 중 90% 가 모두 스타크래프트만 했습니다. 도저히 안되겠다 싶어서 게임을 배우기 시작했고 금방 그 재미에 푹 빠지고 말았지요. 20년이 훌쩍 지난 지금까지도 이 게임을 즐기는 사람들이 많은 것을 보면 참 신기하면서도 고개가 끄덕여집니다. GG (Good Game) 라는 신조어를 만들어낸 국민 게임 스타크래프트, 파이썬으로 조금이나마 함께 만들어 봅시다.

 

이번에 배울 클래스는 처음 접하는 분들에게는 다소 어렵게 느껴질 수 있습니다. 어쩌면 파이썬 기본편 내용 전체를 통틀어서 가장 어려운 부분이 아닐까 싶기도 하네요. 하지만 너무나도 중요한 개념이기 때문에 반드시 이해를 하고 넘어가셔야 합니다. 어느 정도 규모 있는 프로젝트에 클래스가 없다는 것은 상상도 할 수 없을 만큼 흔히 쓰이기도 하지요. 여기서는 국민 게임인 스타크래프트를 텍스트 버전으로 만들어보면서 클래스를 하나씩 파헤쳐보도록 하겠습니다. 스타크래프트를 잘 모르시는 분들을 위해 부연 설명도 함께 드릴테니 힘차게 이번 장을 시작하면 좋겠습니다.

 

스타크래프트는 테란(지구인), 저그(괴물), 프로토스(외계인) 라는 이름의 세 종족이 서로 전쟁을 하는 게임입니다. 이 중에서 우리가 가장 이해하기 쉬운 테란 종족을 선택하고 게임을 플레이 한다고 가정하겠습니다. 테란은 전쟁을 위한 군인, 탱크, 전투기와 같은 유닛들을 만들 수 있으며, 이들을 최대한 빠르게, 그리고 많이 만들어서 적군을 공격하여 궤멸시키는 것이 게임의 목표입니다.

 

 

테란의 가장 기본 유닛인 마린을 먼저 만들어보겠습니다. 마린은 총을 쏠 수 있는 군인이라고 이해하시면 됩니다.

 

 

유닛의 이름과 체력 그리고 공격력 정보를 각각의 변수에 저장하고 유닛이 생성되었다는 내용과 함께 유닛의 정보를 출력하는 것까지 코드를 작성하겠습니다.

# 마린 : 공격 유닛, 군인. 총을 쏠 수 있음
name = "마린" # 유닛의 이름
hp = 40 # 유닛의 체력
damage = 5 # 유닛의 공격력

print("{} 유닛이 생성되었습니다.".format(name))
print("체력 {0}, 공격력 {1}\n".format(hp, damage))

 

실행을 해보니 마린이 잘 만들어졌네요.

마린 유닛이 생성되었습니다.
체력 40, 공격력 5

 

이번에는 다른 유닛인 탱크를 하나 만들어보겠습니다. 탱크는 지상전에서는 최고의 유닛이라 불릴 만큼 강력한데요. 이동을 하면서 공격하는 일반 모드도 있지만, 지상에 탱크를 고정시키고 공격하는 시즈모드로 바뀌게 되면 공격 사정거리가 늘어나게 되고 공격력도 막강해집니다. 

 

 

name, hp, damage 라는 변수는 이미 쓰였기 때문에 이번에는 각각의 변수 앞에 tank_ 를 붙여서 탱크 유닛을 만들고 내용을 출력해보겠습니다.

# 탱크 : 공격 유닛, 탱크. 포를 쏠 수 있는데, 일반 모드 / 시즈 모드
tank_name = "탱크"
tank_hp = 150
tank_damage = 35

print("{} 유닛이 생성되었습니다.".format(tank_name))
print("체력 {0}, 공격력 {1}\n".format(tank_hp, tank_damage))

 

지금까지 작성한 전체 코드를 함께 실행시켜보니 마린과 탱크가 각각 잘 만들어진 것을 확인할 수 있습니다.

마린 유닛이 생성되었습니다.
체력 40, 공격력 5

탱크 유닛이 생성되었습니다.
체력 150, 공격력 35

 

이제 이 두 유닛을 데리고 공격을 한다고 가정해보겠습니다. 공격을 하는 부분은 공통으로 처리할 수 있을 것 같으니 함수로 정의해보겠습니다. 앞에서 작성한 코드에 이어서 다음 내용을 추가합니다.

# 공격 함수
def attack(name, location, damage):
	print("{0} : {1} 방향으로 적군을 공격 합니다. [공격력 {2}]".format(name, location, damage))

그리고 attack() 함수를 통해 마린과 탱크에게 1시 방향을 공격을 하도록 명령을 내려보겠습니다.

attack(name, "1시" , damage) # 마린 공격 명령
attack(tank_name, "1시" , tank_damage) # 탱크 공격 명령

실행을 해보니 두 유닛 모두 올바르게 공격을 하는 것을 볼 수가 있습니다.

... (생략) ...

마린 : 1시 방향으로 적군을 공격 합니다. [공격력 5]
탱크 : 1시 방향으로 적군을 공격 합니다. [공격력 35]

 

아직까지는 괜찮아 보입니다. 그런데 만약 탱크를 하나 더 만들면 어떻게 될까요? 앞에서 tank_ 를 붙인 tank_name, tank_hp, tank_damage 변수는 이미 썼으니까 이번에는 tank2_ 라고 하여 tank2_name, tank2_hp, tank2_damage 라고 해볼 수 있겠네요. 새로운 탱크를 추가한 전체 코드는 다음과 같습니다.

# 마린 : 공격 유닛, 군인. 총을 쏠 수 있음
name = "마린" # 유닛의 이름
hp = 40 # 유닛의 체력
damage = 5 # 유닛의 공격력

print("{} 유닛이 생성되었습니다.".format(name))
print("체력 {0}, 공격력 {1}\n".format(hp, damage))

# 탱크 : 공격 유닛, 탱크. 포를 쏠 수 있는데, 일반 모드 / 시즈 모드
tank_name = "탱크"
tank_hp = 150
tank_damage = 35

print("{} 유닛이 생성되었습니다.".format(tank_name))
print("체력 {0}, 공격력 {1}\n".format(tank_hp, tank_damage))

# 탱크2 새로 추가
tank2_name = "탱크"
tank2_hp = 150
tank2_damage = 35

print("{} 유닛이 생성되었습니다.".format(tank2_name))
print("체력 {0}, 공격력 {1}\n".format(tank2_hp, tank2_damage))

# 공격 함수
def attack(name, location, damage):
	print("{0} : {1} 방향으로 적군을 공격 합니다. [공격력 {2}]".format(name, location, damage))

attack(name, "1시" , damage) # 마린 공격 명령
attack(tank_name, "1시" , tank_damage) # 탱크 공격 명령
attack(tank2_name, "1시" , tank2_damage) # 탱크2 공격 명령

 

하지만 실제 게임에서는 서로 다른 종류의 유닛들이 최소 수십에서 많게는 수백개가 존재합니다. 유닛마다 이렇게 서로 다른 정보(이름, 체력, 공격력 등) 를 관리하기에는 무리가 많이 따르겠지요.

 

 

이 때 필요한 것이 바로 클래스입니다. 클래스는 보통 붕어빵 기계의 틀에 비유를 하는데요. 붕어빵을 만들 때 틀에다가 재료를 넣고 불에 구우면 똑같은 모양의 붕어빵을 만들 수 있습니다. 틀은 하나인데 붕어빵은 계속해서 만들 수 있는 것이죠. 클래스도 이러한 하나의 틀이라고 생각하시면 되는데 보통 서로 연관이 있는 변수와 함수의 집합으로 이루어집니다.

 

기본적인 클래스는 이렇게 생겼습니다. class 뒤에 클래스 이름을 정의하고 콜론(:) 을 적습니다. 그리고 다음줄부터는 들여쓰기를 하고 필요한 메소드를 정의합니다. 클래스 내에서 정의되는 함수를 메소드라고 하는데, 앞에서 배운 함수와 거의 동일합니다. 다만 첫 번째 전달값 위치에는 self 라는 것이 적힌다는 것을 주의해주세요. 메소드 내의 각 실행명령문들은 또 한 번 들여쓰기를 통해서 정의해줍니다.

class 클래스명:
    def 메소드1(self, 전달값1, 전달값2, ...):
        실행명령문1
        실행명령문2
        ...

    def 메소드2(self, 전달값1, 전달값2, ...):
        실행명령문1
        실행명령문2
        ...

 

복잡하게 생겼죠? 이렇게만 해서는 사용법이 잘 와닿지 않을 것 같으니 앞에서 만들었던 코드를 클래스를 이용하여 새롭게 만들어보겠습니다. Unit 이라는 이름으로 클래스를 정의하고 메소드를 하나 만드는데 이름은 __init__ (언더바를 앞뒤로 각각 2개씩 적어주세요) 으로 합니다. 그리고 처음에는 일단 self 를 적고 뒤에는 이름, 체력, 데미지에 해당하는 전달값들을 적어줍니다. 메소드 내에서는 다음과 같은 형태로 변수를 정의할 수 있습니다.

self.변수명 = 값

이렇게 정의된 변수를 멤버변수라고 하는데, 클래스 내에서 사용할 수 있는 변수 정도로 이해하시면 됩니다. 자세한 내용은 뒤에 다시 다루도록 하겠습니다. 마지막으로 생성된 유닛 정보를 출력해줍니다.

class Unit:
    def __init__(self, name, hp, damage):
        self.name = name # 멤버변수 name 에 전달값 name 저장
        self.hp = hp
        self.damage = damage
        print("{0} 유닛이 생성되었습니다.".format(self.name))
        print("체력 {0}, 공격력 {1}".format(self.hp, self.damage))

 

처음으로 클래스를 하나 만들었습니다. 그런데 클래스도 함수와 마찬가지로 정의만 해서는 아무 동작을 하지 않습니다. 클래스 밖에서 유닛을 직접 만들어볼텐데요. 이 때 클래스를 통해서 만들어지는 것을 객체(Object)라고 표현하며, 이 객체는 클래스의 인스턴스(Instance)가 됩니다.

marine1 = Unit("마린", 40, 5) # 마린1 생성. 전달값으로 name, hp, damage 를 전달
marine2 = Unit("마린", 40, 5) # 마린2 생성
tank = Unit("탱크", 150, 35) # 탱크 생성

마린 2기와 탱크 1기를 만들었는데요. 클래스를 통해 객체를 생성할 때는 이런 형식으로 합니다.

변수명 = 클래스명(전달값1, 전달값2, ...) # 전달값은 클래스의 __init__() 에 정의된 부분 중 self 를 제외한 값

코드를 실행시켜보면 유닛들이 잘 생성되는 것을 볼 수 있습니다. 하나의 동일한 클래스로 서로 다른 유닛을 만든 것이죠.

마린 유닛이 생성되었습니다.
체력 40, 공격력 5
마린 유닛이 생성되었습니다.
체력 40, 공격력 5
탱크 유닛이 생성되었습니다.
체력 150, 공격력 35

 

지금까지 클래스에 대해 아주 많은 내용이 언급되었는데 간략히 소개하고 넘어간 부분은 뒤에서 하나씩 차근차근 다뤄보도록 하겠습니다. 여기에서는 클래스라는 것이 어떤 건지에 대한 개념만 짚고 넘어가셔도 충분합니다.

 

다시 정리하면, 클래스는 서로 관련이 있는 변수 (멤버변수) 와 함수 (메소드) 들의 집합입니다. 스타크래프트에서 마린과 탱크는 모두 이름, 체력, 공격력이 있습니다. 이들은 공통 속성이므로 하나의 틀, 즉 클래스로 정의할 수 있습니다. 클래스 내에는 여러 개의 메소드를 정의할 수 있는데 각 메소드의 첫 번째 전달값 위치에는 self 를 적어주도록 합니다. __init__() 메소드를 통해 기본적으로 필요한 전달값들을 전달받고 self. 을 통해 클래스의 멤버 변수를 정의합니다. 

 

Unit 클래스를 통해 만들어진 마린과 탱크를 객체라고 하며, 이 때 "마린과 탱크는 Unit 클래스의 인스턴스다" 라고 합니다.

 

 

다음은 클래스 정의 부분부터 작성된 전체 코드입니다.

class Unit:
    def __init__(self, name, hp, damage):
        self.name = name
        self.hp = hp
        self.damage = damage
        print("{0} 유닛이 생성되었습니다.".format(self.name))
        print("체력 {0}, 공격력 {1}".format(self.hp, self.damage))

marine1 = Unit("마린", 40, 5)
marine2 = Unit("마린", 40, 5)
tank = Unit("탱크", 150, 35)

'파이썬 강의 > 기본편' 카테고리의 다른 글

[파이썬 기본편] 9-3.멤버변수  (2) 2021.03.08
[파이썬 기본편] 9-2.__init__  (0) 2021.03.07
[파이썬 기본편] 8-6.퀴즈 #7  (10) 2021.03.05
[파이썬 기본편] 8-5.with  (4) 2021.03.04
[파이썬 기본편] 8-4.pickle  (2) 2021.03.03
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
글 보관함