目錄
前言
改進(jìn)過程一
增加提示信息
原版幫助摘要
pygame.draw
pygame.font
class Rect
class Surface
改進(jìn)過程二
增加顯示得分
改進(jìn)過程三
增加背景景樂
增加提示音效
音樂切換
靜音切換
mixer.music.play 注意事項(xiàng)
原版幫助摘要
pygame.mixer
pygame.mixer.Sound
改進(jìn)過程四
增加WASD方向鍵
增加退出事件的確認(rèn)
小結(jié)
pygame編程框架
完整代碼
前言
在上一篇博文里,從訊飛星火中獲取到游戲“貪吃蛇”的代碼,運(yùn)行效果如上圖。代碼并不完整,當(dāng)蛇死了就退出游戲,不能多次玩這個(gè)游戲。
前文鏈接:
訊飛星火、文心一言和通義千問同時(shí)編“貪吃蛇”游戲,誰(shuí)會(huì)勝出?
代碼如下:
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()
# 設(shè)置屏幕大小
screen_size = (640, 480)
screen = pygame.display.set_mode(screen_size)
# 設(shè)置游戲標(biāo)題
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)
# 定義線段的端點(diǎn)坐標(biāo)
x,y = (-1,640,640,-1)*16, []
for i in range(36):
for _ in range(2):
y.append(19+i*20)
# 使用pygame.draw.lines()函數(shù)繪制線段
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
# 主循環(huán)
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()
改進(jìn)過程一
增加提示信息
之前沒有仔細(xì)學(xué)過pygame的編程,剛好拿這例程練練手,在不斷改進(jìn)中學(xué)習(xí)pygame編程。
原代碼一執(zhí)行,蛇就開始游動(dòng)了,就從這里入手。開始前,增加顯示“按任意鍵開始...”的提示。
蛇死后,提醒是否重來?Yes to play again, No to quit game.
同時(shí),在游戲中允許按ESC鍵暫停游戲,再按一次繼續(xù)。
由于沒查到 pygame 有彈出信息窗口的方法(函數(shù)),于是用了DOS時(shí)代顯示信息窗口的辦法,畫多個(gè)矩形窗口來模擬窗口,最后在矩形框上寫上提示文字。代碼如下:
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) # 邊框?qū)挒?
? ? 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個(gè)狀態(tài)變量,初始狀態(tài)為:
? ? is_running = False
? ? is_paused = False
? ? is_dead = False
增加了4個(gè)按鍵判別:
is_dead時(shí),判斷重新開始還是退出游戲
pygame.K_y: 字母Y/y
pygame.K_n: 字母N/n
暫停和恢復(fù)
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()
# 設(shè)置屏幕大小
screen_size = (640, 480)
screen = pygame.display.set_mode(screen_size)
# 設(shè)置游戲標(biāo)題
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) # 邊框?qū)挒?
screen.blit(text, text_rect)
pygame.display.flip()
def repaint():
# 繪制游戲界面
screen.fill(WHITE)
# 定義線段的端點(diǎn)坐標(biāo)
x,y = (-1,640,640,-1)*16, []
for i in range(36):
for _ in range(2):
y.append(19+i*20)
# 使用pygame.draw.lines()函數(shù)繪制線段
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 ...")
# 主循環(huán)
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: # 任意鍵進(jìn)入開始狀態(tài)
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()
改進(jìn)過程二
增加顯示得分
每吃到一個(gè)食物+10分,蛇長(zhǎng)和食物靠近邊界會(huì)有額外加分;順帶顯示出蛇的坐標(biāo)位置。
函數(shù)show_msg_at(),比show_msg增加x,y坐標(biāo),把信息顯示到指定的位置:
def show_msg_at(x, y, msg):
? ? font = pygame.font.SysFont('Consolas', 14)? # 使用系統(tǒng)字庫(kù)
? ? 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()
另外新增一個(gè)全局變量?scores,當(dāng)碰到食物時(shí)加10分,蛇長(zhǎng)超過5以及食物靠近邊界的距離小3會(huì)有額外加分,規(guī)則可以自己定,例如:
? ? ? ? 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()
# 設(shè)置屏幕大小
screen_size = (640, 480)
screen = pygame.display.set_mode(screen_size)
# 設(shè)置游戲標(biāo)題
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) # 邊框?qū)挒?
screen.blit(text, text_rect)
pygame.display.flip()
def repaint():
# 繪制游戲界面
screen.fill(WHITE)
# 定義線段的端點(diǎn)坐標(biāo)
x,y = (-1,640,640,-1)*16, []
for i in range(36):
for _ in range(2):
y.append(19+i*20)
# 使用pygame.draw.lines()函數(shù)繪制線段
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 ...")
# 主循環(huán)
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: # 任意鍵進(jìn)入開始狀態(tài)
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()
改進(jìn)過程三
增加背景景樂
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 為循環(huán)播放
? ? 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 切換靜音狀態(tài)
? ? ? ? is_mute = not is_mute
? ? ? ? if is_mute:
? ? ? ? ? ? pygame.mixer.music.pause()
? ? ? ? else:
? ? ? ? ? ? pygame.mixer.music.unpause()
mixer.music.play 注意事項(xiàng)
1. pygame.mixer.music.play() 只能播放pygame支持的音頻格式,包括WAV, MP3等。
2. 如果音頻文件未找到或無法讀取,pygame.mixer.music.play( ) 會(huì)拋出一個(gè)異常。使用需要確保音頻文件的路徑正確,且文件存在。導(dǎo)入os庫(kù),用os.path.exists(music_file) 判斷文件是否存在。
3. pygame.mixer.music.play() 是一個(gè)阻塞函數(shù),在音頻播放期間程序?qū)⒉粫?huì)執(zhí)行其他操作。如果需要在播放同時(shí)執(zhí)行其他操作,需要在一個(gè)單獨(dú)的線程中調(diào)用pygame.mixer.music.play()。
4. 多線程需要導(dǎo)入threading庫(kù),例如:
? ? ? ? ??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()
# 設(shè)置屏幕大小
screen_size = (640, 480)
screen = pygame.display.set_mode(screen_size)
# 設(shè)置游戲標(biāo)題
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) # 邊框?qū)挒?
screen.blit(text, text_rect)
pygame.display.flip()
def repaint():
# 繪制游戲界面
screen.fill(WHITE)
# 定義線段的端點(diǎn)坐標(biāo)
x,y = (-1,640,640,-1)*16, []
for i in range(36):
for _ in range(2):
y.append(19+i*20)
# 使用pygame.draw.lines()函數(shù)繪制線段
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 ...")
# 創(chuàng)建一個(gè)線程來播放音樂
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()
# 主循環(huán)
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 切換靜音狀態(tài)
is_mute = not is_mute
if is_mute:
pygame.mixer.music.pause()
else:
pygame.mixer.music.unpause()
is_running = True
else: # 任意鍵進(jìn)入開始狀態(tài)
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()
改進(jìn)過程四
增加WASD方向鍵
DOS時(shí)代的游戲經(jīng)常用W、A、S、D四個(gè)字母,對(duì)應(yīng)上左下右四個(gè)方向鍵,上面的代碼中,快捷鍵 ctrl+S 換成 strl+Q 避免沖突。
另外,游戲中按了與前進(jìn)方向相反的鍵,相當(dāng)于蛇的自殺行為。為了避免這個(gè)bug,引入一個(gè)表示蛇移動(dòng)方向的變量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
把移動(dòng)和按鍵分離,控制移動(dòng)的代碼放到后面去:
? ? ? ? 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]
增加退出事件的確認(rèn)
pygame 沒有彈窗一類的方法,導(dǎo)入tkinter庫(kù),由messagebox來實(shí)現(xiàn):
from tkinter import messagebox
......
? ? ? ? for event in pygame.event.get():
? ? ? ? ? ? if event.type == pygame.QUIT:
? ? ? ? ? ? ? ? if messagebox.askyesno("確認(rèn)", "是否要退出?"):
? ? ? ? ? ? ? ? ? ? game_quit()
? ? ? ? ? ?......
效果如下:
最后,增加了按暫停鍵時(shí)背景音樂也暫停的功能;另外修改了一些小錯(cuò)誤,估計(jì)還會(huì)有bug出現(xiàn),狀態(tài)變量設(shè)置多了感覺邏輯有點(diǎn)亂。
小結(jié)
本文以貪吃蛇游戲?yàn)槔?,?duì)pygame編程的一個(gè)簡(jiǎn)單框架進(jìn)行了深入的學(xué)習(xí),包括對(duì)畫圖、字體、音樂等各個(gè)方面操作的各種方法和函數(shù),學(xué)習(xí)后在pygame這方面的編程能力有所長(zhǎng)進(jìn)提高。
pygame編程框架
import pygame
import sys
# 初始化Pygame
pygame.init()
# 設(shè)置窗口大小
screen_size = (800, 600)
# 創(chuàng)建窗口
screen = pygame.display.set_mode(screen_size)
# 設(shè)置窗口標(biāo)題
pygame.display.set_caption("Pygame Example")
# 主循環(huán)
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()
# 設(shè)置屏幕大小
screen_size = (640, 480)
screen = pygame.display.set_mode(screen_size)
# 設(shè)置游戲標(biāo)題
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) # 邊框?qū)挒?
screen.blit(text, text_rect)
pygame.display.flip()
def repaint():
# 繪制游戲界面
screen.fill(WHITE)
# 定義線段的端點(diǎn)坐標(biāo)
x,y = (-1,640,640,-1)*16, []
for i in range(36):
for _ in range(2):
y.append(19+i*20)
# 使用pygame.draw.lines()函數(shù)繪制線段
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 ...")
# 創(chuàng)建一個(gè)線程來播放音樂
music_no = 1
music_fn = "voice1.mp3"
if exists(music_fn):
t = Thread(target=play_music, args=(music_fn,0.8,))
t.start()
# 主循環(huán)
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("確認(rèn)", "是否要退出?"):
game_quit()
elif event.type == pygame.KEYDOWN:
# 增加 WASD 四鍵對(duì)應(yīng) 上左下右 方向鍵
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 切換靜音狀態(tài)
is_mute = not is_mute
if is_mute:
pygame.mixer.music.pause()
else:
pygame.mixer.music.unpause()
is_running = True
else: # 任意鍵進(jìn)入開始狀態(tài)
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()
最終版的源代碼及音樂文件列表如下:
下載地址:?文章來源:http://www.zghlxwxcb.cn/news/detail-658305.html
https://download.csdn.net/download/boysoft2002/88231961文章來源地址http://www.zghlxwxcb.cn/news/detail-658305.html
到了這里,關(guān)于Python “貪吃蛇”游戲,在不斷改進(jìn)中學(xué)習(xí)pygame編程的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!