在這一章,我們會跟據之前的萬有引力和行星的軌道特徵,製作一個簡單的行星模擬器。
planetSimulator.pyde
xxxxxxxxxx231from Planet import *2
3sun = earth = None4planets = []5
6def setup():7 size(800, 800)8
9 frameRate(60)10
11 sun = Planet(PVector(0, 0), 30, "#FFA500", 1.98892e30)12 sun.isSun = True13
14 earth = Planet(PVector(-1*Planet.AU, 0), 16, "#001EFF", 5.972e24)15
16 planets.append(sun)17 planets.append(earth)18
19def draw():20 background(30)21
22 for planet in planets:23 planet.draw()Planet.py
xxxxxxxxxx211class Planet:2 AU = 149597870700.0 # AU is the astronomical unit, in meters3 G = 6.67408e-11 # G is the gravitational constant, in m^3 kg^-1 s^-24 SCALE = 250.0 / AU # 250pixel/AU5 TIMESTEP = 3600.0*24.0 # 1 day, timestep in seconds6
7 def __init__(self, position, radius, color, mass):8 self.position = position9 self.radius = radius10 self.color = color11 self.mass = mass12
13 self.isSun = False14 self.distanceToSun = 015
16 def draw(self ):17 x = self.position.x * self.SCALE + width/218 y = self.position.y * self.SCALE + height/219 20 fill(self.color)21 ellipse(x, y, self.radius*2, self.radius*2)
這兩段程式碼的要點包括:
第一段程式碼:
引入Planet類別。
創建太陽和地球物件。
設定畫布尺寸和幀率。
將太陽和地球物件加入planets列表。
在draw函式中,設定畫布背景為黑色。
遍歷planets列表中的每個行星物件,並呼叫其draw方法繪製行星。
第二段程式碼:
定義Planet類別。
屬性包括位置、半徑、顏色和質量。
輔助屬性包括isSun和distanceToSun。
draw方法計算並繪製行星的圓形表示。
程式碼的目的是創建和模擬太陽系中的行星運動。
planetSimulator.pyde
x
1from Planet import *2
3sun = earth = mars = mercury = venus = None4planets = []5
6def setup():7 size(800, 800)8
9 frameRate(60)10
11 sun = Planet(PVector(0, 0), 30, "#FFA500", 1.98892e30)12 sun.isSun = True13
14 earth = Planet(PVector(-1*Planet.AU, 0), 16, "#001EFF", 5.972e24)15 mars = Planet(PVector(-1.524*Planet.AU, 0), 12, "#FF1E00", 6.39e23)16 mercury = Planet(PVector(0.387*Planet.AU, 0), 8, "#AAAAAA", 3.285e23)17 venus = Planet(PVector(0.723*Planet.AU, 0), 10, "#FFFF00", 4.867e24)18
19 planets.append(sun)20 planets.append(earth)21 planets.append(mars)22 planets.append(mercury)23 planets.append(venus)24
25def draw():26 background(30)27
28 for planet in planets:29 # planet.updatePos(planets)30 planet.draw()Planet.py
xxxxxxxxxx221class Planet:2 AU = 149597870700.0 # AU is the astronomical unit, in meters3 G = 6.67408e-11 # G is the gravitational constant, in m^3 kg^-1 s^-24 SCALE = 250.0 / AU # 250pixel/AU5 TIMESTEP = 3600.0*24.0 # 1 day, timestep in seconds6
7 def __init__(self, position, radius, color, mass):8 self.position = position9 self.radius = radius10 self.color = color11 self.mass = mass12
13 self.isSun = False14 self.distanceToSun = 015
16 def draw(self):17 x = self.position.x * self.SCALE + width/218 y = self.position.y * self.SCALE + height/219 20 fill(self.color)21 noStroke()22 ellipse(x, y, self.radius*2, self.radius*2)
這兩段程式碼與之前相比增加了以下內容:
在planetSimulator.pyde中:
創建了額外的行星物件,包括火星(Mars)、水星(Mercury)和金星(Venus)。
將火星、水星和金星物件加入planets列表。
在Planet.py中:
在Planet類別中沒有新增任何功能,只有保留了之前的屬性和方法。
這些變更使得模擬器能夠模擬更多的行星運動,不僅僅是太陽和地球。現在,模擬器可以同時模擬太陽、地球、火星、水星和金星的運動。每個行星都有其自己的位置、半徑、顏色和質量,並且根據這些屬性在畫布上繪製圓形表示。
planetSimulator.pyde
x
1from Planet import *2
3sun = earth = mars = mercury = venus = None4planets = []5
6def setup():7 size(800, 800)8
9 sun = Planet(PVector(0, 0), 30, "#FFA500", 1.98892e30)10 sun.isSun = True11
12 earth = Planet(PVector(-1*Planet.AU, 0), 16, "#001EFF", 5.972e24)13 mars = Planet(PVector(-1.524*Planet.AU, 0), 12, "#FF1E00", 6.39e23)14 mercury = Planet(PVector(0.387*Planet.AU, 0), 8, "#AAAAAA", 3.285e23)15 venus = Planet(PVector(0.723*Planet.AU, 0), 10, "#FFFF00", 4.867e24)16
17 planets.append(sun)18 planets.append(earth)19 planets.append(mars)20 planets.append(mercury)21 planets.append(venus)22
23def draw():24 background(30)25
26 for planet in planets:27 planet.updatePos(planets)28 planet.draw()29
30
Planet.py
x
1class Planet:2 AU = 149597870700.0 # AU is the astronomical unit, in meters3 G = 6.67408e-11 # G is the gravitational constant, in m^3 kg^-1 s^-24 SCALE = 250.0 / AU # 250pixel/AU5 TIMESTEP = 3600.0*24.0 # 1 day, timestep in seconds6
7 def __init__(self, position, radius, color, mass):8 self.position = position9 self.radius = radius10 self.color = color11 self.mass = mass12
13 self.isSun = False14 self.distanceToSun = 015
16 self.velocity = PVector(0, 0)17
18 def draw(self):19 x = self.position.x * self.SCALE + width/220 y = self.position.y * self.SCALE + height/221 22 fill(self.color)23 noStroke()24 ellipse(x, y, self.radius*2, self.radius*2)25
26 def attraction(self, other):27 distance = PVector.dist(self.position, other.position)28 force = self.G * self.mass * other.mass / (distance * distance)29 direction = PVector.sub(other.position, self.position).normalize()30 if other.isSun:31 self.distanceToSun = distance32 return PVector.mult(direction, force)33 34 def updatePos(self, planets):35 if not self.isSun:36 force = PVector(0, 0)37 for planet in planets:38 if planet != self:39 force = PVector.add(force, self.attraction(planet))40 acceleration = PVector.div(force, self.mass)41 self.velocity = PVector.add(self.velocity, PVector.mult(acceleration, self.TIMESTEP))42 self.position = PVector.add(self.position, PVector.mult(self.velocity, self.TIMESTEP))
只見到一個太陽是正常的,因為程式一開始,所有行星已被太陽吸引相撞到太陽。
這兩段程式碼相較於之前的版本,新增了以下內容:
在planetSimulator.pyde中:
在draw函式中,對planets列表中的每個行星物件呼叫updatePos方法,以計算行星的運動狀態。
在Planet物件的創建過程中,為每個行星物件設置了初始速度(velocity),並將其設為(0, 0)。
在Planet.py中:
在Planet類別中新增了attraction方法,用於計算行星之間的引力。
在Planet類別中新增了updatePos方法,用於根據行星之間的引力更新行星的位置。
在Planet類別的建構函式中,新增了velocity屬性,用於表示行星的初始速度。
在Planet.py中的attraction方法和updatePos方法的功能如下:
attraction方法:
attraction方法計算兩個行星物件之間的引力,並返回一個表示引力方向和大小的向量。
首先,方法計算兩個行星物件之間的距離,使用self.position.dist(other.position)計算兩個位置向量之間的歐氏距離。
接著,使用牛頓萬有引力定律計算引力的大小,公式為force = self.G * self.mass * other.mass / (distance * distance),其中G是引力常數,self.mass和other.mass分別是兩個行星的質量。
然後,計算引力的方向,使用direction = PVector.sub(other.position, self.position).normalize(),這個向量表示從self.position指向other.position的方向,並將其單位化。
如果other行星是太陽,則將distance賦值給self.distanceToSun,以便在後續使用。
最後,返回引力向量,為direction.mult(force),將方向乘以大小得到最終的引力向量。
updatePos方法:
updatePos方法用於更新行星的位置,根據行星之間的引力相互作用。
首先,檢查行星是否為太陽,如果不是太陽,則進行以下計算:
創建一個初始為(0, 0)的力(force)向量。
對於planets列表中的每個行星物件(除了自身),呼叫attraction方法,計算與其他行星之間的引力,並將計算結果添加到force向量中。
根據牛頓第二定律,force等於質量(self.mass)乘以加速度(acceleration),所以要計算加速度,需要將force除以自身的質量,即acceleration = force.div(self.mass)。
根據瞬時速度等於加速度乘以時間間隔(self.velocity.add(acceleration.mult(self.TIMESTEP))),更新行星的速度。
根據速度等於位移乘以時間間隔(self.position.add(self.velocity.mult(self.TIMESTEP))),更新行星的位置。
planetSimulator.pyde
xxxxxxxxxx1351from Planet import *2
3sun = earth = mars = mercury = venus = None4planets = []5
6def setup():7 size(800, 800)8
9 sun = Planet(PVector(0, 0), 30, "#FFA500", 1.98892e30)10 sun.isSun = True11
12 earth = Planet(PVector(-1*Planet.AU, 0), 16, "#001EFF", 5.972e24)13 mars = Planet(PVector(-1.524*Planet.AU, 0), 12, "#FF1E00", 6.39e23)14 mercury = Planet(PVector(0.387*Planet.AU, 0), 8, "#AAAAAA", 3.285e23)15 venus = Planet(PVector(0.723*Planet.AU, 0), 10, "#FFFF00", 4.867e24)16
17 earth.velocity = PVector(0.0, 29780.0)18 mars.velocity = PVector(0.0, 24077.0)19 mercury.velocity = PVector(0.0, 47362.0)20 venus.velocity = PVector(0.0, 35020.0)21
22 planets.append(sun)23 planets.append(earth)24 planets.append(mars)25 planets.append(mercury)26 planets.append(venus)27
28def draw():29 background(30)30
31 for planet in planets:32 planet.updatePos(planets)33 planet.draw()
只要為每顆行星增加初速,就可以模擬到運行。
Planet.py
xxxxxxxxxx1521class Planet:2 AU = 149597870700.0 # AU is the astronomical unit, in meters3 G = 6.67408e-11 # G is the gravitational constant, in m^3 kg^-1 s^-24 SCALE = 250.0 / AU # 250pixel/AU5 TIMESTEP = 3600.0*24.0 # 1 day, timestep in seconds6
7 def __init__(self, position, radius, color, mass):8 self.position = position9 self.radius = radius10 self.color = color11 self.mass = mass12
13 self.isSun = False14 self.distanceToSun = 015
16 self.velocity = PVector(0, 0)17
18 self.orbit = []19
20 def draw(self):21 x = self.position.x * self.SCALE + width/222 y = self.position.y * self.SCALE + height/223
24 self.orbit.append(PVector(x, y))25 stroke(self.color)26 noFill()27 beginShape()28 for point in self.orbit:29 vertex(point.x, point.y)30 endShape()31
32 fill(self.color)33 noStroke()34 ellipse(x, y, self.radius*2, self.radius*2)35
36 def attraction(self, other):37 distance = PVector.dist(self.position, other.position)38 force = self.G * self.mass * other.mass / (distance * distance)39 direction = PVector.sub(other.position, self.position).normalize()40 if other.isSun:41 self.distanceToSun = distance42 return PVector.mult(direction, force)43 44 def updatePos(self, planets):45 if not self.isSun:46 force = PVector(0, 0)47 for planet in planets:48 if planet != self:49 force = PVector.add(force, self.attraction(planet))50 acceleration = PVector.div(force, self.mass)51 self.velocity = PVector.add(self.velocity, PVector.mult(acceleration, self.TIMESTEP))52 self.position = PVector.add(self.position, PVector.mult(self.velocity, self.TIMESTEP))
在Planet類別的初始化新增:
xxxxxxxxxx11self.orbit = []用來紀錄全部軌道的點。
在draw功能中,新增:
xxxxxxxxxx71self.orbit.append(PVector(x, y))2stroke(self.color)3noFill()4beginShape()5for point in self.orbit:6 vertex(point.x, point.y)7endShape()這段程式碼用於繪製行星的軌道。它將每個軌道上的點存儲在self.orbit列表中,然後使用beginShape()、vertex()和endShape()函式來繪製軌道的形狀。
Planet.py
x
1class Planet:2 AU = 149597870700.0 # AU is the astronomical unit, in meters3 G = 6.67408e-11 # G is the gravitational constant, in m^3 kg^-1 s^-24 SCALE = 250.0 / AU # 250pixel/AU5 TIMESTEP = 3600.0*24.0 # 1 day, timestep in seconds6
7 def __init__(self, position, radius, color, mass):8 self.position = position9 self.radius = radius10 self.color = color11 self.mass = mass12
13 self.isSun = False14 self.distanceToSun = 015
16 self.velocity = PVector(0, 0)17
18 self.orbit = []19
20 def draw(self):21 x = self.position.x * self.SCALE + width/222 y = self.position.y * self.SCALE + height/223
24 self.orbit.append(PVector(x, y))25 stroke(self.color)26 noFill()27 beginShape()28 for point in self.orbit:29 vertex(point.x, point.y)30 endShape()31
32 fill(self.color)33 noStroke()34 ellipse(x, y, self.radius*2, self.radius*2)35 36 textAlign(CENTER)37 text(nfc(self.distanceToSun,0), x, y-25)38
39 def attraction(self, other):40 distance = PVector.dist(self.position, other.position)41 force = self.G * self.mass * other.mass / (distance * distance)42 direction = PVector.sub(other.position, self.position).normalize()43 if other.isSun:44 self.distanceToSun = distance45 return PVector.mult(direction, force)46 47 def updatePos(self, planets):48 if not self.isSun:49 force = PVector(0, 0)50 for planet in planets:51 if planet != self:52 force = PVector.add(force, self.attraction(planet))53 acceleration = PVector.div(force, self.mass)54 self.velocity = PVector.add(self.velocity, PVector.mult(acceleration, self.TIMESTEP))55 self.position = PVector.add(self.position, PVector.mult(self.velocity, self.TIMESTEP))
在draw()的最後,加入:
x
1 textAlign(CENTER)2 text(nfc(self.distanceToSun,0), x, y-25)nfc() 函式用於將數值轉換為指定小數位數的字串。在這個程式碼中,它將 self.distanceToSun 的值轉換為小數點後0位的字串。然後,text() 函式用於在位置 (x, y-25) 繪製這個字串。
從結果你可以發現,行星的半徑並不是固定的,行星的軌道並不是圓型。