# 多元選修專題製作
## 音樂遊戲
### 20722 詹冠甫
---
# 目錄
- 主題
- 第 0 版(照抄)
- 第 1 版(修改樣式)
- 第 2 版(從 osu 到 paletteworks)
- 第 3 版(加上選歌功能)
- 執行
- 心得
---
# 主題
使用 python 製作一個能在電腦上執行的音樂遊戲
---
## 環境
- python 3.11.4
- pygame 2.5.1
- windows 11
- pycharm 17.0.8.1+7-b1000.32
---
# 第 0 版(照抄)
---
從網路上找到有人用 python 自己做音 game
把他抓下來好好研究一番
原版解說網址
https://hackmd.io/@onion0905/BJACHcEuq
原版程式 Github
https://github.com/onion0905/mayo_music_game/tree/main
---
# 第 1 版(修改樣式)
---
## 修改方向
- 軌道數量
- 視窗大小
- 遊戲開始介面
- 音符樣式
---
### 軌道數量修改-1 (原版)
```python=
white_back = pygame.Rect(0, 0, 800, 600)
border_left_line = pygame.Rect(140, 0, 10, 600)
border_right_line = pygame.Rect(650, 0, 10, 600)
display_pressed1 = pygame.Rect(150, 500, 125, 30)
display_pressed2 = pygame.Rect(275, 500, 125, 30)
display_pressed3 = pygame.Rect(400, 500, 125, 30)
display_pressed4 = pygame.Rect(525, 500, 125, 30)
```
---
### 軌道數量修改-1 (1 版)
```python=
white_back = pygame.Rect(0, 0, 1200, 600)
border_left_line = pygame.Rect(230, 0, 20, 600)
border_right_line = pygame.Rect(950, 0, 20, 600)
button1 = pygame.Rect(250, 460, 100, 40)
button2 = pygame.Rect(350, 460, 100, 40)
button3 = pygame.Rect(450, 460, 100, 40)
button4 = pygame.Rect(550, 460, 100, 40)
button5 = pygame.Rect(650, 460, 100, 40)
button6 = pygame.Rect(750, 460, 100, 40)
button7 = pygame.Rect(850, 460, 100, 40)
```
---
### 軌道數量修改-2 (原版)
```python=
coresponding_location = [160, 285, 410, 535]
coresponding_key = {0: pygame.K_d, 1: pygame.K_f, 2: pygame.K_j, 3: pygame.K_k}
```
---
### 軌道數量修改-2 (1版)
```python=
coresponding_location = [250, 350, 450, 550, 650, 750, 850]
coresponding_key = {0: pygame.K_s, 1: pygame.K_d, 2: pygame.K_f, 3: pygame.K_SPACE, 4: pygame.K_j, 5: pygame.K_k, 6: pygame.K_l}
```
---
### 軌道數量修改-3 (原版)
```python=
if one_note.show:
one_note.ycor_update(time_pass)
wn.blit(mayo, (one_note.xcor, one_note.ycor))
if one_note.ycor >= 900:
one_note.show = False
```
---
### 軌道數量修改-3 (1版)
```python=
if one_note.xcor == 550 or one_note.xcor == 250 or one_note.xcor == 850:
wn.blit(click2, (one_note.xcor, one_note.ycor)) #blit 到螢幕上
elif one_note.xcor == 350 or one_note.xcor == 750:
wn.blit(click, (one_note.xcor, one_note.ycor)) # blit 到螢幕上
else:
wn.blit(click3, (one_note.xcor, one_note.ycor))
if one_note.ycor >= 1200:
one_note.show = False
```
---
### 軌道數量修改-4 (原版)
```python=
# 垂直線
pygame.draw.line(wn, (255, 255, 255), (275, 0),(275, 600))
pygame.draw.line(wn, (255, 255, 255), (400, 0),(400, 600))
pygame.draw.line(wn, (255, 255, 255), (525, 0),(525, 600))
# 水平線
pygame.draw.line(wn, (100, 100, 100), (150, 500),(650, 500))
pygame.draw.line(wn, (100, 100, 100), (150, 530),(650, 530))
```
---
### 軌道數量修改-4 (1版)
```python=
# 垂直線
pygame.draw.line(wn, (255, 255, 255), (350, 0), (350, 600))
pygame.draw.line(wn, (255, 255, 255), (450, 0), (450, 600))
pygame.draw.line(wn, (255, 255, 255), (550, 0), (550, 600))
pygame.draw.line(wn, (255, 255, 255), (650, 0), (650, 600))
pygame.draw.line(wn, (255, 255, 255), (750, 0), (750, 600))
pygame.draw.line(wn, (255, 255, 255), (850, 0), (850, 600))
# 水平線
pygame.draw.line(wn, (100, 100, 100), (250, 460), (950, 460))
pygame.draw.line(wn, (100, 100, 100), (250, 500), (950, 500))
```
---
### 軌道數量修改-5 (原版)
```python=
def draw_press():
if keys[pygame.K_d]:
pygame.draw.rect(wn, (99, 170, 219), display_pressed1)
if keys[pygame.K_f]:
pygame.draw.rect(wn, (99, 170, 219), display_pressed2)
if keys[pygame.K_j]:
pygame.draw.rect(wn, (99, 170, 219), display_pressed3)
if keys[pygame.K_k]:
pygame.draw.rect(wn, (99, 170, 219), display_pressed4)
```
---
### 軌道數量修改-5 (1版)
```python=
def draw_press():
if keys[pygame.K_s]:
pygame.draw.rect(wn, (100, 100, 100), button1)
if keys[pygame.K_d]:
pygame.draw.rect(wn, (100, 100, 100), button2)
if keys[pygame.K_f]:
pygame.draw.rect(wn, (100, 100, 100), button3)
if keys[pygame.K_SPACE]:
pygame.draw.rect(wn, (100, 100, 100), button4)
if keys[pygame.K_j]:
pygame.draw.rect(wn, (100, 100, 100), button5)
if keys[pygame.K_k]:
pygame.draw.rect(wn, (100, 100, 100), button6)
if keys[pygame.K_l]:
pygame.draw.rect(wn, (100, 100, 100), button7)
```
---
### 視窗大小 (原版)
```python=
#pygame init
pygame.init()
wn = pygame.display.set_mode((800 ,600))
drop_before_arrive = 0.8
pixel_per_second = 565 / drop_before_arrive
```
---
### 視窗大小 (1版)
```python=
#pygame init
pygame.init()
wn = pygame.display.set_mode((1200, 600))
drop_before_arrive = 0.55
pixel_per_second = 500 / drop_before_arrive
```
---
### 遊戲開始介面 (原版)

