找回密码
 立即注册
查看: 265|回复: 0

虚幻4渲染编程(入门引擎篇)【第一卷:初识虚幻引擎】

[复制链接]
发表于 2022-8-22 06:20 | 显示全部楼层 |阅读模式
参考:
1、引擎安装

关于论坛讨论,可以遇到问题后到论坛查找一下:
打开laucher创建一个新的空白项目。选择一下的设置:


注意这里的项目名称,他说好像会影响在VS中的一些标识符。会根据名字创建相应的.cpp和.h。和他一样就得了。
创建项目的时候,会同时创建VS文件,里面有所有的Cpp代码。我们就在里面写代码。


右上角鼠标浮上去就会有相关的引擎版本信息。
同时VS现在会加载出来。
配合鼠标键盘来操作场景视角。
2、视口

配合移动缩放选择组件


和下面的实现连贯和不连贯的移动。


我们还可以按End键,让物体贴到它下面的面上。
3、编辑器概述



最左上角的时标签栏,用于多个项目打开的时候。然后是菜单栏,右边帽子是一个官方给的介绍的工具,还有一个介绍项目相关信息的。


左边时modes栏,里面都是可以访问的各种资源,可以直接拽到场景中。
上边是工具栏。重要的是play按钮。他的下拉框:


可以有不同的运行模式。


然后右下角view option选择:


可以看到


对于世界大纲:


我们可以在物体对应或者寻找物体的时候双击。
我们可以F聚焦某一个物体,然后按住alt键来从周围各个视角来看该物体。
detail 面板:会显示选中物体的各种属性信息。


可以在这里面修改位置等信息,然后回车就生效了。
4、关卡蓝图



然后点击左上角标签,拖拽就能让他独立处于一个浮动窗口。




一般给他拽到上边去。


通过搜索创建第一个node。这个就相当于游戏开始了。


创建一个print函数节点,然后编译并save


这时候我们运行游戏就可以:


同时,我们点击下拉框:


可以进行更多的设置。颜色和持续的时间。
还有一个节点:event tick这个是每一帧都触发的事件。


然后运行的结果:


这个每一帧都会输出一个。


这个是帧数的显示。
5、创建蓝图



在content右键就可以创建自己的蓝图,


这里会让你选择父类。创建后双击打开。
如果创建一个Actor的,那么就会有一个球,代表这里有一个actor,但是这个球只是给我们看的,实际运行起来并不存在。


然后添加一个static mesh


然后选择我们的mesh,右边会有detail panel:


其中有一个设置:


stati mesh一般会有这三个选择,这三个和光照有关系,如果写的是static,表示告诉引擎物体不会移动,那么引擎就会帮我们做bake shadow,这种阴影就是不会动的,不会实时更新的。
stationary是用于光源的,表示光源不会移动,但是可以调整亮度等信息。
然后我们在static mesh设置rock模型,编译保存之后,我们可以吧我们的蓝图直接拽到场景中,


另外:




这里默认有三个节点。


然后:


这样每一帧都能够让x移动1。另外编译之前,我们需要改一下设置,改成movable:


然后回到编辑器。play就可以看出效果。
6、C++和虚幻4











下面是虚幻中的继承关系:




pawn有额外的特性,比如可以用控制器控制(控制器是一个特殊的Actor类,可以接受用户输入),就意味着可以鼠标等控制移动。
character有专属的运动组件,组件有合适的函数,人的各种动作,跳,跑,等等。
而对于这些东西的实现非常复杂:







继承关系中出现的



一个自定义类型的变量作为另外一个类的成员



虚幻中




7、虚幻引擎类的创建



右键点击就可以创建,同样我们还是可以选择父类:


这里的右上角有一个show all ,然后这里我们选择父类为character。


创建好之后,会在VS中打开:


这里类名多了一个A是因为继承于Actor,会自动加上这个A字母。
然后这里的三个函数也都是对于父类的override。
我们可以利用VS的转到定义,一级级的往上找到父类。最后找到UObject,以后有U字母在前边的表示继承于object,如果继承了Actor,那就会变成A。


关于cpp文件中这三个函数给的实现,都是Super::什么,意思就是调用父类的同名函数。
关于构造函数


这个真表示tick函数起作用,false表示不起作用,可以节省一些资源。
8、反射和垃圾回收



c++本身没有,虚幻有反射系统,负责采集数据,负责合并c++数据和虚幻编辑器系统并显示在蓝图中,负责垃圾回收,


