35

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

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

4 回答 4

53

I assume your game has a main loop, and all your sprites are in a list called sprites.

In your main loop, get all events, and check for the MOUSEBUTTONDOWN or MOUSEBUTTONUP event.

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

So basically you have to check for a click on a sprite yourself every iteration of the mainloop. You'll want to use mouse.get_pos() and rect.collidepoint().

Pygame does not offer event driven programming, as e.g. cocos2d does.

Another way would be to check the position of the mouse cursor and the state of the pressed buttons, but this approach has some issues.

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

You'll have to introduce some kind of flag if you handled this case, since otherwise this code will print "You have opened a chest!" every iteration of the main loop.

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]

Of course you can subclass Sprite and add a method called is_clicked like this:

class MySprite(Sprite):
  ...

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

So, it's better to use the first approach IMHO.

于 2012-06-12T07:29:18.307 回答
11

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

使用对象的rect属性pygame.sprite.Spritecollidepoint方法查看Sprite是否被点击。将事件列表传递给 的update方法,pygame.sprite.Group以便您可以处理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()

请参阅从 Pygame 中的同一精灵类创建具有不同更新()的多个精灵


鼠标的当前位置可以通过 确定pygame.mouse.get_pos()。返回值是一个元组,表示鼠标光标的 x 和 y 坐标。返回代表所有鼠标按钮状态(或)pygame.mouse.get_pressed()的布尔值列表。按钮的状态与按钮被按住的时间一样长。当按下多个按钮时,列表中的多个项目是。列表中的第 1、2、3 个元素代表鼠标左键、中键和右键。TrueFalseTrueTrue

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

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()
于 2020-10-26T08:29:58.227 回答
9

鼠标事件的 pygame 文档在这里

您可以使用与(如果需要)pygame.mouse.get_pressed协作的方法。pygame.mouse.get_pos

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

编辑: 要执行像素完美碰撞,请使用pygame.sprite.collide_rect()他们的 sprites 文档

于 2012-06-12T03:25:52.457 回答
5

我一直在寻找这个问题的相同答案,经过多次挠头,这就是我想出的答案:

# 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()
于 2015-12-16T01:47:23.117 回答