GiantStepDEV
article thumbnail

ํŒŒ์ด์ฌ์˜ ๋Œ€ํ‘œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ค‘ ํ•˜๋‚˜์ธ pygame์„ ์ด์šฉํ•ด Pong!  ๊ฒŒ์ž„์„ ๋งŒ๋“ค์–ด๋ณด์•˜์Šต๋‹ˆ๋‹ค.

ํŒŒ์ด์ฌ์œผ๋กœ ๋งŒ๋“ค๊ธฐ ์ „์— C / C++ ๋กœ ๊ตฌํ˜„ํ•ด๋ณด๋Š” ๋ฐฉ๋ฒ•๋„ ์ฐพ์•„๋ดค๋Š”๋ฐ raylib ์„ธํŒ…ํ•˜๋‹ค๊ฐ€ ๊ฒฐ๊ตญ ์•ˆ๋˜์–ด์„œ ์‹œ๊ฐ„ ๋‹ค ๋‚ ๋ ค๋จน๊ณ ..

๋น„๊ต์  ๊ฐ„๋‹จํ•œ ํŒŒ์ด์ฌ์œผ๋กœ ๊ตฌํ˜„ํ•˜๊ธฐ๋กœ ๋งˆ์Œ์„ ํ‹€์—ˆ์Šต๋‹ˆ๋‹ค. ํ•˜ํ•ซ..

 

ํ˜ผ์ž ๋งŒ๋“ค๊ธฐ์—” ์–ด๋ ค์›Œ์„œ ์œ ํŠœ๋ธŒ์˜ ํž˜์„ ๋นŒ๋ ธ์Šต๋‹ˆ๋‹ค! ^^

'๋‚˜๋„์ฝ”๋”ฉ' ๋‹˜์˜ ํŒŒ์ด์ฌ ๊ฒŒ์ž„ ๋งŒ๋“ค๊ธฐ ์˜์ƒ์„ ์ฐธ์กฐํ•˜์˜€์Šต๋‹ˆ๋‹ค.

๊ธฐ๋ณธ์ ์ธ ํŒŒ์ด์ฌ ์ง€์‹ ํ˜น์€ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์ง€์‹์ด ์—†์–ด๋„ ์ถฉ๋ถ„ํžˆ ๋”ฐ๋ผํ•  ์ˆ˜ ์žˆ์„ ์ •๋„๋กœ ์„ค๋ช…์„ ๊ต‰์žฅํžˆ ์ž์„ธํžˆ ์ž˜ํ•ด์ฃผ์‹ญ๋‹ˆ๋‹ค.

https://youtu.be/Dkx8Pl6QKW0

 

๊ฐœ์ธ์ ์œผ๋กœ ์ฝ”๋“œ ์ž‘์„ฑํ•œ ๊ฒƒ ๋ณด๋‹ค ์ด๋ฏธ์ง€ ์ฐพ๋Š” ์‹œ๊ฐ„์ด ๋” ๊ฑธ๋ ธ์–ด์š”..๐Ÿ˜…

์ €๋Š” ์Šˆํผ๋งˆ๋ฆฌ์˜ค ์ด๋ฏธ์ง€๋กœ ๊ตฌํ˜„ํ•ด๋ณด์•˜์Šต๋‹ˆ๋‹ค.

์†Œ๋ฆฌ๋„ ๋„ฃ์œผ๋‹ˆ ํ›จ์”ฌ ๋” ๊ฒŒ์ž„ ๊ฐ™์•„์ง€๋”๋ผ๊ตฌ์š”. ์ข‹์€ ์„ ํƒ์ด์—ˆ์Šต๋‹ˆ๋‹ค.

 

# 1. ๋ชจ๋“  ๊ณต์„ ์—†์• ๋ฉด ๊ฒŒ์ž„ ์ข…๋ฃŒ (์„ฑ๊ณต)
# 2. ์บ๋ฆญํ„ฐ๊ฐ€ ๊ณต์— ๋งž์•˜์„ ๋•Œ (์‹คํŒจ)
# 3. ์‹œ๊ฐ„ ์ œํ•œ 99์ดˆ ์ดˆ๊ณผ ์‹œ ๊ฒŒ์ž„ ์ข…๋ฃŒ (์‹คํŒจ)
import os
import pygame
import time
##############################################################
# ๊ธฐ๋ณธ ์ดˆ๊ธฐํ™” (๋ฐ˜๋“œ์‹œ ํ•ด์•ผ ํ•˜๋Š” ๊ฒƒ๋“ค)
pygame.init()

