Python利用3D引擎做一个太阳系行星模拟器

这次,我们再来用Ursina引擎来做一个太阳系行星模拟器吧!

想要了解Ursina 3D引擎的基本使用方法的话,查看我的另一篇文章:详解Python 3D引擎Ursina如何绘制立体图形

这一次,我们要实现的效果如下

首先,送上本次需要用到的资源

Earth.jpg

Jupiter.jpg

Mars.jpg

Mercury.jpg

Neptune.jpg

Saturn.jpg

Sun.jpg

Uranus.jpg

Venus.jpg

现在,就开始写代码吧!

首先,导入我们需要的模块,导入3D引擎ursina,数学库math,ursina中自带的第一人称,sys,random随机库

from ursina import *
from math import *
from ursina.prefabs.first_person_controller import FirstPersonController
import sys
import random as rd

然后,创建app

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

创建一个类Planet,继承自实体Entity,传入_type是星的类型,pos是位置,scale是缩放

angle:每次更新的时候行星围绕太阳转的弧度

fastMode的值为1或0,表示是否让行星围绕太阳公转速度增加到200倍

rotation:星球倾斜度,这里我们随机生成

rotspeed:星球自转的速度

rotMode:表示沿着xyz轴的其中一条进行旋转,自动选择

_type存储星球类型

texture则是材质,通过eval获得该变量

然后进行超类的初始化,model是sphere,也就是球体形状,texture表示贴图,color颜色设置为white,position传入坐标

定义turn方法,传入angle,只要不是太阳,就进行自转公转操作,如果是快速模式,则速度增加到200倍,然后计算得出新的xy坐标,并用exec进行自传操作

最后定义input方法,接受用户输入,注意,这里方法名必须用input,因为它是系统自动调用的,它总会向其传入一个参数,为按下的按键名字,我们就进行判断,如果按下回车,则进行快速模式和普通模式间的切换

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

接下来,我们定义Player类,继承自FirstPersonController

为什么不直接用FirstPersonController呢?

因为ursina自带的FirstPersonController自带重力,我们这里只是作为第一人称的视角使用,不需要重力,然后还有一些功能我们不需要用到,所以我们就写一个类继承下来,然后重写它的一部分代码即可。首先,引入全局变量planets,超类初始化,视野设置为90,将初始位置设置为地球的位置,重力(gravity)设置为0,表示没有重力,vspeed表示上升下降时的速度,speed表示水平方向移动的速度,mouse_sensitivity是鼠标灵敏度,需要用Vec2的形式,注意,上面除了vspeed变量可以自己命名,其它的都不可以修改。接下来,重写input,只接收esc按键的信息,当我们按下esc时,如果鼠标为锁定,则释放,如果已经释放,则退出程序。然后创建_update方法,这里我们不重写ursina自动调用的update方法,因为系统代码里面,update方法还有很多操作,如果我们要重写的话,可能还要加上把系统代码复制过来,代码过于繁琐,这里我们自己定义一个名字,在接下来会讲到的代码中自己调用它,在该方法中,监听鼠标左键、左shift和空格的事件,空格原本是跳跃,这里我们设置为上升,系统代码是在input中接收空格键的信息的,我们已经重写过了,所以这里不会触发系统代码的跳跃方法。

这里讲一下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()

以上就是Python利用3D引擎做一个太阳系行星模拟器的详细内容,更多关于Python太阳系行星模拟器的资料请关注我们其它相关文章!

(0)

