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个按钮激活
修改方案
核心逻辑是新增统一的实例管理容器,在激活任意按钮前先重置所有按钮的激活状态,再激活当前按钮,具体修改如下:
- 给
Arrow类新增类属性all_arrows,统一存储所有创建的箭头实例,初始化实例时自动将实例加入该列表,同时修复原代码中重复定义active属性、循环变量与坐标属性重名的冗余问题 - 修改按钮激活逻辑:当点击未激活的当前按钮时,先遍历所有箭头实例将
active属性置为0,再将当前按钮设为激活状态 - 主循环中遍历统一实例列表绘制按钮,简化代码
修改后完整代码
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
相关产品推荐
相关产品推荐

