如何在 Turtle GUI 中跟踪鼠标位置?

问题描述 投票:0回答:1

我正在Python上使用Turtle制作一个四子棋游戏,我的作业要求制作一个鼠标跟踪器,当鼠标与令牌占位符位于同一列时突出显示令牌占位符,如图所示。但我只是不知道如何实现该功能。

game requirement

import turtle
from turtle import *

textinput("Directions", "You need to place a toke down one "
                        "of the columns, and the first person"
                        " to reach 4 consecutive pieces in any "
                        "direction will win. Do you understand? "
                        "(type anything)")

def init_board():
    global gameBoard, winner
    gameBoard = []
    winner = None

    global tokenBoard
    tokenBoard = []

    for i in range(8):
        gameBoard.append([0, 0, 0, 0, 0, 0, 0, 0]), \
        tokenBoard.append(
            [None, None, None, None, None, None, None, None]
        )

'''Sets up the game board on the canvas. It creates a row of eight 
gray rectangles that represent the token holder of the game board.
'''

def start_game(canvas):
    global rectangleHeight, rectangleWidth
    rectangleWidth = 60
    rectangleHeight = 10
    gap = (canvas.window_width() - (rectangleWidth * 8)) / 9
    global rectangleTurtles
    rectangleTurtles = []
    for i in range(8):
        rectangle = turtle.Turtle()
        rectangle.speed(0)
        rectangle.hideturtle()
        rectangle.penup()
        rectangle.goto(-canvas.window_width()
                       / 2 + gap + i
                       * (rectangleWidth + gap)
                       + 0.5 * rectangleWidth,
                       -canvas.window_height()
                       / 2 + 100 + 0.5
                       * rectangleHeight)
        rectangle.color("gray")
        rectangle.shape("square")
        rectangle.shapesize(1, 3)
        rectangle.fillcolor("gray")
        rectangle.showturtle()
        rectangleTurtles.append(rectangle)

'''Takes a two-dimensional list and a column index as input and 
returns the index of the first empty cell in that column, starting 
from the bottom of the board. If the column is full, it returns None.
'''

def search_horizontally(table, column):
    rowNum = 8
    for row in table[::-1]:
        rowNum -= 1
        try:
            if row[column] == 0:
                return rowNum
        except:
            pass

'''Creates a turtle object that represents a token of a specified 
color. The token is placed at a specific location on the game board.
'''

def create_token(x, y, color):
    token = turtle.Turtle()
    token.speed(0)
    token.hideturtle()
    token.penup()
    token.goto(x, y)
    token.color(color)
    token.shape("circle")
    token.shapesize(3, 3)
    token.showturtle()
    return token

'''Takes a column and a row number and checks if the player who 
just placed a token has won the game. It checks for four tokens 
in a row, column, or diagonal.
'''

def check_winner(column, row):
    global gameBoard, winner
    directions = [(-1, 0), (0, 1), (-1, 1), (1, 1)]
    player = gameBoard[row][column]
    for direction in directions:
        count = 1
        winning_tokens = [(row, column)]
        for i in range(1, 4):
            newRow = row + direction[1] * i
            newCol = column + direction[0] * i
            if 0 <= newRow < 8 and \
                    0 <= newCol < 8 and \
                    gameBoard[newRow][newCol] == player:
                count += 1
                winning_tokens.append((newRow, newCol))
            else:
                break
        for i in range(1, 4):
            newRow = row - direction[1] * i
            newCol = column - direction[0] * i
            if 0 <= newRow < 8 and \
                    0 <= newCol < 8 and \
                    gameBoard[newRow][newCol] == player:
                count += 1
                winning_tokens.append((newRow, newCol))
            else:
                break
        if count >= 4:
            winner = player
            highlight_token(winning_tokens)
            return

'''Highlights the winning tokens on the game board by giving 
it yellow outline.
'''

def highlight_token(winning_tokens):
    global tokenBoard
    for row, column in winning_tokens:
        token = tokenBoard[row][column]
        token.shapesize(3, 3, 5)
        token.pencolor('yellow')
    canvas.title(f'Congratulations! '
                 f'Player {3 - winner} has won (*^ - ^*)')
    canvas.update()

'''Updates the game board by placing the current player's 
token in the specified column and row.
'''

def update_board(column, row):
    global gameBoard
    gameBoard[row][column] = currentPlayer + 1

DELAY = 1
timer_triggered = False