# ํ™”๋ฉด ํฌ๊ธฐ ์„ค์ •
screen_width = 640 # ๊ฐ€๋กœ ํฌ๊ธฐ
screen_height = 480 # ์„ธ๋กœ ํฌ๊ธฐ
screen = pygame.display.set_mode((screen_width, screen_height))

# ํ™”๋ฉด ํƒ€์ดํ‹€ ์„ค์ •
pygame.display.set_caption("Nado Pang")

# FPS
clock = pygame.time.Clock()

# ๊ฒŒ์ž„ ์‹œ์ž‘ ์‚ฌ์šด๋“œ
start_sound = pygame.mixer.Sound("C:/Python/Python_2023_01_Game_Pong/sound/game-start-6104.mp3")
start_sound.play()
bgm_sound = pygame.mixer.Sound("C:/Python/Python_2023_01_Game_Pong/sound/bgm.mp3")
bgm_sound.play(-1)
##############################################################

# 1. ์‚ฌ์šฉ์ž ๊ฒŒ์ž„ ์ดˆ๊ธฐํ™” (๋ฐฐ๊ฒฝ ํ™”๋ฉด, ๊ฒŒ์ž„ ์ด๋ฏธ์ง€, ์ขŒํ‘œ, ์†๋„, ํฐํŠธ ๋“ฑ)
current_path = os.path.dirname(__file__) # ํ˜„์žฌ ํŒŒ์ผ์˜ ์œ„์น˜ ๋ฐ˜ํ™˜
image_path = os.path.join(current_path, "images") # images ํด๋” ์œ„์น˜ ๋ฐ˜ํ™˜

# ๋ฐฐ๊ฒฝ ๋งŒ๋“ค๊ธฐ
background = pygame.image.load(os.path.join(image_path, "background.png"))

# ์Šคํ…Œ์ด์ง€ ๋งŒ๋“ค๊ธฐ
stage = pygame.image.load(os.path.join(image_path, "stage.png"))
stage_size = stage.get_rect().size
stage_height = stage_size[1] # ์Šคํ…Œ์ด์ง€์˜ ๋†’์ด ์œ„์— ์บ๋ฆญํ„ฐ๋ฅผ ๋‘๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ

# ์บ๋ฆญํ„ฐ ๋งŒ๋“ค๊ธฐ
character = pygame.image.load(os.path.join(image_path, "character.png"))
character_size = character.get_rect().size
character_width = character_size[0]
character_height = character_size[1]
character_x_pos = (screen_width / 2) - (character_width / 2)
character_y_pos = screen_height - character_height - stage_height

# ์บ๋ฆญํ„ฐ ์ด๋™ ๋ฐฉํ–ฅ
character_to_x = 0

# ์บ๋ฆญํ„ฐ ์ด๋™ ์†๋„
character_speed = 5

# ๋ฌด๊ธฐ ๋งŒ๋“ค๊ธฐ
weapon = pygame.image.load(os.path.join(image_path, "weapon.png"))
weapon_size = weapon.get_rect().size
weapon_width = weapon_size[0]

# ๋ฌด๊ธฐ๋Š” ํ•œ ๋ฒˆ์— ์—ฌ๋Ÿฌ ๋ฐœ ๋ฐœ์‚ฌ ๊ฐ€๋Šฅ
weapons = []

# ๋ฌด๊ธฐ ์ด๋™ ์†๋„
weapon_speed = 10

# ๊ณต ๋งŒ๋“ค๊ธฐ (4๊ฐœ ํฌ๊ธฐ์— ๋Œ€ํ•ด ๋”ฐ๋กœ ์ฒ˜๋ฆฌ)
ball_images = [
    pygame.image.load(os.path.join(image_path, "ball1.png")),
    pygame.image.load(os.path.join(image_path, "ball2.png")),
    pygame.image.load(os.path.join(image_path, "ball3.png")),
    pygame.image.load(os.path.join(image_path, "ball4.png"))]

