如何在基于Pygame的基础国际象棋引擎中实现拖拽功能
问题描述
我正在用Pygame开发国际象棋引擎作为个人项目,之前跟着教程学了基础功能,现在想优化。目前已实现:
- 棋盘显示、棋子初始布局
- 按Z键撤销上一步操作
- 点击选中棋子后点击目标位置完成移动(但无任何规则校验,比如首回合能用兵吃己方国王、不强制玩家交替回合)
- 仅关闭窗口可结束游戏
现在想给棋子添加拖拽功能,但一直没实现,找不到贴合现有项目结构的教程——网上的示例都是极简main.py里的Rect对象操作,没有类似我的代码里的设计约束。我的代码已经把玩家操作管理和显示逻辑分离开,希望能在尽可能保留这个结构的前提下实现拖拽功能,或者说明为什么不可行。
编辑说明:我已经尽可能简化了代码,ChessMain_2_simple.py不能再精简了,因为我想明确看到拖拽功能如何和现有的点击选子落子逻辑共存。
ChessMain_2_simple.py
""" This is our main driver file. It will be responsible for handling user input and displaying the current GameState object. """ import pygame as p import ChessEngine_2_simple WIDTH = HEIGHT = 512 #400 is another option DIMENSION = 4 SQ_SIZE = HEIGHT // DIMENSION MAX_FPS = 15 #for animations later on IMAGES = {} #dictionnary of images """ Initialize a global dictionnary of images. It will be called exactly once in the main """ def loadImage(): pieces = ['bP', 'wP'] for piece in pieces: unscaledImage = p.image.load('images/' + piece + '.png') IMAGES[piece] = p.transform.scale(unscaledImage, (SQ_SIZE, SQ_SIZE)) #note: now can access an image by saying "IMAGES['bP']" """ The main driver for our code. This will handle user input and update graphics """ def main(): p.init() screen = p.display.set_mode((WIDTH, HEIGHT)) clock = p.time.Clock() screen.fill(p.Color('white')) gs = ChessEngine_2_simple.GameState() loadImage() #only do this once before the while loop running = True sqSelected = () #no square is selected initially, keep track of the last click of the user (tuple: (row, col)) playerClicks = [] #keep track of player clicks (two tuples: [(6, 4), (4, 4)] ) while running: for e in p.event.get(): if e.type == p.QUIT: running = False elif e.type == p.MOUSEBUTTONDOWN: location = p.mouse.get_pos() #x, y) location of the mouse #so make sure to take it in account when adding a side panel col = location[0] // SQ_SIZE row = location[1] // SQ_SIZE if sqSelected == (row, col): #the user clicked the same square twice sqSelected = () #deselect playerClicks = [] #clear the player clicks else: sqSelected = (row, col) playerClicks.append(sqSelected) #append for both 1st and 2nd clicks if len(playerClicks) == 2: #after 2nd click move = ChessEngine_2_simple.Move(playerClicks[0], playerClicks[1], gs.board) gs.makeMove(move) sqSelected = () #reset user clicks playerClicks = [] drawGameState(screen, gs) clock.tick(MAX_FPS) p.display.flip() """ Responsible for all the graphics within the current game state. """ def drawGameState(screen, gs): drawBoard(screen) #draw squares on the board #add in piece highlighting or move suggestions (later) drawPiece(screen, gs.board) #draw pieces on top of those squares """ Draw the squares on the board. """ def drawBoard(screen): colors = [p.Color('antiquewhite1'), p.Color('burlywood3')] for r in range(DIMENSION): for c in range(DIMENSION): color = colors[((r+c) % 2)] rectToDraw = p.Rect(c*SQ_SIZE, r*SQ_SIZE, SQ_SIZE, SQ_SIZE) #position then dimensions p.draw.rect(screen, color, rectToDraw) """ Draw the pieces on the board using the current GameState.board """ def drawPiece(screen, board): for r in range(DIMENSION): for c in range(DIMENSION): piece = board[r][c] if piece != '--': #not empty square rectWhereToDrawPiece = p.Rect(c*SQ_SIZE, r*SQ_SIZE, SQ_SIZE, SQ_SIZE) #position then dimensions screen.blit(IMAGES[piece], rectWhereToDrawPiece) if __name__ == '__main__': #google to understand why that "if" statement main()
ChessEngine_2_simple.py
""" This class is responsible for storing all the information about the current state of a chess game. It will also be responsible for determining the valid moves at the current state. It will also keep a move log. """ class GameState(): def __init__(self): #Board is 4x4 2d list, each element of the list has 2 characters #The first character represent the color of the piece: 'b' or 'w' #The second character represent the type of the piece: 'P' #'--' represents an empty square with no piece self.board = [ ["bP", "bP", "bP", "bP"], ["--", "--", "--", "--"], ["--", "--", "--", "--"], ["wP", "wP", "wP", "wP"], ] def makeMove(self, move): self.board[move.startRow][move.startCol] = '--' #clear the square from which the piece has moved self.board[move.endRow][move.endCol] = move.pieceMoved #we've stored what pîece was moved in Move instance before overwrite its square content in Board instance class Move(): def __init__(self, startSq, endSq, board): self.startRow = startSq[0] self.startCol = startSq[1] self.endRow = endSq[0] self.endCol = endSq[1] self.pieceMoved = board[self.startRow][self.startCol] self.pieceCaptured = board[self.endRow][self.endCol]
棋子图片
- 黑兵:

- 白兵:

内容的提问来源于stack exchange,提问作者coding_chicken
相关产品推荐
相关产品推荐