关于垃圾回收:大致就是虚幻引擎会记录对象的引用数,一旦所有引用消失之后,便会进行对象的资源回收。
要想实现这一点,我们需要用到宏。
这里有一个UHT,unreal header tool,他是在编译的时候去识别这些宏的,


当他识别到之后,会为这些宏生成相应的code,这样反射系统就可以发挥作用。
UCLASS放在所有类的顶部,代表反射系统的类。修饰之后该类就会有垃圾回收机制。


同时类里面的变量和函数前面也必须加上相应的宏,才能参与反射系统。


这个头文件包含了所有的


上边说的那些宏他们可以在后面加个括号传进去参数。
9、UObject



选中show all之后创建一个继承object的类。


这里的几个头文件,第一个一般object类都会包含它,它包含了object需要使用的大量后台代码。第二个和第一个是差不多的。第三个就是反射系统的,有了它才有垃圾回收,也能够把变量和函数反射至虚幻编辑器中。


这里的三个宏都是为了反射系统进行服务的。
通常来说,我们创建好cpp类之后,我们喜欢创建一个基于该Cpp类的蓝图。


这一点右键就可以实现,但是这里是不行的,


然后我们只需要回到cpp代码加上一个参数就好了:


然后保存,右键build




现在就好了。这是因为我们的反射系统在起作用。
现在就把刚刚的cpp和这里的蓝图联系在一起了。创建的东西就是之前cpp代码的蓝图版本。


他是object,不是actor,我们之前说class继承关系的时候,说过object不能直接拽到level中,


现在给cpp中加上一些自定义的变量和函数,同时写上构造函数,注意类名需要加上U~
想要在虚幻里面看到这些变量函数,需要加上宏:


但是加了之后只是反射系统弄过去了,但并不能访问,需要访问的话得对宏加上参数,


另外还需要加上public,才能真的访问的到。


同时cpp文件中写上俩函数的定义。执行build


现在回到蓝图之后,我们就可以read and write myfloat。


10、在蓝图中运用UObject



这里我们在两个宏里面加上更多的参数。


这时候就是对于我们的变量进行一个分类。这样可以更好的区分变量和函数。


我们还可以设置为ReadOnly。这样让蓝图那里九只能读。
我们可以对我们的函数写一些实现:




第一个参数表示该日志的类别是临时的,warning表示警告,会输出颜色为黄色。编译之后我们到MyActor:


我们只需要在这里添加一个MyObject_BP类型的变量。detail面板可以修改类型:


这里搜索,不带BP的是c++类,而带BP的是蓝图。注意右边还会出来四个选择,我们通常选第一个。
然后把变量拽到视口中,然后选择get就可以得到MyObject类的对象了。


然后一拽就能够访问它的函数了。然后连接到BeginPlay上:


这样游戏一旦开始就会调用这个函数了。


然后把日志窗口调出来。


这时候直接运行会出错。


原因就是我们创建的myobject_BP对象只是一个指针,指向该类型的指针,同时你看一下默认值是none,也就相当于这是一个空指针,那么这肯定不能访问相应的函数的。
所以我们需要创建处相应的对象,那么怎么创建呢?在C++中需要相应的new和构造函数,这里可以用一个节点:


这里第一个class是我们需要构造对象的那个类,然后outer这里是在Actor类中写的,就写MyActor就好了,最后的返回值其实就是new的结果,也就是指向构造的对象的指针。


然后我们用该指针去set我们的变量,set之后就可以调用函数了。


我们就可以看到我们设置的log了。
所以捋一捋:我们在c++ class 的地方创建一个c++类,然后用VS打开把代码完善,并设置好反射系统,然后回到UE,我们可以创建出这个c++类对应的蓝图类,然后这个类如果是Object的,不能直接拽到level中,那么我们可以在其他蓝图类中创建该类的对象,来使用该类编写好的函数。然后其他的蓝图类可以拽到level中直接创建一个实例。
11、Actors和Actor组件



这里首先创建一个BluePrints文件夹,把我们的蓝图都放进去,便于查找。


我们现在又俩蓝图,对于My Actor来说我们是直接右键创建的蓝图类,也就是说他并不想MyObject那样有一个对应的C++类。
我们现在想要创建一个带有对应c++类的蓝图Actor。我们要创建一个新的actor,它可以四处浮动,所以我们合理命名为Floater。


