2

I made some codes of clicking and dragging images to stack at some point. It worked well at first few clicks, but when I stacked it at same spot several times it suddenly becomes unclickable. How can I fix it and if you are ok, can you make it more compact?

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

The code running gif is at down below.

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

Rabbid76
  • 202,892
  • 27
  • 131
  • 174
zsa778
  • 35
  • 3

1 Answers1

2

You missed to update the rect attribute, when the mouse button is released. When dragging the image, this leads to an error offset between the x, y and the rect attribute:

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


However, you do not need the x and y attributes at all. Instead, use the location saved in the rect attribute:

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()
Rabbid76
  • 202,892
  • 27
  • 131
  • 174