簡體   English   中英

如何使用龜在python中同時繪制項目?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM