为什么不能同时绘制三个行星(海龟)?

时间:2018-11-12 10:29:59

标签: python turtle-graphics

我写了一个python文件来模拟行星的轨道,但是我不能同时绘制它们。 乌龟文档说:“要在屏幕上使用多只乌龟,必须使用面向对象的界面。”但是该怎么做?

# -*- 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()

2 个答案:

答案 0 :(得分:0)

您正在移动每个行星的整个轨道,然后再移动到下一行星。

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

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 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)

另外,行星类可以跟踪ab(需要更好的名称!),然后orbit函数不需要传递值。这意味着Planet类管理其数据和行为,这是面向对象设计的本质:

    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)

答案 1 :(得分:0)

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

  

您可以将行星列入清单:

     

行星= [汞,地球]

仅当此列表是Planet类变量且由创建新行星的过程自动更新时,这对我才有意义。即不是由对象方法引用的外部实体!但是即使那样,太阳还是会(通过列表)移动行星,还是行星绕着太阳自身移动。

作为计时器事件的粉丝,我会采取不同的方式。我将允许行星加入而无需手动或其他方式进行注册,并添加了模拟行星不同速度的功能:

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()

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

enter image description here