ホームページ >バックエンド開発 >Python チュートリアル >3D エンジンを使用して Python で太陽系惑星シミュレーターを作成する方法
今回、達成したい効果は以下の通りです
まず、今回必要なリソースを送ります。
Earth.jpg
Jupiter.jpg
Mars.jpg
水星.jpg
海王星.jpg
土星.jpg
Sun.jpg
天王星.jpg
##金星.jpg さあ、コードを書き始めましょう。 まず、必要なモジュールをインポートし、3D エンジン ursina、数学ライブラリ math、the first person、sys、ursina に付属のランダム ライブラリをインポートします。from ursina import * from math import * from ursina.prefabs.first_person_controller import FirstPersonController import sys import random as rd次に、アプリを作成します
app=Ursina()ウィンドウを全画面に設定し、背景色を設定します
window.fullscreen=True window.color=color.black生成された星を保存するリストを定義します
planets=[]すべての惑星のマテリアルを紹介します
sun_texture=load_texture("texture/Sun.png") mercury_texture=load_texture("texture/Mercury.png") venus_texture=load_texture("texture/Venus.png") earth_texture=load_texture("texture/Earth.png") mars_texture=load_texture("texture/Mars.png") jupiter_texture=load_texture("texture/Jupiter.png") saturn_texture=load_texture("texture/Saturn.png") uranus_texture=load_texture("texture/Uranus.png") neptune_texture=load_texture("texture/Neptune.png")Entity から継承されたクラス Planet を作成します。入力される _type は星のタイプ、pos は位置、scale はスケーリングです。angle: 惑星が太陽の周りを回転する弧 fastMode の値は 1 または 0 で、太陽の周りの惑星の公転速度を 200 倍に増やすかどうかを示します rotation: 惑星の傾き、ここではランダムに生成します rotspeed: 惑星の回転速度rotMode: xyz 軸の 1 つに沿った回転を示し、惑星タイプ
を保存するために
_type を自動的に選択します
texture はマテリアルであり、変数は eval によって取得されます次に、スーパークラスを初期化します。モデルは球の形状である sphere です。テクスチャはテクスチャを表します。色は設定されます白にします。位置は座標を渡します。回転方法を定義し、角度を渡します。太陽以外であれば、自転、公転操作を実行します。高速モードの場合は、速度は 200 倍に増加します。次に、新しい xy 座標を計算し、exec を使用して自動送信操作を実行します。最後に、ユーザー入力を受け入れる入力メソッドを定義します。このメソッドは名前を入力する必要があることに注意してください。これはシステムによって自動的に呼び出され、常に押されたキーの名前であるパラメータが渡されるため、それを判断します。Enter キーを押すと、高速モードと通常モードが切り替わります。Switchclass Planet(Entity): def __init__(self,_type,pos,scale=2): self.angle=rd.uniform(0.0005,0.01) self.fastMode=0 self.rotation=(rd.randint(0,360) for i in range(3)) self.rotspeed=rd.uniform(0.25,1.5) self.rotMode=rd.choice(["x","y","z"]) self._type=_type texture=eval(f"{_type}_texture") super().__init__(model="sphere", scale=scale, texture=texture, color=color.white, position=pos) def turn(self,angle): if self._type!="sun": if self.fastMode: angle*=200 self.x=self.x*cos(radians(angle))-self.y*sin(radians(angle)) self.y=self.x*sin(radians(angle))+self.y*cos(radians(angle)) exec(f"self.rotation_{self.rotMode}+=self.rotspeed") def input(self,key): if key=="enter": self.fastMode=1-self.fastMode次に、FirstPersonController から継承した Player クラスを定義します。FirstPersonController を直接使用しないのはなぜですか? ursina に付属している FirstpersonController は独自の重力を持っているため、ここでは一人称視点としてのみ使用し、重力を必要としません。それを継承するクラスを作成し、そのコードの一部を書き換えるだけです。まず、グローバル変数惑星を導入し、スーパークラスを初期化し、視野を 90 に設定し、初期位置を地球の位置に設定し、重力を 0 (重力がないことを意味します) に設定します。vspeed は上昇時の速度を意味します落下、速度は水平方向の移動を意味します。速度、mouse_sensitivity はマウスの感度であり、Vec2 の形式にする必要があります。上記の vspeed 変数を除き、自分で名前を付けることができるので、他の変数は指定できないことに注意してください。変更される。次に、esc キーの情報のみを受け取るように入力を書き換えます。esc キーを押すと、マウスがロックされていれば解放され、解放されていればプログラムが終了します。次に、_update メソッドを作成します。ここでは、ursina によって自動的に呼び出される update メソッドをオーバーライドしません。システム コードでは、update メソッドにはまだ多くの操作があるためです。書き換える場合は、システム コードもコピーする必要がある場合があります。コードが多すぎる 面倒です ここでは自分で名前を定義し、次に説明するコード内で自分で呼び出します このメソッドでは、マウスの左ボタン、左シフト、スペースのイベントを監視します スペースは本来ジャンプです, ここでは上昇するように設定しています。システム コードは入力でスペース キーの情報を受け取ります。書き換えたので、システム コードのジャンプ メソッドはここではトリガーされません。
这里讲一下input和update中进行按键事件监听操作的不同,input每次只接收一个按键,而且,如果我们一个按键一直按下,它不会一直触发,只会触发一次,然后等到该按键释放,才会重新对该按键进行监听;update相当于主循环,在任何于ursina有关的地方(比如继承自Entity、Button这样的类,或者是主程序)写update方法,ursina都会进行自动调用,我们不需要手动调用它,在update方法中监听事件,我们用到了held_keys,不难发现,held_keys有多个元素,只要按下就为True,所以每次运行到这里,只要按键按下,就执行,而input传入的key本身就是一个元素,所以只有一个,我们按下esc的操作不能连续调用,所以用input,其它移动玩家的代码时可以重复执行的,所以写在update(应该说是用held_keys)中。
class Player(FirstPersonController): def __init__(self): global planets super().__init__() camera.fov=90 self.position=planets[3].position self.gravity=0 self.vspeed=2 self.speed=600 self.mouse_sensitivity=Vec2(160,160) self.on_enable() def input(self,key): if key=="escape": if mouse.locked: self.on_disable() else: sys.exit() def _update(self): if held_keys["left mouse"]: self.on_enable() if held_keys["left shift"]: self.y-=self.vspeed if held_keys["space"]: self.y+=self.vspeed
然后在主程序中写update方法,并在其中调用我们刚刚写的player中的_update方法,再对星球进行自转公转操作
def update(): global planets,player for planet in planets: planet.turn(planet.angle) player._update()
接下来,我们定义两个列表,分别表示星球名称和星球的大小,其实在实际的大小比例中,和这个相差很多,如果地球是1,太阳则大约为130000,木星和图形分别为1500多和700多,这样相差太大,做在程序里看起来很不寻常,所以我们这里对大多数星球的大小进行放大缩小,把它们大小的相差拉近点。然后遍历并绘制,每颗星球的间隔为前一个的10倍
ps=["sun","mercury","venus","earth","mars","jupiter","saturn","uranus","neptune"] cp=[200,15,35,42,20,160,145,90,80] x,y,z=0,0,0 for i,p in enumerate(ps): newPlanet=Planet(p,(x,y,z),cp[i]) planets.append(newPlanet) x+=cp[i]*10
最后实例化player,并运行app
player=Player() if __name__ == '__main__': app.run()
然后就能实现文章前面展示的效果啦~
最后,附上代码
from ursina import * from math import * from ursina.prefabs.first_person_controller import FirstPersonController import sys import random as rd app=Ursina() window.fullscreen=True window.color=color.black planets=[] class Planet(Entity): def __init__(self,_type,pos,scale=2): self.angle=rd.uniform(0.0005,0.01) self.fastMode=0 self.rotation=(rd.randint(0,360) for i in range(3)) self.rotspeed=rd.uniform(0.25,1.5) self.rotMode=rd.choice(["x","y","z"]) self._type=_type texture=eval(f"{_type}_texture") super().__init__(model="sphere", scale=scale, texture=texture, color=color.white, position=pos) def turn(self,angle): if self._type!="sun": if self.fastMode: angle*=200 self.x=self.x*cos(radians(angle))-self.y*sin(radians(angle)) self.y=self.x*sin(radians(angle))+self.y*cos(radians(angle)) exec(f"self.rotation_{self.rotMode}+=self.rotspeed") def input(self,key): if key=="enter": self.fastMode=1-self.fastMode class Player(FirstPersonController): def __init__(self): global planets super().__init__() camera.fov=90 self.position=planets[3].position self.gravity=0 self.vspeed=2 self.speed=600 self.mouse_sensitivity=Vec2(160,160) self.on_enable() def input(self,key): if key=="escape": if mouse.locked: self.on_disable() else: sys.exit() def _update(self): if held_keys["left mouse"]: self.on_enable() if held_keys["left shift"]: self.y-=self.vspeed if held_keys["space"]: self.y+=self.vspeed def update(): global planets,player for planet in planets: planet.turn(planet.angle) player._update() sun_texture=load_texture("texture/Sun.png") mercury_texture=load_texture("texture/Mercury.png") venus_texture=load_texture("texture/Venus.png") earth_texture=load_texture("texture/Earth.png") mars_texture=load_texture("texture/Mars.png") jupiter_texture=load_texture("texture/Jupiter.png") saturn_texture=load_texture("texture/Saturn.png") uranus_texture=load_texture("texture/Uranus.png") neptune_texture=load_texture("texture/Neptune.png") ps=["sun","mercury","venus","earth","mars","jupiter","saturn","uranus","neptune"] cp=[200,15,35,42,20,160,145,90,80] x,y,z=0,0,0 for i,p in enumerate(ps): newPlanet=Planet(p,(x,y,z),cp[i]) planets.append(newPlanet) x+=cp[i]*10 player=Player() if __name__ == '__main__': app.run()
以上が3D エンジンを使用して Python で太陽系惑星シミュレーターを作成する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。