这里生成的代码和我们之前的MainCharacter是类似的,但是比character少了一个


这一点我们之前介绍虚幻中这些类的时候说过,character是继承于pawn,而pawn则是来自Actor的,也就是Actor更加基础一些。character功能更多一些,包括鼠标键盘输入等等。
然后我们就可以直接创建想要的蓝图类了,之前我们的Object还需要设置一下Blueprintable,这里并不用了,因为它继承了父类的这一点。(在Actor中)


然后创建相应的蓝图,打开后:


我们看一下这里的组件,组件是UObject的特殊类型,专门被用作Actor中的子对象,每一个Actor都有一个DefaultSceneRoot组件,这个组件不可见,不支持可视化,也不能赋给他网格,这个就是那个白色的球,但是它现在显示一个白色的球,只是告诉我们有东西,实际游戏的时候就没了。


我们把蓝图类拽到场景中,然后创建相应的实例,是可以看到那个球的,但是游戏一旦运行起来就没了。只是给我们一个reference。告诉我们这里有一个Actor。
这个是Scene 组件,他是Actor组件的一种,是一个basic组件,它支持的detail panel有transform等等。
primitive组件更加的具体。他是源于场景组件的,有几何和碰撞等信息。


这里的cube这些组件就是primitive组件,我们创建之后可以有static mesh。


我们创建cube之后,cube是root的child,会随着场景的transform等变化。


然后我们可以把scene root组件给舍弃,用我们创建的cube取而代之。


只需要拽着cube到root上边就好了。刚刚我们按End键对齐是按照球的中心和面对齐的,但是现在改了root之后,再对齐就是以立方体的底部进行对齐了。这样体现了场景组件和primitive组件的不同。
当我们现在把cube组件删除,之前的默认的scene组件就又回来了。
我们可以在该位置创建static mesh来使用,也可以在cpp code中创建。


组件是特殊的Object,所以这里我们不要忘记U前缀:


但是上边我们只是创建了一个指针,并没有实际的组件,我们还需要在构造函数中:


这个函数就是用来创建对象的,可以创建任意类型的对象,模板参数告诉它类型即可,然后参数是一个TEXT。


这时候我们就创建出来了。
12、位置矢量



这里我们先创建一个新的文件夹,然后导入这个模型,导入的同时UE会帮我们创建一个材质。
这里的


这个mesh导入之后会同时导入四个材质球。


我们按住ctrl 或者 shift都可以实现多选,当我们想要移动的时候,按住shift进行一个移动,会使得相机和物体一起移动。
剩余的就是说了一下关于位置表示。
13、FVector 上

我们可以在detail panel中设置位置变换,同样我们在代码中也可以实现:


这样我们就可以实现,让物体在游戏运行的时候把位置重置到原点。
然后点开了FVector看了一波,这个FVector的第一个字母f是因为和计算有关系,f表示float,计算多是float。
14、FVector 中

这里我们尝试把设置的位置作为类的一个成员,然后成员在面板中是可以编辑的。


这里我们多加了一个宏的关键字。他的作用就是:EditInstanceOnly表示该属性可通过属性窗口来编辑,但仅能对实例而非原型进行编辑。
面板中剩余的东西就是这个对象的组件的属性,因为组件其实说白了就是组成该对象的成分,所以组件的属性就是该对象的属性。包括mesh 等等的全都是。


上边的InstanceOnly怎么体现的呢?其实我们在蓝图中是找不到这个值的,蓝图中如果有了,那就相当于对类本身的值进行修改了,而不是对每一个实例去编辑。
这里还有一个位置的设置,就是当我们把一个instance拽到视口中的时候,它放在哪里,这个位置我们可以给显示出来。


这里又用到了一个新的关键字,VisibleInstanceOnly : 表示该属性仅在实例的属性窗口中可见,但对原型则不行,并且无法被编辑。其实对于实例可见对于原型不可见这一点还有一个理解方式:就是每一个实例的该值是可以不一样的,原型你也没法显示。
然后这个位置我们只需要在游戏刚开始的时候获取赋值一下就行了,


我们只需要运行之后按shift + f1就可以把鼠标弄出来,然后用鼠标点击世界大纲中的这些instance,我们就可以看到他们被拽进去的位置。
接下来弄一个bool类型的变量,bool类型的需要在变量名前面加一个b,这个是虚幻的代码习惯,加上就得了。


