Python基于Pygame开发的记忆训练小游戏
基于Pygame开发的记忆方格游戏,玩家需在短暂展示中记住网格内高亮方格位置,随后凭记忆点击。网格从3×3逐步扩大至6×6,高亮数量随16级关卡递增。答对得分为高亮方格数×10,答错游戏结束,可重试或重开。采用深色调界面与状态机驱动流程。
项目概述
说到用 Python 做 2D 游戏,Pygame 绝对是个绕不开的老朋友。它把图形、声音、输入和事件循环打包得整整齐齐,拿来练手或者做些小项目都挺顺手。这次我们用 Pygame 做一个经典记忆类小游戏——记忆方格(Memory Grid)。
玩法很直接:玩家需要在短暂的展示时间里,记住网格中哪些方格被高亮了,然后等亮光消失后,凭记忆把刚才的位置逐个点出来。随着关卡推进,网格从 3×3 一路扩大到 6×6,高亮方格的数量也在不断爬坡,对短期记忆的挑战一步步升级。具体细节如下:
- 记忆阶段:每轮开始时,目标方格会以金色高亮显示 1.2 秒,屏幕底部还有一根倒计时进度条,时刻提醒你抓紧时间。
- 作答阶段:高亮消失后,玩家逐一点击自己认为正确的方格。点对了方格变成青绿色并触发粒子爆炸特效,点错了则变红并立即结束本轮。
- 关卡递进:全部点对后自动进入下一关,难度按照预先设计好的表格线性提升——先增加高亮数量,再扩大网格尺寸,总共 16 级。
- 得分规则:每关得分为
高亮方格数 × 10,方格越多单关分值越高,最高分跨局保留。 - 失败处理:点错即游戏结束,结束画面会同时展示正确的图案(半透明金色),并提供“再试本关”和“重新开始”两个选项。
- 键盘操作:R 键重新开始,Enter 键再试本关(仅游戏结束时有效)。

