티스토리 뷰
지금까지 배운 클래스 내용을 바탕으로 마치 실제로 게임을 하는 것처럼 텍스트 기반의 스타크래프트 프로젝트를 완성해보도록 하겠습니다. 앞 장에서 super 를 공부하며 다뤘던 소스코드 및 유닛 생성 관련 부분은 제외하고 그 이전까지 만들었던 클래스들을 보완하는 방향으로 진행하겠습니다.
가장 기본이 되는 Unit 클래스부터 먼저 보겠습니다. 스타크래프트에서는 유닛이 생성될 때마다 각 유닛의 고유한 소리를 통해 생성되었음을 알려줍니다. 우리 코드에서는 소리 대신 __init__() 생성자에 print() 를 추가하여 어떤 유닛이 생성되었는지를 출력하도록 하겠습니다.
move() 메소드에서는 유닛 이동 관련하여 2번이나 출력하게 되어 있으므로 처음 출력문인 [지상 유닛 이동] 문구는 제외하도록 하겠습니다.
그리고 기존에 공격유닛인 AttackUnit 클래스를 만들면서 적군으로부터 공격을 받을 때 호출되는 damaged() 메소드를 정의하였는데 공격을 할 수 없는 일반 유닛도 공격을 받을 수 있기 때문에 이 메소드는 Unit 클래스로 이동을 하고 AttackUnit 클래스에서는 제외하도록 하겠습니다.
# 일반 유닛
class Unit:
def __init__(self, name, hp, speed):
self.name = name
self.hp = hp
self.speed = speed
print("{0} 유닛이 생성되었습니다.".format(name)) # 출력문 추가
def move(self, location):
# print("[지상 유닛 이동]") # 출력문 제외
print("{0} : {1} 방향으로 이동합니다. [속도 {2}]"\
.format(self.name, location, self.speed))
def damaged(self, damage): # AttackUnit 에서 Unit 으로 이동
print("{0} : {1} 데미지를 입었습니다.".format(self.name, damage))
self.hp -= damage
print("{0} : 현재 체력은 {1} 입니다.".format(self.name, self.hp))
if self.hp <= 0:
print("{0} : 파괴되었습니다.".format(self.name))
다음은 AttackUnit 클래스인데 Unit 클래스로 damaged() 메소드를 이동한 것 외에는 따로 수정하지 않겠습니다.
# 공격 유닛
class AttackUnit(Unit):
def __init__(self, name, hp, speed, damage):
Unit.__init__(self, name, hp, speed)
self.damage = damage
def attack(self, location):
print("{0} : {1} 방향으로 적군을 공격 합니다. [공격력 {2}]" \
.format(self.name, location, self.damage))
앞에서는 AttackUnit 을 통해 마린, 탱크 등 유닛을 생성하였는데 이번에는 각 유닛에 대한 클래스를 직접 정의하겠습니다. 먼저 마린 유닛을 위한 Marine 클래스를 만드는데 마린은 공격 유닛이므로 AttackUnit 을 상속받고 AttackUnit 의 생성자를 통해 체력, 이동 속도, 공격력을 설정하겠습니다.
마린은 스팀팩(stimpack)이라는 특수 기술이 있는데 이 기술을 사용하게 되면 일정 시간 동안 이동 및 공격 속도를 아주 빠르게 증가시킬 수 있습니다. 대신 자기 자신의 체력이 10 만큼 소모되기 때문에 현재 남은 체력이 10 보다 클 때만 사용할 수 있다는 조건이 필요합니다. stimpack() 이라는 메소드를 만들고 체력이 10 보다 크면 체력 10 소모 후 스팀팩 사용 문구 출력, 10보다 작으면 사용 불가하다는 문구 출력을 하도록 하겠습니다.
# 마린
class Marine(AttackUnit):
def __init__(self):
AttackUnit.__init__(self, "마린", 40, 1, 5) # 이름, 체력, 이동속도, 공격력
# 스팀팩 : 일정 시간 동안 이동 및 공격 속도를 증가, 체력 10 감소
def stimpack(self):
if self.hp > 10:
self.hp -= 10 # 체력 10 소모
print("{0} : 스팀팩을 사용합니다. (HP 10 감소)".format(self.name))
else:
print("{0} : 체력이 부족하여 스팀팩을 사용하지 않습니다".format(self.name))
마린에 이어서 탱크를 위한 Tank 클래스를 만들겠습니다. 마린과 동일하게 AttackUnit 클래스를 상속받구요. 탱크는 특수 기술로 시즈(siege)모드가 있는데 이 기술을 사용하면 지상에 탱크를 고정시켜서 무려 2배에 달하는 공격력과 더 넓은 사정거리로 공격이 가능합니다. 다만, 이 기술은 처음부터 바로 사용할 수는 없고 업그레이드를 통한 시즈모드 개발을 완료해야만 사용 가능한 것으로 하겠습니다.
테란 본진에서 시즈모드를 개발하게 되면 그 시점부터는 모든 탱크가 시즈모드로 전환할 수 있게 됩니다. 이미 만들어진 탱크도, 앞으로 만들어질 탱크도 모두 포함해서 말이죠. 이렇게 어떤 클래스로부터 만들어진 객체에 일괄적으로 뭔가를 적용하려면 멤버변수가 아닌 클래스 변수로 선언할 수 있습니다. 코드에서는 siege_developed 라는 이름으로 클래스 변수를 선언하는데 선언 위치가 어디인지를 잘 확인해주세요.
# 탱크
class Tank(AttackUnit):
# 시즈모드 : 탱크를 지상에 고정시켜, 더 높은 파워로 공격 가능. 이동 불가.
siege_developed = False # 시즈모드 개발여부
클래스 변수는 클래스 이름과 함께 어디서든지 사용 가능합니다. Tank.siege_developed 라고 하면 탱크 클래스 변수의 값에 직접 접근하여 시즈모드 개발이 완료되었는지를 확인할 수 있지요. 멤버변수가 각 클래스 객체마다 다른 값을 가진다면 클래스 변수는 모든 객체가 동일한 값을 가진다는 점이 다릅니다.
시즈모드 개발이 완료되었다고 해서 모든 탱크가 시즈모드를 항상 해야하는 것은 아니므로 시즈모드 여부를 확인하기 위해 siege_mode 라는 멤버변수를 정의합니다. 처음에는 일반모드일 테니 시즈모드를 해제 상태로, 즉 False 로 두겠습니다.
# 탱크
class Tank(AttackUnit):
... # 생략
def __init__(self):
AttackUnit.__init__(self, "탱크", 150, 1, 35) # 이름, 체력, 이동속도, 공격력
self.siege_mode = False # 시즈모드 (해제 상태)
그리고 시즈모드와 일반모드를 전환하기 위한 set_siege_mode() 메소드를 정의합니다. 이 메소드가 호출되면 현재 시즈모드 개발이 완료되었는지 여부를 먼저 확인하여 완료되지 않은 경우는 바로 메소드를 탈출하도록 하구요. 완료된 상태라면 지금 이 탱크 객체의 시즈모드 설정 여부를 확인하여 일반모드인 경우는 시즈모드로, 시즈모드인 경우는 일반모드로 전환합니다. 그 과정에서 공격력을 증가하거나 감소시켜주고 필요한 문구를 출력하도록 합니다. 마지막으로 멤버변수인 siege_mode 의 값을 True 또는 False 로 변경하여 시즈모드 설정 / 해제 여부를 저장합니다.
# 탱크
class Tank(AttackUnit):
... # 생략
# 시즈모드
def set_siege_mode(self):
if Tank.siege_developed == False: # 시즈모드가 개발되지 않은 경우 메소드 탈출
return
# 현재 시즈모드가 아닐 때
if self.siege_mode == False:
print("{0} : 시즈모드로 전환합니다.".format(self.name))
self.damage *= 2 # 공격력 2배로 증가
self.siege_mode = True # 시즈 모드 설정
# 현재 시즈모드일 때
else:
print("{0} : 시즈모드를 해제합니다.".format(self.name))
self.damage /= 2 # 공격력 절반으로 감소
self.siege_mode = False # 시즈 모드 해제
이전 장에서 공중 유닛을 위해 만들었던 Flyable 클래스와 공중 공격 유닛을 위한 FlyableAttackUnit 클래스를 가져와서 사용하겠습니다. Flyable 클래스는 수정할 필요 없이 그대로 두고, FlyableAttackUnit 클래스의 move() 메소드 내에 [공중 유닛 이동] 문구는 제외하도록 하겠습니다. move() 메소드가 호출되면 실제로는 부모 클래스인 Flyable 의 fly() 메소드가 실행되면서 어느 방향으로 날아가는지를 출력해주거든요.
# 날 수 있는 기능을 가진 클래스
class Flyable:
def __init__(self, flying_speed):
self.flying_speed = flying_speed
def fly(self, name, location):
print("{0} : {1} 방향으로 날아갑니다. [속도 {2}]"\
.format(name, location, self.flying_speed))
# 공중 공격 유닛
class FlyableAttackUnit(AttackUnit, Flyable):
def __init__(self, name, hp, damage, flying_speed):
AttackUnit.__init__(self, name, hp, 0, damage)
Flyable.__init__(self, flying_speed)
def move(self, location):
# print("[공중 유닛 이동]") # 출력문 제외
self.fly(self.name, location)
마지막으로 공중 공격 유닛인 레이스를 위한 Wraith 클래스를 만들겠습니다. 레이스는 클로킹이라는 특수 기술을 사용하면 상대방이 볼 수가 없습니다. 클로킹 기술은 편의상 업그레이드가 완료되었다고 가정하겠습니다.
Wraith 클래스 생성자에서 부모 클래스인 FlyableAttackUnit 의 생성자를 통해 기본 정보를 설정하고 추가로 클로킹 모드 여부를 확인하기 위한 cloaked 멤버변수를 정의합니다.
# 레이스
class Wraith(FlyableAttackUnit):
def __init__(self):
FlyableAttackUnit.__init__(self, "레이스", 80, 20, 5) # 체력, 공격력, 공중 이동 속도
self.cloaked = False # 클로킹 모드 (해제 상태)
그리고 클로킹 모드를 설정하기 위한 cloaking() 메소드를 정의하는데 탱크의 시즈모드와 비슷하게 현재 클로킹 모드 여부에 따라서 설정 / 해제를 하도록 하며 변경된 정보를 True 또는 False 로 cloaked 멤버변수에 저장합니다. 확인을 위한 문구도 함께 출력을 해주겠습니다.
# 레이스
class Wraith(FlyableAttackUnit):
... # 생략
# 클로킹 모드
def cloaking(self):
# 현재 클로킹 모드일 때
if self.cloaked == True:
print("{0} : 클로킹 모드 해제합니다.".format(self.name))
self.cloaked = False
# 현재 클로킹 모드가 아닐 때
else:
print("{0} : 클로킹 모드 설정합니다.".format(self.name))
self.cloaked = True
지금까지 작성된 전체 코드입니다. 이제 모든 준비가 완료되었고 다음 장에서는 이 클래스들을 이용하여 실제로 게임을 한 판 해보도록 하겠습니다.
# 일반 유닛
class Unit:
def __init__(self, name, hp, speed):
self.name = name
self.hp = hp
self.speed = speed
print("{0} 유닛이 생성되었습니다.".format(name)) # 출력문 추가
def move(self, location):
print("{0} : {1} 방향으로 이동합니다. [속도 {2}]"\
.format(self.name, location, self.speed))
def damaged(self, damage): # AttackUnit 에서 Unit 으로 이동
print("{0} : {1} 데미지를 입었습니다.".format(self.name, damage))
self.hp -= damage
print("{0} : 현재 체력은 {1} 입니다.".format(self.name, self.hp))
if self.hp <= 0:
print("{0} : 파괴되었습니다.".format(self.name))
# 공격 유닛
class AttackUnit(Unit):
def __init__(self, name, hp, speed, damage):
Unit.__init__(self, name, hp, speed)
self.damage = damage
def attack(self, location):
print("{0} : {1} 방향으로 적군을 공격 합니다. [공격력 {2}]" \
.format(self.name, location, self.damage))
# 마린
class Marine(AttackUnit):
def __init__(self):
AttackUnit.__init__(self, "마린", 40, 1, 5) # 이름, 체력, 이동속도, 공격력
# 스팀팩 : 일정 시간 동안 이동 및 공격 속도를 증가, 체력 10 감소
def stimpack(self):
if self.hp > 10:
self.hp -= 10
print("{0} : 스팀팩을 사용합니다. (HP 10 감소)".format(self.name))
else:
print("{0} : 체력이 부족하여 스팀팩을 사용하지 않습니다".format(self.name))
# 탱크
class Tank(AttackUnit):
# 시즈모드 : 탱크를 지상에 고정시켜, 더 높은 파워로 공격 가능. 이동 불가.
siege_developed = False # 시즈모드 개발여부 (클래스 변수)
def __init__(self):
AttackUnit.__init__(self, "탱크", 150, 1, 35) # 이름, 체력, 이동속도, 공격력
self.siege_mode = False # 시즈모드 (해제 상태)
# 시즈모드
def set_siege_mode(self):
if Tank.siege_developed == False: # 시즈모드가 개발되지 않은 경우 메소드 탈출
return
# 현재 시즈모드가 아닐 때
if self.siege_mode == False:
print("{0} : 시즈모드로 전환합니다.".format(self.name))
self.damage *= 2 # 공격력 2배로 증가
self.siege_mode = True # 시즈 모드 설정
# 현재 시즈모드일 때
else:
print("{0} : 시즈모드를 해제합니다.".format(self.name))
self.damage /= 2 # 공격력 절반으로 감소
self.siege_mode = False # 시즈 모드 해제
# 날 수 있는 기능을 가진 클래스
class Flyable:
def __init__(self, flying_speed):
self.flying_speed = flying_speed
def fly(self, name, location):
print("{0} : {1} 방향으로 날아갑니다. [속도 {2}]"\
.format(name, location, self.flying_speed))
# 공중 공격 유닛
class FlyableAttackUnit(AttackUnit, Flyable):
def __init__(self, name, hp, damage, flying_speed):
AttackUnit.__init__(self, name, hp, 0, damage)
Flyable.__init__(self, flying_speed)
def move(self, location):
self.fly(self.name, location)
# 레이스
class Wraith(FlyableAttackUnit):
def __init__(self):
FlyableAttackUnit.__init__(self, "레이스", 80, 20, 5) # 체력, 공격력, 공중 이동 속도
self.cloaked = False # 클로킹 모드 (해제 상태)
# 클로킹 모드
def cloaking(self):
# 현재 클로킹 모드일 때
if self.cloaked == True:
print("{0} : 클로킹 모드 해제합니다.".format(self.name))
self.cloaked = False
# 현재 클로킹 모드가 아닐 때
else:
print("{0} : 클로킹 모드 설정합니다.".format(self.name))
self.cloaked = True
'파이썬 강의 > 기본편' 카테고리의 다른 글
[파이썬 기본편] 9-12.퀴즈 #8 (1) | 2021.03.17 |
---|---|
[파이썬 기본편] 9-11.스타크래프트 프로젝트 후반전 (6) | 2021.03.16 |
[파이썬 기본편] 9-9.super (0) | 2021.03.14 |
[파이썬 기본편] 9-8.pass (0) | 2021.03.13 |
[파이썬 기본편] 9-7.메소드 오버라이딩 (0) | 2021.03.12 |
- Total
- Today
- Yesterday
- 챗GPT
- repl.it
- onlineclass
- 파이썬
- Mac
- Colab
- 행맨
- Tkinter
- coloso
- game
- pycharm
- Visual Studio Code
- 환경설정
- Xcode
- c언어
- 비주얼 스튜디오 코드
- vscode
- pygame
- 나도코딩
- 코랩
- 파이게임
- 주피터노트북
- Unity
- 아나콘다
- ChatGPT
- Coding
- GUI
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |