最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Python基于Pygame開發(fā)的記憶訓練小游戲

 更新時間:2026年06月15日 08:48:30   作者:Wang ruoxi  
Pygame 是 Python 中一個功能強大的 2D 游戲開發(fā)庫,它提供了處理圖形、聲音、輸入和事件循環(huán)的完整工具集,本文通過 Pygame 實現(xiàn)一個經(jīng)典記憶類小游戲——記憶方格(Memory Grid),需要的朋友可以參考下

項目概述

Pygame 是 Python 中一個功能強大的 2D 游戲開發(fā)庫,它提供了處理圖形、聲音、輸入和事件循環(huán)的完整工具集。本文通過 Pygame 實現(xiàn)一個經(jīng)典記憶類小游戲——記憶方格(Memory Grid)。

在這個游戲中,玩家需要在短暫的展示時間內(nèi)記住網(wǎng)格中高亮的方格位置,隨后在空白網(wǎng)格上點擊還原出相同的圖案。隨著關(guān)卡推進,網(wǎng)格尺寸從 3×3 逐漸擴大到 6×6,高亮方格數(shù)量也隨之增加,對短期記憶的挑戰(zhàn)不斷加深。其中:

  • 記憶階段:每輪開始時,目標方格以金色高亮顯示 1.2 秒,同時屏幕底部顯示倒計時進度條,提醒玩家抓緊記憶。
  • 作答階段:高亮消失后,玩家逐一點擊認為正確的方格;點中則變?yōu)榍嗑G色并觸發(fā)粒子爆炸,點錯則變?yōu)榧t色并立即結(jié)束本輪。
  • 關(guān)卡遞進:全部點對后自動進入下一關(guān),難度沿預設表格線性提升——先增加高亮數(shù)量,再擴大網(wǎng)格尺寸,共 16 級。
  • 得分規(guī)則:每關(guān)得分為 高亮方格數(shù) × 10,方格越多單關(guān)分值越高,最高分跨局保留。
  • 失敗處理:點錯即游戲結(jié)束,結(jié)束畫面同時展示正確圖案(半透明金色),并提供"再試本關(guān)"和"重新開始"兩個選項。
  • 鍵盤操作:R:重新開始;Enter:再試本關(guān)(僅游戲結(jié)束時有效)。

游戲?qū)崿F(xiàn)

初始化與基礎設置

游戲啟動時初始化 Pygame 并定義屏幕尺寸和 HUD 高度。

pygame.init()

SIZE  = 520
HUD_H = 70
screen = pygame.display.set_mode((SIZE, SIZE + HUD_H))
pygame.display.set_caption("記憶方格")
clock  = pygame.time.Clock()

游戲區(qū)為 520×520 像素的正方形,頂部 70 像素作為 HUD 信息欄,總窗口高度為 590 像素。

顏色定義

BG      = (12,  10,  18)    # 全局深色背景
HUD_BG  = (18,  14,  28)    # HUD 背景
GRID_BG = (22,  18,  34)    # 網(wǎng)格背景板
EMPTY   = (35,  28,  55)    # 空格底色
CORRECT = (93,  202, 165)   # 答對顏色(青綠)
WRONG   = (226,  75,  74)   # 答錯顏色(紅)
ACTIVE  = (83,   74, 183)   # 強調(diào)色(靛藍)
REVEAL  = (250, 199, 117)   # 展示階段高亮色(金)
WHITE   = (230, 225, 210)   # 主文字
GRAY    = (110, 100, 130)   # 次要文字
DIM     = (60,   52,  90)   # 暗色按鈕底色

整體采用深紫色調(diào)背景,以金色(展示)、青綠色(正確)、紅色(錯誤)三種功能色形成清晰的視覺語義。

難度表格

LEVELS = [
    (3, 2),   # lv1 : 3×3, 2 個高亮格
    (3, 3),   # lv2
    (3, 4),   # lv3
    (4, 3),   # lv4 : 網(wǎng)格擴大至 4×4
    (4, 4),   # lv5
    # ...共 16 級
    (6, 9),   # lv16: 6×6, 9 個高亮格
]

每個元素為 (grid_size, num_lit) 二元組,高亮比例始終維持在 20%~40%,保證難度循序漸進而不失可玩性。關(guān)卡數(shù)超過表格長度時自動停留在最高難度。

