Удаление изображения с холста tkinter на основе его координат

Я работаю над игрой, в которой игрок должен собирать монеты, приземляясь на сундуки. Однако, если они приземлятся на один и тот же сундук три раза, он удалит сундук, который там находится, и вставит на его место бандита, что обнулит их монеты (эта часть не включена в предоставленный код, поскольку он работает правильно).

try:
    import tkinter as tk 
    from tkinter import ttk    
except ImportError: 
    import Tkinter as tk
    from Tkinter import ttk

import random
from collections import Counter

CELL_WIDTH = 50 
CELL_HEIGHT = 50
rows = 8 
columns = 8 
bandit_number = 5
chest_number = 10
moves = 0
coins = 0
chests_visited = ()

def create_grid():
    game_frame.pack()
    game_grid.pack()
    data = {}
    for col in range(columns): 
        for row in range(rows): 
            x1 = col * CELL_WIDTH 
            y1 = row * CELL_HEIGHT
            x2 = x1 + CELL_WIDTH 
            y2 = y1 + CELL_HEIGHT
            data[row, col] = game_grid.create_rectangle(x1, y1, x2, y2,
                                                       fill="green",
                                                        tags="rect")
    return data
def create_chests(chest_image):
    global chest_dict
    chest_dict = {}
    for i in range(chest_number):

        while True:
            row = random.randint(0, rows-1)
            col = random.randint(0, columns-1)
            if (row,col) not in chest_dict: 
                break 
        x1 = col * CELL_WIDTH + 24 
        y1 = row * CELL_HEIGHT - 26 
        x2 = x1 + CELL_WIDTH
        y2 = y1 + CELL_HEIGHT
        chest_dict[row,col] = game_grid.create_image(x1, y1, image=chest_image,
                                                     tags="chest")
    return chest_dict 

def create_bandits(bandit_image):
    global bandit_dict
    bandit_dict = {}
    for i in range(bandit_number): 
        while True: 
            row = random.randint(0, rows-1)
            col = random.randint(0, columns-1)
            if (row,col) not in bandit_dict:
                break            
        x = col * CELL_WIDTH + 22 
        y = row * CELL_HEIGHT - 22
        x2 = x + CELL_WIDTH
        y2 = y + CELL_HEIGHT
        bandit_dict[row,col] = game_grid.create_image(x, y, image=bandit_image)
    return bandit_dict 
def position_player(player_image):
    global arrow
    arrow = game_grid.create_image(26, 375, image=player_image)
    display_widgets()
    return arrow 
def display_widgets():
    global move_entry_x, move_entry_y, help_lbl
    help_lbl = tk.Label(game_grid, text="Enter the x value in the first entry"+
                        " and the y value in the second." + '\n' +
                        "Use negatives to move left and down.")
    game_grid.create_window(200, 420, window=help_lbl) 
    move_entry_x = tk.Entry(game_grid)
    game_grid.create_window(70, 450, window=move_entry_x)
    move_entry_y = tk.Entry(game_grid)
    game_grid.create_window(200, 450, window=move_entry_y)
    enter_btn = ttk.Button(game_grid, text="Enter", command=check_move)
    game_grid.create_window(305, 450, window=enter_btn)

def check_move():
    global help_lbl
    if (
        move_entry_x.get()[0] == "-" or
        move_entry_y.get()[0] == "-"
        ): 
        try:
            if (
                int(move_entry_x.get()[1])*CELL_WIDTH < 26 or
                int(move_entry_x.get()[1])*CELL_WIDTH > int(rows)*CELL_WIDTH
                ):
                print("Illegal move! Enter a different value")
            elif (
                int(move_entry_y.get()[1])*CELL_WIDTH < 26 or
                int(move_entry_y.get()[1])*CELL_WIDTH > int(rows)*CELL_HEIGHT
                ):
                print("Illegal move! Enter a different value")
            else:
                move_player(arrow)
        except ValueError:
            print("Please enter a number!") 
    else: 
        try:
            if (
                int(move_entry_x.get())*CELL_WIDTH < 26 or
                int(move_entry_x.get())*CELL_WIDTH > int(rows)*CELL_WIDTH
                ): 
                print("Illegal move! Enter a different value")
            elif (
                int(move_entry_y.get())*CELL_WIDTH < 26 or
                int(move_entry_y.get())*CELL_WIDTH > int(rows)*CELL_HEIGHT
                ): 
                print("Illegal move! Enter a different value")
            else: 
                move_player(arrow) 
        except ValueError:
            print("Please enter a number!")