相关推荐

  • 详解Python 3D引擎Ursina如何绘制立体图形

    目录 编写第一个程序 绘制实体长方体 对实体进行同样比例的放大和缩小 对实体进行任意放大 绘制球体 为你的实体上色 Python有一个不错的3D引擎——Ursina Ursina官网:www.ursinaengine.org 打开cmd,控制台输入pip install ursina以安装ursina 编写第一个程序 首先导入ursina from ursina import * 然后创建app app=Ursina() 运行app app.run() 最终代码: from ursina imp

  • Python利用3D引擎制作一个3D迷宫游戏

    Ursina是一个3D引擎,初步使用方法,见文章:详解Python 3D引擎Ursina如何绘制立体图形 了解完Ursina的初步用法,接下来,我们就开始设计这个3D迷宫游戏啦! 效果: 墙面.地板.起始块.终点块所需要的图像资源我放在下面供大家下载 ↓↓ brick.png redstoneblock.jpg greendiamondblock.jpg  plank.jpg 代码详解: 首先,要用Prim最小生成树的方法生成迷宫,原理就是不断遍历还未遍历过的墙,并不断地删除不需要的墙块,代码见

  • Python算法绘制特洛伊小行星群实现示例

    目录 最小势能点 拉格朗日点 特洛伊小行星群 书接上文 用Python搓一个太阳系 你们要的3D太阳系 3体人真的存在吗 太长不看版 最小势能点 在由两个大质量物体构成的重力系统中,有一些特殊的区域会在两个天体的顶级拉扯之下达到平衡,这些点就是拉格朗日点.而所谓平衡并非受力平衡,而是要求这个区域的物体会跟着双星系统以相同的角速度运动. 根据上帝是个胖子这个假定,状态稳定意味着低势能.所以在解析求解拉格朗日点之前,我们可以试着画出这个双星系统的势能分布. 接下来搞一下太阳和木星: 可见木星在太阳的

  • Python利用3D引擎写一个Pong游戏

    目录 前言 实现方法 完整代码 前言 之前,我们用pygame做了一个2D的Pong游戏,今天我们做一个3D的,游戏画面如下: 用ad和←→操作,双人对战 实现该效果我们使用Python强大的3D引擎Ursina,基础的使用方法见这篇文章:详解Python 3D引擎Ursina如何绘制立体图形 接下来开始写代码吧! 实现方法 首先,导入ursina和随机库 from ursina import * import random as rd 定义两个玩家的分数 scorea=scoreb=0 然后,

  • Python利用3D引擎做一个太阳系行星模拟器

    这次,我们再来用Ursina引擎来做一个太阳系行星模拟器吧! 想要了解Ursina 3D引擎的基本使用方法的话,查看我的另一篇文章:详解Python 3D引擎Ursina如何绘制立体图形 这一次,我们要实现的效果如下 首先,送上本次需要用到的资源 Earth.jpg Jupiter.jpg Mars.jpg Mercury.jpg Neptune.jpg Saturn.jpg Sun.jpg Uranus.jpg Venus.jpg 现在,就开始写代码吧! 首先,导入我们需要的模块,导入3D引擎

  • Python利用物理引擎Pymunk编写一个解压小游戏

    用鼠标创建小球,一个蹦来蹦去的解压小游戏…… 本次需要的外置包:pygame,pymunk,cmd运行该命令安装: pip install pygame pip install pymunk 首先,导入 import pymunk import pygame from pygame.locals import * import sys import random as rd 结合pygame,创建若干障碍,并设置重力.弹跳力等参数  class Demo: WIDTH=800 HEIGHT=80

  • Python利用Turtle库绘制一个小老虎

    目录 导语 1.定义库以及初始化界面 2.画出左右两只耳朵 3.画出小老虎头部轮廓 4. 画出老虎的两只眼睛 5.画出老虎的鼻子和嘴巴 6.画出小老虎的左右肢体和脚趾 7.在需要的位置写上我们的新年祝福 8. 显示倒数3,2,1 9.显示我们需要的文字 10.设定代码运行入口,调用目标函数 成果展示 导语 哈喽铁汁们好久不见吖~小编已经复工了于是马不停蹄赶来给大家准备新年礼物算开工礼物吧! 海龟来作图 虎年就是要画老虎 2022不用纸和笔~ 今晚画老虎~ 一二三四五 老虎宝宝示意图 虎年怎么能少

  • python利用rsa库做公钥解密的方法教程

    前言 对于RSA的解密,即密文的数字的 D 次方求mod N 即可,即密文和自己做 D 次乘法,再对结果除以 N 求余数即可得到明文.D 和 N 的组合就是私钥(private key). 算法的加密和解密还是很简单的,可是公钥和私钥的生成算法却不是随意的.使用RSA公钥解密,用openssl命令就是openssl rsautl -verify -in cipher_text -inkey public.pem -pubin -out clear_text,但其python网上还真没有找到有博文

  • python利用文件读写编写一个博客

    代码展示 import random import json import time import os     def zhuce():     print("*********************正在注册*********************")     try:         users = readfile()     except:         fa = open(r'test.json', "w",encoding="utf-8&

  • python利用装饰器进行运算的实例分析

    今天想用python的装饰器做一个运算,代码如下 >>> def mu(x): def _mu(*args,**kwargs): return x*x return _mu >>> @mu def test(x,y): print '%s,%s' %(x,y) >>> test(3,5) Traceback (most recent call last): File "<pyshell#111>", line 1, in

  • 使用jquery+iframe做一个ajax上传效果(实例)

    html页面 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" lang="zh-CN"> <head> <title>利用j

  • Python利用PyQt5制作一个获取网络实时NBA数据并播报的GUI程序

    制作NBA数据爬虫 捋顺思路 我们在这里选择的是百度体育带来的数据,我们在百度当中直接搜索NBA跳转到网页,我们可以看到,百度已经为我们提供了相关的数据 我们点击进去后,可以发现这是一个非常简洁的网址 我们看一下这个地址栏,发现毫无规律https://tiyu.baidu.com/live/detail/576O5Zu955S35a2Q6IGM5Lia56%2Bu55CD6IGU6LWbI2Jhc2tldGJhbGwjMjAyMS0wNi0xMyPniLXlo6t2c%2BWspritq%2Bi

  • Python利用PyQt5制作一个获取网络实时数据NBA数据播报GUI功能

    制作NBA数据爬虫 捋顺思路 我们在这里选择的是百度体育带来的数据,我们在百度当中直接搜索NBA跳转到网页,我们可以看到,百度已经为我们提供了相关的数据 我们点击进去后,可以发现这是一个非常简洁的网址 我们看一下这个地址栏,发现毫无规律https://tiyu.baidu.com/live/detail/576O5Zu955S35a2Q6IGM5Lia56%2Bu55CD6IGU6LWbI2Jhc2tldGJhbGwjMjAyMS0wNi0xMyPniLXlo6t2c%2BWspritq%2Bi

随机推荐