字體加載

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)
    # ...

優(yōu)先加載系統(tǒng)宋體以支持中文;若路徑不存在則回退到 SysFont,保證跨平臺兼容性。

布局計算

網(wǎng)格尺寸隨關(guān)卡動態(tài)變化,因此方格大小需要實時計算。

布局函數(shù) 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 均勻分配可用寬度,水平居中整個網(wǎng)格。網(wǎng)格尺寸從 3 增大到 6 時,方格邊長自動從約 160px 縮小至約 73px,始終填滿同一區(qū)域。

方格矩形 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)

與打磚塊游戲中的粒子效果類似,點擊方格時觸發(fā)小型爆炸粒子動畫,根據(jù)答對或答錯使用不同顏色。

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 類通過狀態(tài)機驅(qū)動整個流程,所有邏輯集中在一處。

狀態(tài)機設計

reveal → input → correct → (下一關(guān) reveal)
                ↘ wrong → gameover → restart / retry

游戲共有 5 個狀態(tài),每個狀態(tài)決定繪制內(nèi)容和事件響應方式,職責清晰,擴展方便。

構(gòu)造函數(shù) __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 個,保證每局圖案隨機且不重疊。clickedwrong_set 分開存儲,方便繪制時分顏色渲染。

重開與重試

def _restart(self):
    """完全重開:分數(shù)和關(guān)卡歸零。"""
    self.score = 0
    self.level = 0
    self.particles = []
    self._new_round()

def _retry(self):
    """再試本關(guān):保留分數(shù)和最高分,重置圖案。"""
    self.particles = []
    self._new_round()

兩種重置策略分離設計,_retry 不修改 self.level,使玩家可以在同一關(guān)卡反復練習,同時不影響歷史最高分。

事件處理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

遍歷所有格子矩形,找到鼠標點擊位置對應的格子線性索引。返回值為 行 × 列數(shù) + 列,與 pattern 集合中的索引格式統(tǒng)一。

核心更新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:            # 短暫綠色反饋后進入下一關(guān)
            self.level = min(self.level + 1, len(LEVELS) - 1)
            self._new_round()
    elif self.state == "wrong":
        if now - self.timer >= 1.0:            # 短暫紅色反饋后顯示結(jié)束畫面
            self.state = "gameover"

    for p in self.particles[:]:
        p.update()
        if p.life <= 0:
            self.particles.remove(p)

使用 time.time() 計時而非幀計數(shù),保證在不同幀率環(huán)境下狀態(tài)切換時間一致。"答對"和"答錯"各保留一段短暫的視覺反饋時間,再執(zhí)行后續(xù)狀態(tài)跳轉(zhuǎn),避免畫面突兀切換。

繪制方法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)

進度條寬度與剩余展示時間線性對應,實時縮短,給玩家直觀的時間壓力感。

方格多狀態(tài)渲染

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:
        # 游戲結(jié)束時半透明顯示正確答案
        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)

每個方格根據(jù)當前狀態(tài)和所屬集合(pattern/clicked/wrong_set)選擇渲染顏色,邏輯清晰。游戲結(jié)束時以半透明金色疊加顯示正確答案,幫助玩家對照學習。

鼠標懸停高亮

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)

僅在作答階段、鼠標懸停于未點擊格時疊加 30/255 透明度的白色高亮,提供輕微的交互反饋,不干擾游戲信息。

結(jié)束畫面按鈕