---
### 遊戲開始介面 (1版)

---
### 音符樣式 (原版)

---
### 音符樣式 (1版)

---
# 第 2 版(從 osu 到 paletteworks)
音樂遊戲除了程式還要有一些額外的檔案,像是音樂,音符資訊,節拍資訊,歌曲列表等等...
原版的程式是依照 osu 這款遊戲的做法依樣畫葫蘆做出來的
---
但是我不熟 osu 這款遊戲,也就抓不到這些檔案
所以我往自製譜面的方向去走,找到了 paletteworks 這款線上製譜軟體並用它做出我的第一張譜。做完譜面後,發現原版的程式採用 osu 的作法,使用秒來計算音符的出現時間,paletteworks 則是採用節拍的方式在記錄。由於兩者對於音符出現時間的處理方式不同,因此我又自己新增了幾段程式
---
## 修改方向
- 改變檔案紀錄方式
- 修改資料讀入模式
---
### 改變檔案紀錄方式 (原版)

---
### 改變檔案紀錄方式 (2版)

---
### 修改資料讀入模式 (原版)
```python=
note_dict = {64:0, 192:1, 320:2, 448:3}
with open(f"note_and_time\\times_normal.txt", "r") as time_f:
for i in time_f:
i = int(i)
i /= 1000
i = round(i, 4)
times_arrive.append(i)
with open(f"note_and_time\\notes_normal.txt", "r") as note_f:
for i in note_f:
i = int(i)
i = note_dict[i]
notes.append(i)
```
---
### 修改資料讀入模式 (2版)
```python=
rate = 60 / 185 / 4
rate = round(rate, 6)
ratenow = 0.3535
with open(f"chart/"+tf, "r") as time_f:
for i in time_f:
showtime = str(i)
showtime = list(showtime)
showtime = showtime[::2]
for j in range(len(showtime)):
if showtime[j] == '\n':
showtime.pop()
for j in showtime:
for k in range(int(j)):
times_arrive.append(ratenow)
ratenow += rate
with open(f"chart/"+nf, "r") as note_f:
for i in note_f:
readnote = str(i)
readnote = list(readnote)
for j in readnote:
if j == '\n':
readnote.pop()
for j in readnote:
notes.append(int(j))
```
---
# 第 3 版(加上選歌功能)
後來我自製譜越做越多,我希望不要每次玩一首不同的歌就要再開一個相同的程式,或是每次想玩的時候都要進到程式裡修改參數,所以我設計了一個選歌的功能讓我可以用一支程式玩到所有的曲子
---
## 修改方向
- 把檔案分類放在不同資料夾
- 建立 option_list.txt 記錄曲目資訊
- 設計成玩家要指定曲目,程式會從 option_list.txt 去抓到曲子的對應資訊
---
### 把檔案分類放在不同資料夾