游戏实现
初始化与基础设置
游戏启动时先初始化 Pygame,然后定义好屏幕尺寸和 HUD 高度。游戏区是 520×520 像素的正方形,顶部留出 70 像素作为 HUD 信息栏,总窗口高度就是 590。
pygame.init()
SIZE = 520
HUD_H = 70
screen = pygame.display.set_mode((SIZE, SIZE + HUD_H))
pygame.display.set_caption("记忆方格")
clock = pygame.time.Clock()
颜色定义
BG = (12, 10, 18) # 全局深色背景 HUD_BG = (18, 14, 28) # HUD 背景 GRID_BG = (22, 18, 34) # 网格背景板 EMPTY = (35, 28, 55) # 空格底色 CORRECT = (93, 202, 165) # 答对颜色(青绿) WRONG = (226, 75, 74) # 答错颜色(红) ACTIVE = (83, 74, 183) # 强调色(靛蓝) REVEAL = (250, 199, 117) # 展示阶段高亮色(金) WHITE = (230, 225, 210) # 主文字 GRAY = (110, 100, 130) # 次要文字 DIM = (60, 52, 90) # 暗色按钮底色
整体采用深紫色调背景,金色、青绿色、红色三种功能色分工明确,视觉语义一眼就能看懂。
难度表格
LEVELS = [
(3, 2), # lv1 : 3×3, 2 个高亮格
(3, 3), # lv2
(3, 4), # lv3
(4, 3), # lv4 : 网格扩大至 4×4
(4, 4), # lv5
# ...共 16 级
(6, 9), # lv16: 6×6, 9 个高亮格
]
每个元素是 (grid_size, num_lit) 二元组,高亮比例始终控制在 20%~40% 之间,保证难度循序渐进又不至于卡关。如果关卡数超过了表格长度,就自动停留在最高难度。
字体加载
CHINESE_FONT_PATH = r"C:/Windows/Fonts/simsun.ttc"
try:
font_hud = pygame.font.Font(CHINESE_FONT_PATH, 22)
font_big = pygame.font.Font(CHINESE_FONT_PATH, 52)
font_mid = pygame.font.Font(CHINESE_FONT_PATH, 26)
font_sm = pygame.font.Font(CHINESE_FONT_PATH, 18)
except FileNotFoundError:
font_hud = pygame.font.SysFont("Arial", 20, bold=True)
# ...
优先加载系统宋体,这样中文能正常显示;万一路径不对,就回退到 SysFont,保证跨平台都能跑。
布局计算
网格尺寸会随关卡动态变化,所以每个方格的大小也需要实时算。布局函数 compute_layout 专门干这个事:
def compute_layout(cols):
area = SIZE - GAP * (cols + 1) # 可用像素宽度(扣除所有间距)
tw = area // cols # 单格宽度
th = tw # 保持正方形
total_w = cols * tw + GAP * (cols + 1)
ox = (SIZE - total_w) // 2 # 水平居中偏移
return tw, th, ox
固定间距 GAP = 10,均匀分配可用宽度,整个网格水平居中。当网格从 3 列增加到 6 列时,方格边长会自动从约 160px 缩小到约 73px,始终填满同一区域。
而 tile_rect 则通过行列索引直接算出每个方格的像素坐标,供绘制和碰撞检测复用:
def tile_rect(row, col, cols, tile_w, tile_h, ox):
x = ox + GAP + col * (tile_w + GAP)
y = HUD_H + GAP + row * (tile_h + GAP)
return pygame.Rect(x, y, tile_w, tile_h)
核心类设计
粒子类(Particle)
跟打砖块游戏里的粒子效果类似,点击方格时触发小型爆炸动画,答对和答错用不同颜色区分:
class Particle:
def __init__(self, x, y, color):
self.vx = random.uniform(-2.5, 2.5)
self.vy = random.uniform(-3.5, 0.5)
self.life = 22
self.color = color
def update(self):
self.x += self.vx
self.y += self.vy
self.vy += 0.18 # 模拟重力
self.life -= 1
def draw(self, surf):
a = min(255, self.life * 11) # 透明度线性衰减
s = pygame.Surface((5, 5), pygame.SRCALPHA)
s.fill((*self.color[:3], a))
surf.blit(s, (int(self.x), int(self.y)))
答对生成青绿色粒子,答错生成红色粒子,颜色直接告诉玩家结果。
游戏主类(Game)
Game 类用状态机驱动整个流程,所有逻辑集中在一处,清晰又好扩展。
状态机设计:
reveal → input → correct → (下一关 reveal)
↘ wrong → gameover → restart / retry
五个状态各有各的绘制逻辑和事件响应方式,职责分明。
构造函数 __init__:
def __init__(self):
self.score = 0
self.best = 0
self.level = 0 # LEVELS 表格索引
self.particles = []
self._new_round()
新回合初始化 _new_round:
def _new_round(self):
cols, num_lit = LEVELS[min(self.level, len(LEVELS) - 1)]
self.cols = cols
self.num_lit = num_lit
self.tile_w, self.tile_h, self.ox = compute_layout(cols)
self.pattern = set(random.sample(range(cols * cols), num_lit))
self.clicked = set() # 玩家已点中的正确格
self.wrong_set = set() # 玩家点错的格
self.state = "reveal"
self.timer = time.time()
pattern 用 random.sample 从所有格子索引中无重复抽取 num_lit 个,保证每局图案随机且不重叠。clicked 和 wrong_set 分开存储,绘制时分颜色渲染。
重开与重试:
def _restart(self):
"""完全重开:分数和关卡归零。"""
self.score = 0
self.level = 0
self.particles = []
self._new_round()
def _retry(self):
"""再试本关:保留分数和最高分,重置图案。"""
self.particles = []
self._new_round()
两种重置策略分开处理,_retry 不修改 self.level,玩家可以在同一关卡反复练,不影响历史最高分。
事件处理 handle_events
def handle_events(self):
for event in pygame.event.get():
...
if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
if self.state == "input":
idx = self._cell_at(*event.pos)
if idx is not None and idx not in self.clicked and idx not in self.wrong_set:
if idx in self.pattern:
self.clicked.add(idx)
# 生成青绿粒子
if self.clicked == self.pattern:
self.score += self.num_lit * 10
self.state = "correct"
else:
self.wrong_set.add(idx)
# 生成红色粒子
self.state = "wrong"
点击逻辑分三层:① 点到有效格子、② 该格尚未被点过、③ 是否在答案集合中。用 self.clicked == self.pattern 集合相等判断是否全部答对,避免了逐一遍历。
单元格点击检测 _cell_at:
def _cell_at(self, mx, my):
for r in range(self.cols):
for c in range(self.cols):
rect = tile_rect(r, c, self.cols, self.tile_w, self.tile_h, self.ox)
if rect.collidepoint(mx, my):
return r * self.cols + c
return None
遍历所有格子矩形,找到鼠标位置对应的线性索引,与 pattern 集合中的索引格式一致。
核心更新 update
def update(self):
now = time.time()
if self.state == "reveal":
if now - self.timer >= REVEAL_SECS: # 展示 1.2 秒后切换
self.state = "input"
elif self.state == "correct":
if now - self.timer >= 0.7: # 短暂绿色反馈后进入下一关
self.level = min(self.level + 1, len(LEVELS) - 1)
self._new_round()
elif self.state == "wrong":
if now - self.timer >= 1.0: # 短暂红色反馈后显示结束画面
self.state = "gameover"
for p in self.particles[:]:
p.update()
if p.life <= 0:
self.particles.remove(p)
用 time.time() 计时,而不是帧计数,这样不管机器帧率多少,状态切换时间都是一致的。“答对”和“答错”都预留了一小段视觉反馈时间,画面不会突然跳变。
绘制方法 draw
倒计时进度条:
if self.state == "reveal":
remaining = max(0.0, REVEAL_SECS - (time.time() - self.timer))
bar_w = int((remaining / REVEAL_SECS) * (SIZE - 40))
pygame.draw.rect(screen, DIM, (20, y, SIZE - 40, 6), border_radius=3)
pygame.draw.rect(screen, REVEAL, (20, y, bar_w, 6), border_radius=3)
进度条的宽度跟剩余展示时间线性对应,实时缩短,给玩家一种“时间在跑”的紧迫感。
方格多状态渲染:
for idx in range(cols * cols):
r, c = divmod(idx, cols)
rect = tile_rect(r, c, cols, tw, th, ox)
pygame.draw.rect(screen, EMPTY, rect, border_radius=6) # 基础底色
if revealing and idx in self.pattern:
pygame.draw.rect(screen, REVEAL, rect, border_radius=6) # 金色展示
elif idx in self.clicked:
pygame.draw.rect(screen, CORRECT, rect, border_radius=6) # 青绿已答
elif idx in self.wrong_set:
pygame.draw.rect(screen, WRONG, rect, border_radius=6) # 红色答错
elif showing_answer and idx in self.pattern:
# 游戏结束时半透明显示正确答案
s = pygame.Surface((tw, th), pygame.SRCALPHA)
pygame.draw.rect(s, (*REVEAL, 120), (0, 0, tw, th), border_radius=6)
screen.blit(s, rect.topleft)
每个方格根据当前状态和所属集合选择渲染颜色,逻辑清晰。游戏结束时用半透明金色叠加显示正确答案,方便玩家对照学习。
鼠标悬停高亮:
if self.state == "input":
mx, my = pygame.mouse.get_pos()
if rect.collidepoint(mx, my) and idx not in self.clicked and idx not in self.wrong_set:
s = pygame.Surface((tw, th), pygame.SRCALPHA)
pygame.draw.rect(s, (255, 255, 255, 30), (0, 0, tw, th), border_radius=6)
screen.blit(s, rect.topleft)
仅在作答阶段、鼠标悬停在未点击格子上时叠加一个半透明白色高亮,交互反馈很轻,不会干扰信息。
结束画面按钮:
for btn, label, color in [
(btn_retry, "再试本关 Enter", ACTIVE),
(btn_restart, "重新开始 R", DIM),
]:
hover = btn.collidepoint(mx, my)
bg = tuple(min(255, v + 30) for v in color) if hover else color
pygame.draw.rect(screen, bg, btn, border_radius=8)
pygame.draw.rect(screen, WHITE, btn, width=1, border_radius=8)
鼠标悬停时按钮颜色各通道提亮 30,模拟简单的 hover 效果;同时按钮内显示对应的键盘快捷键,提醒玩家也能用键盘操作。
绘制顺序是:背景 → HUD → 网格底板 → 方格 → 粒子 → 状态遮罩 → 结束按钮,层次严格保证。
主循环 run:
def run(self):
while True:
self.handle_events()
self.update()
self.draw()
clock.tick(60)
固定 60 FPS,保证动画和计时器在不同性能的机器上表现一致。
全部代码
import pygame
import sys
import random
import time
pygame.init()
SIZE = 520
HUD_H = 70
screen = pygame.display.set_mode((SIZE, SIZE + HUD_H))
pygame.display.set_caption("记忆方格")
clock = pygame.time.Clock()
# ── Colors ──────────────────────────────────────────────────────────────────
BG = (12, 10, 18)
HUD_BG = (18, 14, 28)
GRID_BG = (22, 18, 34)
EMPTY = (35, 28, 55)
CORRECT = (93, 202, 165) # teal-green
WRONG = (226, 75, 74) # red
ACTIVE = (83, 74, 183) # indigo
REVEAL = (250,199, 117) # gold
WHITE = (230, 225, 210)
GRAY = (110, 100, 130)
DIM = (60, 52, 90)
CHINESE_FONT_PATH = r"C:/Windows/Fonts/simsun.ttc"
try:
font_hud = pygame.font.Font(CHINESE_FONT_PATH, 22)
font_big = pygame.font.Font(CHINESE_FONT_PATH, 52)
font_mid = pygame.font.Font(CHINESE_FONT_PATH, 26)
font_sm = pygame.font.Font(CHINESE_FONT_PATH, 18)
except FileNotFoundError:
font_hud = pygame.font.SysFont("Arial", 20, bold=True)
font_big = pygame.font.SysFont("Arial", 48, bold=True)
font_mid = pygame.font.SysFont("Arial", 24, bold=True)
font_sm = pygame.font.SysFont("Arial", 16)
# ── Difficulty table (grid_size, num_lit) ──────────────────────────────────
# Keep lit-ratio between ~20%-40% for good difficulty
LEVELS = [
(3, 2), # lv1 : 3×3, 2 lit
(3, 3), # lv2
(3, 4), # lv3
(4, 3), # lv4 : 4×4, 3 lit (grid grows)
(4, 4), # lv5
(4, 5), # lv6
(4, 6), # lv7
(5, 4), # lv8 : 5×5
(5, 5), # lv9
(5, 6), # lv10
(5, 7), # lv11
(6, 5), # lv12 : 6×6
(6, 6), # lv13
(6, 7), # lv14
(6, 8), # lv15
(6, 9), # lv16
]
REVEAL_SECS = 1.2 # how long to show the pattern
GAP = 10 # gap between tiles
def compute_layout(cols):
"""Return (tile_w, tile_h, offset_x) for a given grid size."""
area = SIZE - GAP * (cols + 1)
tw = area // cols
th = tw
total_w = cols * tw + GAP * (cols + 1)
ox = (SIZE - total_w) // 2
return tw, th, ox
def tile_rect(row, col, cols, tile_w, tile_h, ox):
x = ox + GAP + col * (tile_w + GAP)
y = HUD_H + GAP + row * (tile_h + GAP)
return pygame.Rect(x, y, tile_w, tile_h)
class Particle:
def __init__(self, x, y, color):
self.x = float(x)
self.y = float(y)
self.vx = random.uniform(-2.5, 2.5)
self.vy = random.uniform(-3.5, 0.5)
self.life = 22
self.color = color
def update(self):
self.x += self.vx
self.y += self.vy
self.vy += 0.18
self.life -= 1
def draw(self, surf):
if self.life <= 0: return
a = min(255, self.life * 11)
s = pygame.Surface((5, 5), pygame.SRCALPHA)
s.fill((*self.color[:3], a))
surf.blit(s, (int(self.x), int(self.y)))
class Game:
def __init__(self):
self.score = 0
self.best = 0
self.level = 0 # index into LEVELS
self.particles = []
self._new_round()
# ── State machine ──────────────────────────────────────────────────────
# state: "reveal" → showing pattern
# "input" → waiting for player clicks
# "correct" → brief green flash
# "wrong" → brief red flash
# "gameover"
def _restart(self):
"""Full restart: score and level reset."""
self.score = 0
self.level = 0
self.particles = []
self._new_round()
def _retry(self):
"""Same level, keep score and best."""
self.particles = []
self._new_round()
def _new_round(self):
cols, num_lit = LEVELS[min(self.level, len(LEVELS) - 1)]
self.cols = cols
self.num_lit = num_lit
self.tile_w, self.tile_h, self.ox = compute_layout(cols)
self.pattern = set(random.sample(range(cols * cols), num_lit))
self.clicked = set()
self.wrong_set = set()
self.state = "reveal"
self.timer = time.time()
self.flash_alpha = 0
def _cell_at(self, mx, my):
"""Return (row, col) or None."""
cols = self.cols
for r in range(cols):
for c in range(cols):
rect = tile_rect(r, c, cols, self.tile_w, self.tile_h, self.ox)
if rect.collidepoint(mx, my):
return r * cols + c
return None
def _btn_rects(self):
"""Return (btn_restart_rect, btn_retry_rect) for the gameover overlay."""
cx = SIZE // 2
cy = HUD_H + SIZE // 2
bw, bh = 160, 38
gap = 20
btn_retry = pygame.Rect(cx - bw - gap // 2, cy + 60, bw, bh)
btn_restart = pygame.Rect(cx + gap // 2, cy + 60, bw, bh)
return btn_restart, btn_retry
def handle_events(self):
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit(); sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_r:
self._restart()
if event.key == pygame.K_RETURN and self.state == "gameover":
self._retry()
if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
if self.state == "input":
idx = self._cell_at(*event.pos)
if idx is not None and idx not in self.clicked and idx not in self.wrong_set:
if idx in self.pattern:
self.clicked.add(idx)
cols = self.cols
r, c = divmod(idx, cols)
rect = tile_rect(r, c, cols, self.tile_w, self.tile_h, self.ox)
for _ in range(10):
self.particles.append(Particle(rect.centerx, rect.centery, CORRECT))
if self.clicked == self.pattern:
self.score += self.num_lit * 10
if self.score > self.best: self.best = self.score
self.state = "correct"
self.timer = time.time()
else:
self.wrong_set.add(idx)
cols = self.cols
r, c = divmod(idx, cols)
rect = tile_rect(r, c, cols, self.tile_w, self.tile_h, self.ox)
for _ in range(10):
self.particles.append(Particle(rect.centerx, rect.centery, WRONG))
self.state = "wrong"
self.timer = time.time()
elif self.state == "gameover":
btn_restart, btn_retry = self._btn_rects()
if btn_restart.collidepoint(event.pos):
self._restart()
elif btn_retry.collidepoint(event.pos):
self._retry()
def update(self):
now = time.time()
if self.state == "reveal":
if now - self.timer >= REVEAL_SECS:
self.state = "input"
elif self.state == "correct":
if now - self.timer >= 0.7:
self.level = min(self.level + 1, len(LEVELS) - 1)
self._new_round()
elif self.state == "wrong":
if now - self.timer >= 1.0:
# show correct pattern then game over
self.state = "gameover"
for p in self.particles[:]:
p.update()
if p.life <= 0:
self.particles.remove(p)
def draw(self):
screen.fill(BG)
cols = self.cols
tw, th, ox = self.tile_w, self.tile_h, self.ox
# ── HUD ─────────────────────────────────────────────────────────────
pygame.draw.rect(screen, HUD_BG, (0, 0, SIZE, HUD_H))
pygame.draw.line(screen, ACTIVE, (0, HUD_H), (SIZE, HUD_H), 1)
screen.blit(font_hud.render("记忆方格", True, REVEAL), (14, 10))
lv_text = f"LV {self.level + 1} ({cols}×{cols} {self.num_lit}格)"
screen.blit(font_hud.render(lv_text, True, WHITE), (14, 38))
screen.blit(font_hud.render(f"得分 {self.score}", True, WHITE), (SIZE // 2 - 50, 10))
screen.blit(font_hud.render(f"最高 {self.best}", True, GRAY), (SIZE // 2 - 50, 38))
screen.blit(font_sm.render("R=重开", True, GRAY), (SIZE - 70, 42))
# ── Grid background ──────────────────────────────────────────────────
grid_total_h = cols * (th + GAP) + GAP
grid_rect = pygame.Rect(ox - 2, HUD_H + GAP - 2,
cols * (tw + GAP) + GAP + 4,
grid_total_h + 4)
pygame.draw.rect(screen, GRID_BG, grid_rect, border_radius=10)
revealing = self.state == "reveal"
showing_answer = self.state in ("wrong", "gameover")
# ── Tiles ────────────────────────────────────────────────────────────
for idx in range(cols * cols):
r, c = divmod(idx, cols)
rect = tile_rect(r, c, cols, tw, th, ox)
# base slot
pygame.draw.rect(screen, EMPTY, rect, border_radius=6)
if revealing and idx in self.pattern:
pygame.draw.rect(screen, REVEAL, rect, border_radius=6)
elif self.state == "input" or self.state in ("correct","wrong","gameover"):
if idx in self.clicked:
pygame.draw.rect(screen, CORRECT, rect, border_radius=6)
elif idx in self.wrong_set:
pygame.draw.rect(screen, WRONG, rect, border_radius=6)
elif showing_answer and idx in self.pattern:
# dim reveal of correct answer
s = pygame.Surface((tw, th), pygame.SRCALPHA)
pygame.draw.rect(s, (*REVEAL, 120), (0, 0, tw, th), border_radius=6)
screen.blit(s, rect.topleft)
# hover highlight in input state
if self.state == "input":
mx, my = pygame.mouse.get_pos()
if rect.collidepoint(mx, my) and idx not in self.clicked and idx not in self.wrong_set:
s = pygame.Surface((tw, th), pygame.SRCALPHA)
pygame.draw.rect(s, (255, 255, 255, 30), (0, 0, tw, th), border_radius=6)
screen.blit(s, rect.topleft)
# ── Particles ────────────────────────────────────────────────────────
for p in self.particles:
p.draw(screen)
# ── Status overlays ──────────────────────────────────────────────────
if self.state == "reveal":
remaining = max(0.0, REVEAL_SECS - (time.time() - self.timer))
bar_w = int((remaining / REVEAL_SECS) * (SIZE - 40))
pygame.draw.rect(screen, DIM, (20, HUD_H + grid_total_h + GAP * 2 + 4, SIZE - 40, 6), border_radius=3)
pygame.draw.rect(screen, REVEAL, (20, HUD_H + grid_total_h + GAP * 2 + 4, bar_w, 6), border_radius=3)
label = font_sm.render("记住这些方格!", True, REVEAL)
screen.blit(label, (SIZE // 2 - label.get_width() // 2,
HUD_H + grid_total_h + GAP * 2 + 14))
elif self.state == "input":
left = self.num_lit - len(self.clicked)
label = font_sm.render(f"还需选 {left} 个方格", True, GRAY)
screen.blit(label, (SIZE // 2 - label.get_width() // 2, SIZE + HUD_H - 28))
elif self.state == "correct":
overlay = pygame.Surface((SIZE, SIZE), pygame.SRCALPHA)
overlay.fill((93, 202, 165, 40))
screen.blit(overlay, (0, HUD_H))
t = font_mid.render("✓ 全部正确!", True, CORRECT)
screen.blit(t, (SIZE // 2 - t.get_width() // 2, HUD_H + SIZE // 2 - 20))
elif self.state in ("wrong", "gameover"):
overlay = pygame.Surface((SIZE, SIZE), pygame.SRCALPHA)
overlay.fill((226, 75, 74, 35))
screen.blit(overlay, (0, HUD_H))
if self.state == "gameover":
overlay2 = pygame.Surface((SIZE, SIZE), pygame.SRCALPHA)
overlay2.fill((12, 10, 18, 180))
screen.blit(overlay2, (0, HUD_H))
t1 = font_big.render("GAME OVER", True, WRONG)
t2 = font_hud.render(f"得分 {self.score} 最高 {self.best}", True, WHITE)
cx = SIZE // 2
cy = HUD_H + SIZE // 2
screen.blit(t1, (cx - t1.get_width() // 2, cy - 80))
screen.blit(t2, (cx - t2.get_width() // 2, cy - 10))
btn_restart, btn_retry = self._btn_rects()
mx, my = pygame.mouse.get_pos()
for btn, label, color in [
(btn_retry, "再试本关 Enter", ACTIVE),
(btn_restart, "重新开始 R", DIM),
]:
hover = btn.collidepoint(mx, my)
bg = tuple(min(255, v + 30) for v in color) if hover else color
pygame.draw.rect(screen, bg, btn, border_radius=8)
pygame.draw.rect(screen, WHITE, btn, width=1, border_radius=8)
txt = font_sm.render(label, True, WHITE)
screen.blit(txt, (btn.centerx - txt.get_width() // 2,
btn.centery - txt.get_height() // 2))
pygame.display.flip()
def run(self):
while True:
self.handle_events()
self.update()
self.draw()
clock.tick(60)
if __name__ == "__main__":
Game().run()
Windows 10 是一款微软推出的经典操作系统,拥有硬件兼容性与多任务处理能力。它更偏向把系统状态查看和常用调节动作放在一起,适合需要持续观察和微调设备状态的场景。
极度公式是一款跨平台专业LaTeX公式识别编辑软件,支持OCR公式识别和多平台编辑。和使用说明,避免使用,享受完整功能与稳定支持。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。
















