【问题标题】:Pygame mouse clicking detectionPygame鼠标点击检测
【发布时间】:2021-09-06 04:01:06
【问题描述】:

我想知道如何编写检测鼠标点击精灵的代码。例如:

if #Function that checks for mouse clicked on Sprite:
    print ("You have opened a chest!")

【问题讨论】:

    标签: python mouseevent pygame


    【解决方案1】:

    The pygame documentation for mouse events is here.

    您可以将pygame.mouse.get_pressed 方法与pygame.mouse.get_pos 结合使用(如果需要)。

    请记住通过主事件循环使用鼠标单击事件。事件循环更好的原因是“短点击”。在普通机器上您可能不会注意到这些,但在触控板上使用轻击点击的计算机的点击周期过短。使用鼠标事件可以防止这种情况发生。

    编辑: 要执行像素完美碰撞,请使用their docs for sprites 上的pygame.sprite.collide_rect()

    【讨论】:

    • 我如何将其应用于点击精灵?
    • @EliasBenevedes 我用像素完美碰撞编辑了我的答案。
    【解决方案2】:

    我假设你的游戏有一个主循环,你所有的精灵都在一个名为sprites的列表中。

    在您的主循环中,获取所有事件,并检查 MOUSEBUTTONDOWNMOUSEBUTTONUP 事件。

    while ... # your main loop
      # get all events
      ev = pygame.event.get()
    
      # proceed events
      for event in ev:
    
        # handle MOUSEBUTTONUP
        if event.type == pygame.MOUSEBUTTONUP:
          pos = pygame.mouse.get_pos()
    
          # get a list of all sprites that are under the mouse cursor
          clicked_sprites = [s for s in sprites if s.rect.collidepoint(pos)]
          # do something with the clicked sprites...
    

    所以基本上你必须在主循环的每次迭代中自己检查一个精灵的点击。你会想要使用mouse.get_pos()rect.collidepoint()

    Pygame 不提供事件驱动编程,例如cocos2d 会。

    另一种方法是检查鼠标光标的位置和按下按钮的状态,但这种方法存在一些问题。

    if pygame.mouse.get_pressed()[0] and mysprite.rect.collidepoint(pygame.mouse.get_pos()):
      print ("You have opened a chest!")
    

    如果你处理这种情况,你必须引入某种标志,否则这段代码将打印“你已经打开了一个箱子!”主循环的每次迭代。

    handled = False
    
    while ... // your loop
    
      if pygame.mouse.get_pressed()[0] and mysprite.rect.collidepoint(pygame.mouse.get_pos()) and not handled:
        print ("You have opened a chest!")
        handled = pygame.mouse.get_pressed()[0]
    

    当然你可以继承Sprite 并添加一个名为is_clicked 的方法,如下所示:

    class MySprite(Sprite):
      ...
    
      def is_clicked(self):
        return pygame.mouse.get_pressed()[0] and self.rect.collidepoint(pygame.mouse.get_pos())
    

    所以,恕我直言,最好使用第一种方法。

    【讨论】:

    • 另外注意鼠标的位置在event.pos下的事件本身也可以得到
    【解决方案3】:

    我一直在寻找这个问题的相同答案,经过一番摸索,这是我想出的答案:

    # Python 3.4.3 with Pygame
    from sys import exit
    import pygame
    pygame.init()
    
    WIDTH = HEIGHT = 300
    window = pygame.display.set_mode((WIDTH, HEIGHT))
    pygame.display.set_caption('Crash!')
    
    # Draw Once
    rectangle = pygame.draw.rect(window, (255, 0, 0), (100, 100, 100, 100))
    pygame.display.update()
    
    # Main Loop
    while True:
        # Mouse position and button clicking
        pos = pygame.mouse.get_pos()
        pressed1 = pygame.mouse.get_pressed()[0]
    
        # Check if rectangle collided with pos and if the left mouse button was pressed
        if rectangle.collidepoint(pos) and pressed1:
            print("You have opened a chest!")
    
        # Quit pygame
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                exit()
    

    【讨论】:

      【解决方案4】:

      单击鼠标按钮时会发生一次MOUSEBUTTONDOWN 事件,松开鼠标按钮时会发生一次MOUSEBUTTONUP 事件。 pygame.event.Event() 对象有两个属性提供有关鼠标事件的信息。 pos 是一个存储被点击位置的元组。 button 存储被点击的按钮。每个鼠标按钮都关联一个值。例如,鼠标左键、鼠标中键、鼠标右键、鼠标滚轮向上和鼠标滚轮向下的属性值为 1、2、3、4、5。当按下多个键时,会发生多个鼠标按钮事件。进一步的解释可以在模块pygame.event的文档中找到。

      使用pygame.sprite.Sprite 对象的rect 属性和collidepoint 方法查看Sprite 是否被点击。 将事件列表传递给pygame.sprite.Groupupdate 方法,以便您可以在Sprite 类中处理事件:

      class SpriteObject(pygame.sprite.Sprite):
          # [...]
      
          def update(self, event_list):
      
              for event in event_list:
                  if event.type == pygame.MOUSEBUTTONDOWN:
                      if self.rect.collidepoint(event.pos):
                          # [...]
      
      my_sprite = SpriteObject()
      group = pygame.sprite.Group(my_sprite)
      
      # [...]
      
      run = True
      while run:
          event_list = pygame.event.get()
          for event in event_list:
              if event.type == pygame.QUIT:
                  run = False 
      
          group.update(event_list)
      
          # [...]
      

      最小示例: repl.it/@Rabbid76/PyGame-MouseClick

      import pygame
      
      class SpriteObject(pygame.sprite.Sprite):
          def __init__(self, x, y, color):
              super().__init__() 
              self.original_image = pygame.Surface((50, 50), pygame.SRCALPHA)
              pygame.draw.circle(self.original_image, color, (25, 25), 25)
              self.click_image = pygame.Surface((50, 50), pygame.SRCALPHA)
              pygame.draw.circle(self.click_image, color, (25, 25), 25)
              pygame.draw.circle(self.click_image, (255, 255, 255), (25, 25), 25, 4)
              self.image = self.original_image 
              self.rect = self.image.get_rect(center = (x, y))
              self.clicked = False
      
          def update(self, event_list):
              for event in event_list:
                  if event.type == pygame.MOUSEBUTTONDOWN:
                      if self.rect.collidepoint(event.pos):
                          self.clicked = not self.clicked
      
              self.image = self.click_image if self.clicked else self.original_image
      
      pygame.init()
      window = pygame.display.set_mode((300, 300))
      clock = pygame.time.Clock()
      
      sprite_object = SpriteObject(*window.get_rect().center, (128, 128, 0))
      group = pygame.sprite.Group([
          SpriteObject(window.get_width() // 3, window.get_height() // 3, (128, 0, 0)),
          SpriteObject(window.get_width() * 2 // 3, window.get_height() // 3, (0, 128, 0)),
          SpriteObject(window.get_width() // 3, window.get_height() * 2 // 3, (0, 0, 128)),
          SpriteObject(window.get_width() * 2// 3, window.get_height() * 2 // 3, (128, 128, 0)),
      ])
      
      run = True
      while run:
          clock.tick(60)
          event_list = pygame.event.get()
          for event in event_list:
              if event.type == pygame.QUIT:
                  run = False 
      
          group.update(event_list)
      
          window.fill(0)
          group.draw(window)
          pygame.display.flip()
      
      pygame.quit()
      exit()
      

      进一步查看Creating multiple sprites with different update()'s from the same sprite class in Pygame


      可以通过pygame.mouse.get_pos() 确定鼠标的当前位置。返回值是一个元组,表示鼠标光标的 x 和 y 坐标。 pygame.mouse.get_pressed() 返回一个布尔值列表,代表所有鼠标按钮的状态(TrueFalse)。只要按下按钮,按钮的状态就是True。当按下多个按钮时,列表中的多个项目为True。列表中的第 1、2、3 个元素分别代表鼠标左键、中键和右键。

      Detect 在pygame.sprite.Sprite 对象的Update 方法中评估鼠标状态:

      class SpriteObject(pygame.sprite.Sprite):
          # [...]
      
          def update(self, event_list):
      
              mouse_pos = pygame.mouse.get_pos()
              mouse_buttons = pygame.mouse.get_pressed()
      
              if  self.rect.collidepoint(mouse_pos) and any(mouse_buttons):
                  # [...]
      
      my_sprite = SpriteObject()
      group = pygame.sprite.Group(my_sprite)
      
      # [...]
      
      run = True
      while run:
          for event in pygame.event.get():
              if event.type == pygame.QUIT:
                  run = False
      
          group.update(event_list)
      
          # [...]
      

      最小示例: repl.it/@Rabbid76/PyGame-MouseHover

      import pygame
      
      class SpriteObject(pygame.sprite.Sprite):
          def __init__(self, x, y, color):
              super().__init__() 
              self.original_image = pygame.Surface((50, 50), pygame.SRCALPHA)
              pygame.draw.circle(self.original_image, color, (25, 25), 25)
              self.hover_image = pygame.Surface((50, 50), pygame.SRCALPHA)
              pygame.draw.circle(self.hover_image, color, (25, 25), 25)
              pygame.draw.circle(self.hover_image, (255, 255, 255), (25, 25), 25, 4)
              self.image = self.original_image 
              self.rect = self.image.get_rect(center = (x, y))
              self.hover = False
      
          def update(self):
              mouse_pos = pygame.mouse.get_pos()
              mouse_buttons = pygame.mouse.get_pressed()
      
              #self.hover = self.rect.collidepoint(mouse_pos)
              self.hover = self.rect.collidepoint(mouse_pos) and any(mouse_buttons)
      
              self.image = self.hover_image if self.hover else self.original_image
      
      pygame.init()
      window = pygame.display.set_mode((300, 300))
      clock = pygame.time.Clock()
      
      sprite_object = SpriteObject(*window.get_rect().center, (128, 128, 0))
      group = pygame.sprite.Group([
          SpriteObject(window.get_width() // 3, window.get_height() // 3, (128, 0, 0)),
          SpriteObject(window.get_width() * 2 // 3, window.get_height() // 3, (0, 128, 0)),
          SpriteObject(window.get_width() // 3, window.get_height() * 2 // 3, (0, 0, 128)),
          SpriteObject(window.get_width() * 2// 3, window.get_height() * 2 // 3, (128, 128, 0)),
      ])
      
      run = True
      while run:
          clock.tick(60)
          for event in pygame.event.get():
              if event.type == pygame.QUIT:
                  run = False 
      
          group.update()
      
          window.fill(0)
          group.draw(window)
          pygame.display.flip()
      
      pygame.quit()
      exit()
      

      【讨论】:

        猜你喜欢
        相关资源
        最近更新 更多