πŸ‘¦ 내일배움캠프/TIL(Today I Learned)

TIL_220426

  • -

개인 ν”„λ‘œμ νŠΈ μ£Όκ°„

 

 

 


무엇을 λŠκΌˆλŠ”κ°€.

개인 ν”„λ‘œμ νŠΈλ₯Ό μ§„ν–‰ν•˜λ©΄μ„œ, 배운 것보닀 μ½”λ“œ 였λ₯˜λ‘œ ν•΄κ²°ν•˜λŠ” μ‹œκ°„μ˜ μ†Œμš”κ°€ κ°€μž₯ 크닀.

λ‚˜μ—κ²ŒλŠ” μ‹€λ ₯이 λ˜κ² μ§€λ§Œ, 아무리 생각해도 λ„ˆλ¬΄ 아쉽고, λ„ˆλ¬΄ 아깝닀.

 

 

 

λ‹¨μ‹œκ°„μ— 찾을 수 μžˆμ—ˆλ˜ 였λ₯˜μ˜€λ‹€.

ν•˜μ§€λ§Œ 이런 였λ₯˜μ— λŒ€ν•΄μ„œ μ–΄λŠ 뢀뢄을 μ€‘μ μœΌλ‘œ 두고 확인해야 ν•˜λŠ”μ§€, 사전 지식이 μ—†μœΌλ‹ˆ μ²˜μŒλΆ€ν„° λκΉŒμ§€ λ‹€μ‹œ λ³΄λŠ” λ―Έλ ¨ν•œ 행동을 λ³΄μ˜€λ‹€.

 

μ΄μ œλ³΄λ‹ˆ 였λ₯˜λŠ” κ°€μž₯ 맨 λ§ˆμ§€λ§‰μ— μ˜€νƒˆμžλ‘œ λ°œκ²¬λ˜μ–΄ 마무리 λ˜μ—ˆλ‹€.

κ·Έ 외에도 였λ₯˜λŠ” μ•„λ‹ˆμ§€λ§Œ, μ½”λ“œ ν™œμš©μ— μžˆμ–΄μ„œ μ–΄λŠ 뢀뢄에 μ μš©μ‹œμΌœ κ²Œμž„μ΄ λ™μž‘λ˜λŠ”μ§€ ν•˜λ‚˜ ν•˜λ‚˜λ₯Ό 넣어보며 ν™•μΈν•΄μ•Όλ§Œ ν–ˆλ‹€.

 

μ΄λ ‡κ²Œ 보낸 μ‹œκ°„μ΄ 벌써 2일이 λλ‚˜κ³  λ‹Ήμž₯ λ°œν‘œμΌμ΄ λ˜μ—ˆλ‹€.

 

ν•˜μ§€λ§Œ λ‚˜λŠ” 무엇을 λŠκΌˆλŠ”κ°€.

κ·Έλ ‡κ²Œ 맀달리고, μ«’κ³ , νŒŒν—€μ³€λ˜ κ·Έ 과정을 거쳐 ν•΄κ²°λ‘œ λ„λ‹¬ν–ˆμ„ λ•Œμ˜ 성취감.

λ‚΄ λ¨Έλ¦¬μ†μœΌλ‘œ κ·Έλ € λ‚˜μ•„κ°€λ©°, μ‹€μ œλ‘œ μ½”λ“œμ— μ μš©ν•΄ λ™μž‘λ˜λŠ” 것을 보고 λŠλΌλŠ” 희열감.

그리고 λ‚΄κ°€ 배우고 μ„±μž₯ν•˜κ³  μžˆλ‹€λŠ” 것을 느끼게 ν•΄μ£ΌλŠ” μ§€κΈˆμ˜ κ²°κ³Ό.

 

μ‹€νŒ¨λ‘œ 끝났닀가 μ•„λ‹ˆλΌ ν•œ 걸음 더 λ‚˜μ•„κ°ˆ 발판이 λ˜μ—ˆμŒμ„ λ§ˆμŒμ†μ— ν’ˆκ³ ,

λΆ€λ”” 포기말고,

계속 λ‚˜μ•„κ°€μž.

 


개인 ν”„λ‘œμ νŠΈ 기획 [22. 04. 27. μˆ˜μ •]

1. μ°½ ν™”λ©΄

- 640 * 640 크기

 

2. κ²Œμž„ 이미지

- λ°°κ²½ 이미지, 점수 ν™”λ©΄ 이미지 640 * 640

- κ²Œμž„ 메뉴 ν™”λ©΄ 이미지 640 * 640

- μš°μ£Όμ„  이미지 42 * 40

- 폭발 이미지 70 * 55

- 미사일 이미지 20 * 20

- μš΄μ„ 이미지 (75 * 37, 75 * 55, , 75 * 25, 75 * 52, , 75 * 61)

 

3. μ’Œν‘œ

- μš°μ£Όμ„  κ³ μ • μœ„μΉ˜ : μ°½ ν™”λ©΄μ˜ 쀑앙

- 미사일 이동 μœ„μΉ˜(μš°μ£Όμ„  μ€‘μ‹¬μœΌλ‘œ) : λ„€ λ°©ν–₯ 직진

- μš΄μ„ 이동 μœ„μΉ˜(λ„€ λ°©ν–₯ μ°½ μ€‘μ‹¬μœΌλ‘œ μš°μ£Όμ„ μ„ ν–₯ν•΄) : λ„€ λ°©ν–₯ μ•ˆμͺ½ 이동

- λ°°κ²½ 이미지 μœ„μΉ˜ : (0, 0)

- κ²Œμž„ 메뉴 ν™”λ©΄ 이미지 μœ„μΉ˜ : (0, 0)

- 폭발 이미지 μœ„μΉ˜

- 졜고 점수 기둝 μœ„μΉ˜ : (150, 20)

- κ²Œμž„ 제λͺ© ν…μŠ€νŠΈ μœ„μΉ˜ : (μ°½ λ„ˆλΉ„ 쀑심, μ°½ 높이 쀑심)

- μ—”ν„° ν‚€ μ•ˆλ‚΄ ν…μŠ€νŠΈ μœ„μΉ˜ : (μ°½ λ„ˆλΉ„ 쀑심, μ°½ 높이 쀑심 + 200)

- κ²Œμž„ μ‹œμž‘ ν…μŠ€νŠΈ μœ„μΉ˜ : (μ°½ λ„ˆλΉ„ 쀑심, μ°½ 높이 쀑심 + 250)

- 점수 확인 μ•ˆλ‚΄ ν…μŠ€νŠΈ μœ„μΉ˜ : (μ°½ λ„ˆλΉ„ 쀑심, μ°½ 높이 쀑심 + 350)

- 점수 ν…μŠ€νŠΈ μœ„μΉ˜ 1 : (μ°½ λ„ˆλΉ„ 쀑심, μ°½ 높이 / 4 + 100)

- 점수 ν…μŠ€νŠΈ μœ„μΉ˜ 2 : (μ°½ λ„ˆλΉ„ 쀑심, μ°½ 높이 / 4 + 200)

 

4. FPS

- μ΄ˆλ‹Ή 60

 

5. 색상

- BLACK = (0, 0, 0)
- WHITE = (255, 255, 255)
- YELLOW = (250, 250, 50)
- RED = (250, 50, 50)

 

6. μœ„μΉ˜ μ •μ˜

- μš°μ£Όμ„ μ˜ ν™”λ©΄ μœ„μΉ˜ κ³ μ •

- 이벀트 ν‚€ μž…λ ₯에 λ”°λ₯Έ λ„€ λ°©ν–₯ 미사일 μ‚¬μΆœ μœ„μΉ˜ μ •μ˜

-- 미사일이 ν™”λ©΄ λ°–μœΌλ‘œ λ‚˜κ°ˆ 경우 미사일 제거

- 창의 쀑심 λ„€ λ°©ν–₯으둜 μš°μ£Όμ„ μ„ ν–₯ν•˜κ²Œ μš΄μ„μ˜ 이동 μœ„μΉ˜ μ •μ˜

 

7. 좩돌 처리

- μš°μ£Όμ„ κ³Ό μš΄μ„μ˜ 좩돌 처리

- 미사일과 μš΄μ„μ˜ 좩돌 처리

 

8. κ·œμΉ™ μ •μ˜

- μš°μ£Όμ„ μœΌλ‘œ ν–₯ν•˜λŠ” μš΄μ„μ˜ μΆ©λŒμ„ 막아야 함.

- μš°μ£Όμ„ μ€ λ„€ λ°©ν–₯으둜 미사일을 λ°œμ‚¬

- μš΄μ„μ€ λ„€ λ°©ν–₯μ—μ„œ 랜덀의 ν™•λ₯ λ‘œ 5κ°€μ§€μ˜ μš΄μ„ μ’…λ₯˜ μΆœν˜„

- 100/ 200/ 300 의 μš΄μ„ 격좔에 λ”°λ₯Έ λ‚œμ΄λ„ 증가

 

 

기반이 λ˜λŠ” μ†ŒμŠ€ 따라쓰며 μ΄ν•΄ν•˜κΈ°

더보기
import random
from time import sleep

import pygame as pg
from pygame.locals import *

