Проблема в том, что вы обрабатываете событие пользовательского ввода для Knight
в функции Knight.move()
. Это , а не , где должно go. Лучше всего иметь только одно место для обработки пользовательского ввода, а затем решить, где этот ввод должен быть go, исходя из состояния игры в данный момент. Хорошее место для этого кода - основной l oop.
В настоящее время события проверяются только в течение доли секунды, в которую вызывается функция Knight.move()
, поэтому, вероятно, большую часть времени , события не обрабатываются, и это затрудняет щелчок. Вы действительно не хотите, чтобы обработка ввода игроком распространялась на 6 различных реализаций типов шахматных фигур.
Итак ... код нуждается в значительной реструктуризации. Но сначала давайте добавим несколько вспомогательных функций:
Добавьте второй 2D-список, чтобы сохранить логическую позицию всех ваших частей. Как насчет того, чтобы он содержал None
для пустой ячейки или ссылку на объект Sprite
(например: Knight
), если эта ячейка занята. Например:
# Create an empty board
board_pieces = []
for i in range( 8 ):
board_pieces.append( [None] * 8 )
Возможно, он у вас уже есть, но я его не видел. Затем мы напишем функцию, которая может выполнять щелчок мышью и определять, был ли этот щелчок на части. Но сначала нам нужно преобразовать координаты мыши в координаты платы и обратно.
def windowToBoardCoord( win_x, win_y ):
""" Convert the window co-ordinates to board co-ordinates """
board_x = win_x // ( WINDOW_WIDTH // 8 )
board_y = win_y // ( WINDOW_HEIGHT // 8 )
# Debugging, comment out later when it all works
print( "Window (%d,%d) => Board (%d,%d)" % ( win_x, win_y, board_x, board_y ) )
return board_x, board_y
def boardToWindowCoord( board_x, board_y ):
""" Convert the board co-ordinates to window co-ordinates """
# NOTE: returns the top-left corner
win_x = board_x * 8
win_y = board_y * 8
# Debugging, comment out later when it all works
print( "Board (%d,%d) => Window (%d,%d)" % ( board_x, board_y, win_x, win_y ) )
return win_x, win_y
def getPieceAt( board, board_x, board_y ):
""" Get the piece on the board, or None """
any_piece = board[board_y][board_x] # could be None
# Debugging, comment out later when it all works
if ( any_piece == None ):
print( "No piece at board[%d][%d]" % ( board_y, board_x ) )
else:
print( "Piece [%s] is at board[%d][%d]here" % ( str( any_piece ), board_y, board_x ) )
return any_piece
Это позволяет нам видеть щелчок мышью, получать позицию мыши, а затем определять, где это щелкнуло по доске.
Мы добавим переменную с именем current_selection
, чтобы сохранить выбранную в данный момент фишку игрока, которая изначально равна None
.
Итак, вернемся к основному событию l oop:
current_selection = None # any piece the player has selected
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
elif event.type == pygame.MOUSEBUTTONDOWN: # user clicked the mouse
mouse_x, mouse_y = event.pos # where was it clicked
board_x, board_y = windowToBoardCoord( mouse_x, mouse_y )
# Is there a piece at those co-ordinates?
piece = getPieceAt( board_pieces, board_x, board_y )
# If the player has already selected a piece, this is a move
# to that new location
if ( current_selected != None ):
if ( piece == current_selected ):
# clicked on the same piece twice, un-select it
current_selected = None
else:
# This is a move, but is it valid?
if ( current_selected.isLegalMove( board_pieces, board_x, board_y )
# Valid move
# Update the board ( maybe this should be a function )
current_x, current_y = current_selected.getBoardPosition()
board[ current_y ][ current_x ] = None
board[ board_y ][ board_x ] = current_selected
# Update the screen
current_selected.moveTo( board_x, board_y )
# ... handle taking pieces, etc. TODO
elif ( piece != None ):
# Nothing selected, is this a new selection
if ( piece.isOwnedByPlayer() ):
current_selected = piece
else:
# can't select opponents pieces
makeErrorBeep()
#UPDATE BOARD UI
bgupdategrid()
...
Это оставляет Knight Sprite немного проще. Он просто должен иметь image
и rect
, но также реализовывать различные правила для этого типа фигур.
class Knight( pygame.sprite.Sprite ):
def __init__( self, x, y, colour ):
pygame.sprite.Sprite.__init__(self)
self.name = 'Knight'
# TODO: use os.path.join() here ~
self.image = pygame.image.load("D:\PythonProjects\Chess\Assets/blackKnight.png")
self.image = pygame.transform.scale(self.image, (120,120))
self.rect = self.image.get_rect()
self.rect.topleft = ( x, y )
def update(self):
# image does not change (yet)
pass
def moveTo( self, board_x, board_y ):
win_x, win_y = boardToWindowCoord( board_x, board_y )
self.rect.topleft = ( win_x, win_y )
def getBoardPosition( self ):
x, y = self.rect.topleft
board_x, board_y = windowToBoardCoord( x, y )
return board_x, board_y
def isLegalMove( self, board, move_x, move_y ):
""" Is it a legal move from current-position to (x,y) """
board_x, board_y = self.getBoardPostion()
# TODO: check all those L-shaped movements
# Can we move from (board_x, board_y) to (move_x, move_y)
result = True # TODO: just accept any movement for testing
return result