You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

树莓派Python投票游戏界面停留与GPIO按键响应问题求助

问题原因

你现在的代码有3个核心错误,直接导致页面停留、按键响应逻辑失效:

  • 把整个游戏流程全写在了GPIO中断回调函数里:RPi.GPIO的事件回调运行在独立子线程,和pygame的主线程UI渲染存在线程冲突,而且回调里嵌套多层无退出条件的while True死循环,会直接打乱正常的页面流转顺序
  • 用了不存在的API:RPi.GPIO没有BUTTON_1.is_pressed这种调用方式,读取引脚电平必须用GPIO2.input(引脚编号)方法
  • 页面等待逻辑没有阻塞控制:你写的等待按键的循环没有正确的跳出判断,跑起来之后会直接滑过所有页面,没法停在投票页等输入
修复思路

不要在GPIO中断回调里写任何UI、流程跳转逻辑,回调只负责做「按键被按下」的标记。所有页面渲染、状态跳转全放在pygame主线程实现,用状态机标记当前所处的页面阶段,每个阶段只做对应操作:

  • 介绍页状态:持续渲染介绍页,检测到任意按键按下就切到第一题投票状态
  • 投票页状态:持续渲染当前投票题页面,检测到对应按键按下就更新投票计数,切到单题结果状态
  • 单题结果状态:渲染当前题的投票结果,停留固定时长后自动切到下一题投票状态;如果已经是最后一题就切到总榜状态
  • 总榜状态:渲染全量统计结果,停留固定时长后自动切回介绍页状态
修复后的代码框架
import RPi.GPIO as GPIO2
import time
import pygame

# 硬件配置
BUTTON_1 = 3
BUTTON_2 = 5 
BOUNCE_TIME = 200
GPIO2.setmode(GPIO2.BOARD)
GPIO2.setup(BUTTON_1, GPIO2.IN, pull_up_down=GPIO2.PUD_UP)
GPIO2.setup(BUTTON_2, GPIO2.IN, pull_up_down=GPIO2.PUD_UP)

# pygame初始化
pygame.init()
WIDTH = 1900
HEIGHT = 1000
display = pygame.display.set_mode((WIDTH, HEIGHT))
clock = pygame.time.Clock()

# 资源加载
intro = pygame.image.load('intro.png')
voting_pages = [pygame.image.load('voting1.png')] # 后续可以加voting2.png、voting3.png...
result_show_time = 3000 # 单题结果停留3秒,单位毫秒
final_show_time = 5000 # 总榜停留5秒,单位毫秒

# 全局状态标记
key_pressed = None # 取值:None/BUTTON_1/BUTTON_2
current_state = "INTRO" # 状态:INTRO/VOTING/RESULT/FINAL
current_vote_index = 0
state_start_tick = 0
vote_counts = [] # 存每道题两个选项的票数

# 按键回调:只做按键标记,不写任何业务逻辑
def button_callback(channel):
    global key_pressed
    # 消抖判断,确保按键是按下状态
    if GPIO2.input(channel) == GPIO2.LOW:
        key_pressed = channel

GPIO2.add_event_detect(BUTTON_1, GPIO2.FALLING, callback=button_callback, bouncetime=BOUNCE_TIME)
GPIO2.add_event_detect(BUTTON_2, GPIO2.FALLING, callback=button_callback, bouncetime=BOUNCE_TIME)

try:
    while True:
        # 处理pygame内置退出事件
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                raise KeyboardInterrupt

        # 清空画布
        display.fill((125,125,125))

        # 状态机流转
        if current_state == "INTRO":
            # 渲染介绍页
            display.blit(intro, (0,0))
            # 检测到任意按键,切到第一题投票
            if key_pressed in (BUTTON_1, BUTTON_2):
                key_pressed = None
                current_vote_index = 0
                vote_counts = [[0,0] for _ in voting_pages]
                current_state = "VOTING"
                state_start_tick = pygame.time.get_ticks()

        elif current_state == "VOTING":
            # 渲染当前投票题页面
            display.blit(voting_pages[current_vote_index], (0,0))
            # 检测投票按键
            if key_pressed == BUTTON_1:
                key_pressed = None
                vote_counts[current_vote_index][0] += 1
                # 这里加渲染第一题选1的结果页逻辑
                current_state = "RESULT"
                state_start_tick = pygame.time.get_ticks()
            elif key_pressed == BUTTON_2:
                key_pressed = None
                vote_counts[current_vote_index][1] += 1
                # 这里加渲染第一题选2的结果页逻辑
                current_state = "RESULT"
                state_start_tick = pygame.time.get_ticks()

        elif current_state == "RESULT":
            # 这里放你已经调试好的单题结果渲染逻辑
            # 停留时间到了就跳转
            if pygame.time.get_ticks() - state_start_tick >= result_show_time:
                current_vote_index += 1
                if current_vote_index >= len(voting_pages):
                    # 所有题投完,切总榜
                    current_state = "FINAL"
                else:
                    # 切下一题
                    current_state = "VOTING"
                state_start_tick = pygame.time.get_ticks()

        elif current_state == "FINAL":
            # 这里放你已经调试好的高分榜/总统计结果渲染逻辑
            # 停留时间到了切回介绍页
            if pygame.time.get_ticks() - state_start_tick >= final_show_time:
                current_state = "INTRO"
                state_start_tick = pygame.time.get_ticks()

        # 更新显示,控制帧率60,避免CPU占满
        pygame.display.update()
        clock.tick(60)

except KeyboardInterrupt:
    GPIO2.cleanup()
    pygame.quit()
注意事项
  • 按键接线要对应上拉/下拉配置,代码里开了内部上拉,按键要接在GPIO引脚和GND之间,按下时引脚读低电平,如果你是接3.3V的话改下输入检测逻辑就行
  • 你之前调试好的计数、文本渲染逻辑,直接对应填到RESULT和FINAL状态的渲染位置即可,不需要改动原有逻辑
  • 所有和pygame显示、更新相关的代码全放在主线程的循环里,不要放到子线程或者回调里,不然会出现随机的显示崩溃问题

内容的提问来源于stack exchange,提问作者chawancut

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.31 10:24:14