# μ°½ μ‚¬μ΄μ¦ˆ μ „μ—­λ³€μˆ˜
WINDOW_WIDTH = 480
WINDOW_HEIGHT = 640

# 색상 μ •μ˜
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
YELLOW = (250, 250, 50)
RED = (250, 50, 50)

# μ΄ˆλ‹Ή ν”„λ ˆμž„
FPS = 60


# μš°μ£Όμ„  클래슀
# κ²Œμž„μ—μ„œ λ‚˜νƒ€λ‚΄λŠ” λͺ¨λ“  캐릭터, μž₯애물등을 ν‘œν˜„ν•  λ•Œ μ‚¬μš©ν•˜λŠ” Surface 상속을 λ°›μ•„μ˜¨λ‹€.
class Fighter(pg.sprite.Sprite):
    # λ‹€λ₯Έ 객체지ν–₯ μ–Έμ–΄μ—μ„œλŠ” μƒμ„±μž(constructor)라고 λΆ€λ₯Έλ‹΅λ‹ˆλ‹€
    # μ΄ˆκΈ°ν™” λ©”μ„œλ“œ, μ–΄λ–€ 클래슀의 객체가 λ§Œλ“€μ–΄μ§ˆ λ•Œ μžλ™μœΌλ‘œ ν˜ΈμΆœλ˜μ–΄μ„œ κ·Έ 객체가 κ°–κ²Œ 될 μ—¬λŸ¬ 가지 μ„±μ§ˆμ„ μ •ν•΄μ£ΌλŠ” 일
    def __init__(self):  # 단일
        super(Fighter, self).__init__()  # μƒμœ„ 클래슀 __init__ 호좜
        self.image = pg.image.load('fighter.png')  # self(Fighter의 μ΄ˆκΈ°ν™” κ°’) 에 μž…νž 이미지λ₯Ό κ°€μ Έμ˜¨λ‹€.
        self.rect = self.image.get_rect()  # 이미지 크기 μ‘°μ • .get_rect(none)[크기 정보 + μ’Œν‘œ 정보]
        self.rect.x = int(WINDOW_WIDTH / 2)  # 처음 μš°μ£Όμ„ μ˜ λ“±μž₯ μœ„μΉ˜ (WINDOW_WIDTH / 2 = 창의 λ„ˆλΉ„μ˜ 쀑앙)
        self.rect.y = WINDOW_HEIGHT - self.rect.height  # μš°μ£Όμ„ μ˜ 높이 만큼 λΉΌμ„œ y 값을 지정
        self.dx = 0  # x λ°©ν–₯
        self.dy = 0  # y λ°©ν–₯

    # ν™”λ©΄ λ°–μœΌλ‘œ λ‚˜κ°”μ„ 경우λ₯Ό λŒ€λΉ„ν•œ 루트
    def update(self):
        self.rect.x += self.dx  # μš°μ£Όμ„ .rect.x μœ„μΉ˜κ°€ μš°μ£Όμ„ .dx μ΄λ™ν•œ μœ„μΉ˜ 만큼 더해진닀.
        self.rect.y += self.dy  # μ›€μ§μž„ ν•„μˆ˜μ μΈ λΆ€λΆ„

        # μš°μ£Όμ„ .rect.x μ’Œν‘œκ°€ 0 보닀 μž‘μ€ κ²½μš°λŠ” = ν™”λ©΄ λ°–μœΌλ‘œ λ‚˜κ°€λŠ” 경우
        # λ§Œμ•½ X μœ„μΉ˜κ°€ μš°μ£Όμ„ μ˜ λ„ˆλΉ„λ₯Ό ν¬ν•¨ν•œ μ’Œν‘œκ°€ 창의 λ„ˆλΉ„λ³΄λ‹€ 클 경우
        if self.rect.x < 0 or self.rect.x + self.rect.width > WINDOW_WIDTH:  # 창의 λ°–μœΌλ‘œ λ‚˜κ°”μ„ 경우λ₯Ό λŒ€λΉ„
            self.rect.x -= self.dx  # λ‚˜κ°€λ©΄ μ›€μ§μž„μ„ 멈좀

        # μš°μ£Όμ„ .rect.y μ’Œν‘œκ°€ 0 보닀 μž‘μ€ κ²½μš°λŠ” = ν™”λ©΄ λ°–μœΌλ‘œ λ‚˜κ°€λŠ” 경우
        # λ§Œμ•½ Y μœ„μΉ˜κ°€ μš°μ£Όμ„ μ˜ 높이λ₯Ό ν¬ν•¨ν•œ μ’Œν‘œκ°€ 창의 높이보닀 클 경우
        if self.rect.y < 0 or self.rect.y + self.rect.height > WINDOW_HEIGHT:
            self.rect.y -= self.dy

    # κ·Έλ €μ£ΌλŠ” λΆ€λΆ„
    def draw(self, screen):  # self μ—μ„œ 슀크린 값을 λ°›μ•„μ˜¨λ‹€.
        screen.blit(self.image, self.rect)  # 화면에 그렀쀌 μš°μ£Όμ„ (self) 의 이미지와 μš°μ£Όμ„ (self) 의 μ‚¬μ΄μ¦ˆ

    def collide(self, sprites):
        for sprite in sprites:  # 객체 관리λ₯Ό νŽΈν•˜κ²Œ ν•˜κΈ° μœ„ν•œ 방법
            if pg.sprite.collide_rect(self, sprite):  # 검사 쀑 μš°μ£Όμ„ κ³Ό sprite 와 μΆ©λŒν–ˆμ„ 경우 / .collide_rect = 좩돌 체크
                return sprite  # 좩돌 λ‚œ sprite return


# 미사일 클래슀
class Missile(pg.sprite.Sprite):
    def __init__(self, xpos, ypos, speed):  # μ΄ˆκΈ°ν™” λ©”μ„œλ“œ, 뢈러올 κ°’ 지정
        super(Missile, self).__init__()
        self.image = pg.image.load('missile.png')
        self.rect = self.image.get_rect()  # 미사일 μ‚¬μ΄μ¦ˆ
        self.rect.x = xpos  # 미사일 ν˜ΈμΆœν•˜λŠ” μœ„μΉ˜ κ°’ 지정 / μš°μ£Όμ„ μ—μ„œ λ°œμ‚¬ν•  수 있게 λ§Œλ“€κΈ° μœ„ν•œ
        self.rect.y = ypos
        self.speed = speed
        self.sound = pg.mixer.Sound('missile.wav')

    def launch(self):  # λ°œμ‚¬μ— λŒ€ν•œ μ†Œλ¦¬
        self.sound.play()  # μ†Œλ¦¬ μž¬μƒ

    # λ―Έμ‚¬μΌμ˜ μœ„μΉ˜
    def update(self):
        self.rect.y -= self.speed  # μ•„λž˜μ—μ„œ μœ„λ‘œ λ°œμ‚¬λ˜λŠ” μ’Œν‘œ - / ν•΄λ‹Ήν•˜λŠ” 속도 만큼
        if self.rect.y + self.rect.height < 0:  # λ§Œμ•½μ— y 값에 높이가 더해진 κ°’μœΌλ‘œ 0 보닀 μž‘μœΌλ©΄ = 미사일이 ν™”λ©΄ λ°–μœΌλ‘œ λ‚˜κ°
            self.kill()  # ν™”λ©΄ λ°–μœΌλ‘œ λ‚˜κ°„ 미사일은 μ—†μ• μ€Œ

    # 미사일 좩돌 체크
    def collide(self, sprites):
        for sprite in sprites:
            if pg.sprite.collide_rect(self, sprite):
                return sprite


# μš΄μ„ 클래슀
class Rock(pg.sprite.Sprite):
    def __init__(self, xpos, ypos, speed):  # μ΄ˆκΈ°ν™” λ©”μ„œλ“œ, μš΄μ„μ˜ μ’Œν‘œ 및 μŠ€ν”Όλ“œ
        super(Rock, self).__init__()
        rock_images = ('rock01.png', 'rock02.png', 'rock03.png', 'rock04.png', 'rock05.png', \
                       'rock06.png', 'rock07.png', 'rock08.png', 'rock09.png', 'rock10.png', \
                       'rock11.png', 'rock12.png', 'rock13.png', 'rock14.png', 'rock15.png', \
                       'rock16.png', 'rock17.png', 'rock18.png', 'rock19.png', 'rock20.png', \
                       'rock21.png', 'rock22.png', 'rock23.png', 'rock24.png', 'rock25.png', \
                       'rock26.png', 'rock27.png', 'rock28.png', 'rock29.png', 'rock30.png')  # μš΄μ„ 1 ~ 30 μ •μ˜ / νŠœν”Œ 적용
        self.image = pg.image.load(random.choice(rock_images))  # rock_images μ—μ„œ 랜덀으둜 이미지λ₯Ό 골라쀘
        self.rect = self.image.get_rect()
        self.rect.x = xpos
        self.rect.y = ypos
        self.speed = speed

    # μš΄μ„ μ—…λ°μ΄νŠΈ
    def update(self):
        self.rect.y += self.speed  # μœ„μ—μ„œ λ°‘μœΌλ‘œ λ‚΄λ €μ˜€λŠ” κ°’ +

    # μš΄μ„μ΄ ν™”λ©΄ λ°–μœΌλ‘œ λ‚˜κ°”μ„ 경우
    def out_of_screen(self):
        if self.rect.y > WINDOW_HEIGHT:  # μš΄μ„μ˜ y 값이 λ§Œμ•½μ— ν™”λ©΄μ˜ 높이보닀 컀지면 = μš΄μ„μ΄ μ•„λž˜ ν™”λ©΄ λκΉŒμ§€ λ‚˜κ°”μ„ λ•Œ
            return True  # λ‚˜κ°”μ„ 경우의 상황을 ν˜ΈμΆœν•˜κΈ° μœ„ν•œ True