# ๊ณต ํฌ๊ธฐ์— ๋”ฐ๋ฅธ ์ตœ์ดˆ ์Šคํ”ผ๋“œ
ball_speed_y = [-18, -15, -12, -12] # index 0, 1, 2, 3 ์— ํ•ด๋‹นํ•˜๋Š” ๊ฐ’

# ๊ณต๋“ค
balls = []

# ์ตœ์ดˆ ๋ฐœ์ƒํ•˜๋Š” ํฐ ๊ณต ์ถ”๊ฐ€
balls.append({
    "pos_x" : 50, # ๊ณต์˜ x ์ขŒํ‘œ
    "pos_y" : 50, # ๊ณต์˜ y ์ขŒํ‘œ
    "img_idx" : 0, # ๊ณต์˜ ์ด๋ฏธ์ง€ ์ธ๋ฑ์Šค
    "to_x": 3, # x์ถ• ์ด๋™๋ฐฉํ–ฅ, -3 ์ด๋ฉด ์™ผ์ชฝ์œผ๋กœ, 3 ์ด๋ฉด ์˜ค๋ฅธ์ชฝ์œผ๋กœ
    "to_y": -6, # y์ถ• ์ด๋™๋ฐฉํ–ฅ,
    "init_spd_y": ball_speed_y[0]})# y ์ตœ์ดˆ ์†๋„

# ์‚ฌ๋ผ์งˆ ๋ฌด๊ธฐ, ๊ณต ์ •๋ณด ์ €์žฅ ๋ณ€์ˆ˜
weapon_to_remove = -1
ball_to_remove = -1

# ํฐํŠธ ์ •์˜
game_font = pygame.font.Font(None, 40)
total_time = 31
start_ticks = pygame.time.get_ticks() # ์‹œ์ž‘ ์‹œ๊ฐ„ ์ •์˜

# ๊ฒŒ์ž„ ์ข…๋ฃŒ ๋ฉ”์‹œ์ง€
# Time Over(์‹œ๊ฐ„์ดˆ๊ณผ)
# Mission Complete(์„ฑ๊ณต)
# Game Over(๊ณต์— ๋งž์Œ)
game_result = "Game Over"

