当前位置:

首页 > 编程开发 > 使用Python和3D引擎制作一个太阳系行星模拟器的教程

使用Python和3D引擎制作一个太阳系行星模拟器的教程

这一次,我们要实现的效果如下首先,送上本次需要用到的资源Earth.jpgJupiter.jpgMars.jpgMercury.jpgNeptune.jpgSaturn.jpgSun.jpgUranus.jpgVenus.jpg现在,就开始写代码吧!首先,导入我们需要的模块,导入3D引擎ursina,数学库math,ursina中自带的第一人称,sys,random随机库fromursinaimport*frommathimport*fromursina.prefabs.first_person_cont

本文目录

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

    使用Python和3D引擎制作一个太阳系行星模拟器的教程

    使用Python和3D引擎制作一个太阳系行星模拟器的教程

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

    Earth.jpg

    使用Python和3D引擎制作一个太阳系行星模拟器的教程

    Jupiter.jpg

    使用Python和3D引擎制作一个太阳系行星模拟器的教程

    Mars.jpg

    使用Python和3D引擎制作一个太阳系行星模拟器的教程

    Mercury.jpg

    使用Python和3D引擎制作一个太阳系行星模拟器的教程

    Neptune.jpg

    使用Python和3D引擎制作一个太阳系行星模拟器的教程

    Saturn.jpg

    使用Python和3D引擎制作一个太阳系行星模拟器的教程

    Sun.jpg

    使用Python和3D引擎制作一个太阳系行星模拟器的教程

    Uranus.jpg

    使用Python和3D引擎制作一个太阳系行星模拟器的教程

    Venus.jpg

    使用Python和3D引擎制作一个太阳系行星模拟器的教程

    现在,就开始写代码吧!

    首先,导入我们需要的模块,导入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()

    然后就能实现文章前面展示的效果啦~

    使用Python和3D引擎制作一个太阳系行星模拟器的教程

    使用Python和3D引擎制作一个太阳系行星模拟器的教程

    最后,附上代码

    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()
    本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系bd@zhengruan.com
    作者最新文章
    编程开发 Python
    相关文章 更多
    python删除一个列表里的重复元素的方法与代码示例
    python删除一个列表里的重复元素的方法与代码示例

    学习如何使用Python高效删除列表中的重复元素。本文提供5种常见方法的代码示例,涵盖保持顺序与不保持顺序的场景,适合初学者和进阶开发者参考。

    Python写接口的步骤及完整代码示例
    Python写接口的步骤及完整代码示例

    详细讲解使用Python编写Web接口的核心步骤与完整代码示例,涵盖环境准备、路由定义、数据校验、服务启动及调试测试方法。

    codex怎么读取word文档及docx文件操作教程
    codex怎么读取word文档及docx文件操作教程

    介绍如何利用编程工具读取和解析Word文档(docx格式),涵盖基础文本提取代码示例、结构化数据处理逻辑,以及处理复杂排版时的技术局限与替代方案。

    怎么在Python中调用C语言代码提升性能
    怎么在Python中调用C语言代码提升性能

    详细讲解在Python中调用C语言代码提升性能的完整实践指南,包含原理分析、编译步骤、ctypes与CFFI具体实现、性能对比及常见陷阱。

    Python与C语言的性能差异及底层原理
    Python与C语言的性能差异及底层原理

    深入解析Python与C语言在执行效率上的数量级差异,从编译机制、变量内存布局、动态类型推断到GIL锁,系统阐明底层核心原理。

    Python和C语言哪个更适合编程入门
    Python和C语言哪个更适合编程入门

    客观对比Python与C语言在心智负担、底层机制与学习反馈上的核心差异,提供清晰有据的选择标准与切实的入门学习路径。

    selenium上传文件教程本地文件路径设置方法
    selenium上传文件教程本地文件路径设置方法

    深入解析Selenium处理文件上传的技术细节,涵盖标准HTML控件的路径直接注入法与非标准控件的系统级模拟方案,提供Windows与Linux环境下的路径设置最佳实践及常见异常排查。

    大数据开发语言选型:Java对比Scala与Python的优缺点及适用场景
    大数据开发语言选型:Java对比Scala与Python的优缺点及适用场景

    针对大数据工程场景,系统对比Java、Scala与Python在执行性能、生态结合、开发效率和维护成本上的核心差异,给出清晰的架构选型依据与落地方案。

    langgraph python guide中文入门教程详解
    langgraph python guide中文入门教程详解

    本篇LangGraph Python中文入门教程详解,系统梳理StateGraph状态机定义、节点编写、边与条件路由、检查点持久化(MemorySaver)等核心机制,提供从环境安装到完整循环智能体构建的代码示例与实操指导。

    Windows 安装 Python:从官方入口到虚拟环境的可复现实践
    Windows 安装 Python:从官方入口到虚拟环境的可复现实践

    面向后端开发者,基于 Python 官方文档说明如何在 Windows 上安装 Python、创建 venv 虚拟环境及使用 pip 管理依赖。包含可复制命令、验证方法及工具选择边界,避免常见配置误区。

    查看更多
    精品专题 更多
    装机必备
    装机必备

    正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

    Windows
    Windows

    正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

    PDF教程
    PDF教程

    正软商城PDF教程频道提供PDF编辑、转换、合并、拆分、压缩及格式处理方法,同时介绍常用PDF软件和工具的使用技巧。

    Mac软件 更多
    讯飞智作 网页版
    讯飞智作 网页版
    Windows/ macOS/ Linux

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版
    Windows/ macOS/ Linux

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    Aperty macOS版
    Aperty macOS版
    macOS

    Aperty 是 Skylum 推出的 AI 人像修图软件,支持自然肤质修饰、瑕疵处理、面部与身体调整、预设及批量同步。

    WINDOWS 更多
    讯飞智作 网页版
    讯飞智作 网页版
    Windows/ macOS/ Linux

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版
    Windows/ macOS/ Linux

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    PixTV 网页版
    PixTV 网页版
    Windows

    PixTV 是一款在浏览器中使用的 AI 视觉内容创作平台,提供图片、视频、音频、文字生成、AI 分镜、局部重绘、提示词反推和无限画布等工具,适合短剧、漫剧、广告及社交媒体内容制作。