# κ²Œμž„ ν™”λ©΄ 상에 ν‘œμ‹œ λ˜λŠ” ν…μŠ€νŠΈ 좜λ ₯
def draw_text(text, font, surface, x, y, main_color):
    text_obj = font.render(text, True, main_color)  # font.render 둜 폰트 μ •μ˜ / μ›ν•˜λŠ” ν…μŠ€νŠΈ 색상 지정
    text_rect = text_obj.get_rect()  # ν…μŠ€νŠΈμ˜ μœ„μΉ˜ 지정
    text_rect.centerx = x
    text_rect.centery = y
    surface.blit(text_obj, text_rect)  # .blit(ν™”λ©΄ 좜λ ₯ν•  개체, 좜λ ₯ν•  μœ„μΉ˜)


# 폭발 효과
def occur_explosion(surface, x, y):
    explosion_image = pg.image.load('explosion.png')
    explosion_rect = explosion_image.get_rect()
    explosion_rect.x = x
    explosion_rect.y = y
    surface.blit(explosion_image, explosion_rect)

    explosion_sounds = ('explosion01.wav', 'explosion02.wav', 'explosion03.wav')
    explosion_sound = pg.mixer.Sound(random.choice(explosion_sounds))
    explosion_sound.play()


# 메인 κ²Œμž„μ˜ 루프
def game_loop():
    default_font = pg.font.Font('NanumGothic.ttf', 28)  # κ²Œμž„ 폰트
    background_image = pg.image.load('background.png')  # κ²Œμž„ λ°°κ²½ 이미지
    gameover_sound = pg.mixer.Sound('gameover.wav')  # κ²Œμž„ μ’…λ£Œ
    pg.mixer.music.load('music.wav')  # κ²Œμž„ μŒμ•…
    pg.mixer.music.play(-1)  # λͺ‡ 번 μž¬μƒν•  것인가 (-1 = λ¬΄ν•œ)
    fps_clock = pg.time.Clock()  # ν”„λ ˆμž„

    fighter = Fighter()  # λ§Œλ“€μ—ˆλ˜ 클래슀λ₯Ό μΈμŠ€ν„΄μŠ€λ‘œ 지정
    missiles = pg.sprite.Group()  # μ—¬λŸ¬ 개의 미사일을 .Group() 으둜 묢음
    rocks = pg.sprite.Group()  # μ—¬λŸ¬ 개의 μš΄μ„μ„ 묢음

    occur_prob = 40  # ν™•λ₯ μ μœΌλ‘œ μ–Όλ§ŒνΌ λ‚˜μ˜€κ²Œ ν•˜λŠ”κ°€
    shot_count = 0  # 맞좘 개수
    count_missed = 0  # λ†“μΉœ 개수

    # κ²Œμž„μ˜ 반볡
    done = False
    while not done:  # done 이 λ§Œμ•½μ— True κ°€ λœλ‹€λ©΄ 반볡문 μ’…λ£Œ
        for event in pg.event.get():  # event 에 pg.event.get() λ₯Ό κ°€μ Έμ˜€κ³ 
            if event.type == pg.KEYDOWN:  # event.type 이 ν‚€ λ‹€μš΄ μƒνƒœμΌ λ•Œ = μž…λ ₯ μƒνƒœμΌ λ•Œ
                if event.key == pg.K_LEFT:  # 근데 λ§Œμ•½μ— event.key κ°€ μ™Όμͺ½μ΄ λˆŒλ Έλ‹€λ©΄
                    fighter.dx -= 5  # μ™Όμͺ½(-x이동) 으둜 5 만큼 이동
                elif event.key == pg.K_RIGHT:
                    fighter.dx += 5  # 였λ₯Έμͺ½(+x이동) 으둜 5 만큼 이동
                elif event.key == pg.K_UP:
                    fighter.dy -= 5  # μœ„(-y이동) 둜 5 만큼 이동
                elif event.key == pg.K_DOWN:
                    fighter.dy += 5  # μ•„λž˜(+y이동) 둜 5 만큼 이동
                elif event.key == pg.K_SPACE:
                    missile = Missile(fighter.rect.centerx, fighter.rect.y, 10)  # Missle class > (xpos, ypos, speed)
                    missile.launch()
                    missiles.add(missile)  # μ™œ λ„£μ–΄μ£ΌλŠ”λ°?

            if event.type == pg.KEYUP:  # ν‚€μ—… 인 μƒνƒœμ—μ„œ
                if event.key == pg.K_LEFT or event.key == pg.K_RIGHT:  # μ™Όμͺ½ or 였λ₯Έμͺ½ ν‚€λ₯Ό λ• λ‹€λ©΄
                    fighter.dx = 0  # x 이동을 λ©ˆμΆ˜λ‹€
                elif event.key == pg.K_UP or event.key == pg.K_DOWN:  # μœ„ or μ•„λž˜ ν‚€λ₯Ό λ• λ‹€λ©΄
                    fighter.dy = 0  # y 이동을 λ©ˆμΆ˜λ‹€

        screen.blit(background_image, background_image.get_rect())  # ν™”λ©΄ 좜λ ₯(λ°±κ·ΈλΌμš΄λ“œ 이미지, λ°±κ·ΈλΌμš΄λ“œ μœ„μΉ˜ μ’Œν‘œ)

        # λ§Œμ•½μ˜ μš΄μ„μ„ 100개 파괴 ν–ˆλ‹€λ©΄, μŠ€ν”Όλ“œμ™€ μš΄μ„ 수λ₯Ό μ¦κ°€μ‹œν‚¨λ‹€ = λ‚œμ΄λ„ μƒμŠΉ
        occur_of_rocks = 1 + int(shot_count / 300)  # shot_count = μ–Όλ§ŒνΌ μš΄μ„μ„ λ§žμ·„λŠ”κ°€
        min_rock_speed = 1 + int(shot_count / 200)
        max_rock_speed = 1 + int(shot_count / 100)

        if random.randint(1, occur_prob) == 1:  # 1 λΆ€ν„° occur_prob(40) μ‚¬μ΄μ˜ 1이 λ“±μž₯ν•  ν™•λ₯  = 1/40
            for i in range(occur_of_rocks):
                speed = random.randint(min_rock_speed, max_rock_speed)  # μŠ€ν”Όλ“œλ₯Ό 랜덀으둜 선택
                rock = Rock(random.randint(0, WINDOW_WIDTH - 30), 0, speed)  # 0 λΆ€ν„° X μ’Œν‘œ(λ„ˆλΉ„ μ’Œν‘œμ—μ„œ 30정도 λΊ€ κ°’)κΉŒμ§€
                rocks.add(rock)

        # ('ν‘œμ‹œν•  ν…μŠ€νŠΈ', μ‚¬μš©ν•  폰트, ν‘œμ‹œν•  ν™”λ©΄, xμ’Œν‘œ, yμ’Œν‘œ, 색상)
        draw_text('νŒŒκ΄΄ν•œ μš΄μ„ : {}'.format(shot_count), default_font, screen, 100, 20, YELLOW)  # νŒŒκ΄΄ν•œ μš΄μ„ ν‘œμ‹œ
        draw_text('λ†“μΉœ μš΄μ„ : {}'.format(count_missed), default_font, screen, 400, 20, RED)  # λ†“μΉœ μš΄μ„ ν‘œμ‹œ

        # 미사일이 μ—¬λŸ¬κ°œ λ°œμ‚¬ 됐을 λ•Œ
        for missile in missiles:
            rock = missile.collide(rocks)  # 미사일이 μš΄μ„κ³Όμ˜ 좩돌 체크
            if rock:  # 좩돌이 났닀면
                missile.kill()  # 미사일 터짐
                rock.kill()  # μš΄μ„ 터짐
                occur_explosion(screen, rock.rect.x, rock.rect.y)  # μš΄μ„μ΄ ν„°μ§€λŠ” 효과(좜λ ₯ν•  ν™”λ©΄, x μœ„μΉ˜, y μœ„μΉ˜)
                shot_count += 1  # μš΄μ„μ„ νŒŒκ΄΄ν–ˆμ„ λ•Œ 점수 μŠ΅λ“

        # 전체 μš΄μ„λ“€ μ€‘μ—μ„œ
        for rock in rocks:
            if rock.out_of_screen():  # λ§Œμ•½ μš΄μ„μ΄ ν™”λ©΄ λ°–μœΌλ‘œ λ‚˜κ°”λ‹€λ©΄
                rock.kill()  # μš΄μ„ μ†Œλ©Έ
                count_missed += 1  # λ†“μΉœ 수 증가

        rocks.update()
        rocks.draw(screen)
        missiles.update()
        missiles.draw(screen)
        fighter.update()
        fighter.draw(screen)
        pg.display.flip()

        # κ²Œμž„μ΄ λλ‚˜λŠ” 쑰건
        if fighter.collide(rocks) or count_missed >= 3:  # μš°μ£Όμ„ μ΄ 좩돌이 났을 λ•Œ or μš΄μ„ λ†“μΉœ κ°œμˆ˜κ°€ 3개 이상일 λ•Œ
            pg.mixer_music.stop()  # κ²Œμž„ μŒμ•…μ΄ 꺼짐
            occur_explosion(screen, fighter.rect.x, fighter.rect.y)  # μš°μ£Όμ„ μ΄ μœ„μΉ˜ν•œ κ³³μ—μ„œ ν„°μ§€λŠ” 효과
            pg.display.update()
            gameover_sound.play()  # κ²Œμž„μ΄ μ’…λ£Œλ˜λŠ” μŒμ•…
            sleep(1)  # μž μ‹œ λŒ€κΈ° 1초
            done = True  # done 이 True κ°€ 될 경우 κ²Œμž„μ€ μ’…λ£Œλœλ‹€. 153μ—΄ μ°Έμ‘°

        fps_clock.tick(FPS)  # ν”„λ ˆμž„ 지정

    return 'game_menu'  # κ²Œμž„ λ©”λ‰΄λ‘œ λŒμ•„κ°