这里新的关键词,EditDefaultsOnly,表示该属性可通过属性窗口来编辑,但仅能对原型编辑。


这时候虚幻把我们的bool类型b字母就给自动去掉了。
15、FVector 下



16、碰撞



这里的模型本身没有带简单碰撞,我们可以自己去为他添加:


点击后:


我们根据这个组件,是可以对碰撞的盒子进行一个编辑的,包括平移缩放旋转等。


也可以进行remove。还可以尝试其他各种各样的包围盒。


回到蓝图中,这里有一个物理模拟的开关,然后下面的Mass是质量,后面还有是否开启重力,如果关闭物理模拟,开启重力是没用的。
damping那俩是线速度阻尼和角速度阻尼。就是减慢平移速度和转动速度的。


场景中的这种图标没了按一下G就回来了,回来之后再按就消失了。
17、碰撞(续篇)



在蓝图中我们创建一个节点,创建之前,我们要在左边点一下选中这个:


才能搜索到该节点。因为他们需要static mesh,这样选中之后生成的节点会自动帮我们带出来一个static mesh。这个static mesh我们也可以选中上边的,然后拽进去也会出现。


我们把力的值设置好之后,我们编译会出现警告,我们一定要弄清楚原因,这里就是静态网格节点有限制,不可以在蓝图中使用。我们需要在cpp中消除这一点限制。


加上上边这个就好了,其实这就是cpp中限制了蓝图操作,而蓝图中硬操作出现的结果。


然后我们如果把椅子的物理模拟也加上,就会出现互相碰撞,椅子被撞翻了的情况:


然后我们可以查看这些物体的


这时候我们运行,然后shift+f1把鼠标显示出来,按一下键盘上的~键,就可以出现一个cmd:


然后我们输入show collision然后直接回车,就可以看到物体的碰撞检测的盒子了:


另外这里如果我们关闭重力:


就直接像太空人一样飘起来了,如上图的桌子。
18、扫除



这里的shape,各种的网格形状,如果我们把他们拽到视口中,那么实则是创建了一个带静态网格的Actor。


然后把立方体给缩放成一个墙,关闭物理模拟和力量的节点(需要在实例的面板和默认设置面板都给关了)。


然后勾选一下自动Float的,这时候我们去运行游戏,我们的盒子并不会和墙相撞,而是直接float穿过墙。直接穿透过去。
原因就是我们关闭了物理模拟。


然后回到我们的c++代码中,这里的第二个参数是是否sweep,而这个sweep就和我们的碰撞检测相关。
如果我们把刚刚的物理模拟关掉,然后把这里的sweep改成true,这样再运行就会发现盒子不能穿过墙了,


也就是sweep为true,会组织碰撞发生。


第三个参数是一个结构体,他里面有一个成员,首先这个结构体是一个hit result表示hit命中结果,然后这个成员的意思是:该命中结果是否是阻挡碰撞的结果。




这里还有一个成员,表示hit的location,这里他的类型是FVector的优化版本,我们可以把他当作FVector使用。


然后我们吧hitLocation给输出一下:


刚开始没有hit信息,也就是保持默认初始化的状态,全都是0,然后第一次碰撞发生之后就更新hitlocation。


对于每一个物体还有一个collision模块,


其中的设置还可以自定义,让我们有很大的自由度。


这里有一个Object Type,这个选项能够决定该对象和其他对象碰撞时的表现。同时她下面的勾选,是对于其他类物体的回应,可以忽略可以重叠,阻挡。


我们的floater,他的object 类型是world dynamic,然后我们修改一下墙的


变成自定义的,然后我们设置和world dynamic碰撞为overlap也就是重叠。这样我们运行之后就算sweep为true,但是这里设置的类型是overlap,他也会进行一个穿透了。当然在floater那里修改该physicsBody类型的选择也是一样可行的。
19、局部与世界偏移

把之前的每一帧平移给关掉,然后再beginplay的地方加上:


这里我们给我们的物体发生一些旋转,


然后通过上边的这个地方,我们就可以对物体身上的平移组件显示的轴进行一个切换,切换世界或者local轴。而我们旋转之后,世界轴和局部轴不再统一,这时候我们可以发现我们刚刚的offset是顺着局部轴进行的。因为他就叫 localoffset。
我们想要顺着世界的轴平移,那就可以换个函数。


我们出了平移还有旋转:


