目錄
前言
改進過程一
增加提示信息
原版幫助摘要
pygame.draw
pygame.font
class Rect
class Surface
改進過程二
增加顯示得分
改進過程三
增加背景景樂
增加提示音效
音樂切換
靜音切換
mixer.music.play 注意事項
原版幫助摘要
pygame.mixer
pygame.mixer.Sound
小結
pygame編程框架
?
前言
在上一篇博文里,從訊飛星火中獲取到游戲“貪吃蛇”的代碼,運行效果如上圖。代碼并不完整,當蛇死了就退出游戲,不能多次玩這個游戲。
前文鏈接:
訊飛星火、文心一言和通義千問同時編“貪吃蛇”游戲,誰會勝出?
代碼如下:
import pygame
import sys
import random# 定義顏色
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
GREY = (211, 211, 211) # 淡灰色def init():global screen, screen_sizeglobal snake_pos, food_pos, snake_speed# 初始化pygamepygame.init()# 設置屏幕大小screen_size = (640, 480)screen = pygame.display.set_mode(screen_size)# 設置游戲標題pygame.display.set_caption("貪吃蛇")# 蛇的初始位置snake_pos = [[100, 100], [80, 100], [60, 100]]# 食物的初始位置food_pos = [300, 300]# 蛇的初始速度snake_speed = [20, 0]def repaint():# 繪制游戲界面screen.fill(WHITE)# 定義線段的端點坐標x,y = (-1,640,640,-1)*16, []for i in range(36):for _ in range(2):y.append(19+i*20)# 使用pygame.draw.lines()函數繪制線段points = list(zip(x,y))pygame.draw.lines(screen, GREY, False, points, 1) # 線寬為1points = list(zip(y,x))pygame.draw.lines(screen, GREY, False, points, 1) # 重畫蛇和食物for pos in snake_pos:pygame.draw.rect(screen, GREEN, pygame.Rect(pos[0], pos[1], 20, 20))pygame.draw.rect(screen, RED, pygame.Rect(food_pos[0], food_pos[1], 20, 20))pygame.display.flip()def game_quit():pygame.quit()sys.exit()def main():global screen, screen_sizeglobal snake_pos, food_pos, snake_speed# 主循環while True:# 處理游戲事件for event in pygame.event.get():if event.type == pygame.QUIT:game_quit()elif event.type == pygame.KEYDOWN:if event.key == pygame.K_UP:snake_speed = [0, -20]elif event.key == pygame.K_DOWN:snake_speed = [0, 20]elif event.key == pygame.K_LEFT:snake_speed = [-20, 0]elif event.key == pygame.K_RIGHT:snake_speed = [20, 0]# 更新蛇的位置snake_pos.insert(0, [snake_pos[0][0] + snake_speed[0], snake_pos[0][1] + snake_speed[1]])# 檢查蛇頭是否碰到食物if snake_pos[0] == food_pos:food_pos = [random.randrange(1, screen_size[0] // 20) * 20, random.randrange(1, screen_size[1] // 20) * 20]else:snake_pos.pop()# 檢查蛇頭是否碰到墻壁或者蛇身if snake_pos[0][0] < 0 or snake_pos[0][0] >= screen_size[0] or snake_pos[0][1] < 0 or snake_pos[0][1] >= screen_size[1] or snake_pos[0] in snake_pos[1:]:game_quit()'''此處可增加與用戶的交互,如:if askyesno('title','again?'):init() # Yes to Play againelse:game_quit() # No to Exit'''# 重畫界面及蛇和食物repaint()# 控制游戲速度pygame.time.Clock().tick(10)if __name__ == "__main__":init()main()
改進過程一
增加提示信息
之前沒有仔細學過pygame的編程,剛好拿這例程練練手,在不斷改進中學習pygame編程。
原代碼一執行,蛇就開始游動了,就從這里入手。開始前,增加顯示“按任意鍵開始...”的提示。
蛇死后,提醒是否重來?Yes to play again, No to quit game.
同時,在游戲中允許按ESC鍵暫停游戲,再按一次繼續。
由于沒查到 pygame 有彈出信息窗口的方法(函數),于是用了DOS時代顯示信息窗口的辦法,畫多個矩形窗口來模擬窗口,最后在矩形框上寫上提示文字。代碼如下:
def show_msg(msg, color = BLUE):
? ? x = screen.get_rect().centerx
? ? y = screen.get_rect().centery - 50
? ? font = pygame.font.Font(None, 36)
? ? text = font.render(msg, True, color)
? ? text_rect = text.get_rect()
? ? text_rect.centerx = x
? ? text_rect.centery = y
? ? rectangle1 = pygame.Rect(x-155, y-25, 320, 60)
? ? rectangle2 = pygame.Rect(x-160, y-30, 320, 60)
? ? pygame.draw.rect(screen, DARK, rectangle1)
? ? pygame.draw.rect(screen, GREY, rectangle2)
? ? pygame.draw.rect(screen, BLACK, rectangle2, 2) # 邊框寬為2
? ? screen.blit(text, text_rect)
? ? pygame.display.flip()
原版幫助摘要
pygame.draw
NAME
? ? pygame.draw - pygame module for drawing shapes
FUNCTIONS
? ? aaline(...)
? ? ? ? aaline(surface, color, start_pos, end_pos) -> Rect
? ? ? ? aaline(surface, color, start_pos, end_pos, blend=1) -> Rect
? ? ? ? draw a straight antialiased line
? ??
? ? aalines(...)
? ? ? ? aalines(surface, color, closed, points) -> Rect
? ? ? ? aalines(surface, color, closed, points, blend=1) -> Rect
? ? ? ? draw multiple contiguous straight antialiased line segments
? ??
? ? arc(...)
? ? ? ? arc(surface, color, rect, start_angle, stop_angle) -> Rect
? ? ? ? arc(surface, color, rect, start_angle, stop_angle, width=1) -> Rect
? ? ? ? draw an elliptical arc
? ??
? ? circle(...)
? ? ? ? circle(surface, color, center, radius) -> Rect
? ? ? ? circle(surface, color, center, radius, width=0, draw_top_right=None, draw_top_left=None, draw_bottom_left=None, draw_bottom_right=None) -> Rect
? ? ? ? draw a circle
? ??
? ? ellipse(...)
? ? ? ? ellipse(surface, color, rect) -> Rect
? ? ? ? ellipse(surface, color, rect, width=0) -> Rect
? ? ? ? draw an ellipse
? ??
? ? line(...)
? ? ? ? line(surface, color, start_pos, end_pos) -> Rect
? ? ? ? line(surface, color, start_pos, end_pos, width=1) -> Rect
? ? ? ? draw a straight line
? ??
? ? lines(...)
? ? ? ? lines(surface, color, closed, points) -> Rect
? ? ? ? lines(surface, color, closed, points, width=1) -> Rect
? ? ? ? draw multiple contiguous straight line segments
? ??
? ? polygon(...)
? ? ? ? polygon(surface, color, points) -> Rect
? ? ? ? polygon(surface, color, points, width=0) -> Rect
? ? ? ? draw a polygon
? ??
? ? rect(...)
? ? ? ? rect(surface, color, rect) -> Rect
? ? ? ? rect(surface, color, rect, width=0, border_radius=0, border_top_left_radius=-1, border_top_right_radius=-1, border_bottom_left_radius=-1, border_bottom_right_radius=-1) -> Rect
? ? ? ? draw a rectangle
pygame.font
NAME
? ? pygame.font - pygame module for loading and rendering fonts
CLASSES
? ? builtins.object
? ? ? ? Font
? ??
? ? class Font(builtins.object)
? ? ?| ?Font(file_path=None, size=12) -> Font
? ? ?| ?Font(file_path, size) -> Font
? ? ?| ?Font(pathlib.Path, size) -> Font
? ? ?| ?Font(object, size) -> Font
? ? ?| ?create a new Font object from a file
? ? ?| ?
? ? ?| ?Methods defined here:
? ? ?| ?
? ? ?| ?__init__(self, /, *args, **kwargs)
? ? ?| ? ? ?Initialize self. ?See help(type(self)) for accurate signature.
? ? ?| ?
? ? ?| ?get_ascent(...)
? ? ?| ? ? ?get_ascent() -> int
? ? ?| ? ? ?get the ascent of the font
? ? ?| ?
? ? ?| ?get_bold(...)
? ? ?| ? ? ?get_bold() -> bool
? ? ?| ? ? ?check if text will be rendered bold
? ? ?| ?
? ? ?| ?get_descent(...)
? ? ?| ? ? ?get_descent() -> int
? ? ?| ? ? ?get the descent of the font
? ? ?| ?
? ? ?| ?get_height(...)
? ? ?| ? ? ?get_height() -> int
? ? ?| ? ? ?get the height of the font
? ? ?| ?
? ? ?| ?get_italic(...)
? ? ?| ? ? ?get_italic() -> bool
? ? ?| ? ? ?check if the text will be rendered italic
? ? ?| ?
? ? ?| ?get_linesize(...)
? ? ?| ? ? ?get_linesize() -> int
? ? ?| ? ? ?get the line space of the font text
? ? ?| ?
? ? ?| ?get_strikethrough(...)
? ? ?| ? ? ?get_strikethrough() -> bool
? ? ?| ? ? ?check if text will be rendered with a strikethrough
? ? ?| ?
? ? ?| ?get_underline(...)
? ? ?| ? ? ?get_underline() -> bool
? ? ?| ? ? ?check if text will be rendered with an underline
? ? ?| ?
? ? ?| ?metrics(...)
? ? ?| ? ? ?metrics(text) -> list
? ? ?| ? ? ?gets the metrics for each character in the passed string
? ? ?| ?
? ? ?| ?render(...)
? ? ?| ? ? ?render(text, antialias, color, background=None) -> Surface
? ? ?| ? ? ?draw text on a new Surface
? ? ?| ?
? ? ?| ?set_bold(...)
? ? ?| ? ? ?set_bold(bool) -> None
? ? ?| ? ? ?enable fake rendering of bold text
? ? ?| ?
? ? ?| ?set_italic(...)
? ? ?| ? ? ?set_italic(bool) -> None
? ? ?| ? ? ?enable fake rendering of italic text
? ? ?| ?
? ? ?| ?set_script(...)
? ? ?| ? ? ?set_script(str) -> None
? ? ?| ? ? ?set the script code for text shaping
? ? ?| ?
? ? ?| ?set_strikethrough(...)
? ? ?| ? ? ?set_strikethrough(bool) -> None
? ? ?| ? ? ?control if text is rendered with a strikethrough
? ? ?| ?
? ? ?| ?set_underline(...)
? ? ?| ? ? ?set_underline(bool) -> None
? ? ?| ? ? ?control if text is rendered with an underline
? ? ?| ?
? ? ?| ?size(...)
? ? ?| ? ? ?size(text) -> (width, height)
? ? ?| ? ? ?determine the amount of space needed to render text
? ? ?| ?
? ? ?| ?----------------------------------------------------------------------
? ? ?| ?Data descriptors defined here:
? ? ?| ?
? ? ?| ?bold
? ? ?| ? ? ?bold -> bool
? ? ?| ? ? ?Gets or sets whether the font should be rendered in (faked) bold.
? ? ?| ?
? ? ?| ?italic
? ? ?| ? ? ?italic -> bool
? ? ?| ? ? ?Gets or sets whether the font should be rendered in (faked) italics.
? ? ?| ?
? ? ?| ?strikethrough
? ? ?| ? ? ?strikethrough -> bool
? ? ?| ? ? ?Gets or sets whether the font should be rendered with a strikethrough.
? ? ?| ?
? ? ?| ?underline
? ? ?| ? ? ?underline -> bool
? ? ?| ? ? ?Gets or sets whether the font should be rendered with an underline.
class Rect
Help on class Rect in module pygame.rect:
class Rect(builtins.object)
?| ?Rect(left, top, width, height) -> Rect
?| ?Rect((left, top), (width, height)) -> Rect
?| ?Rect(object) -> Rect
?| ?pygame object for storing rectangular coordinates
?| ?
?| ?Methods defined here:
?| ?
?| ?clamp(...)
?| ? ? ?clamp(Rect) -> Rect
?| ? ? ?moves the rectangle inside another
?| ?
?| ?clamp_ip(...)
?| ? ? ?clamp_ip(Rect) -> None
?| ? ? ?moves the rectangle inside another, in place
?| ?
?| ?clip(...)
?| ? ? ?clip(Rect) -> Rect
?| ? ? ?crops a rectangle inside another
?| ?
?| ?clipline(...)
?| ? ? ?clipline(x1, y1, x2, y2) -> ((cx1, cy1), (cx2, cy2))
?| ? ? ?clipline(x1, y1, x2, y2) -> ()
?| ? ? ?clipline((x1, y1), (x2, y2)) -> ((cx1, cy1), (cx2, cy2))
?| ? ? ?clipline((x1, y1), (x2, y2)) -> ()
?| ? ? ?clipline((x1, y1, x2, y2)) -> ((cx1, cy1), (cx2, cy2))
?| ? ? ?clipline((x1, y1, x2, y2)) -> ()
?| ? ? ?clipline(((x1, y1), (x2, y2))) -> ((cx1, cy1), (cx2, cy2))
?| ? ? ?clipline(((x1, y1), (x2, y2))) -> ()
?| ? ? ?crops a line inside a rectangle
?| ?
?| ?collidedict(...)
?| ? ? ?collidedict(dict) -> (key, value)
?| ? ? ?collidedict(dict) -> None
?| ? ? ?collidedict(dict, use_values=0) -> (key, value)
?| ? ? ?collidedict(dict, use_values=0) -> None
?| ? ? ?test if one rectangle in a dictionary intersects
?| ?
?| ?collidedictall(...)
?| ? ? ?collidedictall(dict) -> [(key, value), ...]
?| ? ? ?collidedictall(dict, use_values=0) -> [(key, value), ...]
?| ? ? ?test if all rectangles in a dictionary intersect
?| ?
?| ?collidelist(...)
?| ? ? ?collidelist(list) -> index
?| ? ? ?test if one rectangle in a list intersects
?| ?
?| ?collidelistall(...)
?| ? ? ?collidelistall(list) -> indices
?| ? ? ?test if all rectangles in a list intersect
?| ?
?| ?collideobjects(...)
?| ? ? ?collideobjects(rect_list) -> object
?| ? ? ?collideobjects(obj_list, key=func) -> object
?| ? ? ?test if any object in a list intersects
?| ?
?| ?collideobjectsall(...)
?| ? ? ?collideobjectsall(rect_list) -> objects
?| ? ? ?collideobjectsall(obj_list, key=func) -> objects
?| ? ? ?test if all objects in a list intersect
?| ?
?| ?collidepoint(...)
?| ? ? ?collidepoint(x, y) -> bool
?| ? ? ?collidepoint((x,y)) -> bool
?| ? ? ?test if a point is inside a rectangle
?| ?
?| ?colliderect(...)
?| ? ? ?colliderect(Rect) -> bool
?| ? ? ?test if two rectangles overlap
?| ?
?| ?contains(...)
?| ? ? ?contains(Rect) -> bool
?| ? ? ?test if one rectangle is inside another
?| ?
?| ?copy(...)
?| ? ? ?copy() -> Rect
?| ? ? ?copy the rectangle
?| ?
?| ?fit(...)
?| ? ? ?fit(Rect) -> Rect
?| ? ? ?resize and move a rectangle with aspect ratio
?| ?
?| ?inflate(...)
?| ? ? ?inflate(x, y) -> Rect
?| ? ? ?grow or shrink the rectangle size
?| ?
?| ?inflate_ip(...)
?| ? ? ?inflate_ip(x, y) -> None
?| ? ? ?grow or shrink the rectangle size, in place
?| ?
?| ?move(...)
?| ? ? ?move(x, y) -> Rect
?| ? ? ?moves the rectangle
?| ?
?| ?move_ip(...)
?| ? ? ?move_ip(x, y) -> None
?| ? ? ?moves the rectangle, in place
?| ?
?| ?normalize(...)
?| ? ? ?normalize() -> None
?| ? ? ?correct negative sizes
?| ?
?| ?scale_by(...)
?| ? ? ?scale_by(scalar) -> Rect
?| ? ? ?scale_by(scalex, scaley) -> Rect
?| ? ? ?scale the rectangle by given a multiplier
?| ?
?| ?scale_by_ip(...)
?| ? ? ?scale_by_ip(scalar) -> None
?| ? ? ?scale_by_ip(scalex, scaley) -> None
?| ? ? ?grow or shrink the rectangle size, in place
?| ?
?| ?union(...)
?| ? ? ?union(Rect) -> Rect
?| ? ? ?joins two rectangles into one
?| ?
?| ?union_ip(...)
?| ? ? ?union_ip(Rect) -> None
?| ? ? ?joins two rectangles into one, in place
?| ?
?| ?unionall(...)
?| ? ? ?unionall(Rect_sequence) -> Rect
?| ? ? ?the union of many rectangles
?| ?
?| ?unionall_ip(...)
?| ? ? ?unionall_ip(Rect_sequence) -> None
?| ? ? ?the union of many rectangles, in place
?| ?
?| ?update(...)
?| ? ? ?update(left, top, width, height) -> None
?| ? ? ?update((left, top), (width, height)) -> None
?| ? ? ?update(object) -> None
?| ? ? ?sets the position and size of the rectangle
class Surface
class Surface(builtins.object)
?| ?Surface((width, height), flags=0, depth=0, masks=None) -> Surface
?| ?Surface((width, height), flags=0, Surface) -> Surface
?| ?pygame object for representing images
?| ?
?| ?Methods defined here:
?| ?
?| ?blit(...)
?| ? ? ?blit(source, dest, area=None, special_flags=0) -> Rect
?| ? ? ?draw one image onto another
?| ?
?| ?blits(...)
?| ? ? ?blits(blit_sequence=((source, dest), ...), doreturn=1) -> [Rect, ...] or None
?| ? ? ?blits(((source, dest, area), ...)) -> [Rect, ...]
?| ? ? ?blits(((source, dest, area, special_flags), ...)) -> [Rect, ...]
?| ? ? ?draw many images onto another
?| ?
?| ?convert(...)
?| ? ? ?convert(Surface=None) -> Surface
?| ? ? ?convert(depth, flags=0) -> Surface
?| ? ? ?convert(masks, flags=0) -> Surface
?| ? ? ?change the pixel format of an image
?| ?
?| ?convert_alpha(...)
?| ? ? ?convert_alpha(Surface) -> Surface
?| ? ? ?convert_alpha() -> Surface
?| ? ? ?change the pixel format of an image including per pixel alphas
?| ?
?| ?copy(...)
?| ? ? ?copy() -> Surface
?| ? ? ?create a new copy of a Surface
?| ?
?| ?fill(...)
?| ? ? ?fill(color, rect=None, special_flags=0) -> Rect
?| ? ? ?fill Surface with a solid color
?| ?
?| ?get_abs_offset(...)
?| ? ? ?get_abs_offset() -> (x, y)
?| ? ? ?find the absolute position of a child subsurface inside its top level parent
?| ?
?| ?get_abs_parent(...)
?| ? ? ?get_abs_parent() -> Surface
?| ? ? ?find the top level parent of a subsurface
?| ?
?| ?get_alpha(...)
?| ? ? ?get_alpha() -> int_value
?| ? ? ?get the current Surface transparency value
?| ?
?| ?get_at(...)
?| ? ? ?get_at((x, y)) -> Color
?| ? ? ?get the color value at a single pixel
?| ?
?| ?get_at_mapped(...)
?| ? ? ?get_at_mapped((x, y)) -> Color
?| ? ? ?get the mapped color value at a single pixel
?| ?
?| ?get_bitsize(...)
?| ? ? ?get_bitsize() -> int
?| ? ? ?get the bit depth of the Surface pixel format
?| ?
?| ?get_blendmode(...)
?| ? ? ?Return the surface's SDL 2 blend mode
?| ?
?| ?get_bounding_rect(...)
?| ? ? ?get_bounding_rect(min_alpha = 1) -> Rect
?| ? ? ?find the smallest rect containing data
?| ?
?| ?get_buffer(...)
?| ? ? ?get_buffer() -> BufferProxy
?| ? ? ?acquires a buffer object for the pixels of the Surface.
?| ?
?| ?get_bytesize(...)
?| ? ? ?get_bytesize() -> int
?| ? ? ?get the bytes used per Surface pixel
?| ?
?| ?get_clip(...)
?| ? ? ?get_clip() -> Rect
?| ? ? ?get the current clipping area of the Surface
?| ?
?| ?get_colorkey(...)
?| ? ? ?get_colorkey() -> RGB or None
?| ? ? ?Get the current transparent colorkey
?| ?
?| ?get_flags(...)
?| ? ? ?get_flags() -> int
?| ? ? ?get the additional flags used for the Surface
?| ?
?| ?get_height(...)
?| ? ? ?get_height() -> height
?| ? ? ?get the height of the Surface
?| ?
?| ?get_locked(...)
?| ? ? ?get_locked() -> bool
?| ? ? ?test if the Surface is current locked
?| ?
?| ?get_locks(...)
?| ? ? ?get_locks() -> tuple
?| ? ? ?Gets the locks for the Surface
?| ?
?| ?get_losses(...)
?| ? ? ?get_losses() -> (R, G, B, A)
?| ? ? ?the significant bits used to convert between a color and a mapped integer
?| ?
?| ?get_masks(...)
?| ? ? ?get_masks() -> (R, G, B, A)
?| ? ? ?the bitmasks needed to convert between a color and a mapped integer
?| ?
?| ?get_offset(...)
?| ? ? ?get_offset() -> (x, y)
?| ? ? ?find the position of a child subsurface inside a parent
?| ?
?| ?get_palette(...)
?| ? ? ?get_palette() -> [RGB, RGB, RGB, ...]
?| ? ? ?get the color index palette for an 8-bit Surface
?| ?
?| ?get_palette_at(...)
?| ? ? ?get_palette_at(index) -> RGB
?| ? ? ?get the color for a single entry in a palette
?| ?
?| ?get_parent(...)
?| ? ? ?get_parent() -> Surface
?| ? ? ?find the parent of a subsurface
?| ?
?| ?get_pitch(...)
?| ? ? ?get_pitch() -> int
?| ? ? ?get the number of bytes used per Surface row
?| ?
?| ?get_rect(...)
?| ? ? ?get_rect(**kwargs) -> Rect
?| ? ? ?get the rectangular area of the Surface
?| ?
?| ?get_shifts(...)
?| ? ? ?get_shifts() -> (R, G, B, A)
?| ? ? ?the bit shifts needed to convert between a color and a mapped integer
?| ?
?| ?get_size(...)
?| ? ? ?get_size() -> (width, height)
?| ? ? ?get the dimensions of the Surface
?| ?
?| ?get_view(...)
?| ? ? ?get_view(<kind>='2') -> BufferProxy
?| ? ? ?return a buffer view of the Surface's pixels.
?| ?
?| ?get_width(...)
?| ? ? ?get_width() -> width
?| ? ? ?get the width of the Surface
?| ?
?| ?lock(...)
?| ? ? ?lock() -> None
?| ? ? ?lock the Surface memory for pixel access
?| ?
?| ?map_rgb(...)
?| ? ? ?map_rgb(Color) -> mapped_int
?| ? ? ?convert a color into a mapped color value
?| ?
?| ?mustlock(...)
?| ? ? ?mustlock() -> bool
?| ? ? ?test if the Surface requires locking
?| ?
?| ?premul_alpha(...)
?| ? ? ?premul_alpha() -> Surface
?| ? ? ?returns a copy of the surface with the RGB channels pre-multiplied by the alpha channel.
?| ?
?| ?scroll(...)
?| ? ? ?scroll(dx=0, dy=0) -> None
?| ? ? ?Shift the surface image in place
?| ?
?| ?set_alpha(...)
?| ? ? ?set_alpha(value, flags=0) -> None
?| ? ? ?set_alpha(None) -> None
?| ? ? ?set the alpha value for the full Surface image
?| ?
?| ?set_at(...)
?| ? ? ?set_at((x, y), Color) -> None
?| ? ? ?set the color value for a single pixel
?| ?
?| ?set_clip(...)
?| ? ? ?set_clip(rect) -> None
?| ? ? ?set_clip(None) -> None
?| ? ? ?set the current clipping area of the Surface
?| ?
?| ?set_colorkey(...)
?| ? ? ?set_colorkey(Color, flags=0) -> None
?| ? ? ?set_colorkey(None) -> None
?| ? ? ?Set the transparent colorkey
?| ?
?| ?set_masks(...)
?| ? ? ?set_masks((r,g,b,a)) -> None
?| ? ? ?set the bitmasks needed to convert between a color and a mapped integer
?| ?
?| ?set_palette(...)
?| ? ? ?set_palette([RGB, RGB, RGB, ...]) -> None
?| ? ? ?set the color palette for an 8-bit Surface
?| ?
?| ?set_palette_at(...)
?| ? ? ?set_palette_at(index, RGB) -> None
?| ? ? ?set the color for a single index in an 8-bit Surface palette
?| ?
?| ?set_shifts(...)
?| ? ? ?set_shifts((r,g,b,a)) -> None
?| ? ? ?sets the bit shifts needed to convert between a color and a mapped integer
?| ?
?| ?subsurface(...)
?| ? ? ?subsurface(Rect) -> Surface
?| ? ? ?create a new surface that references its parent
?| ?
?| ?unlock(...)
?| ? ? ?unlock() -> None
?| ? ? ?unlock the Surface memory from pixel access
?| ?
?| ?unmap_rgb(...)
?| ? ? ?unmap_rgb(mapped_int) -> Color
?| ? ? ?convert a mapped integer color value into a Color
另外增加了3個狀態變量,初始狀態為:
? ? is_running = False
? ? is_paused = False
? ? is_dead = False
增加了4個按鍵判別:
is_dead時,判斷重新開始還是退出游戲
pygame.K_y: 字母Y/y
pygame.K_n: 字母N/n
暫停和恢復
pygame.K_ESCAPE: Esc鍵
pygame.K_SPACE: 空格鍵
完整代碼如下:
import pygame
import sys
import random# 定義顏色
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
GREY = (220, 220, 220) # 淡灰色
DARK = (120, 120, 120) # 深灰色def init():global screen, screen_sizeglobal snake_pos, food_pos, snake_speed# 初始化pygamepygame.init()# 設置屏幕大小screen_size = (640, 480)screen = pygame.display.set_mode(screen_size)# 設置游戲標題pygame.display.set_caption("貪吃蛇")# 蛇的初始位置snake_pos = [[100, 100], [80, 100], [60, 100]]# 食物的初始位置food_pos = [300, 300]# 蛇的初始速度snake_speed = [20, 0]def show_msg(msg, color = BLUE):x = screen.get_rect().centerxy = screen.get_rect().centery - 50font = pygame.font.Font(None, 36)text = font.render(msg, True, color)text_rect = text.get_rect()text_rect.centerx = xtext_rect.centery = yrectangle1 = pygame.Rect(x-155, y-25, 320, 60)rectangle2 = pygame.Rect(x-160, y-30, 320, 60)pygame.draw.rect(screen, DARK, rectangle1)pygame.draw.rect(screen, GREY, rectangle2)pygame.draw.rect(screen, BLACK, rectangle2, 2) # 邊框寬為2screen.blit(text, text_rect)pygame.display.flip()def repaint():# 繪制游戲界面screen.fill(WHITE)# 定義線段的端點坐標x,y = (-1,640,640,-1)*16, []for i in range(36):for _ in range(2):y.append(19+i*20)# 使用pygame.draw.lines()函數繪制線段points = list(zip(x,y))pygame.draw.lines(screen, GREY, False, points, 1) # 線寬為1points = list(zip(y,x))pygame.draw.lines(screen, GREY, False, points, 1) # 重畫蛇和食物for pos in snake_pos:pygame.draw.rect(screen, GREEN, pygame.Rect(pos[0], pos[1], 20, 20))pygame.draw.rect(screen, RED, pygame.Rect(food_pos[0], food_pos[1], 20, 20))pygame.display.flip()def game_quit():pygame.quit()sys.exit()def main():global screen, screen_sizeglobal snake_pos, food_pos, snake_speedis_running = Falseis_paused = Falseis_dead = Falserepaint()show_msg("Press any key to start ...")# 主循環while True:# 處理游戲事件for event in pygame.event.get():if event.type == pygame.QUIT:game_quit()elif event.type == pygame.KEYDOWN:if event.key == pygame.K_UP:snake_speed = [0, -20]elif event.key == pygame.K_DOWN:snake_speed = [0, 20]elif event.key == pygame.K_LEFT:snake_speed = [-20, 0]elif event.key == pygame.K_RIGHT:snake_speed = [20, 0]elif event.key == pygame.K_y:if is_dead:init()is_dead = Falseis_running = Trueelif event.key == pygame.K_n:if is_dead: game_quit()else: is_running = Trueelif event.key == pygame.K_ESCAPE:if is_running:show_msg(">>> Paused <<<")is_paused = not is_pausedelse: # 任意鍵進入開始狀態is_running = Trueif not is_running: continueif is_paused and is_running: continue# 更新蛇的位置snake_pos.insert(0, [snake_pos[0][0] + snake_speed[0], snake_pos[0][1] + snake_speed[1]])# 檢查蛇頭是否碰到食物if snake_pos[0] == food_pos:food_pos = [random.randrange(1, screen_size[0] // 20) * 20, random.randrange(1, screen_size[1] // 20) * 20]else:snake_pos.pop()# 檢查蛇頭是否碰到墻壁或者蛇身if snake_pos[0][0] < 0 or snake_pos[0][0] >= screen_size[0] or snake_pos[0][1] < 0 or snake_pos[0][1] >= screen_size[1] or snake_pos[0] in snake_pos[1:]:show_msg("Dead! Again? (Y or N)")is_running = Falseis_dead = Truecontinue# 重畫界面及蛇和食物repaint()# 控制游戲速度pygame.time.Clock().tick(10)if __name__ == "__main__":init()main()
改進過程二
增加顯示得分
每吃到一個食物+10分,蛇長和食物靠近邊界會有額外加分;順帶顯示出蛇的坐標位置。
函數show_msg_at(),比show_msg增加x,y坐標,把信息顯示到指定的位置:
def show_msg_at(x, y, msg):
? ? font = pygame.font.SysFont('Consolas', 14)? # 使用系統字庫
? ? text = font.render(msg, True, BLACK)
? ? text_rect = text.get_rect()
? ? text_rect.x, text_rect.y = x, y
? ? screen.blit(text, text_rect)
? ? pygame.display.flip()
另外新增一個全局變量?scores,當碰到食物時加10分,蛇長超過5以及食物靠近邊界的距離小3會有額外加分,規則可以自己定,例如:
? ? ? ? if snake_pos[0] == food_pos:
? ? ? ? ? ? scores += 10?+ len(snake_pos) // 5
? ? ? ? ? ? if not 1 < snake_pos[0][0]//20 < 30 or not 1 < snake_pos[0][1]//20 < 22:
? ? ? ? ? ? ? ? scores += 5?
完整代碼如下:?
import pygame
import sys
import random# 定義顏色
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
GREY = (220, 220, 220) # 淡灰色
DARK = (120, 120, 120) # 深灰色def init():global screen, screen_size, scoresglobal snake_pos, food_pos, snake_speed# 初始化pygamescores = 0pygame.init()# 設置屏幕大小screen_size = (640, 480)screen = pygame.display.set_mode(screen_size)# 設置游戲標題pygame.display.set_caption("貪吃蛇")# 蛇的初始位置snake_pos = [[100, 100], [80, 100], [60, 100]]# 食物的初始位置food_pos = [300, 300]# 蛇的初始速度snake_speed = [20, 0]def show_msg(msg, color = BLUE):x = screen.get_rect().centerxy = screen.get_rect().centery - 50font = pygame.font.Font(None, 36)text = font.render(msg, True, color)text_rect = text.get_rect()text_rect.centerx = xtext_rect.centery = yrectangle1 = pygame.Rect(x-155, y-25, 320, 60)rectangle2 = pygame.Rect(x-160, y-30, 320, 60)pygame.draw.rect(screen, DARK, rectangle1)pygame.draw.rect(screen, GREY, rectangle2)pygame.draw.rect(screen, BLACK, rectangle2, 2) # 邊框寬為2screen.blit(text, text_rect)pygame.display.flip()def repaint():# 繪制游戲界面screen.fill(WHITE)# 定義線段的端點坐標x,y = (-1,640,640,-1)*16, []for i in range(36):for _ in range(2):y.append(19+i*20)# 使用pygame.draw.lines()函數繪制線段points = list(zip(x,y))pygame.draw.lines(screen, GREY, False, points, 1) # 線寬為1points = list(zip(y,x))pygame.draw.lines(screen, GREY, False, points, 1) # 重畫蛇和食物for pos in snake_pos:pygame.draw.rect(screen, GREEN, pygame.Rect(pos[0], pos[1], 20, 20))pygame.draw.rect(screen, RED, pygame.Rect(food_pos[0], food_pos[1], 20, 20))pygame.display.flip()show_msg_at(22, 6, f'Scores: {scores}')show_msg_at(410, 6, f'Snake coordinate: ({1+snake_pos[0][0]//20:2}, {1+snake_pos[0][1]//20:2})')def show_msg_at(x, y, msg):font = pygame.font.SysFont('Consolas', 14)text = font.render(msg, True, BLACK)text_rect = text.get_rect()text_rect.x, text_rect.y = x, yscreen.blit(text, text_rect)pygame.display.flip()def game_quit():pygame.quit()sys.exit()def main():global screen, screen_size, scoresglobal snake_pos, food_pos, snake_speedis_running = Falseis_paused = Falseis_dead = Falserepaint()show_msg("Press any key to start ...")# 主循環while True:# 處理游戲事件for event in pygame.event.get():if event.type == pygame.QUIT:game_quit()elif event.type == pygame.KEYDOWN:if event.key == pygame.K_UP:snake_speed = [0, -20]elif event.key == pygame.K_DOWN:snake_speed = [0, 20]elif event.key == pygame.K_LEFT:snake_speed = [-20, 0]elif event.key == pygame.K_RIGHT:snake_speed = [20, 0]elif event.key == pygame.K_y:if is_dead:init()is_dead = Falseis_running = Trueelif event.key == pygame.K_n:if is_dead: game_quit()else: is_running = Trueelif event.key == pygame.K_SPACE:if is_dead: continueif is_paused: is_paused = Falseis_running = Trueelif event.key == pygame.K_ESCAPE:if is_running:show_msg(">>> Paused <<<")is_paused = not is_pausedelse: # 任意鍵進入開始狀態if is_dead: continueis_running = Trueif not is_running: continueif is_paused and is_running: continue# 更新蛇的位置snake_pos.insert(0, [snake_pos[0][0] + snake_speed[0], snake_pos[0][1] + snake_speed[1]])# 檢查蛇頭是否碰到食物if snake_pos[0] == food_pos:scores += 10?+ len(snake_pos) // 5if not 1 < snake_pos[0][0]//20 < 30 or not 1 < snake_pos[0][1]//20 < 22:scores += 5????????food_pos = [random.randrange(1, screen_size[0] // 20) * 20, random.randrange(1, screen_size[1] // 20) * 20]else:snake_pos.pop()# 檢查蛇頭是否碰到墻壁或者蛇身if snake_pos[0][0] < 0 or snake_pos[0][0] >= screen_size[0] or snake_pos[0][1] < 0 or snake_pos[0][1] >= screen_size[1] or snake_pos[0] in snake_pos[1:]:show_msg("Dead! Again? (Y or N)")is_running = Falseis_dead = Truecontinue# 重畫界面及蛇和食物repaint()# 控制游戲速度pygame.time.Clock().tick(10)if __name__ == "__main__":init()main()
改進過程三
增加背景景樂
def play_music(mp3, volume = 1, loops = -1):
? ? # 初始化pygame的mixer模塊
? ? pygame.mixer.init()
? ? # 加載音樂文件
? ? pygame.mixer.music.load(mp3)
? ? # 控制音量?volume = 0~1,1為最高音量
? ? pygame.mixer.music.set_volume(volume)
? ? # 播放音樂 loops = -1 為循環播放
? ? pygame.mixer.music.play(loops)
增加提示音效
def play_sound(wav_no):
? ? sound_fn = f'sound{wav_no}.wav'
? ? if os.path.exists(sound_fn):
? ? ? ? alert_sound = pygame.mixer.Sound(sound_fn)
? ? ? ? alert_sound.play()
音樂切換
快捷鍵 Ctrl+M?
? ? elif event.key == pygame.K_m and event.mod & pygame.KMOD_CTRL:
? ? ? ? # Ctrl+M 切換背景音樂
? ? ? ? is_mute = False
? ? ? ? music_no = 1 if music_no == 3 else music_no + 1
? ? ? ? music_fn = f"voice{music_no}.mp3"
? ? ? ? if os.path.exists(music_fn):
? ? ? ? ? ? t = threading.Thread(target=play_music, args=(music_fn,0.8,))
? ? ? ? ? ? t.start()
靜音切換
快捷鍵 Ctrl+S
? ? elif event.key == pygame.K_s and event.mod & pygame.KMOD_CTRL:
? ? ? ? # Ctrl+S 切換靜音狀態
? ? ? ? is_mute = not is_mute
? ? ? ? if is_mute:
? ? ? ? ? ? pygame.mixer.music.pause()
? ? ? ? else:
? ? ? ? ? ? pygame.mixer.music.unpause()
mixer.music.play 注意事項
1. pygame.mixer.music.play() 只能播放pygame支持的音頻格式,包括WAV, MP3等。
2. 如果音頻文件未找到或無法讀取,pygame.mixer.music.play( ) 會拋出一個異常。使用需要確保音頻文件的路徑正確,且文件存在。導入os庫,用os.path.exists(music_file) 判斷文件是否存在。
3. pygame.mixer.music.play() 是一個阻塞函數,在音頻播放期間程序將不會執行其他操作。如果需要在播放同時執行其他操作,需要在一個單獨的線程中調用pygame.mixer.music.play()。
4. 多線程需要導入threading庫,例如:
? ? ? ? ??t = threading.Thread(target=play_music, args=(music_fn,0.8,))
? ? ? ? ? t.start()
原版幫助摘要
pygame.mixer
NAME
? ? pygame.mixer_music - pygame module for controlling streamed audio
FUNCTIONS
? ? fadeout(...)
? ? ? ? fadeout(time) -> None
? ? ? ? stop music playback after fading out
? ??
? ? get_busy(...)
? ? ? ? get_busy() -> bool
? ? ? ? check if the music stream is playing
? ??
? ? get_endevent(...)
? ? ? ? get_endevent() -> type
? ? ? ? get the event a channel sends when playback stops
? ??
? ? get_pos(...)
? ? ? ? get_pos() -> time
? ? ? ? get the music play time
? ??
? ? get_volume(...)
? ? ? ? get_volume() -> value
? ? ? ? get the music volume
? ??
? ? load(...)
? ? ? ? load(filename) -> None
? ? ? ? load(fileobj, namehint=) -> None
? ? ? ? Load a music file for playback
? ??
? ? pause(...)
? ? ? ? pause() -> None
? ? ? ? temporarily stop music playback
? ??
? ? play(...)
? ? ? ? play(loops=0, start=0.0, fade_ms=0) -> None
? ? ? ? Start the playback of the music stream
? ??
? ? queue(...)
? ? ? ? queue(filename) -> None
? ? ? ? queue(fileobj, namehint=, loops=0) -> None
? ? ? ? queue a sound file to follow the current
? ??
? ? rewind(...)
? ? ? ? rewind() -> None
? ? ? ? restart music
? ??
? ? set_endevent(...)
? ? ? ? set_endevent() -> None
? ? ? ? set_endevent(type) -> None
? ? ? ? have the music send an event when playback stops
? ??
? ? set_pos(...)
? ? ? ? set_pos(pos) -> None
? ? ? ? set position to play from
? ??
? ? set_volume(...)
? ? ? ? set_volume(volume) -> None
? ? ? ? set the music volume
? ??
? ? stop(...)
? ? ? ? stop() -> None
? ? ? ? stop the music playback
? ??
? ? unload(...)
? ? ? ? unload() -> None
? ? ? ? Unload the currently loaded music to free up resources
? ??
? ? unpause(...)
? ? ? ? unpause() -> None
? ? ? ? resume paused music
pygame.mixer.Sound
class Sound(builtins.object)
?| ?Sound(filename) -> Sound
?| ?Sound(file=filename) -> Sound
?| ?Sound(file=pathlib_path) -> Sound
?| ?Sound(buffer) -> Sound
?| ?Sound(buffer=buffer) -> Sound
?| ?Sound(object) -> Sound
?| ?Sound(file=object) -> Sound
?| ?Sound(array=object) -> Sound
?| ?Create a new Sound object from a file or buffer object
?| ?
?| ?Methods defined here:
?| ?
?| ?__init__(self, /, *args, **kwargs)
?| ? ? ?Initialize self. ?See help(type(self)) for accurate signature.
?| ?
?| ?fadeout(...)
?| ? ? ?fadeout(time) -> None
?| ? ? ?stop sound playback after fading out
?| ?
?| ?get_length(...)
?| ? ? ?get_length() -> seconds
?| ? ? ?get the length of the Sound
?| ?
?| ?get_num_channels(...)
?| ? ? ?get_num_channels() -> count
?| ? ? ?count how many times this Sound is playing
?| ?
?| ?get_raw(...)
?| ? ? ?get_raw() -> bytes
?| ? ? ?return a bytestring copy of the Sound samples.
?| ?
?| ?get_volume(...)
?| ? ? ?get_volume() -> value
?| ? ? ?get the playback volume
?| ?
?| ?play(...)
?| ? ? ?play(loops=0, maxtime=0, fade_ms=0) -> Channel
?| ? ? ?begin sound playback
?| ?
?| ?set_volume(...)
?| ? ? ?set_volume(value) -> None
?| ? ? ?set the playback volume for this Sound
?| ?
?| ?stop(...)
?| ? ? ?stop() -> None
?| ? ? ?stop sound playback
完整代碼:
import pygame
import sys, os
import random
import threading# 定義顏色
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
GREY = (220, 220, 220) # 淡灰色
DARK = (120, 120, 120) # 深灰色def init():global screen, screen_size, scoresglobal snake_pos, food_pos, snake_speed# 初始化pygamescores = 0pygame.init()# 設置屏幕大小screen_size = (640, 480)screen = pygame.display.set_mode(screen_size)# 設置游戲標題pygame.display.set_caption("貪吃蛇")# 蛇的初始位置snake_pos = [[100, 100], [80, 100], [60, 100]]# 食物的初始位置food_pos = [300, 300]# 蛇的初始速度snake_speed = [20, 0]def play_music(mp3, volume = 1, loops = -1):# 初始化pygame的mixer模塊pygame.mixer.init()# 加載音樂文件pygame.mixer.music.load(mp3)# 控制音量pygame.mixer.music.set_volume(volume)# 播放音樂pygame.mixer.music.play(loops)def play_sound(wav_no):sound_fn = f'sound{wav_no}.wav'if os.path.exists(sound_fn):alert_sound = pygame.mixer.Sound(sound_fn)alert_sound.play()def show_msg(msg, color = BLUE):x = screen.get_rect().centerxy = screen.get_rect().centery - 50font = pygame.font.Font(None, 36)text = font.render(msg, True, color)text_rect = text.get_rect()text_rect.centerx = xtext_rect.centery = yrectangle1 = pygame.Rect(x-155, y-25, 320, 60)rectangle2 = pygame.Rect(x-160, y-30, 320, 60)pygame.draw.rect(screen, DARK, rectangle1)pygame.draw.rect(screen, GREY, rectangle2)pygame.draw.rect(screen, BLACK, rectangle2, 2) # 邊框寬為2screen.blit(text, text_rect)pygame.display.flip()def repaint():# 繪制游戲界面screen.fill(WHITE)# 定義線段的端點坐標x,y = (-1,640,640,-1)*16, []for i in range(36):for _ in range(2):y.append(19+i*20)# 使用pygame.draw.lines()函數繪制線段points = list(zip(x,y))pygame.draw.lines(screen, GREY, False, points, 1) # 線寬為1points = list(zip(y,x))pygame.draw.lines(screen, GREY, False, points, 1) # 重畫蛇和食物for pos in snake_pos:pygame.draw.rect(screen, GREEN, pygame.Rect(pos[0], pos[1], 20, 20))pygame.draw.rect(screen, RED, pygame.Rect(food_pos[0], food_pos[1], 20, 20))pygame.display.flip()show_msg_at(22, 6, f'Scores: {scores}')show_msg_at(410, 6, f'Snake coordinate: ({1+snake_pos[0][0]//20:2}, {1+snake_pos[0][1]//20:2})')def show_msg_at(x, y, msg):font = pygame.font.SysFont('Consolas', 14)text = font.render(msg, True, BLACK)text_rect = text.get_rect()text_rect.x, text_rect.y = x, yscreen.blit(text, text_rect)pygame.display.flip()def game_quit():pygame.quit()sys.exit()def main():global screen, screen_size, scoresglobal snake_pos, food_pos, snake_speedis_running = Falseis_paused = Falseis_dead = Falseis_mute = Falserepaint()show_msg("Press any key to start ...")# 創建一個線程來播放音樂music_no = 1music_fn = "voice1.mp3"if os.path.exists(music_fn):t = threading.Thread(target=play_music, args=(music_fn,0.8,))t.start()# 主循環while True:# 處理游戲事件for event in pygame.event.get():if event.type == pygame.QUIT:game_quit()elif event.type == pygame.KEYDOWN:if event.key == pygame.K_UP:snake_speed = [0, -20]elif event.key == pygame.K_DOWN:snake_speed = [0, 20]elif event.key == pygame.K_LEFT:snake_speed = [-20, 0]elif event.key == pygame.K_RIGHT:snake_speed = [20, 0]elif event.key == pygame.K_y:if is_dead:init()is_dead = Falseis_running = Trueelif event.key == pygame.K_n:if is_dead: game_quit()else: is_running = Trueelif event.key == pygame.K_SPACE:if is_dead: continueif is_paused: is_paused = Falseis_running = Trueelif event.key == pygame.K_ESCAPE:if is_running:show_msg(">>> Paused <<<")is_paused = not is_pausedif not is_mute and is_paused: play_sound(1)elif event.key == pygame.K_m and event.mod & pygame.KMOD_CTRL:# Ctrl+M 切換背景音樂is_mute = Falsemusic_no = 1 if music_no == 3 else music_no + 1music_fn = f"voice{music_no}.mp3"if os.path.exists(music_fn):t = threading.Thread(target=play_music, args=(music_fn,0.8,))t.start()elif event.key == pygame.K_s and event.mod & pygame.KMOD_CTRL:# Ctrl+S 切換靜音狀態is_mute = not is_muteif is_mute:pygame.mixer.music.pause()else:pygame.mixer.music.unpause()is_running = Trueelse: # 任意鍵進入開始狀態if is_dead: continueis_running = Trueif not is_running: continueif is_paused and is_running: continue# 更新蛇的位置snake_pos.insert(0, [snake_pos[0][0] + snake_speed[0], snake_pos[0][1] + snake_speed[1]])# 檢查蛇頭是否碰到食物if snake_pos[0] == food_pos:scores += 10 + len(snake_pos) // 5if not 1 < snake_pos[0][0]//20 < 30 or not 1 < snake_pos[0][1]//20 < 22:scores += 5if not is_mute: play_sound(2)food_pos = [random.randrange(1, screen_size[0] // 20) * 20, random.randrange(1, screen_size[1] // 20) * 20]else:snake_pos.pop()# 檢查蛇頭是否碰到墻壁或者蛇身if snake_pos[0][0] < 0 or snake_pos[0][0] >= screen_size[0] or snake_pos[0][1] < 0 or snake_pos[0][1] >= screen_size[1] or snake_pos[0] in snake_pos[1:]:show_msg("Dead! Again? (Y or N)")is_running = Falseis_dead = Trueif not is_mute: play_sound(3)continue# 重畫界面及蛇和食物repaint()# 控制游戲速度pygame.time.Clock().tick(10)if __name__ == "__main__":init()main()
小結
本文以貪吃蛇游戲為例,對pygame編程的一個簡單框架進行了深入的學習,包括對畫圖、字體、音樂等各個方面操作的各種方法和函數,學習后在pygame這方面的編程能力有所長進提高。
pygame編程框架
import pygame
import sys# 初始化Pygame
pygame.init()# 設置窗口大小
screen_size = (800, 600)# 創建窗口
screen = pygame.display.set_mode(screen_size)# 設置窗口標題
pygame.display.set_caption("Pygame Example")# 主循環
while True:# 處理事件for event in pygame.event.get():if event.type == pygame.QUIT:pygame.quit()sys.exit()elif event.type == ...... // 處理按鍵事件# 填充背景色screen.fill((255, 255, 255))# 繪制矩形pygame.draw.rect(screen, (0, 0, 255), (400, 300, 100, 50))# 更新顯示pygame.display.flip()
最終版的源代碼及音樂文件列表如下:
下載地址:?
https://download.csdn.net/download/boysoft2002/88231961