# κ²Œμž„ 메뉴
def game_menu():
    start_image = pg.image.load('background.png')
    screen.blit(start_image, [0, 0])
    draw_x = int(WINDOW_WIDTH / 2)
    draw_y = int(WINDOW_HEIGHT / 4)
    font_70 = pg.font.Font('NanumGothic.ttf', 70)
    font_40 = pg.font.Font('NanumGothic.ttf', 40)

    draw_text('지ꡬλ₯Ό μ§€μΌœλΌ!', font_70, screen, draw_x, draw_y, YELLOW)
    draw_text('μ—”ν„° ν‚€λ₯Ό λˆ„λ₯΄λ©΄', font_40, screen, draw_x, draw_y + 200, WHITE)
    draw_text('κ²Œμž„μ΄ μ‹œμž‘λ©λ‹ˆλ‹€.', font_40, screen, draw_x, draw_y + 250, WHITE)

    pg.display.update()

    # 이 ν™”λ©΄ λ‚΄μ—μ„œ λ°›μ•„μ˜€λŠ” ν‚€ 값을 이벀트 처리
    for event in pg.event.get():
        if event.type == pg.KEYDOWN:
            if event.key == pg.K_RETURN:  # K_RETURN = μ—”ν„° κ°’
                return 'play'
        if event.type == QUIT:  # κ²Œμž„ μ’…λ£Œ
            return 'quit'

    return 'game_menu'


# κ²Œμž„ μ…‹νŒ…
def main():
    global screen

    pg.init()  # μ΄ˆκΈ°ν™”
    screen = pg.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))  # ν™”λ©΄ μ…‹νŒ… .set_mode
    pg.display.set_caption('PyShooting')  # ν™”λ©΄ 이름

    action = 'game_menu'
    while action != 'quit':  # λ§Œμ•½μ— action 이 quit 이 μ•„λ‹ˆλ©΄
        if action == 'game_menu':  # λ§Œμ•½μ— action 이 κ²Œμž„ 메뉴이면
            action = game_menu()
        elif action == 'play':  # μ•„λ‹ˆλΌλ©΄ action 이 ν”Œλ ˆμ΄ 라면
            action = game_loop()  # κ²Œμž„ μˆ˜ν–‰

    pg.quit()


# main 을 μ‹€ν–‰μ‹œν‚€κΈ° μœ„ν•΄ __name__ 이 __main__ 일 κ²½μš°μ—
if __name__ == "__main__":
    main()  # main() 을 μ‹€ν–‰ μ‹œμΌœλΌ > κ²Œμž„ μ…‹νŒ…μ„ μˆ˜ν–‰

좜처 : https://youtu.be/W92RjjptAsM

 

 


 

 

 

λ‚˜μ˜ μŠ€νƒ€μΌ arrange

- 기쑴의 속성을 κΉ¨κ³  μžμ‹ λ§Œμ˜ μ½”λ“œλ‘œ λ°”κΎΈμ–΄ μ‹€λ ₯ ν‚€μš°κΈ°
- 클래슀의 μ‚¬μš©λ°©λ²•κ³Ό λΆ€λΆ„ ν•¨μˆ˜μ˜ ν™œμš© 이해

- μ½”λ“œμ˜ 흐름 이해

 

κ²Œμž„ λͺ©ν‘œ : λ„€ λ°©ν–₯ μš΄μ„ 막기

 

κΈ°λŠ₯ μ •μ˜

- μš°μ£Όμ„  μœ„μΉ˜ κ³ μ •

- μš°μ£Όμ„  λ°œμ‚¬ λ°©ν–₯ μ „ν™˜

- μš°μ£Όμ„  미사일 μ‚¬μΆœ λ°©ν–₯

- μš°μ£Όμ„  미사일 이미지 λ°©ν–₯

- μš΄μ„ 좩돌 λ°©ν–₯

 

- 경둜 : Route

- 닀양해진 νŒŒμΌλ“€μ„ 폴더화 ν•΄μ„œ μ •λ¦¬ν•˜κ³ , os λ₯Ό μž„ν¬νŠΈ ν•΄μ„œ ν΄λ”μ˜ 경둜 μ„€μ •κ³Ό 지정 ν΄λ”μ˜ 파일 ν˜ΈμΆœμ„ κ°„νŽΈν•˜κ²Œ μ‚¬μš©

import os

# 이미지 폴더 경둜 μ„€μ • / 파일λͺ… 지정
current_path = os.path.dirname(__file__)
image_path = os.path.join(current_path, "image")
sound_path = os.path.join(current_path, "sound")
font_path = os.path.join(current_path, "font")

user_image = pg.image.load(os.path.join(image_path, "fighter.png"))

 

- 미사일 이미지 λ°©ν–₯

- μš°μ£Όμ„ μ˜ 일관적인 미사일 이미지λ₯Ό νšŒμ „μ‹œμΌœ λ‚˜μ•„κ°€λŠ” λ°©ν–₯으둜 μ •μ˜

- Missile λ©”μ„œλ“œμ—μ„œ rotate ν•¨μˆ˜λ₯Ό μ •μ˜ν•˜κ³  λ°©ν–₯ μž…λ ₯값에 λ”°λ₯Έ 이미지λ₯Ό μ „ν™˜

def rotate(self, direction):  # 이미지 νšŒμ „
    self.direction = direction
    if self.direction == 2:
        self.image = pg.transform.rotate(self.image, 180)
    elif self.direction == 3:
        self.image = pg.transform.rotate(self.image, 90)
    elif self.direction == 4:
        self.image = pg.transform.rotate(self.image, 270)

 

- 미사일 μ‚¬μΆœ λ°©ν–₯

- μš°μ£Όμ„ μ˜ ν•œ λ°©ν–₯으둜만 μ‚¬μΆœλ˜λŠ” 미사일을 λ„€ λ°©ν–₯으둜 μ •μ˜

- νšŒμ „κ³Ό λ§ˆμ°¬κ°€μ§€λ‘œ μ •μ˜λœ λ°©ν–₯값에 따라 Missile 클래슀의 이동 μ’Œν‘œ λ°©ν–₯을 μ •μ˜

- ν™”λ©΄ λ°–μœΌλ‘œ λ‚˜κ°ˆ μ‹œ 미사일 제거