这里的三个参数表示的pitch yaw roll。


我们现在的形状不容易看出旋转效果,可以给他处理一下:


我们只需要添加一个新的static mesh组件,然后给他放上去我们的轴mesh。


现在就能明显看出旋转之后的效果了。可以看出pitch是抬头低头,yaw是左右扭头。roll是身体左右摇摆。
我们也可以把这个rotation操作放在每一帧中,也可以设置worldrotation。
20、力矩和扭矩

之前我们说过一个AddForce,也就是给物体加一个恒定方向和大小的力,那个带来的结果就是物体会发生平移,而这里有一个类似的力,就是让物体发生旋转的,扭矩。torque。


加上这两行,这里视频中出现了一些问题,他的VS不认识StaticMesh对应的类型,也就是缺了一个头文件,然后缺的什么头文件呢?


可以直接搜索这个名字,然后发现有这么一个头文件:


加上就好了,我这里并不需要这个头文件就可以跑起来,可能是版本问题吧~
运行之前需要开启物理模拟才会有效果。
另外一个小经验,就是在测试力这类东西的时候,因为大小可能需要随时调节,所以我们最好加个UPROPERTY,这样可以设置成面板那里直接手动调节了。不需要每次修改code,然后compile了。
类似的我们也在面板上设置一个torque的,




21、随机数值

这里主要是介绍关于虚幻里面的数学函数,有一个FMath,F开头是一个结构,然后他里面有很多的静态函数,我们可以::来直接调用,至于每一个函数的左右,我们可以通过函数名字和一些转到定义的手段来确定,并且可以多做做实验。
我们可以FMath::FRand来生成一个随机值,来作为initialLocation。


这里你会发现随机值永远是正数,我们想要负数可能还需要两个相减,但是我们还有一个RandRange,这个就可以自己指定范围了。
22、正弦函数

我们利用正弦函数来对物体的浮动方式进行一个控制。


正弦需要随着时间来进行一个计算,我们这里获取时间的方式就是利用每一帧的deltaTime,然后利用一个变量对这些deltaTime进行不断累加。


正弦函数返回值是-1到1的,如果我们想要实现上下的漂浮,那么我们只需要让我们的xy不变,然后z和sin函数一致进行周期性变化就好了。


这样球就可以实现浮动的效果了。我们可以修改正弦函数的系数,外面的系数可以影响上下浮动的最大幅度,里面加一个系数可以修改浮动的周期。当然也可以尝试最后面加一个上下平移。


我们这里可以把三角函数的三个参数给变成成员,然后暴露到蓝图中,这样可以直接在面板中进行一个修改。


这里我们在分类的时候分类一个子类,Wave Parameters,只需要在中间加一个 | 符号就可以实现。


另外注意,我们每次重现编译代码,都会让面板上的这些参数重置为构造函数中写的值。
改一下名字:A是Amplitude,表示波幅,B叫TimeStretch,表示波左右伸展。


当然它的作用不只是浮动,我们可以这么对xy使用,这样就可以画圆了。


我们回顾一下原来的式子,其实这个东西并不是表示的在初始z位置上-1到1的浮动,他是拿的上一次的z去和三角函数做加法,第一次z = 0,然后加了0.1,第二次z = 0.1,z加了0.2,这样第二次相加之后就等于0.3了,这也是为啥我们A=1的时候还能有那么大的幅度。
如果我们是只对最开始的时候的z值加上三角函数,A 等于1 的时候上下浮动基本上是看不出来的。但我们看具体的z值是可以看出确实在上下浮动的。


另外这里如果在UPROPERTY里面加上一个BlueprintReadOnly,我们再进行编译会报错,这个错误我们只需要把他们放在public下面就好了。


这里其实还有一个,就是加在sin()括号内部的值,这个影响并不大,知道就好了:


23、删除类

我们现在知道了如何为类添加组件,添加静态网格组件,
删除蓝图的话,直接按delete


然后所有的instance都会消失,但是对于cpp class直接delete是不行的,而且右键也不能删除。
具体方式:




把这俩文件删除就行了。但是还没完,还得删除一些文件,


这个给删除了。


然后右键项目文件,generate那一项。然后重新打开项目,会提示dll确实,点yes重新生成就好了。刚刚删除的Binaries会重新生成,这样我们的cpp类就删除干净了。
flaoter.h
// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Floater.generated.h"

