
目次
前言
改进过程一
增长提示信息
原版资助择要
pygame.draw
pygame.font
class Rect
class Surface
改进过程二
增长体现得分
改进过程三
增长配景景乐
增长提示音效
音乐切换
静音切换
mixer.music.play 留意事项
原版资助择要
pygame.mixer
pygame.mixer.Sound
改进过程四
增长WASD方向键
增长退失变乱简直认
小结
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_size
- global snake_pos, food_pos, snake_speed
-
- # 初始化pygame
- pygame.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) # 线宽为1
- points = 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_size
- global 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 again
- else:
- 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_size
- global snake_pos, food_pos, snake_speed
- # 初始化pygame
- pygame.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().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()
- 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) # 线宽为1
- points = 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_size
- global snake_pos, food_pos, snake_speed
- is_running = False
- is_paused = False
- is_dead = False
- repaint()
- 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 = False
- is_running = True
- elif event.key == pygame.K_n:
- if is_dead: game_quit()
- else: is_running = True
- elif event.key == pygame.K_ESCAPE:
- if is_running:
- show_msg(">>> Paused <<<")
- is_paused = not is_paused
- else: # 任意键进入开始状态
- is_running = True
- if not is_running: continue
- if 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 = False
- is_dead = True
- continue
- # 重画界面及蛇和食物
- 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, scores
- global snake_pos, food_pos, snake_speed
- # 初始化pygame
- scores = 0
- pygame.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().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()
- 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) # 线宽为1
- points = 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, y
- screen.blit(text, text_rect)
- pygame.display.flip()
- def game_quit():
- pygame.quit()
- sys.exit()
- def main():
- global screen, screen_size, scores
- global snake_pos, food_pos, snake_speed
- is_running = False
- is_paused = False
- is_dead = False
- repaint()
- 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 = False
- is_running = True
- elif event.key == pygame.K_n:
- if is_dead: game_quit()
- else: is_running = True
- elif event.key == pygame.K_SPACE:
- if is_dead: continue
- if is_paused: is_paused = False
- is_running = True
- elif event.key == pygame.K_ESCAPE:
- if is_running:
- show_msg(">>> Paused <<<")
- is_paused = not is_paused
- else: # 任意键进入开始状态
- if is_dead: continue
- is_running = True
- if not is_running: continue
- if 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) // 5
- if 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 = False
- is_dead = True
- continue
- # 重画界面及蛇和食物
- 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, scores
- global snake_pos, food_pos, snake_speed
- # 初始化pygame
- scores = 0
- pygame.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().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()
- 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) # 线宽为1
- points = 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, y
- screen.blit(text, text_rect)
- pygame.display.flip()
- def game_quit():
- pygame.quit()
- sys.exit()
- def main():
- global screen, screen_size, scores
- global snake_pos, food_pos, snake_speed
- is_running = False
- is_paused = False
- is_dead = False
- is_mute = False
-
- repaint()
- show_msg("Press any key to start ...")
- # 创建一个线程来播放音乐
- music_no = 1
- music_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 = False
- is_running = True
- elif event.key == pygame.K_n:
- if is_dead: game_quit()
- else: is_running = True
- elif event.key == pygame.K_SPACE:
- if is_dead: continue
- if is_paused: is_paused = False
- is_running = True
- elif event.key == pygame.K_ESCAPE:
- if is_running:
- show_msg(">>> Paused <<<")
- is_paused = not is_paused
- if 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 = 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()
- 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()
- is_running = True
- else: # 任意键进入开始状态
- if is_dead: continue
- is_running = True
- if not is_running: continue
- if 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) // 5
- if not 1 < snake_pos[0][0]//20 < 30 or not 1 < snake_pos[0][1]//20 < 22:
- scores += 5
- if 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 = False
- is_dead = True
- if not is_mute: play_sound(3)
- continue
- # 重画界面及蛇和食物
- repaint()
- # 控制游戏速度
- pygame.time.Clock().tick(10)
- if __name__ == "__main__":
- init()
- main()
复制代码 改进过程四
增长WASD方向键
DOS时代的游戏常常用W、A、S、D四个字母,对应上左下右四个方向键,上面的代码中,快捷键 ctrl+S 换成 strl+Q 克制辩论。
别的,游戏中按了与进步方向相反的键,相当于蛇的自杀行为。为了克制这个bug,引入一个表现蛇移动方向的变量direction:
if not is_paused:
if (event.key == pygame.K_w or event.key == pygame.K_UP) and direction != DOWN:
direction = UP
elif (event.key == pygame.K_s or event.key == pygame.K_DOWN) and direction != UP:
direction = DOWN
elif (event.key == pygame.K_a or event.key == pygame.K_LEFT) and direction != RIGHT:
direction = LEFT
elif (event.key == pygame.K_f or event.key == pygame.K_RIGHT) and direction != LEFT:
direction = RIGHT
把移动和按键分离,控制移动的代码放到后面去:
if direction == UP:
snake_speed = [0, -20]
elif direction == DOWN:
snake_speed = [0, 20]
elif direction == LEFT:
snake_speed = [-20, 0]
elif direction == RIGHT:
snake_speed = [20, 0]
增长退失变乱简直认
pygame 没有弹窗一类的方法,导入tkinter库,由messagebox来实现:
from tkinter import messagebox
......
for event in pygame.event.get():
if event.type == pygame.QUIT:
if messagebox.askyesno("确认", "是否要退出?"):
game_quit()
......
结果如下:

