为什么三个行星(海龟)不能同时画出来?

Why can't the three planets(turtles) be drawn at the same time?

我写了一个python文件来模拟行星的轨道,但是我不能同时画出来。 turtle 文档说:"To use multiple turtles on a screen one has to use the object-oriented interface." 但是怎么做呢?

# -*- coding:utf-8 -*-

import math
import turtle

#define a class of planets, which rotate in a oval
class Planet(turtle.Turtle):
    def orbit(self, a, b, t):
        c = math.sqrt(a ** 2 - b ** 2)
        self.goto(a * math.cos(t / 200) + c, b * math.sin(t / 200))

def Sun():
    sun.color('yellow')
    sun.pd()
    sun.showturtle()
    for t in range(1000):
        sun.orbit(0, 0, t)

def Mercury():
    mercury.color('blue')
    mercury.speed(0)
    mercury.pu()
    mercury.goto(50+math.sqrt(50 ** 2 - 49.9 ** 2), 0)
    mercury.pd()
    mercury.showturtle()
    mercury.lt(90)
    for t in range(1000):
        mercury.orbit(50, 49.9, t)

def Earth():
    earth.color('red')
    earth.speed(0)
    earth.pu()
    earth.goto(75+math.sqrt(75 ** 2 - 74.9 ** 2), 0)
    earth.pd()
    earth.showturtle()
    earth.lt(90)
    for t in range(1000):
        earth.orbit(75, 74.9,t)

sun = Planet(shape='circle')
mercury = Planet(shape='circle')
earth = Planet(shape='circle')

turtle.Screen().ontimer(Sun, 100)
turtle.Screen().ontimer(Mercury, 100)
turtle.Screen().ontimer(Earth, 100)

turtle.Screen().mainloop()

在移动到下一个之前,您正在为每个行星执行整个轨道。

您可以创建一个函数来执行交错的轨道:

def orbit_planets():
    for t in range(1000):
        mercury.orbit(50, 49.9, t)
        earth.orbit(75, 74.9,t)

turtle.Screen().ontimer(orbit_planets, 100)

您还需要从行星函数中删除轨道代码。 另外行星函数只需要调用一次来初始化它们的位置。

但是,您可以将此代码放入您的 Planet class:

class Planet(turtle.Turtle):
    def __init__(self, colour, a, b):
        turtle.Turtle.__init__(self)
        self.color(colour)
        self.speed(0)
        self.pu()
        self.goto(a + math.sqrt(a ** 2 - b ** 2), 0)
        self.pd()
        self.showturtle()
        self.lt(90)
    ...

然后:

mercury = Planet('blue', 50, 49.9)
earth = Planet('red', 75, 74.9)

此外,行星 class 可以跟踪 ab(需要更好的名字!)然后 orbit 函数就不需要这些值通过。这意味着 Planet class 管理其数据和行为,这是面向对象设计的本质:

    def __init__(self, a, b):
        ...
        self.a = a
        self.b = b

和:

    def orbit(self, t):
        c = math.sqrt(self.a ** 2 - self.b ** 2)
        self.goto(self.a * math.cos(t / 200) + c,
                  self.b * math.sin(t / 200))

那么轨道定时器功能就是:

def orbit_planets():
    for t in range(1000):
        mercury.orbit(t)
        earth.orbit(t)

更进一步,您可以将行星列在一个列表中:

planets = [mercury, earth]

def orbit_planets():
    for t in range(1000):
        for planet in planets:
            planet.orbit(t)

到目前为止我和@PeterWood 在一起:

you could keep the planets in a list:

planets = [mercury, earth]

只有当此列表是 Planetclass 变量 并且在创建新行星的过程中自动更新时,这对我才有意义. IE。不是对象方法引用的外部实体!但即便如此,是太阳移动行星(通过列表)还是行星自己围绕太阳移动。

作为计时器事件的粉丝,我会以不同的方式处理这个问题。我允许行星加入而无需手动或以其他方式注册,再加上模拟行星不同速度的能力:

from math import sqrt, cos, sin, pi
from turtle import Screen, Turtle

class Star(Turtle):
    def __init__(self, colour):
        super().__init__(shape='circle')

        self.color(colour)

class Planet(Turtle):
    def __init__(self, colour, a, b, period):
        super().__init__(shape='circle')

        self.color(colour)
        self.a = a
        self.b = b
        self.period = period

        self.t = 0
        self.speed('fastest')
        self.shapesize(0.25)

        self.penup()
        self.orbit()
        self.pendown()

    def orbit(self):
        c = sqrt(self.a ** 2 - self.b ** 2)
        angle = self.t / (2 * pi)

        self.goto(self.a * cos(angle) + c, self.b * sin(angle))

        self.t += 1
        screen.ontimer(self.orbit, self.period)

screen = Screen()

sun = Star('yellow')
mercury = Planet('blue', 50, 49.9, 88)
earth = Planet('red', 75, 74.9, 365)

screen.mainloop()

这种方法在编码方面和现实方面都有其自身的问题,但它使事情变得相当简单并且有空间添加功能: