下载pygame
pip install pygame==2.0.1
项目结构
- background.png 为背景
- icon.png 为窗口图标
- stone.wav 为落子声
- callbacks.py 处理算法
- configs.py 定义游戏常量
- game.py 为主程序
- render.py 绘制游戏界面
下载素材
下载链接
提取码: x4f1
代码
configs.py
GAME_WIDTH = 19 # 几路棋盘
BACKGROUND_PATH = 'resources/background.png' # 背景图片
ICON_PATH = 'resources/icon.png' # 窗口图标
WIDTH = 720 # 窗口长
HEIGHT = 720 # 窗口宽
GRID_WIDTH = WIDTH // (GAME_WIDTH + 1) # 网格边长
SOUND_PATH = 'resources/stone.wav' # 落子音效
PLAYER1 = (0, 0, 0)
PLAYER2 = (255, 255, 255)
PLAYER3 = (255, 0, 0)
PLAYER4 = (0, 0, 255)
ORDER = [PLAYER1, PLAYER2, PLAYER3, PLAYER4] # 玩家落子顺序
TITLE = '四人五子棋' # 窗口标题
FPS = 35 # fps
BOARD = [[None] * (GAME_WIDTH + 1) for _ in range(GAME_WIDTH + 1)] # 棋盘列表
RADIUS = 16 # 棋子半径
callbacks.py
import pygame
from copy import deepcopy
from configs import *
def get_mouse_position(): # 获取鼠标位置
return pygame.mouse.get_pos()
def get_row_column(*mouse_position): # 根据x, y获得行列
x, y = mouse_position
return (int(round(x / (GRID_WIDTH + .0))),
int(round(y / (GRID_WIDTH + .0))))
def is_game_over(color, board, *pos): # 判断游戏是否结束
flatten = lambda x: [y for i in x for y in flatten(i)] if type(x) is list else [x]
temp_board = flatten(deepcopy(board))
if not any(temp_board):
return None
temp_hor = 1
temp_vert = 1
temp_slash = 1
temp_backslash = 1
left = pos[0] - 1
right = pos[0] + 1
up = pos[1] - 1
down = pos[1] + 1
while left > 0 and board[left][pos[1]] == color:
left -= 1
temp_hor += 1
while right < 20 and board[right][pos[1]] == color:
right += 1
temp_hor += 1
while up > 0 and board[pos[0]][up] == color:
up -= 1
temp_vert += 1
while down < 20 and board[pos[0]][down] == color:
down += 1
temp_vert += 1
left = pos[0] - 1
up = pos[1] - 1
right = pos[0] + 1
down = pos[1] + 1
while left > 0 and up > 0 and board[left][up] == color:
left -= 1
up -= 1
temp_backslash += 1
while right < 20 and down < 20 and board[right][down] == color:
right += 1
down += 1
temp_backslash += 1
right = pos[0] + 1
up = pos[1] - 1
left = pos[0] - 1
down = pos[1] + 1
while right < 20 and up > 0 and board[right][up] == color:
right += 1
up -= 1
temp_slash += 1
while left > 0 and down < 20 and board[left][down] == color:
left -= 1
down += 1
temp_slash += 1
return max((temp_hor, temp_vert, temp_slash, temp_backslash)) >= 5
def get_player(color): # 根据棋子颜色获得玩家名称
return {
PLAYER1: '玩家1',
PLAYER2: '玩家2',
PLAYER3: '玩家3',
PLAYER4: '玩家4'
}.get(color)
render.py
import pygame
from configs import *
def draw_board(screen: pygame.Surface, background: pygame.Surface): # 绘制19×19棋盘
screen.blit(background, (0, 0)) # 画背景
rect_lines = [
((GRID_WIDTH, GRID_WIDTH), (GRID_WIDTH, HEIGHT - GRID_WIDTH)),
((GRID_WIDTH, GRID_WIDTH), (WIDTH - GRID_WIDTH, GRID_WIDTH)),
((GRID_WIDTH, HEIGHT - GRID_WIDTH),
(WIDTH - GRID_WIDTH, HEIGHT - GRID_WIDTH)),
((WIDTH - GRID_WIDTH, GRID_WIDTH),
(WIDTH - GRID_WIDTH, HEIGHT - GRID_WIDTH)),
] # 网格线
for line in rect_lines:
pygame.draw.line(screen, (0, 0, 0), line[0], line[1], 2)
for count in range(19):
pygame.draw.line(screen, (0, 0, 0),
(GRID_WIDTH * (2 + count), GRID_WIDTH),
(GRID_WIDTH * (2 + count), HEIGHT - GRID_WIDTH))
pygame.draw.line(screen, (0, 0, 0),
(GRID_WIDTH, GRID_WIDTH * (2 + count)),
(HEIGHT - GRID_WIDTH, GRID_WIDTH * (2 + count)))
rect_circles = [
(GRID_WIDTH * 4, GRID_WIDTH * 4),
(WIDTH - GRID_WIDTH * 4, GRID_WIDTH * 4),
(WIDTH - GRID_WIDTH * 4, HEIGHT - GRID_WIDTH * 4),
(GRID_WIDTH * 4, HEIGHT - GRID_WIDTH * 4),
(GRID_WIDTH * 10, GRID_WIDTH * 10),
(GRID_WIDTH * 10, GRID_WIDTH * 4),
(GRID_WIDTH * 4, GRID_WIDTH * 10),
(GRID_WIDTH * 10, GRID_WIDTH * 16),
(GRID_WIDTH * 16, GRID_WIDTH * 10)
] # 9个点
for circle in rect_circles:
pygame.draw.circle(screen, (0, 0, 0), circle, 5)
def draw_movements(board, screen: pygame.Surface): # 根据board绘制棋子
for row, i in enumerate(board):
for column, j in enumerate(i):
if j:
pygame.draw.circle(screen, j,
(row * GRID_WIDTH, column * GRID_WIDTH),
RADIUS)
game.py
import pygame
import sys
from pygame.locals import *
from copy import deepcopy
from configs import *
from callbacks import *
from render import *
from tkinter import Tk
from tkinter.messagebox import showinfo
def init(): # 初始化
pygame.init()
pygame.mixer.init()
def destroy(): # 关闭窗口
pygame.quit()
sys.exit()
init()
board = deepcopy(BOARD)
background = pygame.image.load(BACKGROUND_PATH)
background = pygame.transform.scale(background, (WIDTH, HEIGHT)) # 缩放
icon = pygame.image.load(ICON_PATH)
stone_sound = pygame.mixer.Sound(SOUND_PATH)
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption(TITLE)
pygame.display.set_icon(icon)
clock = pygame.time.Clock()
counter = 0 # 记录落子玩家
tips = ''
while True:
clock.tick(FPS) # 设置FPS
for event in pygame.event.get():
if event.type == QUIT:
destroy()
elif event.type == KEYDOWN:
if event.key == K_ESCAPE: # ESC键退出
destroy()
elif event.type == MOUSEBUTTONDOWN:
pos = get_mouse_position()
row, column = get_row_column(*pos)
if not board[row][column]:
player = ORDER[counter]
board[row][column] = player
counter += 1
stone_sound.play()
if counter == len(ORDER):
counter = 0
game_over = is_game_over(player, board, row, column)
if game_over is None:
tips = '和棋'
if game_over:
player = get_player(player)
if not tips:
tips = f'{player}赢了!'
Tk().withdraw() # 隐藏tk窗口
showinfo('游戏结束', tips)
destroy()
draw_board(screen, background)
draw_movements(board, screen)
pygame.display.update()
效果
pygame技巧
如果用上代码,控制台会输出:
pygame 2.0.1 (SDL 2.0.14, Python 3.8.3)
Hello from the pygame community. https://www.pygame.org/contribute.html
解决方案:
在game.py的第一、二行添加:
import os
os.environ['PYGAME_HIDE_SUPPORT_PROMPT'] = 'true'