앞서 종합 아케이드 게임기를 만들며 리듬게임을 만들어 보았다. 사실 그렇게 완성도도 높지 않고 아직 허술하지만 팀원과 함께 만들면서 재미도 있었고, 많은 노력이 들어갔던 만큼 완성했을 때 뿌듯함도 있었다.
그런데 노래선택을 할 수 없고, 메인 창이 없어서 되돌아가기도 못하기 때문에 그렇게 완성도 있는 작품이라고 하기엔 조금 허술한 점이 있다.
먼저 가장 핵심이 되는 노트가 내려오는 타이밍은 파이썬의 라이브러리인 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 |
댓글