UCLASS()
class FIRSTPROJECT_API AFloater : public AActor
{
        GENERATED_BODY()
       
public:       
        // Sets default values for this actor's properties
        AFloater();

        UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = "ActorMeshComponents")
        UStaticMeshComponent* StaticMesh;

        UPROPERTY(EditInstanceOnly, BlueprintReadWrite, Category = "Floater Variable")//实例信息可编辑
        FVector InitialLocation;

        UPROPERTY(VisibleInstanceOnly, BlueprintReadWrite, Category = "Floater Variable")//实例信息可见
        FVector PlacedLocation;

        UPROPERTY(VisibleDefaultsOnly, BlueprintReadOnly, Category = "Floater Variable")//原型可见
        FVector WorldOrigin;

        UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Floater Variable")//原型,实例均可编辑
        FVector InitialDirection;

        UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Floater Variable")//原型,实例均可编辑
        bool bShouldFloat;

        UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "Floater Variable")//原型可编辑(默认设置下就是所说的原型)
        bool bInitializeFloaterLocation;

        UPROPERTY(EditInstanceOnly, BlueprintReadWrite, Category = "Floater Variable")
        FVector InitialForce;

        UPROPERTY(EditInstanceOnly, BlueprintReadWrite, Category = "Floater Variable")
        FVector InitialTorque;

private:
        float RuningTime;
public:
        UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Floater Variable | Wave Parameters")
        float A;
        UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Floater Variable | Wave Parameters")
        float B;
        UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Floater Variable | Wave Parameters")
        float C;
        float BaseZLocation;

protected:
        // Called when the game starts or when spawned
        virtual void BeginPlay() override;
         
public:       
        // Called every frame
        virtual void Tick(float DeltaTime) override;

};
floater.cpp
// Fill out your copyright notice in the Description page of Project Settings.


#include "Floater.h"

// Sets default values
AFloater::AFloater()
{
        // Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
        PrimaryActorTick.bCanEverTick = true;
        StaticMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("CustomStaticMesh"));

        InitialLocation = FVector(0.0f);
        PlacedLocation = FVector(0.0f);
        WorldOrigin = FVector(0.0f);
        InitialDirection = FVector(0.0f);
        bInitializeFloaterLocation = false;
        bShouldFloat = false;
        InitialForce = FVector(2000000.0f, 0.0f, 0.0f);
        InitialTorque = FVector(2000000.0f, 0.0f, 0.0f);
        RuningTime = 0.f;
        A = 1.f;
        B = 1.f;
        C = 0.f;
}

// Called when the game starts or when spawned
void AFloater::BeginPlay()
{
        Super::BeginPlay();


        InitialLocation = FVector(FMath::FRandRange(-1000.f, 1000.f), FMath::FRandRange(-1000.f, 1000.f), FMath::FRandRange(-1000.f, 1000.f));

        PlacedLocation = GetActorLocation();
        if (bInitializeFloaterLocation) {
                SetActorLocation(InitialLocation);
        }
       
        BaseZLocation = PlacedLocation.Z;

       
        //StaticMesh->AddForce(InitialForce);
        //StaticMesh->AddTorque(InitialTorque);

        //FHitResult FHitResult;
        //FVector LocationOffset = FVector(200.0f, 0.0f, 0.0f);
        //AddActorWorldOffset(LocationOffset, true, &FHitResult);
        //FRotator Rotation = FRotator(0.0f, 0.0f, 50.0f);
        //AddActorLocalRotation(Rotation);
}

// Called every frame
void AFloater::Tick(float DeltaTime)
{
        Super::Tick(DeltaTime);

        if (bShouldFloat)
        {

                RuningTime += DeltaTime;
                FVector NewLocation = GetActorLocation();
                NewLocation.Z = BaseZLocation + A * FMath::Sin(B * RuningTime) + C;


                SetActorLocation(NewLocation);


                //FHitResult FHitResult;
                //AddActorLocalOffset(InitialDirection, true, &FHitResult);

                //FVector HitLocation = FHitResult.Location;

                //UE_LOG(LogTemp, Warning, TEXT("Hit Location : X = %f, Y = %f, Z = %f"), HitLocation.X, HitLocation.Y, HitLocation.Z);
        }

        //FRotator Rotation = FRotator(0.0f, 0.0f, 1.0f);
        //AddActorWorldRotation(Rotation);
}

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-6-27 18:16 , Processed in 0.072434 second(s), 23 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表