[英]How to make items draw at the same time in python using turtle?
我有一个家庭作业,我必须让四只不同的海龟移动,就像它们是围绕太阳的行星一样。 我写完了所有内容,这只是让乌龟同时画画的问题。 我想知道是否有一种相对简单的方法可以让它们在同一时间内开始(在合理范围内)? 无论如何,这是代码:
def planets():
"""simulates motion of Mercury, Venus, Earth, and Mars"""
import turtle
mercury = turtle.Turtle()
venus = turtle.Turtle()
earth = turtle.Turtle()
mars = turtle.Turtle()
mercury.shape('circle')
venus.shape('circle')
earth.shape('circle')
mars.shape('circle')
mercury.pu()
venus.pu()
earth.pu()
mars.pu()
mercury.sety(-58)
venus.sety(-108)
earth.sety(-150)
mars.sety(-228)
mercury.pd()
venus.pd()
earth.pd()
mars.pd()
mars.speed(7.5)
venus.speed(3)
earth.speed(2)
mars.speed(1)
mercury.circle(58)
venus.circle(108)
earth.circle(150)
mars.circle(228)
提前致谢!
一般来说,如果你想同时做多件事,有两种选择:
在这种情况下,它是您想要的第二个。 (好吧,你可能想要第一个,但你不能拥有它; tkinter
,因此turtle
,只能在主线程上运行。)绘制,比如说,每个圆圈的第一个1°,然后是下一个1°每个圆圈,依此类推。
那么,你是怎么做到的? circle
方法有一个可选的extent
参数,它是要绘制的角度(以度为单位)。 所以,你可以这样做:
for i in range(360):
mercury.circle(58, 1)
venus.circle(108, 1)
earth.circle(150, 1)
mars.circle(228, 1)
当然,你获得该extent
值越小,每只乌龟所采取的“步数”越多,因此它们进入轨道的速度就越慢。
另外,我不确定你真的想以你使用它的方式使用speed
。 这导致每个动作的动画更慢。 它不会影响它们围绕太阳运行的速度,它只影响每个步骤绘制的时间。 所以我认为你真正想做的是将所有速度保持在0(没有动画延迟),但是每一步都要移动更快的行星:
mercury.speed(0)
venus.speed(0)
earth.speed(0)
mars.speed(0)
for i in range(360):
mercury.circle(58, 7.5)
venus.circle(108, 3)
earth.circle(150, 2)
mars.circle(228, 1)
当然这意味着水星将最终绕太阳运行7.5次,而火星只能运行一次......但这正是你想要的,对吧?
由于以前的答案都没有提到turtle自己的ontimer()
来运行模拟,我决定做一个使用它的实现,并使整个问题更加面向数据:
from turtle import Turtle, Screen
""" Simulate motion of Mercury, Venus, Earth, and Mars """
planets = {
'mercury': {'diameter': 0.383, 'orbit': 58, 'speed': 7.5, 'color': 'gray'},
'venus': {'diameter': 0.949, 'orbit': 108, 'speed': 3, 'color': 'yellow'},
'earth': {'diameter': 1.0, 'orbit': 150, 'speed': 2, 'color': 'blue'},
'mars': {'diameter': 0.532, 'orbit': 228, 'speed': 1, 'color': 'red'},
}
def setup_planets(planets):
for planet in planets:
dictionary = planets[planet]
turtle = Turtle(shape='circle')
turtle.speed("fastest") # speed controlled elsewhere, disable here
turtle.shapesize(dictionary['diameter'])
turtle.color(dictionary['color'])
turtle.pu()
turtle.sety(-dictionary['orbit'])
turtle.pd()
dictionary['turtle'] = turtle
screen.ontimer(revolve, 50)
def revolve():
for planet in planets:
dictionary = planets[planet]
dictionary['turtle'].circle(dictionary['orbit'], dictionary['speed'])
screen.ontimer(revolve, 50)
screen = Screen()
setup_planets(planets)
screen.exitonclick()
输出快照及时
在我的另一个答案中,我说你必须做某种协作调度,因为tkinter
不是线程安全的。 但事实并非如此。 tkinter
是线程安全的,它没有任何类型的调度机制来从后台线程在主循环上发布事件,因此你必须添加一个队列或其他一些方法来执行它。
我绝对不建议在这里使用线程,但值得看看它是如何工作的。
Allen B. Taylor的聪明的mtTkinter
库为你包装了所有的魔法。 它不适用于Python 3,但我移植了它,你可以在GitHub mttkinter
它作为mttkinter
。 该模块有任何安装程序; 你必须将它复制到与planets.py
相同的目录中。 但是你可以这样做:
import threading
import turtle
import mttkinter
def planets():
"""simulates motion of Mercury, Venus, Earth, and Mars"""
# Use your existing code, up to...
mars.speed(1)
# Now create a thread for each planet and start them
mercury_thread = threading.Thread(target=lambda: mercury.circle(58))
venus_thread = threading.Thread(target=lambda: venus.circle(108))
earth_thread = threading.Thread(target=lambda: earth.circle(150))
mars_thread = threading.Thread(target=lambda: mars.circle(228))
mercury_thread.start()
venus_thread.start()
earth_thread.start()
mars_thread.start()
# Unfortunately, if we just exit the function here, the main thread
# will try to exit, which means it'll wait on all the background threads.
# But since they're all posting events and waiting on the main thread to
# reply, they'll deadlock. So, we need to do something tkinter-related
# here, like:
turtle.Screen().exitonclick()
planets()
turtle.py以两个测试演示结束。 第二个结尾是一只海龟'三'追逐另一只'海龟'。 它执行abarnet在循环中的第一个后增量中建议的内容。
while tri.distance(turtle) > 4:
turtle.fd(3.5)
turtle.lt(0.6)
tri.setheading(tri.towards(turtle))
tri.fd(4)
turtledemo包有多个例子可供学习。 python -m turtledemo
是启动查看器的简便方法。 为将来的版本修复了一些错误。
其他用户发布的方法效果很好。 然而,我做了一个类似面向对象设计的太阳系模型,我所做的是创建一个名为System的类,我创建一个具有所需高度和宽度的系统,并创建一个stepAll函数,其中包含一个代理列表并推进所有该列表中的代理商有一个“步骤”:
class System:
"""A two-dimensional world class."""
def __init__(self, width, height):
"""Construct a new flat world with the given dimensions."""
self._width = width
self._height = height
self._agents = { }
self.message = None
def getWidth(self):
"""Return the width of self."""
return self._width
def getHeight(self):
"""Return the height of self."""
return self._height
def stepAll(self):
"""All agents advance one step in the simulation."""
agents = list(self._agents.values())
for agent in agents:
agent.step()
然后,我创建了一个Planet类,并制作了行星代理,并定义了它们在Step函数中的步骤。
class Planet:
"""A planet object"""
def __init__(self, mySystem, distance, size, color, velocity, real_size, real_mass, name):
self = self
self._system = mySystem
mySystem._agents[self] = self #make planet an agent
self._velocity = velocity
self._color = color
self._distance = distance
self._size = size
self._position = [distance, distance - distance]
self._angle = 90
self._real_size = real_size
self._real_mass = real_mass
self._name = name
#MAKE PLANET
self._turtle = turtle.Turtle(shape = 'circle')
self._turtle.hideturtle()
#INITIALIZE PLANET
self._turtle.speed('fastest')
self._turtle.fillcolor(color)
self._turtle.penup()
self._turtle.goto(self._position)
self._turtle.turtlesize(size,size,size)
self._turtle.showturtle()
def getmySystem(self):
"""Returns the system the planet is in"""
return self._mySystem
def getdistance(self):
"""Returns the distance the planet is from the sun"""
return self._distance
def getposition(self):
"""Returns the position of the planet"""
return self._position
def getvelocity(self):
"""Returns the velocity of the planet"""
return self._velocity
def step(self):
"""Moves the planet one step on its orbit according to its velocity and previous position"""
xvar = self._position[0]
yvar = self._position[1]
newx = int(self._distance*math.cos(math.radians(90-self._angle)))
newy = int(self._distance*math.sin(math.radians(90-self._angle)))
self._turtle.goto(newx, newy)
self._angle = self._angle - self._velocity
然后在我的main()函数中,我用各自的值初始化了所有行星并说:
while True:
space.stepAll()
这样就完成了你的目标,并且通过调用Planet Class,而不是绘制一个全新的行星并尝试单独移动它与其他行星一起,可以更容易地在以后添加另一个行星,并使用您希望它包含的特定参数。
希望这有助于某人!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.