I am following a tutorial on YouTube for the GUI portion of a chess program in Python. However, whenever I drag a piece around the board, it feels very sluggish, as if the piece cannot keep up with the mouse's position.
At the start of the loop, I blit the background, and then I blit the pieces over the background. I then check if a piece is being dragged, if it is, we blit the piece icon.
- I thought that here, I could try to update the mouse position before blitting, but it does not seem to work
Then we check the state of the mouse, if the mouse button is being pressed down, we update the mouse position, we then check if the clicked square has a piece, if it does, we save the initial position of the piece, set that as the active piece being dragged, and set dragging boolean to True.
If there is mouse motion and the dragging boolean is True, we update the position of the mouse, blit the bg, blit the other pieces, then blit the dragged piece icon.
Once the mouse is released, we set the boolean to False and clear the active dragging piece.
- I think to many things are being blitted but I am not sure if there is anyway I can change the code without visual bugs
MAINLOOP
def mainloop(self):
game = self.game
screen = self.screen
drag = self.game.drag
board = self.game.board
while True:
game.show_bg(screen)
game.show_pieces(screen)
if drag.dragging:
drag.blit_icon(screen)
for event in pygame.event.get():
# mouse click
if event.type == pygame.MOUSEBUTTONDOWN:
drag.update_mouse(event.pos)
clicked_row = drag.mouseY // SQSIZE
clicked_col = drag.mouseX // SQSIZE
# does clicked square contain a piece
if board.squares[clicked_row][clicked_col].has_piece():
clicked_piece = board.squares[clicked_row][clicked_col].piece
drag.save_initial_pos(event.pos)
drag.drag_piece(clicked_piece)
# mouse movement
elif event.type == pygame.MOUSEMOTION:
if drag.dragging:
drag.update_mouse(event.pos)
game.show_bg(screen)
game.show_pieces(screen)
drag.blit_icon(screen)
# click released
elif event.type == pygame.MOUSEBUTTONUP:
drag.undrag_piece()
# quit
elif event.type == pygame.QUIT:
pygame.quit()
sys.exit()
pygame.display.update()
DRAG CLASS
class Drag:
def __init__(self):
self.mouseX = 0
self.mouseY = 0
self.initial_row = 0
self.initial_col = 0
self.piece = None
self.dragging = False
def update_mouse(self, pos):
self.mouseX, self.mouseY = pos # (x,y)
def save_initial_pos(self, pos):
initial_row = pos[1] // SQSIZE
initial_col = pos[0] // SQSIZE
def drag_piece(self, piece):
self.piece = piece
self.dragging = True
def undrag_piece(self):
self.piece = None
self.dragging = False
def blit_icon(self, surface):
img_center = self.mouseX, self.mouseY
self.piece.texture_rect = self.piece.img.get_rect(center=img_center)
surface.blit(self.piece.img, self.piece.texture_rect)
SHOW PIECES/BG
def show_bg(self, surface):
for row in range(ROWS):
for col in range(COLS):
if (row + col) % 2 == 0:
color = (240, 236, 184) # light squares
else:
color = (75, 115, 153, 255) # dark squares
rect = (col * SQSIZE, row * SQSIZE, SQSIZE, SQSIZE)
pygame.draw.rect(surface, color, rect)
def show_pieces(self, surface):
for row in range(ROWS):
for col in range(COLS):
if self.board.squares[row][col].has_piece():
piece = self.board.squares[row][col].piece
# make sure piece is not being dragged before blit
if piece is not self.drag.piece:
piece.img = pygame.image.load(piece.texture).convert_alpha()
img_center = col * SQSIZE + SQSIZE // 2, row * SQSIZE + SQSIZE // 2 # center y first, then x
piece.texture_rect = piece.img.get_rect(center=img_center)
surface.blit(piece.img, piece.texture_rect)