
OOP의 특징 중 하나로,
클래스는 기존 클래스에서 속성(외형)과 메소드(행동)를 상속받을 수 있음
🧑🍳 Chef👩🍳 pastry Chef👨🍳 ...class Animal:
def __init__(self):
self.num_eyes = 2
def breathe(self):
print("Inhale, exhale.")
class Fish(Animal):
def __init__(self):
super().__init__()
def breathe(self):
super().breathe()
print("doing this underwater.")
def swim(self):
print("moving in water.")
nemo = Fish()
nemo.breathe()
super().__init__()super()를 호출하는 것을 추천하지만 필수는 아님def 메소드(self): : 상위 클래스의 메소드를 호출super().메소드() : 상위 클래스의 메소드가 하는 동작을 모두 한다는 것터틀 그래픽으로 구현한 스네이크 게임 - 2부
🔍 유의 사항
- 뱀이 먹이와 닿을 때마다 먹이는 임의의 위치로 이동
- 먹이는 turtle 객체
- 📄food.py에
Food클래스 생성
- 먹이를 Food 클래스의 속성으로 지정하지 않고,
Turtle클래스를 상속받아 사용Food클래스는 기능이 향상된Turtle클래스가 됨- 10x10 사이즈로 설정
- shapesize( stretch_wid=None, stretch_len=None, outline=None )
- 기본 사이즈 20x20을 각각 절반으로 줄이기
- 먹이의 위치를 랜덤으로 설정하되, 너무 가장자리에 가깝게 붙지 않게 하기
Food클래스를 main.py에 임포트하면Turtle클래스의 임포트는 삭제해도 됨- 뱀이 먹이와 닿았는지 확인해야 한다
- distance( x, y=None ) : 터틀과 괄호 안에 입력된 것과의 거리를 반환하는 메소드
- x는 좌표 또는 다른 turtle 객체일 수 있음
- y는 x가 좌표라면 좌표, 아니면 생략
- 정확하게 먹이 위치를 지나가야 닿은 것으로 하려면 distance가 10 이하가 되어야 함
- 적당한 숫자는 약 15 정도
⌨️ food.py
from turtle import Turtle
import random
class Food(Turtle):
def __init__(self):
super().__init__()
self.shape("circle")
self.penup()
self.shapesize(stretch_len=0.5, stretch_wid=0.5)
self.color("yellow")
self.speed("fastest")
self.refresh()
def refresh(self):
random_x = random.randint(-280, 280)
random_y = random.randint(-280, 280)
self.goto(random_x, random_y)
⌨️ main.py
from turtle import Screen
from snake import Snake
from food import Food
import time
screen = Screen()
screen.setup(width=600, height=600)
screen.bgcolor("black")
screen.title("Snake Game")
screen.tracer(0)
snake = Snake()
food = Food()
screen.listen()
screen.onkey(snake.up, "Up")
screen.onkey(snake.down, "Down")
screen.onkey(snake.left, "Left")
screen.onkey(snake.right, "Right")
game_is_on = True
while game_is_on:
screen.update()
time.sleep(0.1)
snake.move()
if snake.head.distance(food) < 15:
food.refresh()
screen.exitonclick()
🔍 유의 사항
- 창 안에 점수판을 텍스트로 넣고, 먹이를 먹을 때마다 1점씩 업데이트
- 점수판은 turtle 객체
- 📄scoreboard.py에
Turtle클래스를 상속받는Scoreboard클래스 생성- 점수를 기록하고 출력하는 방법을 아는 터틀 객체가 됨
- write( arg, move=False, align="left", font("fontname", fontsize, "fonttype" )
- arg : 텍스트 내용
- move : True/False ( 디폴트 값 = False )
- aline : "left"(왼쪽 정렬), "center"(가운데 정렬), "right"(오른쪽 정렬)
- font : 폰트 정보를 튜플로 작성(폰트 타입은 굵은 글꼴, 밑줄 등을 의미)
- 텍스트 입력 시, 먼저 터틀 색상을 바꾸고 나서 입력해야 원하는 색이 적용됨
- ❗️하드코딩을 피하기 위해 write 메소드의 인수를 상수로 선언하기
- 하드코딩은 상수나 변수에 들어가는 데이터를 코드에 직접 입력하는 것
- 나중에 코드를 변경하기 번거로운 등의 단점 때문에 아주 간단한 코드가 아닌 이상 피하기
⌨️ scordboard.py
from turtle import Turtle
ALIGNMENT = 'center'
FONT = ('Courier', 24, 'normal')
class Scoreboard(Turtle):
def __init__(self):
super().__init__()
self.score = 0
self.hideturtle()
self.color("white")
self.penup()
self.goto(0, 270)
self.update_scordboard()
def update_scordboard(self):
self.write(f"Score: {self.score}", align=ALIGNMENT, font=FONT)
def score_up(self):
self.score += 1
self.clear()
self.update_scordboard()
⌨️ main.py
from turtle import Screen
from snake import Snake
from food import Food
from scoreboard import Scoreboard
import time
screen = Screen()
screen.setup(width=600, height=600)
screen.bgcolor("black")
screen.title("Snake Game")
screen.tracer(0)
snake = Snake()
food = Food()
scoreboard = Scoreboard()
screen.listen()
screen.onkey(snake.up, "Up")
screen.onkey(snake.down, "Down")
screen.onkey(snake.left, "Left")
screen.onkey(snake.right, "Right")
game_is_on = True
while game_is_on:
screen.update()
time.sleep(0.1)
snake.move()
if snake.head.distance(food) < 15:
food.refresh()
scoreboard.score_up()
screen.exitonclick()
🔍 유의 사항
- 게임이 종료될 수 있는 상황 1 : 뱀이 경계선을 지나갈 때
- 여러 번 테스트하며 창 사이즈에 맞는 적절한 경계선 지점을 찾아야 한다
Scoreboard클래스에서 게임 오버됐을 경우 문구를 프린트하는 함수 추가
⌨️ scordboard.py
from turtle import Turtle
ALIGNMENT = 'center'
FONT = ('Courier', 24, 'normal')
class Scoreboard(Turtle):
def __init__(self):
super().__init__()
self.score = 0
self.hideturtle()
self.color("white")
self.penup()
self.goto(0, 270)
self.update_scordboard()
def update_scordboard(self):
self.write(f"Score: {self.score}", align=ALIGNMENT, font=FONT)
def game_over(self):
self.home()
self.write("GAME OVER", align=ALIGNMENT, font=FONT)
def score_up(self):
self.score += 1
self.clear()
self.update_scordboard()
⌨️ main.py
from turtle import Screen
from snake import Snake
from food import Food
from scoreboard import Scoreboard
import time
screen = Screen()
screen.setup(width=600, height=600)
screen.bgcolor("black")
screen.title("Snake Game")
screen.tracer(0)
snake = Snake()
food = Food()
scoreboard = Scoreboard()
screen.listen()
screen.onkey(snake.up, "Up")
screen.onkey(snake.down, "Down")
screen.onkey(snake.left, "Left")
screen.onkey(snake.right, "Right")
game_is_on = True
while game_is_on:
screen.update()
time.sleep(0.1)
snake.move()
# 먹이와의 충돌 감지
if snake.head.distance(food) < 15:
food.refresh()
scoreboard.score_up()
# 벽(경계선)과의 충돌 감지
if snake.head.xcor() > 280 or snake.head.xcor() < -280 or snake.head.ycor() > 280 or snake.head.ycor() < -280:
game_is_on = False
scoreboard.game_over()
screen.exitonclick()
🔍 유의 사항
- 게임이 종료될 수 있는 상황 2 : 뱀의 머리가 꼬리 부분에 부딪혔을 때
- 먹이를 먹으면 길이가 길어지도록 설정해야 한다
Snake클래스를 수정
- 초기에 뱀을 생성하는 데 쓰였던 함수를 수정해서 몸통을 하나 추가하는 add_segment 함수 추가
- 뱀의 길이를 늘리는 extend 함수 추가
- 마지막 몸통(꼬리)가 있던 위치에 add_segment 함수로 새 몸통을 추가하는 함수
- 인덱스를 [-1]로 설정하여 마지막 원소 가져오기
- position() : 터틀의 현재 위치 (x, y)를 반환하는 메소드
- 머리가 꼬리의 아무 세그먼트와 충돌하면 게임을 종료해야 한다
- 머리는 첫 번째 세그먼트이기 때문에 머리와 세그먼트의 비교에서 pass 하기
⌨️ snake.py
from turtle import Turtle
STARTING_POSITION = [(20, 0), (0, 0), (-20, 0)]
MOVE_DISTANCE = 20
UP = 90
DOWN = 270
LEFT = 180
RIGHT = 0
class Snake:
def __init__(self):
self.segments = []
self.creat_snake()
self.head = self.segments[0]
def creat_snake(self):
for position in STARTING_POSITION:
self.add_segment(position)
def add_segment(self, position):
new_segment = Turtle(shape="square")
new_segment.color("white")
new_segment.penup()
new_segment.goto(position)
self.segments.append(new_segment)
def extend(self):
self.add_segment(self.segments[-1].position())
def move(self):
for seg_num in range((len(self.segments) - 1), 0, -1):
new_x = self.segments[seg_num - 1].xcor()
new_y = self.segments[seg_num - 1].ycor()
self.segments[seg_num].goto(new_x, new_y)
self.head.forward(MOVE_DISTANCE)
def up(self):
if self.head.heading() != DOWN:
self.head.setheading(UP)
def down(self):
if self.head.heading() != UP:
self.head.setheading(DOWN)
def left(self):
if self.head.heading() != RIGHT:
self.head.setheading(LEFT)
def right(self):
if self.head.heading() != LEFT:
self.head.setheading(RIGHT)
⌨️ main.py
from turtle import Screen
from snake import Snake
from food import Food
from scoreboard import Scoreboard
import time
screen = Screen()
screen.setup(width=600, height=600)
screen.bgcolor("black")
screen.title("Snake Game")
screen.tracer(0)
snake = Snake()
food = Food()
scoreboard = Scoreboard()
screen.listen()
screen.onkey(snake.up, "Up")
screen.onkey(snake.down, "Down")
screen.onkey(snake.left, "Left")
screen.onkey(snake.right, "Right")
game_is_on = True
while game_is_on:
screen.update()
time.sleep(0.1)
snake.move()
# 먹이와의 충돌 감지
if snake.head.distance(food) < 15:
food.refresh()
snake.extend()
scoreboard.score_up()
# 벽(경계선)과의 충돌 감지
if snake.head.xcor() > 280 or snake.head.xcor() < -280 or snake.head.ycor() > 280 or snake.head.ycor() < -280:
game_is_on = False
scoreboard.game_over()
# 꼬리와의 충돌 감지
for segment in snake.segments:
if segment == snake.head:
pass
elif snake.head.distance(segment) < 10:
game_is_on = False
scoreboard.game_over()
screen.exitonclick()
슬라이싱(slicing)
리스트에서 원하는 부분만 잘라서 떼어내는 것
piano_keys = ["a", "b", "c", "d", "e", "f", "g"]
print(piano_keys[3:6]) # 인덱스 2부터 5까지 자른 덩어리
print(piano_keys[1:]) # 인덱스 1부터 끝까지 자른 덩어리
print(piano_keys[:4]) # 인덱스 처음부터 4까지 자른 덩어리
print(piano_keys[1:7:2]) # 마지막 숫자는 증가분
print(piano_keys[::]) # 인덱스 처음에서부터 끝까지 하나씩 증가
print(piano_keys[::-1]) # 인덱스 끝에서부터 처음까지 거꾸로 하나씩 증가
| 리스트 | a | b | c | d | e | f | g | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 슬라이싱 | ↑ 0 | ↑ 1 | ↑ 2 | ↑ 3 | ↑ 4 | ↑ 5 | ↑ 6 | ↑ 7 |
튜플에서도 슬라이싱 가능
piano_tuple = ("do", "re", "mi", "fa", "so", "la", "ti")
print(piano_tuple[3:6])
🔍 유의 사항
- 스네이크 게임 7번 과정에서 작성한 것처럼 for문으로 모든 원소를 체크하면 너무 복잡함
- 슬라이싱으로 세그먼트 리스트에서 머리만 제거하면 됨
⌨️ main.py
# 꼬리와의 충돌 감지
for segment in snake.segments[1:]:
if snake.head.distance(segment) < 10:
game_is_on = False
scoreboard.game_over()
🖍️ 전체 답안
###################################################📄 snake.py
from turtle import Turtle
STARTING_POSITIONS = [(0, 0), (-20, 0), (-40, 0)]
MOVE_DISTANCE = 20
UP = 90
DOWN = 270
LEFT = 180
RIGHT = 0
class Snake:
def __init__(self):
self.segments = []
self.create_snake()
self.head = self.segments[0]
def create_snake(self):
for position in STARTING_POSITIONS:
self.add_segment(position)
def add_segment(self, position):
new_segment = Turtle("square")
new_segment.color("white")
new_segment.penup()
new_segment.goto(position)
self.segments.append(new_segment)
def extend(self):
self.add_segment(self.segments[-1].position())
def move(self):
for seg_num in range(len(self.segments) - 1, 0, -1):
new_x = self.segments[seg_num - 1].xcor()
new_y = self.segments[seg_num - 1].ycor()
self.segments[seg_num].goto(new_x, new_y)
self.head.forward(MOVE_DISTANCE)
def up(self):
if self.head.heading() != DOWN:
self.head.setheading(UP)
def down(self):
if self.head.heading() != UP:
self.head.setheading(DOWN)
def left(self):
if self.head.heading() != RIGHT:
self.head.setheading(LEFT)
def right(self):
if self.head.heading() != LEFT:
self.head.setheading(RIGHT)
###################################################📄 food.py
from turtle import Turtle
import random
class Food(Turtle):
def __init__(self):
super().__init__()
self.shape("circle")
self.penup()
self.shapesize(stretch_len=0.5, stretch_wid=0.5)
self.color("blue")
self.speed("fastest")
self.refresh()
def refresh(self):
random_x = random.randint(-280, 280)
random_y = random.randint(-280, 280)
self.goto(random_x, random_y)
###################################################📄 scoreboard.py
from turtle import Turtle
ALIGNMENT = "center"
FONT = ("Courier", 24, "normal")
class Scoreboard(Turtle):
def __init__(self):
super().__init__()
self.score = 0
self.color("white")
self.penup()
self.goto(0, 270)
self.hideturtle()
self.update_scoreboard()
def update_scoreboard(self):
self.write(f"Score: {self.score}", align=ALIGNMENT, font=FONT)
def game_over(self):
self.goto(0, 0)
self.write("GAME OVER", align=ALIGNMENT, font=FONT)
def increase_score(self):
self.score += 1
self.clear()
self.update_scoreboard()
###################################################📄 main.py
from turtle import Screen
from snake import Snake
from food import Food
from scoreboard import Scoreboard
import time
screen = Screen()
screen.setup(width=600, height=600)
screen.bgcolor("black")
screen.title("My Snake Game")
screen.tracer(0)
snake = Snake()
food = Food()
scoreboard = Scoreboard()
screen.listen()
screen.onkey(snake.up, "Up")
screen.onkey(snake.down, "Down")
screen.onkey(snake.left, "Left")
screen.onkey(snake.right, "Right")
game_is_on = True
while game_is_on:
screen.update()
time.sleep(0.1)
snake.move()
#Detect collision with food.
if snake.head.distance(food) < 15:
food.refresh()
snake.extend()
scoreboard.increase_score()
#Detect collision with wall.
if snake.head.xcor() > 280 or snake.head.xcor() < -280 or snake.head.ycor() > 280 or snake.head.ycor() < -280:
game_is_on = False
scoreboard.game_over()
#Detect collision with tail.
for segment in snake.segments[1:]:
if snake.head.distance(segment) < 10:
game_is_on = False
scoreboard.game_over()
screen.exitonclick()