---
### 建立 option_list.txt 記錄曲目資訊

---
### 設計成玩家要指定曲目,程式會從 option_list.txt 去抓到曲子的對應資訊
```python=
#option
musiclist = 0 #存放可供遊玩的清單
count = 0
music_to_play = 0
with open("option_list.txt", "r",encoding="utf-8") as option:
for i in option:
if count == 0:
pass
else:
musiclist = str(i)
musiclist = musiclist.split('-----')
print('(',count,')',musiclist[0])
count += 1
music_to_play = int(input('Enter the number which you want to play: '))
count = 0
with open("option_list.txt", "r",encoding="utf-8") as option:
for i in option:
if count != music_to_play:
count += 1
else:
musiclist = str(i)
musiclist = musiclist.split('-----')
print(musiclist)
name = musiclist[0]
ratenow = float(musiclist[1])
bpm = int(musiclist[2])
beat = int(musiclist[3])
nf = musiclist[4]
tf = musiclist[5]
tf = list(tf)
for j in range(len(tf)):
if tf[j] == '\n':
tf.pop()
tf = "".join(tf)
print(name,ratenow,bpm,beat,nf,tf)
break
```
---

---
# 執行
https://youtu.be/_Urb6C0IUmc
https://youtu.be/-Z8EywTN8LY
https://youtu.be/pg3d1Jwe2QI
---
# 心得
做這項專題除了填滿我玩遊戲的慾望,也是我給自己練習程式的一個方向,而在第二版試圖修改音符讀取方式是我認為這次最困難的部分,除了因為我要接觸很多新東西,像是新的檔案、新的處理方式,還需要接觸新的工具,以及了解音符、拍子、小節這些音樂課才會用到的東西,要把它們裝到一隻程式裡對我來說有點難度,而且這次沒有網路上別人的經驗可以參考,當時的我在這裡折磨了兩個多禮拜,辛苦的同時也體會到一支大型程式需要多麼專業團隊的討論與分工。
{"contributors":"[{\"id\":\"7098718c-64be-4dfe-b2fb-208332d5e8a7\",\"add\":17136,\"del\":8416}]","title":"多元選修專題製作","description":"音樂遊戲"}