running = True
while running:
    dt = clock.tick(30)
    
    # 2. ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ (ํ‚ค๋ณด๋“œ, ๋งˆ์šฐ์Šค ๋“ฑ)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False 

        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_LEFT: # ์บ๋ฆญํ„ฐ๋ฅผ ์™ผ์ชฝ์œผ๋กœ
                character_to_x -= character_speed
            elif event.key == pygame.K_RIGHT: # ์บ๋ฆญํ„ฐ๋ฅผ ์˜ค๋ฅธ์ชฝ์œผ๋กœ
                character_to_x += character_speed
            elif event.key == pygame.K_SPACE: # ๋ฌด๊ธฐ ๋ฐœ์‚ฌ
                weapon_x_pos = character_x_pos + (character_width / 2) - (weapon_width / 2)
                weapon_y_pos = character_y_pos
                weapons.append([weapon_x_pos, weapon_y_pos])
        
        if event.type == pygame.KEYUP:
            if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
                character_to_x = 0

    # 3. ๊ฒŒ์ž„ ์บ๋ฆญํ„ฐ ์œ„์น˜ ์ •์˜
    character_x_pos += character_to_x

    if character_x_pos < 0:
        character_x_pos = 0
    elif character_x_pos > screen_width - character_width:
        character_x_pos = screen_width - character_width

    # ๋ฌด๊ธฐ ์œ„์น˜ ์กฐ์ •
    # 100, 200 -> 180, 160, 140, ...
    # 500, 200 -> 180, 160, 140, ...
    weapons = [ [w[0], w[1] - weapon_speed] for w in weapons] # ๋ฌด๊ธฐ ์œ„์น˜๋ฅผ ์œ„๋กœ

    # ์ฒœ์žฅ์— ๋‹ฟ์€ ๋ฌด๊ธฐ ์—†์• ๊ธฐ
    weapons = [ [w[0], w[1]] for w in weapons if w[1] > 0]
    
    # ๊ณต ์œ„์น˜ ์ •์˜
    for ball_idx, ball_val in enumerate(balls):
        ball_pos_x = ball_val["pos_x"]
        ball_pos_y = ball_val["pos_y"]
        ball_img_idx = ball_val["img_idx"]

        ball_size = ball_images[ball_img_idx].get_rect().size
        ball_width = ball_size[0]
        ball_height = ball_size[1]

        # ๊ฐ€๋กœ๋ฒฝ์— ๋‹ฟ์•˜์„ ๋•Œ ๊ณต ์ด๋™ ์œ„์น˜ ๋ณ€๊ฒฝ (ํŠ•๊ฒจ ๋‚˜์˜ค๋Š” ํšจ๊ณผ)
        if ball_pos_x < 0 or ball_pos_x > screen_width - ball_width:
            ball_val["to_x"] = ball_val["to_x"] * -1

        # ์„ธ๋กœ ์œ„์น˜
        # ์Šคํ…Œ์ด์ง€์— ํŠ•๊ฒจ์„œ ์˜ฌ๋ผ๊ฐ€๋Š” ์ฒ˜๋ฆฌ
        if ball_pos_y >= screen_height - stage_height - ball_height:
            ball_val["to_y"] = ball_val["init_spd_y"]
        else: # ๊ทธ ์™ธ์˜ ๋ชจ๋“  ๊ฒฝ์šฐ์—๋Š” ์†๋„๋ฅผ ์ฆ๊ฐ€
            ball_val["to_y"] += 0.5

        ball_val["pos_x"] += ball_val["to_x"]
        ball_val["pos_y"] += ball_val["to_y"]

    # 4. ์ถฉ๋Œ ์ฒ˜๋ฆฌ

    # ์บ๋ฆญํ„ฐ rect ์ •๋ณด ์—…๋ฐ์ดํŠธ
    character_rect = character.get_rect()
    character_rect.left = character_x_pos
    character_rect.top = character_y_pos

    for ball_idx, ball_val in enumerate(balls):
        ball_pos_x = ball_val["pos_x"]
        ball_pos_y = ball_val["pos_y"]
        ball_img_idx = ball_val["img_idx"]

        # ๊ณต rect ์ •๋ณด ์—…๋ฐ์ดํŠธ
        ball_rect = ball_images[ball_img_idx].get_rect()
        ball_rect.left = ball_pos_x
        ball_rect.top = ball_pos_y

        # ๊ณต๊ณผ ์บ๋ฆญํ„ฐ ์ถฉ๋Œ ์ฒดํฌ
        if character_rect.colliderect(ball_rect):
            bgm_sound.stop()
            gameover_sound = pygame.mixer.Sound("C:/Python/Python_2023_01_Game_Pong/sound/gameover.mp3")
            gameover_sound.play()
            running = False
            break

        # ๊ณต๊ณผ ๋ฌด๊ธฐ๋“ค ์ถฉ๋Œ ์ฒ˜๋ฆฌ
        for weapon_idx, weapon_val in enumerate(weapons):
            weapon_pos_x = weapon_val[0]
            weapon_pos_y = weapon_val[1]

            # ๋ฌด๊ธฐ rect ์ •๋ณด ์—…๋ฐ์ดํŠธ
            weapon_rect = weapon.get_rect()
            weapon_rect.left = weapon_pos_x
            weapon_rect.top = weapon_pos_y

            # ์ถฉ๋Œ ์ฒดํฌ
            if weapon_rect.colliderect(ball_rect):
                hit_sound = pygame.mixer.Sound("C:/Python/Python_2023_01_Game_Pong/sound/hit.mp3")
                hit_sound.play()
                weapon_to_remove = weapon_idx # ํ•ด๋‹น ๋ฌด๊ธฐ ์—†์• ๊ธฐ ์œ„ํ•œ ๊ฐ’ ์„ค์ •
                ball_to_remove = ball_idx # ํ•ด๋‹น ๊ณต ์—†์• ๊ธฐ ์œ„ํ•œ ๊ฐ’ ์„ค์ •

                # ๊ฐ€์žฅ ์ž‘์€ ํฌ๊ธฐ์˜ ๊ณต์ด ์•„๋‹ˆ๋ผ๋ฉด ๋‹ค์Œ ๋‹จ๊ณ„์˜ ๊ณต์œผ๋กœ ๋‚˜๋ˆ ์ฃผ๊ธฐ
                if ball_img_idx < 3:
                    # ํ˜„์žฌ ๊ณต ํฌ๊ธฐ ์ •๋ณด๋ฅผ ๊ฐ€์ง€๊ณ  ์˜ด
                    ball_width = ball_rect.size[0]
                    ball_height = ball_rect.size[1]

                    # ๋‚˜๋ˆ ์ง„ ๊ณต ์ •๋ณด
                    small_ball_rect = ball_images[ball_img_idx + 1].get_rect()
                    small_ball_width = small_ball_rect.size[0]
                    small_ball_height = small_ball_rect.size[1]

                    # ์™ผ์ชฝ์œผ๋กœ ํŠ•๊ฒจ๋‚˜๊ฐ€๋Š” ์ž‘์€ ๊ณต
                    balls.append({
                        "pos_x" : ball_pos_x + (ball_width / 2) - (small_ball_width / 2), # ๊ณต์˜ x ์ขŒํ‘œ
                        "pos_y" : ball_pos_y + (ball_height / 2) - (small_ball_height / 2), # ๊ณต์˜ y ์ขŒํ‘œ
                        "img_idx" : ball_img_idx + 1, # ๊ณต์˜ ์ด๋ฏธ์ง€ ์ธ๋ฑ์Šค
                        "to_x": -3, # x์ถ• ์ด๋™๋ฐฉํ–ฅ, -3 ์ด๋ฉด ์™ผ์ชฝ์œผ๋กœ, 3 ์ด๋ฉด ์˜ค๋ฅธ์ชฝ์œผ๋กœ
                        "to_y": -6, # y์ถ• ์ด๋™๋ฐฉํ–ฅ,
                        "init_spd_y": ball_speed_y[ball_img_idx + 1]})# y ์ตœ์ดˆ ์†๋„

                    # ์˜ค๋ฅธ์ชฝ์œผ๋กœ ํŠ•๊ฒจ๋‚˜๊ฐ€๋Š” ์ž‘์€ ๊ณต
                    balls.append({
                        "pos_x" : ball_pos_x + (ball_width / 2) - (small_ball_width / 2), # ๊ณต์˜ x ์ขŒํ‘œ
                        "pos_y" : ball_pos_y + (ball_height / 2) - (small_ball_height / 2), # ๊ณต์˜ y ์ขŒํ‘œ
                        "img_idx" : ball_img_idx + 1, # ๊ณต์˜ ์ด๋ฏธ์ง€ ์ธ๋ฑ์Šค
                        "to_x": 3, # x์ถ• ์ด๋™๋ฐฉํ–ฅ, -3 ์ด๋ฉด ์™ผ์ชฝ์œผ๋กœ, 3 ์ด๋ฉด ์˜ค๋ฅธ์ชฝ์œผ๋กœ
                        "to_y": -6, # y์ถ• ์ด๋™๋ฐฉํ–ฅ,
                        "init_spd_y": ball_speed_y[ball_img_idx + 1]})# y ์ตœ์ดˆ ์†๋„

                break
        else: # ๊ณ„์† ๊ฒŒ์ž„์„ ์ง„ํ–‰
            continue # ์•ˆ์ชฝ for๋ฌธ ์กฐ๊ฑด์ด ๋งž์ง€ ์•Š์œผ๋ฉด continue. ๋ฐ”๊นฅ for๋ฌธ ๊ณ„์† ์ˆ˜ํ–‰
        break # ์•ˆ์ชฝ for๋ฌธ์—์„œ break๋ฅผ ๋งŒ๋‚˜๋ฉด ์—ฌ๊ธฐ๋กœ ์ง„์ž… ๊ฐ€๋Šฅ. 2์ค‘ for๋ฌธ ํ•œ๋ฒˆ์— ํƒˆ์ถœ ๊ฐ€๋Šฅ

    # ์ถฉ๋Œ๋œ ๊ณต or ๋ฌด๊ธฐ ์—†์• ๊ธฐ
    if ball_to_remove > -1:
        del balls[ball_to_remove]
        ball_to_remove = -1

    if weapon_to_remove > -1:
        del weapons[weapon_to_remove]
        weapon_to_remove = -1

    # ๋ชจ๋“  ๊ณต์„ ์—†์•ค ๊ฒฝ์šฐ ๊ฒŒ์ž„ ์ข…๋ฃŒ (์„ฑ๊ณต)
    if len(balls) == 0:
        bgm_sound.stop()
        win_sound = pygame.mixer.Sound("C:/Python/Python_2023_01_Game_Pong/sound/win.mp3")
        win_sound.play()
        game_result = "Mission Complete !!"
        running = False

    # 5. ํ™”๋ฉด์— ๊ทธ๋ฆฌ๊ธฐ
    screen.blit(background, (0, 0))
    
    for weapon_x_pos, weapon_y_pos in weapons:
        screen.blit(weapon, (weapon_x_pos, weapon_y_pos))

    for idx, val in enumerate(balls):
        ball_pos_x = val["pos_x"]
        ball_pos_y = val["pos_y"]
        ball_img_idx = val["img_idx"]
        screen.blit(ball_images[ball_img_idx], (ball_pos_x, ball_pos_y))

    screen.blit(stage, (0, screen_height - stage_height))
    screen.blit(character, (character_x_pos, character_y_pos))
    
    # ๊ฒฝ๊ณผ ์‹œ๊ฐ„ ๊ณ„์‚ฐ
    elapsed_time = (pygame.time.get_ticks() - start_ticks) / 1000
    timer = game_font.render("Time : {}".format(int(total_time - elapsed_time)), True, (255,255,255))
    screen.blit(timer, (10, 10))

    # ์‹œ๊ฐ„ ์ดˆ๊ณผํ–ˆ๋‹ค๋ฉด(์Œ์ˆ˜ ๊ฐ’์ด ๋˜๋ฉด)
    if total_time - elapsed_time <= 0:
        bgm_sound.stop()
        gameover_sound = pygame.mixer.Sound("C:/Python/Python_2023_01_Game_Pong/sound/gameover.mp3")
        gameover_sound.play()
        game_result = "Time Over"
        running = False

    
    pygame.display.update()

