18. 사례 연구: 상속#
18.1. 클래스 상속#
16장에서 사용한 Sprite
클래스를 상속해서
캐릭터에 새로운 기능을 추가한다.
참고
여기서 사용하는 코드는 (레플릿) 충돌 감지 - 상속 1에서 확인하고 직접 실행할 수 있다.
기본 설정
기본 설정은 이전과 동일하다.
import turtle
import math
wn = turtle.Screen()
wn.bgcolor("black")
wn.title("Collision Detection by @TokyoEdtech")
wn.tracer(0)
pen = turtle.Turtle()
pen.speed(0)
pen.hideturtle()
shapes = ["wizard.gif", "goblin.gif", "pacman.gif", "cherry.gif", "bar.gif", "ball.gif", "x.gif"]
for shape in shapes:
wn.register_shape(shape)
스프라이트 클래스
이전에 정의했던 Sprite
클래스는 다음과 같다.
class Sprite():
## 생성자: 스프라이트의 위치, 가로/세로 크기, 이미지 지정
def __init__(self, x, y, width, height, image):
self.x = x
self.y = y
self.width = width
self.height = height
self.image = image
## 스프라이트 메서드
# 지정된 위치로 스프라이트 이동 후 도장 찍기
def render(self, pen):
pen.goto(self.x, self.y)
pen.shape(self.image)
pen.stamp()
# 충돌 감지 방법 1: 두 스프라이트의 중심이 일치할 때 충돌 발생
def is_overlapping_collision(self, other):
if self.x == other.x and self.y == other.y:
return True
else:
return False
# 충돌 감지 방법 2: 두 스프라이트 사이의 거리가 두 객체의 너비의 평균값 보다 작을 때 충돌 발생
def is_distance_collision(self, other):
distance = (((self.x-other.x) ** 2) + ((self.y-other.y) ** 2)) ** 0.5
if distance < (self.width + other.width)/2.0:
return True
else:
return False
# 충돌 감지 방법 3: 각각의 스프라이트를 둘러썬 경계상자가 겹칠 때 충돌 발생
# aabb: Axis Aligned Bounding Box
def is_aabb_collision(self, other):
x_collision = (math.fabs(self.x - other.x) * 2) < (self.width + other.width)
y_collision = (math.fabs(self.y - other.y) * 2) < (self.height + other.height)
return (x_collision and y_collision)
스프라이트 클래스 상속
Sprite
클래스를 상속하면서 Character
클래스를 정의한다.
생성자 함수가 조금 달라지며,
객체의 점프 기능을 담당하는 hop()
메서드가 추가된다.
하지만 hop()
함수를 실행했을 때
점프 기능이 지정된 경우에만 작동하도록 설정한다.
class Character(Sprite):
def __init__(self, x, y, width, height, image, jump=False):
super().__init__(x, y, width, height, image) # 부모 클래스의 초기화 그대로 활용
self.jump = jump # jump 기능 지정
# 점프 기능 담당 메서드: jump=True일 경우에만 작동.
def hop(self, distance=300):
if self.jump == True:
self.x += distance
객체 생성
부모 클래스와 자식 클래스 모두를 이용하여 객체를 생성할 수 있다.
wizard
와 pacman
은 Character
클래스의 인스턴스로,
나머지는 Sprite
클래스의 인스턴스로 선언된다.
또한 pacman
객체는 점프 기능도 갖는다.
wizard
객체는 점프 기능을 제대로 갖추지 못했기에 Sprite
클래스의 인스턴스와
동일한 기능만 수행한다.
wizard = Character(-128, 200, 128, 128, "wizard.gif")
goblin = Sprite(128, 200, 108, 128, "goblin.gif")
pacman = Character(-128, 0, 128, 128, "pacman.gif", jump=True)
cherry = Sprite(128, 0, 128, 128, "cherry.gif")
bar = Sprite(0, -400, 128, 24, "bar.gif")
ball = Sprite(0,-200, 32, 32, "ball.gif")
# 스프라이트 모음 리스트
sprites = [wizard, goblin, pacman, cherry, bar, ball]
이벤트와 콜백 함수
팩맨의 점프 기능을 담당하는 콜백 함수와 이벤트 처리 기능이 추가된다.
# 고블린 이동
def move_goblin():
goblin.x -= 64
# 팩맨 이동
def move_pacman():
pacman.x += 30
# 팩맨 점프
def jump_pacman(distance=300):
pacman.hop(distance)
# 야구공 이동
def move_ball():
ball.y -= 24
# 이벤트 처리
wn.listen()
wn.onkeypress(move_goblin, "Left") # 왼쪽 방향 화살표 입력
wn.onkeypress(move_pacman, "Right") # 오른쪽 방향 화살표 입력
wn.onkeypress(jump_pacman, "space") # 스페이크 키 입력
wn.onkeypress(move_ball, "Down") # 아래방향 화살표 입력
게임 실행
게임 실행 코드는 이전과 동일하다.
while True:
# 각 스프라이트 위치 이동 및 도장 찍기
for sprite in sprites:
sprite.render(pen)
# 충돌 여부 확인
if wizard.is_overlapping_collision(goblin):
wizard.image = "x.gif"
if pacman.is_distance_collision(cherry):
cherry.image = "x.gif"
if bar.is_aabb_collision(ball):
ball.image = "x.gif"
wn.update() # 화면 업데이트
pen.clear() # 스프라이트 이동흔적 삭제
18.2. 모듈 활용 클래스 상속#
다른 파이썬 파일(모듈)에 정의된 Sprite
클래스를 상속하는 Character
클래스를 선언한다.
참고
여기서 사용하는 코드는
(레플릿) 충돌 감지 - 상속 2에서
확인하고 직접 실행할 수 있다.
레플릿 사이트의 특성상 주 실행파일의 이름은 main.py
이어야 한다.
따라서 Sprite
클래스는 collision_detection.py
라는 다른 파일에 정의되어 있다.
파일 구성
아래 두 개의 파일로 구성된다.
collision_detection.py
: 캔버스 기본 설정과Sprite
클래스 정의main.py
:Character
클래스 정의와 실행에 필요한 모든 코드
collision_dection.py
파일
캔버스 기본 설정과 Sprite
클래스의 정의가 포함된다.
import turtle
import math
wn = turtle.Screen()
wn.bgcolor("black")
wn.title("Collision Detection by @TokyoEdtech")
wn.tracer(0)
pen = turtle.Turtle()
pen.speed(0)
pen.hideturtle()
shapes = ["wizard.gif", "goblin.gif", "pacman.gif", "cherry.gif", "bar.gif", "ball.gif", "x.gif"]
for shape in shapes:
wn.register_shape(shape)
class Sprite():
## 생성자: 스프라이트의 위치, 가로/세로 크기, 이미지 지정
def __init__(self, x, y, width, height, image):
self.x = x
self.y = y
self.width = width
self.height = height
self.image = image
## 스프라이트 메서드
# 지정된 위치로 스프라이트 이동 후 도장 찍기
def render(self, pen):
pen.goto(self.x, self.y)
pen.shape(self.image)
pen.stamp()
# 충돌 감지 방법 1: 두 스프라이트의 중심이 일치할 때 충돌 발생
def is_overlapping_collision(self, other):
if self.x == other.x and self.y == other.y:
return True
else:
return False
# 충돌 감지 방법 2: 두 스프라이트 사이의 거리가 두 객체의 너비의 평균값 보다 작을 때 충돌 발생
def is_distance_collision(self, other):
distance = (((self.x-other.x) ** 2) + ((self.y-other.y) ** 2)) ** 0.5
if distance < (self.width + other.width)/2.0:
return True
else:
return False
# 충돌 감지 방법 3: 각각의 스프라이트를 둘러썬 경계상자가 겹칠 때 충돌 발생
# aabb: Axis Aligned Bounding Box
def is_aabb_collision(self, other):
x_collision = (math.fabs(self.x - other.x) * 2) < (self.width + other.width)
y_collision = (math.fabs(self.y - other.y) * 2) < (self.height + other.height)
return (x_collision and y_collision)
main.py
파일
실행 관련 나머지 코드를 포함한다.
단, Sprite
클래스가 선언된 collision_detection
모듈에서 필요한 모든 것을 불러온다.
from collision_detection import *
class Character(Sprite):
def __init__(self, x, y, width, height, image, jump=False):
super().__init__(x, y, width, height, image) # 부모 클래스의 초기화 그대로 활용
self.jump = jump # jump 기능 지정
# 점프 기능 담당 메서드: jump=True일 경우에만 작동.
def hop(self, distance=300):
if self.jump == True:
self.x += distance
wizard = Character(-128, 200, 128, 128, "wizard.gif")
goblin = Sprite(128, 200, 108, 128, "goblin.gif")
pacman = Character(-128, 0, 128, 128, "pacman.gif", jump=True)
cherry = Sprite(128, 0, 128, 128, "cherry.gif")
bar = Sprite(0, -400, 128, 24, "bar.gif")
ball = Sprite(0,-200, 32, 32, "ball.gif")
# 스프라이트 모음 리스트
sprites = [wizard, goblin, pacman, cherry, bar, ball]
# 고블린 이동
def move_goblin():
goblin.x -= 64
# 팩맨 이동
def move_pacman():
pacman.x += 30
# 팩맨 점프
def jump_pacman(distance=300):
pacman.hop(distance)
# 야구공 이동
def move_ball():
ball.y -= 24
# 이벤트 처리
wn.listen()
wn.onkeypress(move_goblin, "Left") # 왼쪽 방향 화살표 입력
wn.onkeypress(move_pacman, "Right") # 오른쪽 방향 화살표 입력
wn.onkeypress(jump_pacman, "space") # 스페이크 키 입력
wn.onkeypress(move_ball, "Down") # 아래방향 화살표 입력
while True:
# 각 스프라이트 위치 이동 및 도장 찍기
for sprite in sprites:
sprite.render(pen)
# 충돌 여부 확인
if wizard.is_overlapping_collision(goblin):
wizard.image = "x.gif"
if pacman.is_distance_collision(cherry):
cherry.image = "x.gif"
if bar.is_aabb_collision(ball):
ball.image = "x.gif"
wn.update() # 화면 업데이트
pen.clear() # 스프라이트 이동흔적 삭제
18.3. 연습문제#
참고: (실습) 사례 연구: 상속