파이썬을 이용한 리듬게임 만들기

2023. 6. 21. 15:22·Project

앞서 종합 아케이드 게임기를 만들며 리듬게임을 만들어 보았다. 사실 그렇게 완성도도 높지 않고 아직 허술하지만 팀원과 함께 만들면서 재미도 있었고, 많은 노력이 들어갔던 만큼 완성했을 때 뿌듯함도 있었다.

 

그런데 노래선택을 할 수 없고, 메인 창이 없어서 되돌아가기도 못하기 때문에 그렇게 완성도 있는 작품이라고 하기엔 조금 허술한 점이 있다.

 

먼저 가장 핵심이 되는 노트가 내려오는 타이밍은 파이썬의 라이브러리인 librosa를 사용했다. 이 라이브러리를 사용하면 음악의 특징을 뽑아내서 템포에 맞춰 노트를 생성하는게 가능하다. 여기서 추가로 음의 변화에 따라 노트를 생성하고 싶었는데 라이브러리에 미숙한 탓인지 실패했다.

 

 

다음은 내가 코드를 작성했던 순서이다.

1. 노트가 내려오는 트랙 그리기

2. 노트 클래스 만들기 > 트랙이 아래로 내려 올 수록 넓어지기 때문에 노트의 높이와 넓이 조절

3. librosa 라이브러리를 이용해 음악의 템포 추출

4. 그 템포에 맞춰 노트 생성

5. 노트가 일정 범위 안에 들어왔을 때 버튼을 누르면 이펙트가 생기며 점수 증가

 

이렇게 5가지로 나누었고 다음은 메인 화면이다.

마지막으로 코드와 실행 영상이다.

import pygame
import sys
import random
import librosa
import time


def Rithomgame_run():

    pygame.init()

    h, w = 600, 900
    screen = pygame.display.set_mode((w, h))
    font = pygame.font.SysFont("Courier", 18, True, True)
    text_color = (255, 255, 255)

    song = "sound/gd.mp3"  # replace with your song file

    pygame.mixer.music.load(song)

    # Load the song using librosa
    y, sr = librosa.load(song, sr=None)
    tempo, beat_frames = librosa.beat.beat_track(y=y, sr=sr)
    beats_timing = librosa.frames_to_time(beat_frames, sr=sr)

    current_beat = 0
    pygame.mixer.music.play()

    class Block:
        # 초기값
        def __init__(self, x, y, dx):
            self.x = x
            self.y = y
            self.dx = dx
            self.width = 50
            self.created_time = time.time()
            self.hit = False

            # 업데이트
        def update(self):
            self.y += 1
            self.x += self.dx
            self.width = int(50 + (150 - 50) * (self.y / h))  # 블록의 크기 업데이트

        def draw(self):
            pygame.draw.rect(screen, (255, 255, 255), (self.x, self.y, self.width, 15))

        def process_note(self, key):
            if not self.hit and 500 < self.y < 650:
                if key == 'left' and self.dx < 0:
                    self.hit = True
                    if 550 < self.y < 650:
                        return 30
                    elif 500 < self.y < 550:
                        return 15
                elif key == 'mid':
                    self.hit = True
                    if 550 < self.y < 650:
                        return 30
                    elif 500 < self.y < 550:
                        return 15
                elif key == 'right' and self.dx > 0:
                    self.hit = True
                    if 550 < self.y < 650:
                        return 30
                    elif 500 < self.y < 550:
                        return 15

            if not self.hit and 450 < self.y < 500:
                if key == 'left' and self.dx < 0:
                    self.hit = True
                    return 10
                elif key == 'mid':
                    self.hit = True
                    return 10
                elif key == 'right' and self.dx > 0:
                    self.hit = True
                    return 10
            return 0

    def lerp_color(color1, color2, factor):
        return (
            int(color1[0] + (color2[0] - color1[0]) * factor),
            int(color1[1] + (color2[1] - color1[1]) * factor),
            int(color1[2] + (color2[2] - color1[2]) * factor)
        )

    blocks = []
    tracks = [(250, 0, -0.24), (300, 0, -0.08), (350, 0, 0.08)]  # 트랙별 시작 위치와 x 이동 속도
    start_time = time.time() - 1  # Add this line to initialize start_time

    # 이펙트 색
    blue_points = [(300, 600), (250, 0), (400, 0), (350, 600)]

    Right_points = [(350, 600), (400, 0), (548, 0), (400, 600)]
    Left_points = [(250, 600), (108, 0), (252, 0), (300, 600)]
    black = (0, 0, 0)
    blue = (0, 0, 255)
    purple = (255, 0, 0)
    rect_width = 2

    Left = False
    Mid = False
    Right = False

    score = 0
    last_block_creation_time = time.time()

    running = True

    # 게임 루프
    while running:
        screen.fill((0, 0, 0))  # 화면을 검은색으로 지우기
        for event in pygame.event.get():
            if event.type == pygame.QUIT or (event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE):
                running = False

            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_DOWN:
                    Mid = True
                    for block in blocks:
                        score += block.process_note('mid')
            if event.type == pygame.KEYUP:
                if event.key == pygame.K_DOWN:
                    Mid = False

            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_LEFT:
                    Left = True
                    for block in blocks:
                        score += block.process_note('left')
            if event.type == pygame.KEYUP:
                if event.key == pygame.K_LEFT:
                    Left = False

            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_RIGHT:
                    Right = True
                    for block in blocks:
                        score += block.process_note('right')
            if event.type == pygame.KEYUP:
                if event.key == pygame.K_RIGHT:
                    Right = False

            print("점수 : ", score)

        if Mid:
            for i in range(blue_points[1][1], blue_points[0][1], rect_width):
                progress = (i - blue_points[1][1]) / (blue_points[0][1] - blue_points[1][1])
                color = lerp_color(black, blue, progress)
                top_left_x = int(blue_points[0][0] + (blue_points[1][0] - blue_points[0][0]) * progress)
                top_right_x = int(blue_points[3][0] + (blue_points[2][0] - blue_points[3][0]) * progress)

                pygame.draw.rect(screen, color, pygame.Rect(top_left_x, i, top_right_x - top_left_x, rect_width))

        if Right:
            for i in range(Right_points[1][1], Right_points[0][1], rect_width):
                progress = (i - Right_points[1][1]) / (Right_points[0][1] - Right_points[1][1])
                color = lerp_color(black, purple, progress)
                top_left_x = int(Right_points[0][0] + (Right_points[1][0] - Right_points[0][0]) * progress)
                top_right_x = int(Right_points[3][0] + (Right_points[2][0] - Right_points[3][0]) * progress)

                pygame.draw.rect(screen, color, pygame.Rect(top_left_x, i, top_right_x - top_left_x, rect_width))

        if Left:
            for i in range(Left_points[1][1], Left_points[0][1], rect_width):
                progress = (i - Left_points[1][1]) / (Left_points[0][1] - Left_points[1][1])
                color = lerp_color(black, purple, progress)
                top_left_x = int(Left_points[0][0] + (Left_points[1][0] - Left_points[0][0]) * progress)
                top_right_x = int(Left_points[3][0] + (Left_points[2][0] - Left_points[3][0]) * progress)

                pygame.draw.rect(screen, color, pygame.Rect(top_left_x, i, top_right_x - top_left_x, rect_width))

        # 사다리꼴 라인 그리기
        pygame.draw.line(screen, (255, 0, 255), (250, 0), (100, 640), 5)
        pygame.draw.line(screen, (255, 0, 255), (400, 0), (550, 640), 5)
        pygame.draw.line(screen, (1, 85, 255), (300, 0), (250, 640), 3)
        pygame.draw.line(screen, (1, 85, 255), (350, 0), (400, 640), 3)

        for block in blocks:
            block.update()
            block.draw()

        # 스코어 생성
        score_text = font.render(f"Score: {score}", True, text_color)

        screen.blit(score_text, (600, 50))
        pygame.display.flip()

        elapsed_time = time.time() - start_time
        current_time = time.time() + 0.5
        if current_time - last_block_creation_time >= 0.8:
            block_x, _, block_dx = random.choice(tracks)
            blocks.append(Block(block_x, 0, block_dx))
            last_block_creation_time = current_time

    pygame.quit()
    sys.exit()

 

 