# 미사일 μ‚¬μΆœ λ°©ν–₯
# μš°μ£Όμ„  κΈ°μ€€ μƒν•˜μ’Œμš° λ°©ν–₯으둜 λ°œμ‚¬
def update(self):
    if self.direction == 1:
        self.rect.y -= self.speed  # μš°μ£Όμ„ μ—μ„œ μœ„λ‘œ λ°œμ‚¬λ˜λŠ” μ’Œν‘œ - / ν•΄λ‹Ήν•˜λŠ” 속도 만큼
        if self.rect.y + self.rect.height < 0:  # λ§Œμ•½μ— y 값에 높이가 더해진 κ°’μœΌλ‘œ 0 보닀 μž‘μœΌλ©΄ = 미사일이 ν™”λ©΄ λ°–μœΌλ‘œ λ‚˜κ°
            self.kill()  # ν™”λ©΄ λ°–μœΌλ‘œ λ‚˜κ°„ 미사일은 μ—†μ• μ€Œ
    elif self.direction == 2:
        self.rect.y += self.speed  # μš°μ£Όμ„ μ—μ„œ μ•„λž˜λ‘œ λ°œμ‚¬λ˜λŠ” μ’Œν‘œ - / ν•΄λ‹Ήν•˜λŠ” 속도 만큼
        if self.rect.y + self.rect.height < 0:  # λ§Œμ•½μ— y 값에 높이가 더해진 κ°’μœΌλ‘œ 0 보닀 μž‘μœΌλ©΄ = 미사일이 ν™”λ©΄ λ°–μœΌλ‘œ λ‚˜κ°
            self.kill()  # ν™”λ©΄ λ°–μœΌλ‘œ λ‚˜κ°„ 미사일은 μ—†μ• μ€Œ
    elif self.direction == 3:
        self.rect.x -= self.speed  # μš°μ£Όμ„ μ—μ„œ μ™Όμͺ½μœΌλ‘œ λ°œμ‚¬λ˜λŠ” μ’Œν‘œ - / ν•΄λ‹Ήν•˜λŠ” 속도 만큼
        if self.rect.x + self.rect.height < 0:  # λ§Œμ•½μ— y 값에 높이가 더해진 κ°’μœΌλ‘œ 0 보닀 μž‘μœΌλ©΄ = 미사일이 ν™”λ©΄ λ°–μœΌλ‘œ λ‚˜κ°
            self.kill()  # ν™”λ©΄ λ°–μœΌλ‘œ λ‚˜κ°„ 미사일은 μ—†μ• μ€Œ
    elif self.direction == 4:
        self.rect.x += self.speed  # μš°μ£Όμ„ μ—μ„œ 였λ₯Έμͺ½μœΌλ‘œ λ°œμ‚¬λ˜λŠ” μ’Œν‘œ - / ν•΄λ‹Ήν•˜λŠ” 속도 만큼
        if self.rect.x + self.rect.height < 0:  # λ§Œμ•½μ— y 값에 높이가 더해진 κ°’μœΌλ‘œ 0 보닀 μž‘μœΌλ©΄ = 미사일이 ν™”λ©΄ λ°–μœΌλ‘œ λ‚˜κ°
            self.kill()  # ν™”λ©΄ λ°–μœΌλ‘œ λ‚˜κ°„ 미사일은 μ—†μ• μ€Œ

 

- μš°μ£Όμ„  ν‚€ 이벀트 μ„€μ •

- κ³ μ • μ’Œν‘œμ˜ μš°μ£Όμ„ μ—μ„œ ν‚€ 이벀트λ₯Ό 톡해 λ„€ λ°©ν–₯으둜 ν‚€ 이벀트 μ •μ˜

- missile 을 ν‚€ μ΄λ²€νŠΈμ— λ”°λ₯Έ μ‚¬μΆœ 지점과 속도 λ°©ν–₯을 μ •μ˜ν•œ Missile 클래슀λ₯Ό λ‹΄λŠ”λ‹€. λ‹€μŒ 사전 μ •μ˜λœ missiles의 sprite.Group() 으둜 λ‹΄λŠ”λ‹€.

missiles = pg.sprite.Group()  # μ—¬λŸ¬ 개의 미사일을 .Group() 으둜 묢음

# κ²Œμž„μ˜ 반볡
done = False
while not done:  # done 이 λ§Œμ•½μ— True κ°€ λœλ‹€λ©΄ 반볡문 μ’…λ£Œ
    for event in pg.event.get():  # event 에 pg.event.get() λ₯Ό κ°€μ Έμ˜€κ³ 
        if event.type == pg.KEYDOWN:  # event.type 이 ν‚€ λ‹€μš΄ μƒνƒœμΌ λ•Œ = μž…λ ₯ μƒνƒœμΌ λ•Œ
            if event.key == pg.K_UP:
                missile = Missile(fighter.rect.centerx - 9, fighter.rect.centery - 5, 10, 1)  # Missle class > (xpos, ypos, speed)
                # missile.launch()
                missiles.add(missile)
            elif event.key == pg.K_DOWN:
                missile = Missile(fighter.rect.centerx - 9, fighter.rect.centery - 5, 10, 2)  # Missle class > (xpos, ypos, speed)
                missile.rotate(2)
                # missile.launch()
                missiles.add(missile)
            elif event.key == pg.K_LEFT:  # 근데 λ§Œμ•½μ— event.key κ°€ μ™Όμͺ½μ΄ λˆŒλ Έλ‹€λ©΄
                missile = Missile(fighter.rect.centerx - 5, fighter.rect.centery - 5, 10, 3)  # Missle class > (xpos, ypos, speed)
                missile.rotate(3)
                # missile.launch()
                missiles.add(missile)
            elif event.key == pg.K_RIGHT:
                missile = Missile(fighter.rect.centerx - 5, fighter.rect.centery - 5, 10, 4)  # Missle class > (xpos, ypos, speed)
                missile.rotate(4)
                # missile.launch()
                missiles.add(missile)
                
        # 미사일이 μ—¬λŸ¬κ°œ λ°œμ‚¬ 됐을 λ•Œ
        for missile in missiles:
            rock = missile.collide(rocks)  # 미사일이 μš΄μ„κ³Όμ˜ 좩돌 체크
            if rock:  # 좩돌이 났닀면
                missile.kill()  # 미사일 터짐
                rock.kill()  # μš΄μ„ 터짐
                occur_explosion(screen, rock.rect.x, rock.rect.y)  # μš΄μ„μ΄ ν„°μ§€λŠ” 효과(좜λ ₯ν•  ν™”λ©΄, x μœ„μΉ˜, y μœ„μΉ˜)
                shot_count += 1  # μš΄μ„μ„ νŒŒκ΄΄ν–ˆμ„ λ•Œ 점수 μŠ΅λ“

 

- μš΄μ„ 좩돌 λ°©ν–₯

- κ²Œμž„μ˜ μ°½ WIDTH 와 HEIGHT 의 κ°’μœΌλ‘œ 쀑간 지점 μ’Œν‘œλ₯Ό 계산

# μš΄μ„ 좩돌 λ°©ν–₯ & λ“±μž₯ ν™•λ₯ 
if random.randint(1, occur_prob) == 1:  # 1 λΆ€ν„° occur_prob(40) μ‚¬μ΄μ˜ 1이 λ“±μž₯ν•  ν™•λ₯  = 1/40
    for i in range(occur_of_rocks):
        speed = random.randint(min_rock_speed, max_rock_speed)  # μŠ€ν”Όλ“œλ₯Ό 랜덀으둜 선택
        rock_direction = random.randint(1, 4)
        if rock_direction == 1:
            rock = Rock(WINDOW_WIDTH / 2 - 40, 640, speed, 1)  # 0 λΆ€ν„° X μ’Œν‘œ(λ„ˆλΉ„ μ’Œν‘œμ—μ„œ 30정도 λΊ€ κ°’)κΉŒμ§€
        elif rock_direction == 2:
            rock = Rock(WINDOW_WIDTH / 2 - 40, 0, speed, 2)  # 0 λΆ€ν„° X μ’Œν‘œ(λ„ˆλΉ„ μ’Œν‘œμ—μ„œ 30정도 λΊ€ κ°’)κΉŒμ§€
        elif rock_direction == 3:
            rock = Rock(640, WINDOW_HEIGHT / 2 - 20, speed, 3)  # 0 λΆ€ν„° X μ’Œν‘œ(λ„ˆλΉ„ μ’Œν‘œμ—μ„œ 30정도 λΊ€ κ°’)κΉŒμ§€
        elif rock_direction == 4:
            rock = Rock(0, WINDOW_HEIGHT / 2 - 20, speed, 4)  # 0 λΆ€ν„° X μ’Œν‘œ(λ„ˆλΉ„ μ’Œν‘œμ—μ„œ 30정도 λΊ€ κ°’)κΉŒμ§€

        rocks.add(rock)

 

- λ―Έκ΅¬ν˜„ κΈ°λŠ₯

- μš΄μ„κ°„μ˜ 쀑첩 방지

- 졜고점 μŠ€μ½”μ–΄ 기둝 κΈ°λŠ₯

- λ‚œμ΄λ„ μƒμŠΉ μ‹œ ꡬ뢄 ν‘œμ‹œ κΈ°λŠ₯

 


 

- 1μ°¨ μ™„μ„±

더보기
import random
from time import sleep

import os
import pygame as pg
from pygame.locals import *

# μ°½ μ‚¬μ΄μ¦ˆ μ „μ—­λ³€μˆ˜
WINDOW_WIDTH = 640
WINDOW_HEIGHT = 640

# 색상 μ •μ˜
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
YELLOW = (250, 250, 50)
RED = (250, 50, 50)

# 이미지 경둜 μ„€μ •
current_path = os.path.dirname(__file__)
image_path = os.path.join(current_path, "../image")
sound_path = os.path.join(current_path, "../sound")
font_path = os.path.join(current_path, "../font")

# μ΄ˆλ‹Ή ν”„λ ˆμž„
FPS = 60


