Вопрос-Ответ

Pygame mouse clicking detection

Обнаружение щелчка мыши Pygame

Мне было интересно, как написать код, который обнаруживал бы щелчок мышью по спрайту. Например:

if #Function that checks for mouse clicked on Sprite:
print ("You have opened a chest!")
Переведено автоматически
Ответ 1

Я предполагаю, что в вашей игре есть основной цикл, и все ваши спрайты находятся в списке с именем sprites.

В вашем основном цикле получите все события и проверьте наличие события MOUSEBUTTONDOWN or MOUSEBUTTONUP.

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())

Итак, ИМХО, лучше использовать первый подход.

Ответ 2

MOUSEBUTTONDOWN Событие происходит один раз, когда вы нажимаете кнопку мыши, и MOUSEBUTTONUP событие происходит один раз, когда кнопка мыши отпущена. У pygame.event.Event() объекта есть два атрибута, которые предоставляют информацию о событии мыши. pos это кортеж, который хранит позицию, по которой был произведен щелчок. button хранит кнопку, по которой был произведен щелчок. С каждой кнопкой мыши связано значение. Например, значение атрибутов равно 1, 2, 3, 4, 5 для левой кнопки мыши, средней кнопки мыши, правой кнопки мыши, колесика мыши вверх соответственно, колесика мыши вниз. При нажатии нескольких клавиш происходит несколько событий нажатия кнопок мыши. Дополнительные пояснения можно найти в документации модуля pygame.event.

Используйте rect атрибут pygame.sprite.Sprite объекта и collidepoint метод, чтобы определить, был ли нажат спрайт. Передайте список событий 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()

Смотрите далее Создание нескольких спрайтов с разными функциями update() из одного и того же класса спрайтов в Pygame


Текущее положение мыши можно определить с помощью pygame.mouse.get_pos(). Возвращаемое значение представляет собой кортеж, представляющий координаты x и y курсора мыши. pygame.mouse.get_pressed() возвращает список логических значений, которые представляют состояние (True или False) всех кнопок мыши. Состояние кнопки - True пока кнопка удерживается нажатой. При нажатии нескольких кнопок отображается несколько элементов в списке True. 1-й, 2-й и 3-й элементы в списке представляют левую, среднюю и правую кнопки мыши.

Обнаруживать и оценивать состояния мыши в 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()
Ответ 3

Документация pygame по событиям мыши находится здесь.

Вы можете использовать pygame.mouse.get_pressed метод совместно с pygame.mouse.get_pos (при необходимости).

Не забывайте использовать событие щелчка мыши через цикл основного события. Причина, по которой цикл событий лучше, заключается в "коротких щелчках". Вы можете не заметить этого на обычных компьютерах, но у компьютеров, использующих щелчки мышью на трекпадах, периоды щелчков слишком малы. Использование событий мыши предотвратит это.

РЕДАКТИРОВАТЬ: Для выполнения пиксельных столкновений используйте pygame.sprite.collide_rect() найденные в их документах для спрайтов.

Ответ 4

Я искал такой же ответ на этот вопрос, и после долгих размышлений над этим ответом я пришел к:

# 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()
python pygame