Błąd podczas klikania nałożonego obrazu w Pygame [duplikat]
Dec 01 2020
Zrobiłem kilka kodów klikania i przeciągania obrazów w celu ułożenia w stos w pewnym momencie. Działało dobrze na pierwszych kilku kliknięciach, ale kiedy układałem go kilka razy w tym samym miejscu, nagle staje się niemożliwy do kliknięcia. Jak mogę to naprawić i jeśli wszystko w porządku, czy możesz zrobić to bardziej kompaktowym?
import pygame
from pygame import *
import sys
import os
pygame.init()
s_width = 640
s_height = 480
screen = pygame.display.set_mode((s_width, s_height))
pygame.display.set_caption("TITLE")
bigfont = pygame.font.SysFont(None, 50)
smallfont = pygame.font.SysFont(None, 25)
title = bigfont.render("TITLE", True, (0,0,0))
current_path = os.path.dirname(__file__)
img_path = os.path.join(current_path, "images")
img_list = []
place_list = []
temp = []
class Img_Set:
def __init__(self, path, x_pos, y_pos):
self.image = pygame.image.load(path)
self.x_pos = x_pos
self.y_pos = y_pos
self.rect = self.image.get_rect()
self.rect.left = self.x_pos
self.rect.top = self.y_pos
img_list.append(self)
self.click = False
def offset(self):
self.offset_len_x = event.pos[0] - self.x_pos
self.offset_len_y = event.pos[1] - self.y_pos
def drag(self):
self.x_pos = event.pos[0] - self.offset_len_x
self.y_pos = event.pos[1] - self.offset_len_y
self.rect.left = self.x_pos
self.rect.top = self.y_pos
class Place_Set:
def __init__(self, path, x_pos, y_pos):
self.image = pygame.image.load(path)
self.x_pos = x_pos
self.y_pos = y_pos
self.rect = self.image.get_rect()
self.rect.left = self.x_pos
self.rect.top = self.y_pos
place_list.append(self)
self.click = False
img1 = Img_Set("images/80x80_blueball.png", s_width/3, s_height/3)
img2 = Place_Set("images/80x80_ball.png", s_width/2, s_height/3)
img3 = Place_Set("images/80x80_greenball.png", s_width/3*2, s_height/3)
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
elif event.type == MOUSEBUTTONDOWN:
if event.button == 1:
for x in img_list:
if x.rect.collidepoint(event.pos):
temp.append(x)
if len(temp) > 0:
temp[-1].offset()
temp[-1].click = True
img_list.remove(temp[-1])
img_list.append(temp[-1])
temp = []
elif event.type == MOUSEMOTION:
for x in img_list:
if x.click:
x.drag()
elif event.type == MOUSEBUTTONUP:
for x in img_list:
for y in place_list:
if x.rect.colliderect(y.rect):
x.x_pos = y.x_pos
x.y_pos = y.y_pos
for x in img_list:
x.click = False
screen.fill((255, 255, 255))
for x in place_list:
screen.blit(x.image, (x.x_pos, x.y_pos))
for x in img_list:
screen.blit(x.image, (x.x_pos, x.y_pos))
pygame.display.update()
Kod uruchamiający gif znajduje się poniżej.
https://i.stack.imgur.com/vAQyU.gif
Odpowiedzi
2 Rabbid76 Dec 01 2020 at 23:31
Brakowało aktualizacji rect
atrybutu po zwolnieniu przycisku myszy. Podczas przeciągania obrazu prowadzi to do przesunięcia błędu między atrybutem x
, y
a rect
:
while True:
for event in pygame.event.get():
# [...]
elif event.type == MOUSEBUTTONUP:
for x in img_list:
for y in place_list:
if x.rect.colliderect(y.rect):
x.x_pos = y.x_pos
x.y_pos = y.y_pos
x.rect.left = y.x_pos # <-- ADD
x.rect.top = y.y_pos # <-- ADD

Jednak atrybuty x
i nie są y
w ogóle potrzebne. Zamiast tego użyj lokalizacji zapisanej w atrybucie rect:
import pygame
from pygame import *
import sys
import os
pygame.init()
s_width = 640
s_height = 480
screen = pygame.display.set_mode((s_width, s_height))
pygame.display.set_caption("TITLE")
bigfont = pygame.font.SysFont(None, 50)
smallfont = pygame.font.SysFont(None, 25)
title = bigfont.render("TITLE", True, (0,0,0))
current_path = os.path.dirname(__file__)
img_path = os.path.join(current_path, "images")
img_list = []
place_list = []
temp = []
class Img_Set:
def __init__(self, path, x_pos, y_pos):
self.image = path # pygame.image.load(path)
self.rect = self.image.get_rect()
self.rect.left = x_pos
self.rect.top = y_pos
img_list.append(self)
self.click = False
def offset(self):
self.offset_len_x = event.pos[0] - self.rect.x
self.offset_len_y = event.pos[1] - self.rect.y
def drag(self):
self.rect.x = event.pos[0] - self.offset_len_x
self.rect.y = event.pos[1] - self.offset_len_y
class Place_Set:
def __init__(self, path, x_pos, y_pos):
self.image = path # pygame.image.load(path)
self.rect = self.image.get_rect()
self.rect.left = x_pos
self.rect.top = y_pos
place_list.append(self)
self.click = False
img1 = Img_Set("images/80x80_blueball.png", s_width/3, s_height/3)
img2 = Place_Set("images/80x80_ball.png", s_width/2, s_height/3)
img3 = Place_Set("images/80x80_greenball.png", s_width/3*2, s_height/3)
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
elif event.type == MOUSEBUTTONDOWN:
if event.button == 1:
for x in img_list:
if x.rect.collidepoint(event.pos):
temp.append(x)
if len(temp) > 0:
temp[-1].offset()
temp[-1].click = True
img_list.remove(temp[-1])
img_list.append(temp[-1])
temp = []
elif event.type == MOUSEMOTION:
for x in img_list:
if x.click:
x.drag()
elif event.type == MOUSEBUTTONUP:
for x in img_list:
for y in place_list:
if x.rect.colliderect(y.rect):
x.rect.x = y.rect.x
x.rect.y = y.rect.y
for x in img_list:
x.click = False
screen.fill((255, 255, 255))
for x in place_list:
screen.blit(x.image, x.rect)
for x in img_list:
screen.blit(x.image, x.rect)
pygame.display.update()