for btn, label, color in [
    (btn_retry,   "再試本關(guān)  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 效果;同時在按鈕內(nèi)顯示對應的鍵盤快捷鍵,提示玩家也可用鍵盤操作。

繪制順序為:背景 → HUD → 網(wǎng)格底板 → 方格 → 粒子 → 狀態(tài)遮罩 → 結(jié)束按鈕,嚴格保證層次正確。

主循環(huán) run

def run(self):
    while True:
        self.handle_events()
        self.update()
        self.draw()
        clock.tick(60)

固定 60 FPS,保證動畫和計時器在不同性能機器上表現(xiàn)一致。

全部代碼

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,   "再試本關(guān)  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()

以上就是Python基于Pygame開發(fā)的記憶訓練小游戲的詳細內(nèi)容,更多關(guān)于Python Pygame記憶訓練游戲的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Python標準庫os常用函數(shù)和屬性詳解

    Python標準庫os常用函數(shù)和屬性詳解

    os模塊是Python標準庫中的一個用于訪問操作系統(tǒng)相關(guān)功能的模塊,os模塊提供了一種可移植的使用操作系統(tǒng)功能的方法,本文給大家介紹下?OS標準庫常用函數(shù)和屬性,感興趣的朋友跟隨小編一起看看吧
    2022-11-11
  • Pytorch保存模型用于測試和用于繼續(xù)訓練的區(qū)別詳解

    Pytorch保存模型用于測試和用于繼續(xù)訓練的區(qū)別詳解

    今天小編就為大家分享一篇Pytorch保存模型用于測試和用于繼續(xù)訓練的區(qū)別詳解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-01-01
  • PyQt5中QTableWidget如何彈出菜單的示例代碼

    PyQt5中QTableWidget如何彈出菜單的示例代碼

    這篇文章主要介紹了PyQt5中QTableWidget如何彈出菜單的示例代碼,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-02-02
  • 基于python requests庫中的代理實例講解

    基于python requests庫中的代理實例講解

    今天小編就為大家分享一篇基于python requests庫中的代理實例講解,具有很好的參考價值。希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-05-05
  • Python判斷一個目錄下哪些是文件哪些是文件夾的方法

    Python判斷一個目錄下哪些是文件哪些是文件夾的方法

    本文介紹Python中識別目錄文件及文件夾的完整方案,支持跨平臺路徑處理、文件屬性分析(類型/大小/時間)、遞歸掃描、統(tǒng)計匯總,并提供彩色樹形輸出與錯誤處理功能,滿足多樣化需求,需要的朋友可以參考下
    2025-09-09
  • 一文淺析Python中常用的魔法函數(shù)使用指南

    一文淺析Python中常用的魔法函數(shù)使用指南

    Python中的魔法函數(shù)(Magic Methods),也稱為雙下劃線方法(dunder methods),是Python面向?qū)ο缶幊痰暮诵臋C制之一,本文將全面介紹這些魔法函數(shù),助你寫出更Pythonic的代碼
    2025-12-12
  • Python函數(shù)式編程藝術(shù)之修飾器運用場景探索

    Python函數(shù)式編程藝術(shù)之修飾器運用場景探索

    本文將詳細介紹Python修飾器的概念,提供詳細的示例,并介紹如何使用它們來優(yōu)化和擴展代碼,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-11-11
  • Python 基于wxpy庫實現(xiàn)微信添加好友功能(簡潔)

    Python 基于wxpy庫實現(xiàn)微信添加好友功能(簡潔)

    這篇文章主要介紹了Python 基于wxpy庫實現(xiàn)微信添加好友功能,本文給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下
    2019-11-11
  • Python腳本連接MySQL數(shù)據(jù)庫的完整指南

    Python腳本連接MySQL數(shù)據(jù)庫的完整指南

    本文將詳細展示如何使用Python及其pymysql庫來連接MySQL數(shù)據(jù)庫并執(zhí)行SQL語句,除了基本查詢外,還會介紹如何進行數(shù)據(jù)的插入,更新和刪除操作,感興趣的小伙伴可以跟隨小編一起學習一下
    2026-01-01
  • Python使用pickle模塊實現(xiàn)序列化功能示例

    Python使用pickle模塊實現(xiàn)序列化功能示例

    這篇文章主要介紹了Python使用pickle模塊實現(xiàn)序列化功能,結(jié)合實例形式分析了基于pickle模塊的序列化操作相關(guān)操作技巧,需要的朋友可以參考下
    2018-07-07

最新評論

徐水县| 宝鸡市| 琼结县| 连江县| 吴堡县| 晋宁县| 攀枝花市| 安丘市| 汉沽区| 会泽县| 鸡泽县| 诸暨市| 湟中县| 酒泉市| 天津市| 眉山市| 梨树县| 江川县| 阿巴嘎旗| 闻喜县| 贡觉县| 辉南县| 博爱县| 兴安盟| 祁阳县| 沧源| 无为县| 古交市| 庆安县| 大姚县| 黄山市| 西昌市| 临高县| 繁昌县| 哈密市| 九龙县| 河西区| 肥西县| 定日县| 台江县| 聂拉木县|