애니메이션&좌표

JOOYEUN SEO·2024년 8월 28일

100 Days of Python

목록 보기
20/76
post-thumbnail

🗂️ Day20 프로젝트 : 스네이크 게임1

터틀 그래픽으로 구현한 스네이크 게임 - 1부

득점 : 움직이는 뱀을 조작하여 먹이를 먹음 (먹이를 먹을 수록 몸통이 점점 길어짐)
종료 : 뱀 머리가 몸통에 닿거나, 뱀이 장애물 또는 화면 끝에 부딪힘

1. 화면을 구성하고, 뱀 몸체 만들기

🔍 유의 사항

  • 화면은 검정색 바탕에 600x600 사이즈
  • 뱀 몸체는 하얀색 정사각형 3개를 가로로 나란히 이어 붙여서 생성
    • 터틀 3개를 이용
    • 좌표 설정 : 터틀 사이즈가 20x20이므로 다음 사각형은 xx좌표를 20만큼 이동

⌨️ main.py

from turtle import Screen, Turtle

# 스크린 구성
screen = Screen()
screen.setup(width=600, height=600)
screen.bgcolor("black")
screen.title("Snake Game")

# 뱀 생성
x_position = -20
for i in range(3):
    new_segment = Turtle(shape="square")
    new_segment.color("white")
    new_segment.penup()
    new_segment.goto(x=-x_position, y=0)
    x_position += 20

screen.exitonclick()

2. 화면 상에서 뱀 움직이기

🔍 유의 사항

  • 뱀은 계속해서 앞으로 움직이고, 플레이어가 키보드로 방향만 바꿈
  • 뱀의 각 몸통 부분이 자연스럽게 이어져야 한다
    → 뱀 게임의 원리
    여러 이미지를 연결해서 빠른 속도로 재생하는 GIF 애니메이션처럼,
    각 장면을 코드로 작성한 후, 언제 해당 장면을 화면에 그릴 지 정하는 것
  • tracer( n=None, delay=None )
    • 터틀 모듈 스크린 클래스의 메소드로, 애니메이션을 on/off
    • 기능을 끄려면 인수에 0 입력 → update 전까지는 이후에 작성한 코드가 갱신되지 않음
    • update() : 프로그램의 화면을 갱신 (while문과 함께 사용)
  • time.sleep( seconds ) : time 모듈의 함수로, 주어진 시간동안 실행을 지연시킴
    (각 몸통이 어떻게 움직이는지 확인 가능)
  • 뱀의 머리가 방향을 틀어도 뒤의 몸통이 계속 이어져야 한다
    • 3번째 몸통이 2번째 몸통이 있었던 자리로 가고,
    • 2번째 몸통이 1번째 몸통이 있었던 자리로 가고,
    • 1번째 몸통은 방향을 바꿈
  • xcor(), ycor() : 터틀의 xx좌표, yy좌표값을 반환하는 메소드

⌨️ main.py

from turtle import Screen, Turtle
import time

# 스크린 구성
screen = Screen()
screen.setup(width=600, height=600)
screen.bgcolor("black")
screen.title("Snake Game")
screen.tracer(0)

# 뱀의 몸통(머리, 2번째, 3번째... 순)
segments = []
# 각 몸통의 시작 위치
starting_positions = [(20, 0), (0, 0), (-20, 0)]

# 뱀 생성
for position in starting_positions:
    new_segment = Turtle(shape="square")
    new_segment.color("white")
    new_segment.penup()
    new_segment.goto(position)
    segments.append(new_segment)

game_is_on = True
while game_is_on:
    # 뱀의 모든 몸통이 움직이고 나서 화면 업데이트
    screen.update()
    # 모든 몸통을 옮긴 다음에 0.1초간 지연(뱀의 스피드 결정)
    time.sleep(0.1)
	# seg_num은 segments의 마지막 원소부터 첫 번째 원소까지 -1씩 감소
    for seg_num in range((len(segments) - 1), 0, -1):
        # 바로 뒤의 몸통이 옮겨질 위치를 저장
        new_x = segments[seg_num - 1].xcor()
        new_y = segments[seg_num - 1].ycor()
        # 저장된 위치로 뒤의 몸통을 이동시킴
        segments[seg_num].goto(new_x, new_y)
    # 반복문 실행 후, 마지막으로 머리를 한 발자국 이동
    segments[0].forward(20)

screen.exitonclick()

◇ 뱀 클래스를 만들고, OOP하기

🔍 유의 사항

  • 리팩토링 하기
    • snake 클래스를 📄snake.py로 만들어서 임포트
      (뱀과 관련된 기능, 동작, 형태들을 모두 snake 클래스로 넣기)
    • 게임을 수정할 때 코드를 찾아 헤메지 않아도 되도록 주요 값들을 상수로 선언
      • starting_positions
      • 뱀이 한 번에 이동하는 거리(한 발자국)
  • 출력 결과는 이전 단계와 똑같아야 한다

⌨️ snake.py

from turtle import Turtle

STARTING_POSITION = [(20, 0), (0, 0), (-20, 0)]
MOVE_DISTANCE = 20

class Snake:

    def __init__(self):
        self.segments = []
        self.creat_snake()

    def creat_snake(self):
        for position in STARTING_POSITION:
            new_segment = Turtle(shape="square")
            new_segment.color("white")
            new_segment.penup()
            new_segment.goto(position)
            self.segments.append(new_segment)

    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.segments[0].forward(MOVE_DISTANCE)

⌨️ main.py

from turtle import Screen, Turtle
from snake import Snake
import time

screen = Screen()
screen.setup(width=600, height=600)
screen.bgcolor("black")
screen.title("Snake Game")
screen.tracer(0)

snake = Snake()

game_is_on = True
while game_is_on:
    screen.update()
    time.sleep(0.1)

    snake.move()

screen.exitonclick()

3. 키 입력으로 뱀의 방향 바꾸기

🔍 유의 사항

  • 방향키(↑ ↓ ← →)로 뱀을 조작할 수 있어야 한다
    • 방향키는 문자열로 입력(단어 시작만 대문자)
  • setheading( angle ) : 터틀이 보는 방향을 각도로 설정
    • 0 : 동쪽 →
    • 90 : 북쪽 ↑
    • 180 : 서쪽 ←
    • 270 : 남쪽 ↓
  • 뱀의 머리(Segment[0])는 자주 쓰이므로 속성으로 지정 (뱀이 생성된 후 선언해야 함)
  • 뱀은 뒤로 움직일 수 없다
    • 각 방향의 각도를 상수로 지정
    • 머리가 북쪽으로 향할 땐, 바로 남쪽으로 가는 것을 비허용
      머리가 남쪽으로 향할 땐, 바로 북쪽으로 가는 것을 비허용
      머리가 서쪽으로 향할 땐, 바로 동쪽으로 가는 것을 비허용
      머리가 동쪽으로 향할 땐, 바로 서쪽으로 가는 것을 비허용

⌨️ 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:
            new_segment = Turtle(shape="square")
            new_segment.color("white")
            new_segment.penup()
            new_segment.goto(position)
            self.segments.append(new_segment)

    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, Turtle
from snake import Snake
import time

screen = Screen()
screen.setup(width=600, height=600)
screen.bgcolor("black")
screen.title("Snake Game")
screen.tracer(0)

snake = Snake()

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()

screen.exitonclick()




▷ Angela Yu, [Python 부트캠프 : 100개의 프로젝트로 Python 개발 완전 정복], Udemy, https://www.udemy.com/course/best-100-days-python/?couponCode=ST3MT72524

0개의 댓글