def move_player(arrow):
    global  move_entry_x, move_entry_y, help_lbl, moves
    x_move = move_entry_x.get() 
    y_move = move_entry_y.get()
    x = int(x_move)*CELL_WIDTH 
    y = int(y_move)*CELL_HEIGHT 
    game_grid.move(arrow, x, -y) 
    moves += 1 
    print("Moves = "+str(moves))
    check_position(arrow, chest_dict)

def check_position(arrow, chest_dict):
    global coins, arrow_coords, chests_visited
    arrow_coords = game_grid.coords(arrow)
    for i in chest_dict:
        chest_coords = game_grid.coords(chest_dict[i])
        if (
            int(arrow_coords[0])-2 in chest_coords and
            int(arrow_coords[1])-1 in chest_coords
        ):
            coins += 10
            chests_visited += tuple(arrow_coords)
            print("Chests visited: "+str(chests_visited))
    check_chests()
    return arrow, chest_dict
def check_chests():
    global chests_visited, chest_dict, bandit_dict
    cnt = Counter(chests_visited)
    if (
        [k for k, v in cnt.items() if v == 3]
        ):
        game_grid.create_image(arrow_coords[0],arrow_coords[1],
                               image=bandit_image)
        print("bandit_time")    
window = tk.Tk()

game_frame = tk.Frame(window)
game_grid = tk.Canvas(game_frame, width=500, height=500, borderwidth=0,
                      highlightthickness=0)  
game_grid.itemconfig("rect", fill="green")

bandit_image = tk.PhotoImage(file="Bandit.png") 
chest_image  = tk.PhotoImage(file="Treasure Chest.png")
player_image = tk.PhotoImage(file="Arrow.png")

rects = create_grid()
bandits = create_bandits(bandit_image) 
chests = create_chests(chest_image) 
player = position_player(player_image)
window.mainloop() 

Я знаю, что вы можете использовать canvas.delete(item_id) для удаления объекта, учитывая, что он был определен, но моя проблема в том, что, поскольку я создал свои объекты со словарем, у них нет конкретных имен, которые я мог бы использовать, и я хотел бы знать, как я могу удалить объект с холста на основе его координат, а не его имени.

Кроме того, в качестве примечания, поскольку я использую изображения, согласно ответам, которые я нашел на , формат должен быть GIF, но я могу использовать формат PNG, и он все еще работает нормально, но когда я пробую свою игру на другое устройство, я получаю ожидаемую ошибку. Есть причина для этого?


person Community    schedule 24.12.2016    source источник
comment
Tkinter по умолчанию работает только с GIF (и еще одним форматом). Для работы с PNG вам нужен модуль PIL или pillow: effbot.org/tkinterbook/photoimage.htm . Конечно, PIL/pillow может использовать некоторые внешние библиотеки, и если на устройстве нет этих библиотек, то событие PIL/pillow не поможет.   -  person furas    schedule 24.12.2016
comment
@furas Я пошел дальше, но предложенное вами решение заставляет мою программу всегда предполагать, что сундук всегда является 7-й строкой и столбцом, что дает мне key error. Любые идеи?   -  person    schedule 24.12.2016
comment
Я только показываю, что у вас есть эти конкретные имена в вашем словаре, и вы можете использовать их для удаления объекта, но вы должны использовать правильные row и col, а не всегда 7-е. Итак, получите позицию пользователя x, y и преобразуйте ее в правильную row, col.   -  person furas    schedule 25.12.2016


Ответы (1)


С помощью furas я нашел решение:

Поскольку каждый сундук имеет свою уникальную строку и столбец, вы можете обратиться к отдельному сундуку, используя его строку и столбец, то есть мы должны выяснить, что это за строка и столбец.

Поскольку x1 = col * CELL_WIDTH + 24 и y1 = row * CELL_HEIGHT - 26, где x1 — координата x, а y1 — координата y, уравнения для строки и столбца должны быть (x1 - 24) / CELL_WIDTH = col и (y1 + 26) / CELL_HEIGHT = row.

Затем вы замените координаты x и y, используя arrow_coords[0] и arrow_coords[1]. И чтобы получить конкретную строку и столбец из chest_dict, вы должны округлить его до ближайшего целого числа, и он удалит этот конкретный сундук с холста:

game_grid.delete(chest_dict[int(round(int(arrow_coords[0]-24)/50, 0)),
                            int(round(int(arrow_coords[1]+26)/50, 0))])
person Community    schedule 25.12.2016