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

Pygame Arrow类按钮点击激活时自动禁用其他按钮实现方法

飞船模拟器箭头按钮互斥激活实现

问题背景

开发*Space Ship Simulator(飞船模拟器)*项目时,自定义Arrow类创建了4个箭头形状的交互按钮,需要实现按钮单选互斥效果,初始代码存在多按钮可同时激活的问题。

初始实现代码

from pygame.locals import *
pygame.init()

SCR_WIDTH = 700
SCR_HEIGHT = 900

screen = pygame.display.set_mode((SCR_WIDTH, SCR_HEIGHT))
pygame.display.set_caption("Space Ship Simulator")

# 资源加载
bg_image = pygame.image.load("img/space_background.jpg")
bg_image = pygame.transform.scale(bg_image, (SCR_WIDTH, SCR_HEIGHT))
ss_board = pygame.image.load("img/spaceship_board.png")


class Arrow:
    def __init__(self, degree, x, y):
        self.degree = degree
        self.active = 0
        self.arrow_list = []
        self.x = x
        self.y = y
        self.active = 0
        self.released = True
        # 箭头颜色: R: 0, G: 234, B: 0
        for x in range(2):
            img = pygame.image.load(f"img/arrow_{x}.png")
            self.arrow_list.append(img)

        self.image = pygame.transform.rotate(self.arrow_list[self.active], self.degree)
        self.width = self.image.get_width()
        self.height = self.image.get_height()
        self.rect = Rect((self.x, self.y), (self.width, self.height))

    def draw(self):
        # 获取鼠标位置
        mouse_pos = pygame.mouse.get_pos()

        # 检测鼠标悬停和点击状态
        if self.rect.collidepoint(mouse_pos):
            if pygame.mouse.get_pressed()[0] == 1 and self.active == 0 and self.released:
                self.active = 1
                self.released = False
                print('Active')

            if pygame.mouse.get_pressed()[0] == 0:
                self.released = True

            if self.active and self.released:
                if pygame.mouse.get_pressed()[0] == 1:
                    self.active = 0
                    print('Inactive')
                    self.released = False

        # 绘制箭头到屏幕
        self.image = pygame.transform.rotate(self.arrow_list[self.active], self.degree)
        screen.blit(self.image, (self.x, self.y))


arrowRight = Arrow(0, 553, 700)
arrowLeft = Arrow(180, 425, 700)
arrowUp = Arrow(91, 440, 776)
arrowDown = Arrow(271, 557, 779)

run = True
while run:
    # 绘制背景
    screen.blit(bg_image, (0, 0))
    screen.blit(ss_board, (0, 200))

    # 绘制箭头按钮
    arrowRight.draw()
    arrowLeft.draw()
    arrowUp.draw()
    arrowDown.draw()

    # 事件处理
    for event in pygame.event.get():
        # 退出游戏
        if event.type == pygame.QUIT:
            run = False
    pygame.display.update()
pygame.quit()

功能需求

  • 点击已处于激活状态的按钮时,将其切换为非激活状态(该功能初始代码已实现)
  • 点击未激活的按钮时,首先将该按钮切换为激活状态,同时自动将其余所有已激活的按钮切换为非激活状态,保证同一时间最多1个按钮激活

修改方案

核心逻辑是新增统一的实例管理容器,在激活任意按钮前先重置所有按钮的激活状态,再激活当前按钮,具体修改如下:

  1. 给Arrow类新增类属性all_arrows,统一存储所有创建的箭头实例,初始化实例时自动将实例加入该列表,同时修复原代码中重复定义active属性、循环变量与坐标属性重名的冗余问题
  2. 修改按钮激活逻辑:当点击未激活的当前按钮时,先遍历所有箭头实例将active属性置为0,再将当前按钮设为激活状态
  3. 主循环中遍历统一实例列表绘制按钮,简化代码

修改后完整代码

from pygame.locals import *
pygame.init()

SCR_WIDTH = 700
SCR_HEIGHT = 900

screen = pygame.display.set_mode((SCR_WIDTH, SCR_HEIGHT))
pygame.display.set_caption("Space Ship Simulator")

# 资源加载
bg_image = pygame.image.load("img/space_background.jpg")
bg_image = pygame.transform.scale(bg_image, (SCR_WIDTH, SCR_HEIGHT))
ss_board = pygame.image.load("img/spaceship_board.png")


class Arrow:
    all_arrows = [] # 类级别的实例管理列表
    def __init__(self, degree, x, y):
        self.degree = degree
        self.arrow_list = []
        self.x = x
        self.y = y
        self.active = 0
        self.released = True
        # 加载箭头状态图片,修改循环变量名避免和坐标属性冲突
        for i in range(2):
            img = pygame.image.load(f"img/arrow_{i}.png")
            self.arrow_list.append(img)

        self.image = pygame.transform.rotate(self.arrow_list[self.active], self.degree)
        self.width = self.image.get_width()
        self.height = self.image.get_height()
        self.rect = Rect((self.x, self.y), (self.width, self.height))
        # 将当前实例加入统一管理列表
        Arrow.all_arrows.append(self)

    def draw(self):
        mouse_pos = pygame.mouse.get_pos()

        if self.rect.collidepoint(mouse_pos):
            # 点击未激活按钮逻辑:先重置所有按钮状态,再激活当前
            if pygame.mouse.get_pressed()[0] == 1 and self.active == 0 and self.released:
                for arrow in Arrow.all_arrows:
                    arrow.active = 0
                self.active = 1
                self.released = False
                print('Active')

            if pygame.mouse.get_pressed()[0] == 0:
                self.released = True

            # 保留原有的点击已激活按钮取消激活逻辑
            if self.active and self.released:
                if pygame.mouse.get_pressed()[0] == 1:
                    self.active = 0
                    print('Inactive')
                    self.released = False

        self.image = pygame.transform.rotate(self.arrow_list[self.active], self.degree)
        screen.blit(self.image, (self.x, self.y))


# 创建箭头实例,会自动加入all_arrows列表
arrowRight = Arrow(0, 553, 700)
arrowLeft = Arrow(180, 425, 700)
arrowUp = Arrow(91, 440, 776)
arrowDown = Arrow(271, 557, 779)

run = True
while run:
    screen.blit(bg_image, (0, 0))
    screen.blit(ss_board, (0, 200))

    # 遍历绘制所有箭头
    for arrow in Arrow.all_arrows:
        arrow.draw()

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False
    pygame.display.update()
pygame.quit()

修改说明

  • 互斥逻辑生效:点击任意未激活按钮时,其余按钮会自动重置为非激活状态,不会出现多按钮同时激活的问题
  • 原有功能保留:点击已激活的按钮仍然可以正常将其切换为非激活状态
  • 代码冗余清理:移除了重复的self.active = 0定义,修改了图片加载循环的变量名,避免潜在的命名冲突问题

内容的提问来源于stack exchange,提问作者Abdullah Bera Koksal

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 10:18:44