# μš°μ£Όμ„  클래슀
# κ²Œμž„μ—μ„œ λ‚˜νƒ€λ‚΄λŠ” λͺ¨λ“  캐릭터, μž₯애물등을 ν‘œν˜„ν•  λ•Œ μ‚¬μš©ν•˜λŠ” Surface 상속을 λ°›μ•„μ˜¨λ‹€.
class Fighter(pg.sprite.Sprite):
    # λ‹€λ₯Έ 객체지ν–₯ μ–Έμ–΄μ—μ„œλŠ” μƒμ„±μž(constructor)라고 λΆ€λ₯Έλ‹΅λ‹ˆλ‹€
    # μ΄ˆκΈ°ν™” λ©”μ„œλ“œ, μ–΄λ–€ 클래슀의 객체가 λ§Œλ“€μ–΄μ§ˆ λ•Œ μžλ™μœΌλ‘œ ν˜ΈμΆœλ˜μ–΄μ„œ κ·Έ 객체가 κ°–κ²Œ 될 μ—¬λŸ¬ 가지 μ„±μ§ˆμ„ μ •ν•΄μ£ΌλŠ” 일
    def __init__(self):  # 단일
        super(Fighter, self).__init__()  # μƒμœ„ 클래슀 __init__ 호좜
        self.image = pg.image.load(os.path.join(image_path, "fighter3.svg"))  # self(Fighter의 μ΄ˆκΈ°ν™” κ°’) 에 μž…νž 이미지λ₯Ό κ°€μ Έμ˜¨λ‹€.
        self.rect = self.image.get_rect()  # 이미지 크기 μ‘°μ • .get_rect(none)[크기 정보 + μ’Œν‘œ 정보]
        self.rect.x = int(WINDOW_WIDTH / 2 - self.rect.width / 2)  # 처음 μš°μ£Όμ„ μ˜ λ“±μž₯ μœ„μΉ˜ (WINDOW_WIDTH / 2 = 창의 λ„ˆλΉ„μ˜ 쀑앙)
        self.rect.y = int(WINDOW_HEIGHT / 2 - self.rect.height / 2)  # μš°μ£Όμ„ μ˜ 높이 만큼 λΉΌμ„œ y 값을 지정
        self.dx = 0  # x λ°©ν–₯
        self.dy = 0  # y λ°©ν–₯

    # ν™”λ©΄ λ°–μœΌλ‘œ λ‚˜κ°”μ„ 경우λ₯Ό λŒ€λΉ„ν•œ 루트
    def update(self):
        self.rect.x += self.dx  # μš°μ£Όμ„ .rect.x μœ„μΉ˜κ°€ μš°μ£Όμ„ .dx μ΄λ™ν•œ μœ„μΉ˜ 만큼 더해진닀.
        self.rect.y += self.dy  # μ›€μ§μž„ ν•„μˆ˜μ μΈ λΆ€λΆ„

        # μš°μ£Όμ„ .rect.x μ’Œν‘œκ°€ 0 보닀 μž‘μ€ κ²½μš°λŠ” = ν™”λ©΄ λ°–μœΌλ‘œ λ‚˜κ°€λŠ” 경우
        # λ§Œμ•½ X μœ„μΉ˜κ°€ μš°μ£Όμ„ μ˜ λ„ˆλΉ„λ₯Ό ν¬ν•¨ν•œ μ’Œν‘œκ°€ 창의 λ„ˆλΉ„λ³΄λ‹€ 클 경우
        if self.rect.x < 0 or self.rect.x + self.rect.width > WINDOW_WIDTH:  # 창의 λ°–μœΌλ‘œ λ‚˜κ°”μ„ 경우λ₯Ό λŒ€λΉ„
            self.rect.x -= self.dx  # λ‚˜κ°€λ©΄ μ›€μ§μž„μ„ 멈좀

        # μš°μ£Όμ„ .rect.y μ’Œν‘œκ°€ 0 보닀 μž‘μ€ κ²½μš°λŠ” = ν™”λ©΄ λ°–μœΌλ‘œ λ‚˜κ°€λŠ” 경우
        # λ§Œμ•½ Y μœ„μΉ˜κ°€ μš°μ£Όμ„ μ˜ 높이λ₯Ό ν¬ν•¨ν•œ μ’Œν‘œκ°€ 창의 높이보닀 클 경우
        if self.rect.y < 0 or self.rect.y + self.rect.height > WINDOW_HEIGHT:
            self.rect.y -= self.dy

    # κ·Έλ €μ£ΌλŠ” λΆ€λΆ„
    def draw(self, screen):  # self μ—μ„œ 슀크린 값을 λ°›μ•„μ˜¨λ‹€.
        screen.blit(self.image, self.rect)  # 화면에 그렀쀌 μš°μ£Όμ„ (self) 의 이미지와 μš°μ£Όμ„ (self) 의 μ‚¬μ΄μ¦ˆ

    def collide(self, sprites):
        for sprite in sprites:  # 객체 관리λ₯Ό νŽΈν•˜κ²Œ ν•˜κΈ° μœ„ν•œ 방법
            if pg.sprite.collide_rect(self, sprite):  # 검사 쀑 μš°μ£Όμ„ κ³Ό sprite 와 μΆ©λŒν–ˆμ„ 경우 / .collide_rect = 좩돌 체크
                return sprite  # 좩돌 λ‚œ sprite return


# 미사일 클래슀
class Missile(pg.sprite.Sprite):
    def __init__(self, xpos, ypos, speed, direction):  # μ΄ˆκΈ°ν™” λ©”μ„œλ“œ, 뢈러올 κ°’ 지정
        super(Missile, self).__init__()
        self.image = pg.image.load(os.path.join(image_path, "firetrail.png"))
        self.rect = self.image.get_rect()  # 미사일 μ‚¬μ΄μ¦ˆ
        self.rect.x = xpos  # 미사일 ν˜ΈμΆœν•˜λŠ” μœ„μΉ˜ κ°’ 지정 / μš°μ£Όμ„ μ—μ„œ λ°œμ‚¬ν•  수 있게 λ§Œλ“€κΈ° μœ„ν•œ
        self.rect.y = ypos
        self.speed = speed
        self.direction = direction
        self.sound = pg.mixer.Sound(os.path.join(sound_path, "missile.wav"))

    def launch(self):  # λ°œμ‚¬μ— λŒ€ν•œ μ†Œλ¦¬
        self.sound.play()  # μ†Œλ¦¬ μž¬μƒ

    def rotate(self, direction):  # 이미지 νšŒμ „
        self.direction = direction
        if self.direction == 2:
            self.image = pg.transform.rotate(self.image, 180)
        elif self.direction == 3:
            self.image = pg.transform.rotate(self.image, 90)
        elif self.direction == 4:
            self.image = pg.transform.rotate(self.image, 270)

    # 미사일 μ‚¬μΆœ λ°©ν–₯
    # μš°μ£Όμ„  κΈ°μ€€ μƒν•˜μ’Œμš° λ°©ν–₯으둜 λ°œμ‚¬
    def update(self):
        if self.direction == 1:
            self.rect.y -= self.speed  # μš°μ£Όμ„ μ—μ„œ μœ„λ‘œ λ°œμ‚¬λ˜λŠ” μ’Œν‘œ - / ν•΄λ‹Ήν•˜λŠ” 속도 만큼
            if self.rect.y + self.rect.height < 0:  # λ§Œμ•½μ— y 값에 높이가 더해진 κ°’μœΌλ‘œ 0 보닀 μž‘μœΌλ©΄ = 미사일이 ν™”λ©΄ λ°–μœΌλ‘œ λ‚˜κ°
                self.kill()  # ν™”λ©΄ λ°–μœΌλ‘œ λ‚˜κ°„ 미사일은 μ—†μ• μ€Œ
        elif self.direction == 2:
            self.rect.y += self.speed  # μš°μ£Όμ„ μ—μ„œ μ•„λž˜λ‘œ λ°œμ‚¬λ˜λŠ” μ’Œν‘œ - / ν•΄λ‹Ήν•˜λŠ” 속도 만큼
            if self.rect.y + self.rect.height < 0:  # λ§Œμ•½μ— y 값에 높이가 더해진 κ°’μœΌλ‘œ 0 보닀 μž‘μœΌλ©΄ = 미사일이 ν™”λ©΄ λ°–μœΌλ‘œ λ‚˜κ°
                self.kill()  # ν™”λ©΄ λ°–μœΌλ‘œ λ‚˜κ°„ 미사일은 μ—†μ• μ€Œ
        elif self.direction == 3:
            self.rect.x -= self.speed  # μš°μ£Όμ„ μ—μ„œ μ™Όμͺ½μœΌλ‘œ λ°œμ‚¬λ˜λŠ” μ’Œν‘œ - / ν•΄λ‹Ήν•˜λŠ” 속도 만큼
            if self.rect.x + self.rect.height < 0:  # λ§Œμ•½μ— y 값에 높이가 더해진 κ°’μœΌλ‘œ 0 보닀 μž‘μœΌλ©΄ = 미사일이 ν™”λ©΄ λ°–μœΌλ‘œ λ‚˜κ°
                self.kill()  # ν™”λ©΄ λ°–μœΌλ‘œ λ‚˜κ°„ 미사일은 μ—†μ• μ€Œ
        elif self.direction == 4:
            self.rect.x += self.speed  # μš°μ£Όμ„ μ—μ„œ 였λ₯Έμͺ½μœΌλ‘œ λ°œμ‚¬λ˜λŠ” μ’Œν‘œ - / ν•΄λ‹Ήν•˜λŠ” 속도 만큼
            if self.rect.x + self.rect.height < 0:  # λ§Œμ•½μ— y 값에 높이가 더해진 κ°’μœΌλ‘œ 0 보닀 μž‘μœΌλ©΄ = 미사일이 ν™”λ©΄ λ°–μœΌλ‘œ λ‚˜κ°
                self.kill()  # ν™”λ©΄ λ°–μœΌλ‘œ λ‚˜κ°„ 미사일은 μ—†μ• μ€Œ


        # self.rect.x -= self.speed  # μ•„λž˜μ—μ„œ μœ„λ‘œ λ°œμ‚¬λ˜λŠ” μ’Œν‘œ - / ν•΄λ‹Ήν•˜λŠ” 속도 만큼
        # if self.rect.x + self.rect.height < 0:  # λ§Œμ•½μ— y 값에 높이가 더해진 κ°’μœΌλ‘œ 0 보닀 μž‘μœΌλ©΄ = 미사일이 ν™”λ©΄ λ°–μœΌλ‘œ λ‚˜κ°
        #     self.kill()  # ν™”λ©΄ λ°–μœΌλ‘œ λ‚˜κ°„ 미사일은 μ—†μ• μ€Œ

    # 미사일 좩돌 체크
    def collide(self, sprites):
        for sprite in sprites:
            if pg.sprite.collide_rect(self, sprite):
                return sprite