def delayed_on_mouse_y(x, y, color1, color2):
    global timer_triggered
    if not timer_triggered:
        timer_triggered = True
        turtle.ontimer(lambda:
                       on_mouse_y(x, y, color1, color2),
                       DELAY)

on_mouse_y_executed = False
updating = False

'''Called when the user moves the mouse over the game board. 
It checks which column the mouse is currently over and 
highlights that column. It returns the column number.
'''

def on_mouse_y(x, y, color1, color2):
    global timer_triggered, on_mouse_y_executed, updating, column
    timer_triggered = False

    if updating:
        return

    i = -1
    for rectangle in rectangleTurtles:
        i += 1
        if abs(rectangle.xcor() - x) <= 30:
            updating = True
            rectangle.shapesize(1, 3, 5)
            if currentPlayer == 0:
                rectangle.color(color1, 'gray')
            else:
                rectangle.color(color2, 'gray')

            canvas.update()

            updating = False

            on_mouse_y_executed = True

            column = i
        else:
            updating = True
            rectangle.shapesize(1, 3, 1)
            rectangle.color('gray', 'gray')
            canvas.update()
            updating = False

    try:
        return column
    except:
        pass

'''The onclick(x, y, color1, color2) function is called when 
the user clicks on the game board. It calls on_mouse_y() to 
get the column number, then calls searchRow() to get the row 
number where the token should be placed. It creates a token at 
that location, updates the game board, and checks for a winner. 
If a winner is found, the game is over. Otherwise, it switches 
to the other player's turn.
'''

def on_click(x, y, color1, color2):
    global on_mouse_y_executed, currentPlayer, winner
    if winner is not None:
        return

    if on_mouse_y_executed:

        i = on_mouse_y(x, y, color1, color2)

        column = i
        row = search_horizontally(gameBoard, column)
        if row != None:
            if currentPlayer == 0:
                token = create_token(rectangleTurtles[i].xcor(),
                                     rectangleTurtles[i].ycor()
                                     + (8 - row) * 60, color1)

                currentPlayer = 1

            else:
                token = create_token(rectangleTurtles[i].xcor(),
                                     rectangleTurtles[i].ycor()
                                     + (8 - row) * 60, color2)

                currentPlayer = 0

            canvas.update()
            update_board(column, row)
            tokenBoard[row][column] = token
            check_winner(column, row)
            on_mouse_y_executed = False


        else:
            pass


def motion_handler(event, color1, color2):
    global currentPlayer
    canvas_width = turtle.getcanvas().winfo_width()
    canvas_height = turtle.getcanvas().winfo_height()
    x, y = turtle.getcanvas().winfo_pointerxy()
    x = x - canvas_width // 2
    y = -y + canvas_height // 2
    delayed_on_mouse_y(x, y, color1, color2)


def __main__():
    color1 = textinput('Player 1','Enter a color except yellow:')
    color2 = textinput('Player 2', 'Enter a color except yellow:')

    global tokenColors, currentPlayer
    tokenColors = [color1, color2]

    global currentPlayer
    currentPlayer = 0

    global canvas
    canvas = turtle.Screen()
    canvas.title('Connect Four Game')
    canvas.tracer(0)

    init_board()

    start_game(canvas)

    turtle.Screen().getcanvas().bind("<Motion>",
                                     lambda *args:
                                     motion_handler(*args,
                                                    color1,
                                                    color2)
                                     )
    turtle.Screen().getcanvas().bind("<Button-1>",
                                     lambda event:
                                     on_click(event.x
                                              - event.widget.winfo_width() // 2,
                                              -event.y
                                              + event.widget.winfo_height() // 2,
                                              color1, color2)
                                     )

    turtle.mainloop()


__main__()



python turtle-graphics
1个回答
1
投票

turtle.getcanvas().winfo_pointerxy()
返回屏幕坐标,而不是相对窗口坐标。但你想使用相对坐标。这些在事件中提供,因此您的运动处理函数应如下所示:

def motion_handler(event, color1, color2):
    global currentPlayer
    canvas_width = turtle.getcanvas().winfo_width()
    canvas_height = turtle.getcanvas().winfo_height()
    x = event.x
    y = event.y
    x = x - canvas_width // 2
    y = -y + canvas_height // 2
    delayed_on_mouse_y(x, y, color1, color2)
© www.soinside.com 2019 - 2024. All rights reserved.