반응형
저작자표시 (새창열림)

'Project' 카테고리의 다른 글

티스토리 블로그 꾸미기 (1)  (0) 2024.01.03
[ChatGPT] 명언만들기  (0) 2023.09.18
라즈베리 파이를 이용한 게임기 만들기  (0) 2023.06.21
Chat GPT API를 이용한 오늘 뭐입지? 만들기  (4) 2023.04.03
Chat GPT API 사용법  (0) 2023.03.27
'Project' 카테고리의 다른 글
  • 티스토리 블로그 꾸미기 (1)
  • [ChatGPT] 명언만들기
  • 라즈베리 파이를 이용한 게임기 만들기
  • Chat GPT API를 이용한 오늘 뭐입지? 만들기
re-hwi
re-hwi
재휘의 개발일기
    반응형
  • re-hwi
    Dvelopment blog
    re-hwi
  • 전체
    오늘
    어제
    • 재휘의 개발일기 (168)
      • 개발 (1)
        • 소프트웨어 공학 (25)
      • Python (18)
        • numpy (8)
      • OS (23)
        • 쉽게 배우는 운영체제 (23)
      • Front end (1)
        • HTML (6)
        • CSS (9)
        • JavaScript (18)
        • React (2)
        • Vue.js (5)
        • TypeScript (5)
        • Sass (3)
      • Algorithm (1)
        • 파이썬 알고리즘 인터뷰 (2)
        • 자료구조와 함께 배우는 알고리즘 (20)
      • Android (2)
        • 안드로이드 앱 프로그래밍 with 코틀린 (2)
      • Project (15)
      • Network (0)
      • etc (12)
        • 이것저것 (10)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    numpy
    프론트엔드
    리액트
    scss
    REACT
    JavaScript
    CSS
    연결리스트
    FE
    컴포넌트
    정보처리기사
    개발
    vue
    typeScript
    표
    pwa
    자료흐름도
    정처기
    오블완
    TS
    티스토리챌린지
    알고리즘
    뷰
    sass
    js
    타입스크립트
    HTML
    플레이리스트
    파이썬
    자료구조
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
re-hwi
파이썬을 이용한 리듬게임 만들기
상단으로

티스토리툴바