# ๊ฒŒ์ž„ ์˜ค๋ฒ„ ๋ฉ”์‹œ์ง€
msg = game_font.render(game_result, True, (255,255,0))
msg_rect = msg.get_rect(center=(int(screen_width / 2), int(screen_height / 2)))
screen.blit(msg, msg_rect)
pygame.display.update()

pygame.time.delay(2500)

pygame.quit()

 

๋ฐฐํฌ ํ•  ์ค„ ๋ชฐ๋ผ์„œ..๋™์˜์ƒ์œผ๋กœ ์˜ฌ๋ฆฌ๋Š” ๋‚˜๋ž€ ์‚ฌ๋žŒ..

์ถ”ํ›„ ์‘์šฉํ•ด์„œ ์ถ”์–ต์˜ ํ”ผ์นด์ธ„ ๋ฐฐ๊ตฌst ๊ฒŒ์ž„ ๋งŒ๋“ค์–ด ๋ณผ ์ƒ๊ฐ์ธ๋ฐ ๊ทธ ๋•Œ๋Š” ๋ฐฐํฌ๊นŒ์ง€ ๋„์ „ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

(๊ณผ์—ฐ?

profile

GiantStepDEV

@kongmi

ํฌ์ŠคํŒ…์ด ์ข‹์•˜๋‹ค๋ฉด "์ข‹์•„์š”โค๏ธ" ๋˜๋Š” "๊ตฌ๋…๐Ÿ‘๐Ÿป" ํ•ด์ฃผ์„ธ์š”!