# μš΄μ„ 클래슀
class Rock(pg.sprite.Sprite):
    def __init__(self, xpos, ypos, speed, direction):  # μ΄ˆκΈ°ν™” λ©”μ„œλ“œ, μš΄μ„μ˜ μ’Œν‘œ 및 μŠ€ν”Όλ“œ
        super(Rock, self).__init__()
        rock_images = (os.path.join(image_path, "rock01.png"), os.path.join(image_path, "rock02.png"), os.path.join(image_path, "rock03.png"), os.path.join(image_path, "rock04.png"), os.path.join(image_path, "rock05.png"))  # μš΄μ„ 1 ~ 5 μ •μ˜ / νŠœν”Œ 적용
        self.image = pg.image.load(random.choice(rock_images))  # rock_images μ—μ„œ 랜덀으둜 이미지λ₯Ό 골라쀘
        self.rect = self.image.get_rect()
        self.rect.x = xpos
        self.rect.y = ypos
        self.speed = speed
        self.direction = direction

    # μš΄μ„ μ—…λ°μ΄νŠΈ
    def update(self):
        # self.rect.y += self.speed  # μœ„μ—μ„œ λ°‘μœΌλ‘œ λ‚΄λ €μ˜€λŠ” κ°’ +

        if self.direction == 1:  # μ•„λž˜μ—μ„œ μœ„λ‘œ
            self.rect.y -= self.speed
        elif self.direction == 2:  # μœ„μ—μ„œ μ•„λž˜λ‘œ
            self.rect.y += self.speed
        elif self.direction == 3:  # 였λ₯Έμͺ½μ—μ„œ μ™Όμͺ½μœΌλ‘œ
            self.rect.x -= self.speed
        elif self.direction == 4:  # μ™Όμͺ½μ—μ„œ 였λ₯Έμͺ½μœΌλ‘œ
            self.rect.x += self.speed

    # μš΄μ„μ΄ ν™”λ©΄ λ°–μœΌλ‘œ λ‚˜κ°”μ„ 경우
    def out_of_screen(self):
        if self.rect.y > WINDOW_HEIGHT:  # μš΄μ„μ˜ y 값이 λ§Œμ•½μ— ν™”λ©΄μ˜ 높이보닀 컀지면 = μš΄μ„μ΄ μ•„λž˜ ν™”λ©΄ λκΉŒμ§€ λ‚˜κ°”μ„ λ•Œ
            return True  # λ‚˜κ°”μ„ 경우의 상황을 ν˜ΈμΆœν•˜κΈ° μœ„ν•œ True


# κ²Œμž„ ν™”λ©΄ 상에 ν‘œμ‹œ λ˜λŠ” ν…μŠ€νŠΈ 좜λ ₯
def draw_text(text, font, surface, x, y, main_color):
    text_obj = font.render(text, True, main_color)  # font.render 둜 폰트 μ •μ˜ / μ›ν•˜λŠ” ν…μŠ€νŠΈ 색상 지정
    text_rect = text_obj.get_rect()  # ν…μŠ€νŠΈμ˜ μœ„μΉ˜ 지정
    text_rect.centerx = x
    text_rect.centery = y
    surface.blit(text_obj, text_rect)  # .blit(ν™”λ©΄ 좜λ ₯ν•  개체, 좜λ ₯ν•  μœ„μΉ˜)


# 폭발 효과
def occur_explosion(surface, x, y):
    explosion_image = pg.image.load(os.path.join(image_path, "explosion.png"))
    explosion_rect = explosion_image.get_rect()
    explosion_rect.x = x
    explosion_rect.y = y
    surface.blit(explosion_image, explosion_rect)

    explosion_sounds = (os.path.join(sound_path, "explosion01.wav"), os.path.join(sound_path, "explosion02.wav"), os.path.join(sound_path, "explosion03.wav"))
    explosion_sound = pg.mixer.Sound(random.choice(explosion_sounds))
    explosion_sound.play()


