这是我正在创作的游戏的一部分。在游戏中,玩家必须尽快点击标有“deer”而不是“doe”的按钮:
import tkinter
import time
import random
from __main__ import *
level = 2
name = "Oliver"
stop = False
score = 0
global level, name, score
if level >= 10:
level = 10 + level/10
difficulty = level * 2
bonus = 1
def shot(animal):
root.destroy()
time.sleep(1)
if animal == "Doe":
print("You shot a doe!"),time.sleep(1)
print("The rest of the herd have trampled you to death"),time.sleep(1.2)
print("Oh deer!")
elif animal == "Deer":
print("You shot the deer!")
time.sleep(1), print("***Deer Shooting***\n\nShoot the deer, not the does"), time.sleep(2.5)
print("Ready"),time.sleep(1),print("Steady"),time.sleep(1),print("Go!\n\n\n")
root = tkinter.Tk()
NumOfDoe = difficulty
for i in range(0, NumOfDoe):
tkinter.Button(root, text = "Doe", command = lambda: shot("Doe")).pack()
tkinter.Button(root, text = "Deer", command = lambda: shot("Deer")).pack()
root.mainloop()
当这个运行时,Tkinter窗口看起来有点无聊,因为所有的按钮都排好了
我意识到这一点。place()'函数,但我如何在这里使用它来随机分散按钮,并使它们自动随机移动?
谢谢你
首先,正如@furas所提到的,睡眠是一个错误的选择,所以记住在tkinter
中使用after
来表示时间延迟!
此外,请记住构造代码(link#1、link#2),不要试图在一行中放置不必要的多个语句。
对于可移动按钮,最好使用Canvas
widget而不是任何布局管理器(除非您的真正目标是可移动按钮)。将按钮连续两次随机放置
很容易,但如果要模拟移动,则不需要一组新的随机坐标,而需要一组旧坐标、随机距离(偏移)和随机方向。
使用place
可以实现这一想法,但是有一种甜美的move
方法可以为您完成所有这些。
所有你需要的是将每个按钮
在画布
与create_window
(它也给你对象ID
来控制你的小部件在画布上)和模拟大规模移动!
import tkinter as tk
import random
class App(tk.Tk):
def __init__(self, difficulty, *args, **kwargs):
super().__init__(*args, **kwargs)
self.difficulty = difficulty
self.play_area = tk.Canvas(self, background='bisque')
self.play_area.pack(expand=True, fill='both')
self.animals = self.generate_animals()
self.play()
def play(self):
# move all animals continuously (each 100 ms)
self.move_animals()
self.after(100, self.play)
def generate_animals(self):
# generate all button-like animals
animals = [Animal('deer', self, text='DEER')]
for _ in range(self.difficulty * 2):
animals.append(Animal('doe', self, text='DOE'))
return animals
def move_animals(self):
# move all animals
for animal in self.animals:
animal.move()
class Animal(tk.Button):
def __init__(self, animal_type, *args, **kwargs):
super().__init__(*args, **kwargs)
self.animal_type = animal_type
self.base_speed = self.master.difficulty
self.play_area = self.master.play_area
self.move_sets = ['n', 's', 'w', 'e']
# place button on canvas (it's possible to randomize starting locations)
self.id = self.play_area.create_window(0, 0, window=self)
self.configure(command=self.kill)
def move(self):
# move animal
# get random speed and direction
distance = random.randint(0, 15) * self.base_speed
direction = random.choice(self.move_sets)
if direction in self.move_sets[:2]:
if direction == 'n':
distance *= -1
# to prevent case when an animal leaves play area
if 0 <= self.play_area.coords(self.id)[1] + distance <= self.play_area.winfo_height():
self.play_area.move(self.id, 0, distance)
else:
if direction == 'w':
distance *= -1
# to prevent case when an animal leaves play area
if 0 <= self.play_area.coords(self.id)[0] + distance <= self.play_area.winfo_width():
self.play_area.move(self.id, distance, 0)
def kill(self):
if self.animal_type == 'deer':
print('You shot the deer!')
else:
print('You shot a doe!')
print('The rest of the herd have trampled you to death')
print('Oh deer!')
self.master.destroy()
app = App(difficulty=2)
app.mainloop()
正如你所看到的,它以某种方式起作用。
然而,还有很大的改进和调整空间。例如,“更平滑”的运动。虽然这取决于我们移动物体的距离,但也取决于帧速率,对于人类物种,帧速率为24 fps(高帧速率)。再次感谢after
,我们可以通过延时控制该参数,延时可以通过公式time\u delay=1000//desired\u fps
计算:
...
def play(self):
# move all animals continuously
self.move_animals()
self.after(41, self.play) # 24 fps
# self.after(33, self.play) # 30 fps
...
还可以通过附加方向改进移动,并将条件逻辑简化为一条语句:
...
class Animal(tk.Button):
def __init__(self, animal_type, *args, **kwargs):
super().__init__(*args, **kwargs)
...
# dictionary for representation purpose
self.move_sets = {'n': (0, -1), 's': (0, 1), 'w': (-1, 0), 'e': (1, 0),
'nw': (-1, -1), 'sw': (-1, 1), 'ne': (1, -1), 'se': (1, 1)}
...
def move(self):
# move animal
# get random distance and direction
distance = random.randint(0, 5) * self.base_speed
direction = random.choice(list(self.move_sets.values()))
movement = [_ * distance for _ in direction]
current_coords = self.play_area.coords(self.id)
# to prevent case when an animal leaves play area
if 0 <= current_coords[0] + movement[0] <= self.play_area.winfo_width() and \
0 <= current_coords[1] + movement[1] <= self.play_area.winfo_height():
self.play_area.move(self.id, *movement)
...
一种方法是把按钮放在一行(像以前一样),但顺序随机。
您必须创建包含所有单词的列表(有许多Doe
),
随机列表,然后使用此列表创建按钮
num_of_doe = level * 2 # we use CamelCaseNames for class names
# create list with words
all_words = ["Doe"]*num_of_doe + ["Deer"]
# shuffle list ("in-place")
random.shuffle(all_words)
# create buttons using words
for word in all_words:
b = tk.Button(root, text=word, command=lambda txt=word:shot(txt))
b.pack()
顺便说一句:如果在lambda
中使用word
fromfor
则必须使用lambda txt=word:shot(txt)
。如果您使用lambda:shot(word)
,那么它将分配相同的值-列表中的最后一个值-因为它将引用放在变量word
,而不是此变量中的值。
如果需要更多的随机位置,则可以使用pack()
或place()
或grid()
将按钮放置在随机位置或单元格(网格中)
b.place(x=random.randint(0, 200), y=random.randint(0, 100))
或
b.grid(row=random.randint(0, 10), column=random.randint(0, 10))
但这很成问题,因为你可以把两个按钮放在同一个地方。
您需要首先生成所有值。它需要将值保留在列表中,然后获取新的随机值,与列表中的值进行比较,如果已经在列表中,则生成新的值。
这是你的工作;)