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

想要了解Ursina 3D引擎的基本使用方法的话,查看我的另一篇文章:

手把手教你用Python编一个《我的世界》 1. 认识Ursina并学会绘制立体图形_Leleprogrammer的博客-CSDN博客_ursinaPython有一个不错的3D引擎——UrsinaUrsina官网:www.ursinaengine.org打开cmd,控制台输入pip install ursina以安装ursina编写第一个程序首先导入ursinafrom ursina import *然后创建appapp=Ursina()运行appapp.run()最终代码:from ursina import *app=Ursina()app.run()如果出现了一个灰色的窗口,https://blog.csdn.net/leleprogrammer/article/details/124780527?spm=1001.2014.3001.5502


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


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

Earth.png

Jupiter.png

Mars.png

Mercury.png

Neptune.png

Saturn.png

Sun.png

Uranus.png

Venus.png


现在,就开始写代码吧!

首先,导入我们需要的模块,导入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=0self.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=_typetexture=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*=200self.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 planetssuper().__init__()camera.fov=90self.position=planets[3].positionself.gravity=0self.vspeed=2self.speed=600self.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.vspeedif held_keys["space"]:self.y+=self.vspeed

然后在主程序中写update方法,并在其中调用我们刚刚写的player中的_update方法,再对星球进行自转公转操作

def update():global planets,playerfor 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 rdapp=Ursina()
window.fullscreen=True
window.color=color.blackplanets=[]class Planet(Entity):def __init__(self,_type,pos,scale=2):self.angle=rd.uniform(0.0005,0.01)self.fastMode=0self.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=_typetexture=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*=200self.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.fastModeclass Player(FirstPersonController):def __init__(self):global planetssuper().__init__()camera.fov=90self.position=planets[3].positionself.gravity=0self.vspeed=2self.speed=600self.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.vspeedif held_keys["space"]:self.y+=self.vspeeddef update():global planets,playerfor 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]*10player=Player()if __name__ == '__main__':app.run()

喜欢的话就点赞收藏+关注吧~

谢谢支持~

Python 用Ursina 3D引擎做一个太阳系行星模拟器相关推荐

  1. Python 用3D引擎写一个Pong游戏

    之前,我们用pygame做了一个2D的Pong游戏,今天我们做一个3D的,游戏画面如下: 用ad和←→操作,双人对战 实现该效果我们使用Python强大的3D引擎Ursina,基础的使用方法见下方这篇 ...

  2. Python pyglet 自制3D引擎入门(一) -- 绘制几何体、创建3D场景

    Python作为目前较广泛的编程语言, 用于制作3D游戏可谓得心应手.本文讲解应用Python pyglet库绘制3D场景的入门知识. 下篇:Python pyglet 自制3D引擎入门(二) – 绘 ...

  3. Python pyglet 自制3D引擎入门(二) -- 绘制立体心形,动画和相机控制

    Python作为目前较广泛的编程语言, 用于制作3D游戏可谓得心应手.本文讲解使用Python pyglet库自制简易3D引擎的方法技巧. 上篇:Python pyglet 自制3D引擎入门(一) – ...

  4. python手机版做小游戏代码大全-Python大牛手把手教你做一个小游戏,萌新福利!...

    原标题:Python大牛手把手教你做一个小游戏,萌新福利! 引言 最近python语言大火,除了在科学计算领域python有用武之地之外,在游戏.后台等方面,python也大放异彩,本篇博文将按照正规 ...

  5. Unity做一个太阳系

    Unity做一个太阳系(适合初学者学习) 步骤 1.新建Unity项目(我用的unity2019) 2.在assets中建script文件夹,material文件夹. 2.创造9个sphere物体:太 ...

  6. 利用python加上ffmpeg,ffmpy,做一个音视频格式转换器

    利用python加上ffmpeg,可以做一个简单的音乐或者视频格式转换器. 可以利用PyQt5做界面,本例中比较简单: 流程非常简单,点击"选择源文件",选取要转换的音频或者视频文 ...

  7. 用html+ccs3就能 做出一个太阳系行星

    2019独角兽企业重金招聘Python工程师标准>>> 做一个太阳系八大行星的运转动画,不包括行星的卫星,所有行星围绕太阳公转,行星采用纯色,暂时没有自转. 效果静态图: 动画中包括 ...

  8. python大作业数独_python做一个数独小游戏

    最近看了下python的一些知识,在这里记载一下. 1.首先是安装,在官网下载最新的版本3.6,安装的时候要注意在下面勾选上ADD TO PATH,安装的时候会自动写入到环境变量里面,如果没有勾选,可 ...

  9. 用python做生日礼物_如何做一个网页送给女朋友做生日礼物?

    如何做一个网页送给女朋友做生日礼物 本文里面涉及到python,HTML ,css,JavaScript的知识,是基于python的flask框架做的一个小型网站,里面可以实现跳转功能,怎么配置fla ...

最新文章

  1. 美团面试题:JVM 堆内存溢出后,其他线程是否可继续工作?
  2. 如何搭建高可用Redis服务
  3. mongodb自动关闭:页面太小,无法完成操作
  4. Fedora 添加用户与删除用户
  5. Quagga:开源的基于Zebra实现了RIP, OSPF, BGP的动态路由软件
  6. java计算器用什么布局_求JAVA语言写的计算器的代码。用GridLayout布局。
  7. ABAP 读取FTP文件
  8. C#:$符号和@符号的用法介绍
  9. 比特币 转账交易为什么要等6个区块确认才算到账 安全 以太坊12个区块
  10. spring boot first
  11. Android lint工具 检查的常见问题
  12. 自己做的小游戏希望大家能喜欢
  13. 用MediaCreationTool做纯净版Windows 10系统U盘
  14. doc 问卷调查模板表_问卷调查表格式范本.doc
  15. 基于opencv的手眼标定算法详解一-----------opencv之相机标定函数calibrateCamera()介绍
  16. CodeForces1036 F Relatively Prime Powers(莫比乌斯容斥)
  17. 第一周学习报告(关于string)
  18. 智联招聘VSBOSS直聘VS拉勾 竞品分析
  19. 用Python选取神股(简单、粗暴)
  20. 爬取虎扑社区-晒晒照片

热门文章

  1. python随机森林变量重要性_python机器学习之随机森林(七)
  2. geoserver之gs-kml、gs-wcs、gs-rest、gs-gwc、gs-sec-jdbc
  3. 关于windows server 2016服务器 exchange 2010 managment Shell 停止工作的问题(已解决)
  4. 时间、延迟以及延缓操作
  5. 关于调整互联网、电话订票起售时间的公告
  6. LE PETIT PRINCE
  7. 02好好学习读书笔记-- 黄金思考圈
  8. 阿里云Docker仓库操作
  9. 重庆大学计算机学院课题组,【计算机】计算机学院关于智能计算的大规模优化学术报告圆满结束...
  10. VPP DPDK,不是翻墙!!