# 메인 κ²Œμž„μ˜ 루프
def game_loop():
    default_font = pg.font.Font(os.path.join(font_path, "NanumGothic.ttf"), 28)  # κ²Œμž„ 폰트
    background_image = pg.image.load(os.path.join(image_path, "background3.jpg"))  # κ²Œμž„ λ°°κ²½ 이미지
    gameover_sound = pg.mixer.Sound(os.path.join(sound_path, "gameover.wav"))  # κ²Œμž„ μ’…λ£Œ
    pg.mixer.music.load(os.path.join(sound_path, "music.wav"))  # κ²Œμž„ μŒμ•…
    pg.mixer.music.play(-1)  # λͺ‡ 번 μž¬μƒν•  것인가 (-1 = λ¬΄ν•œ)
    fps_clock = pg.time.Clock()  # ν”„λ ˆμž„

    fighter = Fighter()  # λ§Œλ“€μ—ˆλ˜ 클래슀λ₯Ό μΈμŠ€ν„΄μŠ€λ‘œ 지정
    missiles = pg.sprite.Group()  # μ—¬λŸ¬ 개의 미사일을 .Group() 으둜 묢음
    rocks = pg.sprite.Group()  # μ—¬λŸ¬ 개의 μš΄μ„μ„ 묢음

    occur_prob = 30  # ν™•λ₯ μ μœΌλ‘œ μ–Όλ§ŒνΌ λ‚˜μ˜€κ²Œ ν•˜λŠ”κ°€
    shot_count = 0  # 맞좘 개수
    # count_missed = 0  # λ†“μΉœ 개수

    # κ²Œμž„μ˜ 반볡
    done = False
    while not done:  # done 이 λ§Œμ•½μ— True κ°€ λœλ‹€λ©΄ 반볡문 μ’…λ£Œ
        for event in pg.event.get():  # event 에 pg.event.get() λ₯Ό κ°€μ Έμ˜€κ³ 
            if event.type == pg.KEYDOWN:  # event.type 이 ν‚€ λ‹€μš΄ μƒνƒœμΌ λ•Œ = μž…λ ₯ μƒνƒœμΌ λ•Œ
                if event.key == pg.K_UP:
                    missile = Missile(fighter.rect.centerx - 9, fighter.rect.centery - 5, 10, 1)  # Missle class > (xpos, ypos, speed)
                    # missile.launch()
                    missiles.add(missile)
                elif event.key == pg.K_DOWN:
                    missile = Missile(fighter.rect.centerx - 9, fighter.rect.centery - 5, 10, 2)  # Missle class > (xpos, ypos, speed)
                    missile.rotate(2)
                    # missile.launch()
                    missiles.add(missile)
                elif event.key == pg.K_LEFT:  # 근데 λ§Œμ•½μ— event.key κ°€ μ™Όμͺ½μ΄ λˆŒλ Έλ‹€λ©΄
                    missile = Missile(fighter.rect.centerx - 5, fighter.rect.centery - 5, 10, 3)  # Missle class > (xpos, ypos, speed)
                    missile.rotate(3)
                    # missile.launch()
                    missiles.add(missile)
                elif event.key == pg.K_RIGHT:
                    missile = Missile(fighter.rect.centerx - 5, fighter.rect.centery - 5, 10, 4)  # Missle class > (xpos, ypos, speed)
                    missile.rotate(4)
                    # missile.launch()
                    missiles.add(missile)

            # if event.type == pg.KEYUP:  # ν‚€μ—… 인 μƒνƒœμ—μ„œ
            #     if event.key == pg.K_LEFT or event.key == pg.K_RIGHT:  # μ™Όμͺ½ or 였λ₯Έμͺ½ ν‚€λ₯Ό λ• λ‹€λ©΄
            #         fighter.dx = 0  # x 이동을 λ©ˆμΆ˜λ‹€
            #     elif event.key == pg.K_UP or event.key == pg.K_DOWN:  # μœ„ or μ•„λž˜ ν‚€λ₯Ό λ• λ‹€λ©΄
            #         fighter.dy = 0  # y 이동을 λ©ˆμΆ˜λ‹€

        screen.blit(background_image, background_image.get_rect())  # ν™”λ©΄ 좜λ ₯(λ°±κ·ΈλΌμš΄λ“œ 이미지, λ°±κ·ΈλΌμš΄λ“œ μœ„μΉ˜ μ’Œν‘œ)

        # λ§Œμ•½μ˜ μš΄μ„μ„ 100개 파괴 ν–ˆλ‹€λ©΄, μŠ€ν”Όλ“œμ™€ μš΄μ„ 수λ₯Ό μ¦κ°€μ‹œν‚¨λ‹€ = λ‚œμ΄λ„ μƒμŠΉ
        occur_of_rocks = 1 + int(shot_count / 300)  # shot_count = μ–Όλ§ŒνΌ μš΄μ„μ„ λ§žμ·„λŠ”κ°€
        min_rock_speed = 1 + int(shot_count / 200)
        max_rock_speed = 1 + int(shot_count / 100)

        # μš΄μ„ λ“±μž₯ ν™•λ₯ 
        if random.randint(1, occur_prob) == 1:  # 1 λΆ€ν„° occur_prob(40) μ‚¬μ΄μ˜ 1이 λ“±μž₯ν•  ν™•λ₯  = 1/40
            for i in range(occur_of_rocks):
                speed = random.randint(min_rock_speed, max_rock_speed)  # μŠ€ν”Όλ“œλ₯Ό 랜덀으둜 선택
                rock_direction = random.randint(1, 4)
                if rock_direction == 1:
                    rock = Rock(WINDOW_WIDTH / 2 - 40, 640, speed, 1)  # 0 λΆ€ν„° X μ’Œν‘œ(λ„ˆλΉ„ μ’Œν‘œμ—μ„œ 30정도 λΊ€ κ°’)κΉŒμ§€
                elif rock_direction == 2:
                    rock = Rock(WINDOW_WIDTH / 2 - 40, 0, speed, 2)  # 0 λΆ€ν„° X μ’Œν‘œ(λ„ˆλΉ„ μ’Œν‘œμ—μ„œ 30정도 λΊ€ κ°’)κΉŒμ§€
                elif rock_direction == 3:
                    rock = Rock(640, WINDOW_HEIGHT / 2 - 20, speed, 3)  # 0 λΆ€ν„° X μ’Œν‘œ(λ„ˆλΉ„ μ’Œν‘œμ—μ„œ 30정도 λΊ€ κ°’)κΉŒμ§€
                elif rock_direction == 4:
                    rock = Rock(0, WINDOW_HEIGHT / 2 - 20, speed, 4)  # 0 λΆ€ν„° X μ’Œν‘œ(λ„ˆλΉ„ μ’Œν‘œμ—μ„œ 30정도 λΊ€ κ°’)κΉŒμ§€

                rocks.add(rock)

        # ('ν‘œμ‹œν•  ν…μŠ€νŠΈ', μ‚¬μš©ν•  폰트, ν‘œμ‹œν•  ν™”λ©΄, xμ’Œν‘œ, yμ’Œν‘œ, 색상)
        draw_text('νŒŒκ΄΄ν•œ μš΄μ„ : {}'.format(shot_count), default_font, screen, 100, 20, YELLOW)  # νŒŒκ΄΄ν•œ μš΄μ„ ν‘œμ‹œ
        # draw_text('λ†“μΉœ μš΄μ„ : {}'.format(count_missed), default_font, screen, 400, 20, RED)  # λ†“μΉœ μš΄μ„ ν‘œμ‹œ

        # 미사일이 μ—¬λŸ¬κ°œ λ°œμ‚¬ 됐을 λ•Œ
        for missile in missiles:
            rock = missile.collide(rocks)  # 미사일이 μš΄μ„κ³Όμ˜ 좩돌 체크
            if rock:  # 좩돌이 났닀면
                missile.kill()  # 미사일 터짐
                rock.kill()  # μš΄μ„ 터짐
                occur_explosion(screen, rock.rect.x, rock.rect.y)  # μš΄μ„μ΄ ν„°μ§€λŠ” 효과(좜λ ₯ν•  ν™”λ©΄, x μœ„μΉ˜, y μœ„μΉ˜)
                shot_count += 1  # μš΄μ„μ„ νŒŒκ΄΄ν–ˆμ„ λ•Œ 점수 μŠ΅λ“

        rocks.update()
        rocks.draw(screen)
        missiles.update()
        missiles.draw(screen)
        fighter.update()
        fighter.draw(screen)
        pg.display.flip()

        # κ²Œμž„μ΄ λλ‚˜λŠ” 쑰건
        # if fighter.collide(rocks) or count_missed >= 3:  # μš°μ£Όμ„ μ΄ 좩돌이 났을 λ•Œ or μš΄μ„ λ†“μΉœ κ°œμˆ˜κ°€ 3개 이상일 λ•Œ
        if fighter.collide(rocks):  # μš°μ£Όμ„ μ΄ 좩돌이 났을 λ•Œ or μš΄μ„ λ†“μΉœ κ°œμˆ˜κ°€ 3개 이상일 λ•Œ
            pg.mixer_music.stop()  # κ²Œμž„ μŒμ•…μ΄ 꺼짐
            occur_explosion(screen, fighter.rect.x, fighter.rect.y)  # μš°μ£Όμ„ μ΄ μœ„μΉ˜ν•œ κ³³μ—μ„œ ν„°μ§€λŠ” 효과
            pg.display.update()
            gameover_sound.play()  # κ²Œμž„μ΄ μ’…λ£Œλ˜λŠ” μŒμ•…
            sleep(1)  # μž μ‹œ λŒ€κΈ° 1초
            done = True  # done 이 True κ°€ 될 경우 κ²Œμž„μ€ μ’…λ£Œλœλ‹€. 153μ—΄ μ°Έμ‘°

        fps_clock.tick(FPS)  # ν”„λ ˆμž„ 지정

    return 'game_menu'  # κ²Œμž„ λ©”λ‰΄λ‘œ λŒμ•„κ°

#

# κ²Œμž„ 메뉴
def game_menu():
    start_image = pg.image.load(os.path.join(image_path, "background_menu.png"))
    screen.blit(start_image, [0, 0])
    draw_x = int(WINDOW_WIDTH / 2)
    draw_y = int(WINDOW_HEIGHT / 4)
    font_70 = pg.font.Font(os.path.join(font_path, "NanumGothic.ttf"), 70)
    font_40 = pg.font.Font(os.path.join(font_path, "NanumGothic.ttf"), 40)

    draw_text('지ꡬλ₯Ό μ§€μΌœλΌ!', font_70, screen, draw_x, draw_y, YELLOW)
    draw_text('μ—”ν„° ν‚€λ₯Ό λˆ„λ₯΄λ©΄', font_40, screen, draw_x, draw_y + 200, WHITE)
    draw_text('κ²Œμž„μ΄ μ‹œμž‘λ©λ‹ˆλ‹€.', font_40, screen, draw_x, draw_y + 250, WHITE)

    # draw_text('νŒŒκ΄΄ν•œ μš΄μ„ : {}'.format(shot_count), default_font, screen, 100, 20, YELLOW)  # νŒŒκ΄΄ν•œ μš΄μ„ ν‘œμ‹œ

    pg.display.update()

    # κ²Œμž„ 졜고점

    # 이 ν™”λ©΄ λ‚΄μ—μ„œ λ°›μ•„μ˜€λŠ” ν‚€ 값을 이벀트 처리
    for event in pg.event.get():
        if event.type == pg.KEYDOWN:
            if event.key == pg.K_RETURN:  # K_RETURN = μ—”ν„° κ°’
                return 'play'
        if event.type == QUIT:  # κ²Œμž„ μ’…λ£Œ
            return 'quit'

    return 'game_menu'


# κ²Œμž„ μ…‹νŒ…
def main():
    global screen

    pg.init()  # μ΄ˆκΈ°ν™”
    screen = pg.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))  # ν™”λ©΄ μ…‹νŒ… .set_mode
    pg.display.set_caption('PyShooting')  # ν™”λ©΄ 이름

    action = 'game_menu'
    while action != 'quit':  # λ§Œμ•½μ— action 이 quit 이 μ•„λ‹ˆλ©΄
        if action == 'game_menu':  # λ§Œμ•½μ— action 이 κ²Œμž„ 메뉴이면
            action = game_menu()
        elif action == 'play':  # μ•„λ‹ˆλΌλ©΄ action 이 ν”Œλ ˆμ΄ 라면
            action = game_loop()  # κ²Œμž„ μˆ˜ν–‰

    pg.quit()


# main 을 μ‹€ν–‰μ‹œν‚€κΈ° μœ„ν•΄ __name__ 이 __main__ 일 κ²½μš°μ—
if __name__ == "__main__":
    main()  # main() 을 μ‹€ν–‰ μ‹œμΌœλΌ > κ²Œμž„ μ…‹νŒ…μ„ μˆ˜ν–‰

 


 

λŒ€μΆ© 이런 λŠλ‚Œ..

 

 
 
 
Contents

ν¬μŠ€νŒ… μ£Όμ†Œλ₯Ό λ³΅μ‚¬ν–ˆμŠ΅λ‹ˆλ‹€

이 글이 도움이 λ˜μ—ˆλ‹€λ©΄ 곡감 λΆ€νƒλ“œλ¦½λ‹ˆλ‹€.