python - 在 tkinter 中填充正确的网格单元的问题
问题描述
我正在尝试使用 tkinter 在 python 中制作战舰游戏,最小的可重现示例是:
from tkinter import *
from random import randint
import time
tk = Tk()
class player:
def __init__(self, master):
self.master = master
self.placedships = []
self.bombed = []
self.sunk = []
self.ship_sizes = [5, 4, 3]
self.player_canvas = Canvas(master, height=300, width=300, highlightbackground='black', highlightthickness=0.5)
self.ai_canvas = Canvas(master, height=300, width=300, highlightbackground='black', highlightthickness=0.5)
self.player_canvas.grid(row=1, column=0, padx=50)
self.ai_canvas.grid(row=1, column=1, padx=50)
self.direction = 'v'
self.shipChosen = 0
gridLabel_player = Label(master,text="Your grid \nA B C D E F G H I J ")
gridLabel_player.grid(row=0,column=0)
gridLabel_ai = Label(master,text="AI's grid \nA B C D E F G H I J ")
gridLabel_ai.grid(row=0,column=1)
for x in range(10):
for y in range(10):
self.player_canvas.create_rectangle(x * 30, y * 30, 300, 300, fill = 'white')
self.ai_canvas.create_rectangle(x * 30, y * 30, 300, 300, fill = 'white')
#variables to store data for cells on game grid
# # self.player_ocean = 10 * [10 * [0]]
# # self.ai_ocean = 10 * [10 * [0]]
self.player_ocean = []
self.ai_ocean = []
temp = []
for i in range(10):
for y in range(10):
temp += [0]
self.player_ocean += [temp]
self.ai_ocean += [temp]
temp = []
self.selectedCoord = [0,0] # [0] = x coord, [1] = y coord
def placeShip(self):
def moveShip(event):
if event.keysym == 'Down' and self.selectedCoord[1] != 9:
self.selectedCoord[1] += 1
elif event.keysym == 'Up' and self.selectedCoord[1] != 0:
self.selectedCoord[1] -= 1
elif event.keysym == 'Left' and self.selectedCoord[0] != 0:
self.selectedCoord[0] -= 1
elif event.keysym == 'Right' and self.selectedCoord[0] != 9:
self.selectedCoord[0] += 1
print('selected coord:',self.selectedCoord)
def selectPlacement(event):
col = self.selectedCoord[0]
row = self.selectedCoord[1]
if self.direction == 'v':
v_range_start = row - self.ship_sizes[self.shipChosen] + 1
for y in range(v_range_start, row+1):
'''insert validation to reject ship clashing'''
self.player_ocean[y][col] = 1
self.placedships += [y,col]
self.refresh_ocean()
self.master.bind("<Up>", moveShip)
self.master.bind("<Down>", moveShip)
self.master.bind("<Left>", moveShip)
self.master.bind("<Right>", moveShip)
self.master.bind("<Return>", selectPlacement)
def refresh_ocean(self): # 1s turns to green
for y in range(10):
for x in range(10):
if self.player_ocean[y][x] == 1:
self.player_canvas.itemconfig(self.player_canvas.create_rectangle( (x+1) * 30, (y-1) * 30,x * 30, y * 30, fill='green'))
player1 = player(tk)
player1.placeShip()
tk.mainloop()
我遇到的问题是,如果我按下向下箭头,直到我选择的坐标为 [0,9],代码应该在第一列中从上到下为第 6 到第 10 个框着色,但它为第 5 到第 9 个着色盒子。
我尝试通过检查最后一个函数refresh_ocean
中使用的坐标 x 和 y 是否错误来调试它,但它们符合预期
解决方案
因此,简短而简单的解决方法是更改(y-1) to (y+1)
.
那就是说我做了一些改变:
重写了一些你的名字以遵循 PEP8 风格指南。
将您的
refresh_ocean
方法转换为处理初始绘制和所有绘制后记。以及添加一个delete('all')
来清除棋盘,这样我们就不会在之前的对象之上绘制。这将防止在游戏进行时占用更多内存。清理导入并更改
from tkinter import *
为import tkinter as tk
. 这将有助于防止覆盖命名空间中的其他内容。通过编写您来处理所有绘图,我们可以使用 和等
refresh_ocean
标签指定需要绘制的内容。'player1'
'ai'
更改
+=
为.append()
您的列表生成append()
速度是'+=
. 请参阅这篇文章:“.append()”和“+= []”之间的区别?将标题的单个标签更改为循环以均匀地创建每个标签。这将允许更准确的标题,然后尝试在单个字符串中手动设置空格。
最后,因为您已经在检查键是 4 个箭头键之一,我们可以使用单个绑定
'<Key>'
并获得与所有 4 个绑定相同的结果。
更新代码:
import tkinter as tk
class Player(tk.Tk):
def __init__(self):
super().__init__()
self.placed_ships = []
self.player_ocean = []
self.ai_ocean = []
self.bombed = []
self.sunk = []
self.bord_size = list('ABCDEFGHIJ')
self.selected_coord = [0, 0]
self.ship_sizes = [5, 4, 3]
self.direction = 'v'
self.shipChosen = 0
wh = 300
p_label_frame = tk.Frame(self, width=wh, height=30)
a_label_frame = tk.Frame(self, width=wh, height=30)
p_label_frame.grid(row=1, column=0, padx=50)
a_label_frame.grid(row=1, column=1, padx=50)
p_label_frame.grid_propagate(False)
a_label_frame.grid_propagate(False)
for ndex, letter in enumerate(self.bord_size):
p_label_frame.columnconfigure(ndex, weight=1)
a_label_frame.columnconfigure(ndex, weight=1)
tk.Label(p_label_frame, text=letter).grid(row=0, column=ndex)
tk.Label(a_label_frame, text=letter).grid(row=0, column=ndex)
self.player_canvas = tk.Canvas(self, height=wh, width=wh, highlightbackground='black', highlightthickness=0.5)
self.ai_canvas = tk.Canvas(self, height=wh, width=wh, highlightbackground='black', highlightthickness=0.5)
self.player_canvas.grid(row=2, column=0, padx=50)
self.ai_canvas.grid(row=2, column=1, padx=50)
temp = []
for i in range(10):
for y in range(10):
temp.append(0)
self.player_ocean.append(temp)
self.ai_ocean.append(temp)
temp = []
self.refresh_ocean()
self.bind("<Key>", self.move_ship)
self.bind("<Return>", self.select_placement)
def move_ship(self, event):
if event.keysym == 'Down' and self.selected_coord[1] < 9:
self.selected_coord[1] += 1
elif event.keysym == 'Up' and self.selected_coord[1] > 0:
self.selected_coord[1] -= 1
elif event.keysym == 'Left' and self.selected_coord[0] > 0:
self.selected_coord[0] -= 1
elif event.keysym == 'Right' and self.selected_coord[0] < 9:
self.selected_coord[0] += 1
print('selected coord:', self.selected_coord)
def select_placement(self, _=None):
col = self.selected_coord[0]
row = self.selected_coord[1]
if self.direction == 'v':
v_range_start = row - self.ship_sizes[self.shipChosen] + 1
for y in range(v_range_start, row+1):
'''insert validation to reject ship clashing'''
self.player_ocean[y][col] = 1
self.placed_ships += [y, col]
self.refresh_ocean(side='player1')
def refresh_ocean(self, side=None):
self.player_canvas.delete('all')
self.ai_canvas.delete('all')
for y in range(len(self.bord_size)):
for x in range(len(self.bord_size)):
if self.player_ocean[y][x] == 1 and side == 'player1':
self.player_canvas.itemconfig(self.player_canvas.create_rectangle(
(x+1) * 30, (y+1) * 30, x * 30, y * 30, fill='green'))
else:
self.player_canvas.create_rectangle(x * 30, y * 30, 300, 300, fill='white')
if self.ai_ocean[y][x] == 1 and side == 'ai':
self.ai_canvas.itemconfig(self.ai_canvas.create_rectangle(
(x + 1) * 30, (y + 1) * 30, x * 30, y * 30, fill='green'))
else:
self.ai_canvas.create_rectangle(x * 30, y * 30, 300, 300, fill='white')
if __name__ == '__main__':
Player().mainloop()
结果:
推荐阅读
- wordpress - 如何在 WordPress 中为致命错误处理程序 (WSoD) 设置通知电子邮件
- r - 将我的无向网络图(使用 igraph)转换为 R 中 networkd3 中的交互式图
- javascript - 如何使用本机 javascript 调用移动浏览器的共享功能?
- laravel - How to list Jetstream Roles on other view blade
- amazon-web-services - terraform elasticsearch:domain_name 的值无效
- javascript - 从 javascript 调用的 Bootstrap 5 beta 下拉问题
- jquery - 显示匹配多个选定数据属性的元素
- django - 当我添加参数时,DRF url 不起作用
- mysql - MySQL 如何使用外键识别另一个表中的列?
- r - R仅查找带有数字和“,”的元素