最后,增长了按停息键时配景音乐也停息的功能;别的修改了一些小错误,估计还会有bug出现,状态变量设置多了感觉逻辑有点乱。
小结
本文以贪吃蛇游戏为例,对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()
复制代码 完整代码
- import pygame
- from sys import exit as system
- from random import randrange
- from os.path import exists
- from tkinter import messagebox
- from threading import Thread
- # 定义颜色
- 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, scores
- global snake_pos, food_pos, snake_speed
- # 初始化pygame
- scores = 0
- pygame.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 exists(sound_fn):
- alert_sound = pygame.mixer.Sound(sound_fn)
- alert_sound.play()
- 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()
- 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) # 线宽为1
- points = 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, y
- screen.blit(text, text_rect)
- pygame.display.flip()
- def game_quit():
- pygame.quit()
- system()
- def main():
- global screen, screen_size, scores
- global snake_pos, food_pos, snake_speed
- is_running = False
- is_paused = False
- is_dead = False
- is_mute = False
-
- repaint()
- show_msg("Press any key to start ...")
- # 创建一个线程来播放音乐
- music_no = 1
- music_fn = "voice1.mp3"
- if exists(music_fn):
- t = Thread(target=play_music, args=(music_fn,0.8,))
- t.start()
- # 主循环
- UP, DOWN, LEFT, RIGHT = 1, 2, 3, 4
- direction = RIGHT
- while True:
- # 处理游戏事件
- for event in pygame.event.get():
- if event.type == pygame.QUIT:
- if messagebox.askyesno("确认", "是否要退出?"):
- game_quit()
- elif event.type == pygame.KEYDOWN:
- # 增加 WASD 四键对应 上左下右 方向键
- if not is_paused:
- if (event.key == pygame.K_w or event.key == pygame.K_UP) and direction != DOWN:
- direction = UP
- elif (event.key == pygame.K_s or event.key == pygame.K_DOWN) and direction != UP:
- direction = DOWN
- elif (event.key == pygame.K_a or event.key == pygame.K_LEFT) and direction != RIGHT:
- direction = LEFT
- elif (event.key == pygame.K_f or event.key == pygame.K_RIGHT) and direction != LEFT:
- direction = RIGHT
- if event.key == pygame.K_y:
- if is_dead:
- init()
- is_dead = False
- is_running = True
- elif event.key == pygame.K_n:
- if is_dead: game_quit()
- else: is_running = True
- elif event.key == pygame.K_SPACE:
- if is_dead: continue
- if is_paused:
- is_paused = False
- pygame.mixer.music.unpause()
- is_running = True
- elif event.key == pygame.K_ESCAPE:
- if is_running:
- show_msg(">>> Paused <<<")
- is_paused = not is_paused
- if is_paused:
- pygame.mixer.music.pause()
- if not is_mute: play_sound(1)
- else:
- pygame.mixer.music.unpause()
- 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 exists(music_fn):
- t = Thread(target=play_music, args=(music_fn,0.8,))
- t.start()
- elif event.key == pygame.K_q and event.mod & pygame.KMOD_CTRL:
- # Ctrl+Q 切换静音状态
- is_mute = not is_mute
- if is_mute:
- pygame.mixer.music.pause()
- else:
- pygame.mixer.music.unpause()
- is_running = True
- else: # 任意键进入开始状态
- if is_dead: continue
- is_running = True
- if not is_running: continue
- if is_paused: continue
- if direction == UP:
- snake_speed = [0, -20]
- elif direction == DOWN:
- snake_speed = [0, 20]
- elif direction == LEFT:
- snake_speed = [-20, 0]
- elif direction == 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:
- 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
- if not is_mute: play_sound(2)
- food_pos = [randrange(1, screen_size[0] // 20) * 20, 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 = False
- is_dead = True
- direction = RIGHT
- if not is_mute: play_sound(3)
- continue
- # 重画界面及蛇和食物
- repaint()
- # 控制游戏速度
- pygame.time.Clock().tick(10)
- if __name__ == "__main__":
- init()
- main()
复制代码 终极版的源代码及音乐文件列表如下:

下载所在:
https://download.csdn.net/download/boysoft2002/88231961
来源:https://blog.csdn.net/boysoft2002/article/details/132370232
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |