Kesalahan saat mengklik gambar yang ditumpuk di Pygame [duplikat]

Dec 01 2020

Saya membuat beberapa kode untuk mengklik dan menyeret gambar ke tumpukan di beberapa titik. Ini berfungsi dengan baik pada beberapa klik pertama, tetapi ketika saya menumpuknya di tempat yang sama beberapa kali tiba-tiba menjadi tidak dapat diklik. Bagaimana cara memperbaikinya dan jika Anda baik-baik saja, dapatkah Anda membuatnya lebih ringkas?

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

Kode yang menjalankan gif ada di bawah.

https://i.stack.imgur.com/vAQyU.gif

Jawaban

2 Rabbid76 Dec 01 2020 at 23:31

Anda melewatkan untuk memperbarui rectatribut, ketika tombol mouse dilepaskan. Saat menyeret gambar, hal ini menyebabkan kesalahan offset antara x, ydan rectatribut:

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


Namun, Anda tidak membutuhkan atribut xdan ysama sekali. Sebagai gantinya, gunakan lokasi yang disimpan dalam atribut 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()