UE4总结四

1,将一段逻辑改成一个函数,选中逻辑右键collapse to function即可写成了函数

 

3,求得两个向量的夹角,这里求得是一个箭头和角色的两个物体的面向夹角是否是75度以内也可以说箭头的方向是否在人物面向的150度以内

这里的。代表向量的相乘,acos也即反三角函数arccos

 

4,Blend Poses By bool在动画状态机中通过该函数达到一个状态机下面使用多种动画,比如敌人拿着枪的时候不瞄准可以一边移动一边转向你得身边,但是瞄准的时候只能移动不能旋转就这样调用

 

5,将HUD的血条显示和PlayerCharacter中的血量绑定并更新:

在PlayerCharacter中自定义事件PerformUpdateHealth,因为PlayerCharacter要和HUD同时调用一个函数因此采用事件调度器,创建一个UpdateHealth事件调度器,拖动到事件列表中选择调用,每次人物受到伤害就自动调用PerformUpdateHealth事件,再传入到事件调度器中

在HUD中的Designer中设置好血条,在Graph中在事件Construct中拿到PlayerCharacter绑定事件调度器,注意的是,要从红色方框事件向外拉出创建一个自定义事件,而不是创建一个自定义事件再连到方框事件中

如果将感觉血条掉血速度很快,用一个平滑的差值处理,做法如下:用一个TimeLine做平滑处理,也可以用sin等函数,起点0,0终点0.1,1再调用lerp来做差值

 

6,在角色死亡时候调用死亡动画,设置bool值isDead默认false,死亡瞬间置为true,但是瞬间destroy敌人会导致isDead又恢复默认false,解决方法:死亡时刻延时2秒调用死亡动画。

 

7,要拿到animBulePrint首先要拿到该角色的mesh调用Get Anim Instance方法

 

8,pawn可以直接转为子类的character,子类的character里可以拿到mesh组件

pawn可以拿到movement组件

 

9,开门关门动画代码:

 

10,事件调度器:目前知道的是用于逻辑和界面交互的,在逻辑中把数据输入给定义好的事件调度器,在UI中绑定事件调度器,自定义事件将数据显示到控件上

 

11,当人物掉到地面就刷新怪物,给地面设置tag为land,人物character中碰撞到tag为land就触发

犯错点:直接取数组的第0号元素,玩意数组没有元素呢。程序就崩了,所以要加上判定length>0才行。

 

12,对于渐变如果在HUD中不能在蓝图中用时间轴,要用动画,做法:添加动画,自定义动画名称,在时间轴中添加HUD的哪个组件,设置是哪个属性的渐变

 

13,对于旋转rotation的信息可以右键Split Struct Pin转成3个角度的分量

变成这样

 

14,Clamp函数的作用,限制最大值和最小值

 

15,UE_LOG(LogTemp, Warning, TEXT("hitLocation:%s"),*HitLocation.ToString());注意HitLocation.ToString()前面一定要加*  否则报错

CompilerResultsLog: 信息         with
CompilerResultsLog: 信息         [
CompilerResultsLog: 信息             T1=FString
CompilerResultsLog: 信息         ]

 

16,想了解引擎中类的继承结构,点击Windows(窗口)---->开发者工具----->类别查看器---->过滤器将仅actor去掉勾选

 

17,.uasset文件导入不能直接拖,要移动到项目中的content文件夹中才能生成,把调试对象改成当前人物的即可

18,游戏运行时要想知道逻辑运行到哪个分支

 

19,对于这种bug

或者行走动画一闪一闪的,解决办法,勾上就行

还有把右侧的loop Animation去掉勾就行

 

20,箭头的mesh为什么旋转了结果没反应呢?

因为在代码中attach的Rotation Rule使用的Snap to target,因此它和目标的旋转是一样的,因此改成keep Relative

 

 

 

导入坦克部分的总结:

对于人物靠近坦克按r键人物消失切换到坦克视角,做法:拿到gameMode,把Default Pawn切换成坦克,Controller从角色切换成坦克,但是拿到GameMode有set Default Pawn的函数但是没有set Controll的函数,因此可以共用一套controller,判断角色是人物还是坦克。

1,对坦克的FBX导入时不想让导入的是一对散乱的零件而是拼好的整体,将fbx拖动到资源弹出FBX导入选项,在mesh中选择Combine Meshes

2,将多个部分的组件拼接好的做法:创建蓝图类继承actor取名BP_Tank,添加static mesh在mesh选择Tank_Body,然后再加一个static mesh将它放到BP_Tank下面mesh选择左边坦克履带,调整好位置。再加static mesh加入右边履带

3,当然如果不用这种用相对位置拼接的方法还可以通过挂点的方式,步骤

在右侧插槽管理器中创建插槽,存储其他组件的位置,

最后再BP_Tank中添加static mesh选择LeftTrack在插槽中选择刚才创建的那个,这样不用设置相对位置就自动对应好位置了

4,现在要一进游戏就控制坦克怎么控制呢?创建GameModeBase,打开,要想让控制坦克要让属性中的Default Pawn Class选择坦克,但是坦克是actor不是pawn,找到BP_Tank,类设置--->Class Options--->Parent  Class把actor改成pawn

5,如果现在进游戏还不是坦克,打开项目设置,搜索Gamemode把Default GameMode改成创建的那个

6,现在进入游戏有了坦克,但是视角不能左右移动,在tank蓝图类中添加摄像机,首先添加Spring Arm,在下面再加入相机,

Spring Arm的作用是一个手臂举着相机,将Target Arm Length改成1200调整相机视角

7,对于坦克相机的左右镜头和上下镜头的移动,设置好鼠标的pitch和yaw移动,

如果想让坦克只是镜头转动但是坦克不动这样:对于tank这个pawn都不勾,但是相机都勾

效果如下:

如果想让坦克和镜头一起左右转,pawn勾选yaw(z轴转)相机全勾选

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

视频中是这样连的(他是只让相机转动,坦克不转,因此只给相机添加相对旋转):

这里Spring Arm是摇臂,由于摇臂的距离Target Arm Length设定比较远1200,因此根据鼠标的移动改变摇臂的旋转

如果只连其中的一个,鼠标左右移动和上下移动视角都没问题,但是两个都连起来发现视角混乱,

原因是,假如向右移动一点再向上移动,发现相机已经被移乱了,视角已经倾斜了

解决方法:添加一个空的组件Scene,该组件只有位置信息这样设置,把target用Scene连,

这样相机永远是直立的不会反过来了

对于Clamp函数是限定一个数的最小值和最大值,只能在这两个数之间。

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

8  两个Rotator相减

用Delta(Rotator),这个函数作用就是rotator相减取模

	/** Normalized A-B */
	UFUNCTION(BlueprintPure, meta=(DisplayName = "Delta (Rotator)", ScriptMethod = "Delta"), Category="Math|Rotator")
	static FRotator NormalizedDeltaRotator(FRotator A, FRotator B);
FRotator UKismetMathLibrary::NormalizedDeltaRotator(FRotator A, FRotator B)
{
	FRotator Delta = A - B;
	Delta.Normalize();
	return Delta;
}

而一点一点旋转是用的Rinterp To这个函数

如果用的动画蓝图的动画偏移,是这样的

 

对于骨骼动画融合

选择红框里的选项,动画图表里会出现一个新的节点

Base Pose — 基础的动画姿势

Blend Pose 0 — 我们想要混合进来的姿势0

Blend Weights 0 — 姿势0混合时所占的权重 (取值范围0~1)

添加引脚 — 可以继续添加混合的姿势 — 可以混合多个姿势进来

下面我们将原来的状态机连到 Base Pose 节点, 并将 AnimMix 连到 Blend Pose 0 节点。
然后再将混合后的姿势连到最终动画姿势里。

至此,还不能奏效, 因为我们并未设置从哪个骨骼上开始混合,也没有设置混合到什么程度 (权重)

所以接下来我们点击混合节点,可以看到右侧细节面板里出现了一些参数

点击 Branch Filters 后面的加号,会增加一个元素

可以看到 Branch Filters 里面有一个元素, 这个元素包含两个成员

Bone Name 表示想要混合的骨骼名称

Blend Depth 表示混合的深度,关于这个参数的设置,后面会详细说明

可以继续添加元素,以对不同的骨骼设置不同的混合深度

这里只有一个 Branch Filters, 当我们再多添加混合的姿势的时候 (即点击添加引脚), Branch Filters 也会随着它增多

每一个 Branch Filters 对应着一个 Blend Poses

关于 Blend Depth

Blend Depth 决定当前骨骼 (及其孩子骨骼) 混合到原动画的比重

当 Blend Depth 的取值为 0 到 1 之间的任何数 (包括0和1) 时, 当前的骨骼会完全取代原来的骨骼位置,完全混合进去

当 Blend Depth 的取值为 -1 时 (不建议取其他的负值), 当前的骨骼完全不会影响原来的骨骼位置,即完全不会混合

当 Blend Depth 的取值为 大于1 的任何数时, 随着这个数值的增加, 当前骨骼混合到原骨骼的程度逐渐减小

举个比较实用的例子,
如果现在我们只想融合胳膊上部,那么我们可以将整个胳膊的父骨骼的 Blend Depth 设置为 1 (或0)

然后将 胳膊下部的父骨骼的 Blend Depth 设置为 -1

这样整个胳膊的下部就不会融合进去了

原理

Blend Depth 在 ue4 中的源代码位置记录如下, 方便以后详查

//Engine\Engine\Source\Runtime\Engine\Private\Animation\AnimationRuntime.cpp 1280行

void FAnimationRuntime::CreateMaskWeights(TArray<FPerBoneBlendWeight>& BoneBlendWeights, const TArray<FInputBlendPose>& BlendFilters, const USkeleton* Skeleton)
{
	if ( Skeleton )
	{
		const FReferenceSkeleton& RefSkeleton = Skeleton->GetReferenceSkeleton();
		
		const int32 NumBones = RefSkeleton.GetNum();
		BoneBlendWeights.Reset(NumBones);
		BoneBlendWeights.AddZeroed(NumBones);

		// base mask bone
		for (int32 PoseIndex=0; PoseIndex<BlendFilters.Num(); ++PoseIndex)
		{
			const FInputBlendPose& BlendPose = BlendFilters[PoseIndex];

			for (int32 BranchIndex=0; BranchIndex<BlendPose.BranchFilters.Num(); ++BranchIndex)
			{
				const FBranchFilter& BranchFilter = BlendPose.BranchFilters[BranchIndex];
				const int32 MaskBoneIndex = RefSkeleton.FindBoneIndex(BranchFilter.BoneName);

				if (MaskBoneIndex != INDEX_NONE)
				{
					// how much weight increase Per depth
					const float IncreaseWeightPerDepth = (BranchFilter.BlendDepth != 0) ? (1.f/((float)BranchFilter.BlendDepth)) : 1.f;

					// go through skeleton bone hierarchy.
					// Bones are ordered, parents before children. So we can start looking at MaskBoneIndex for children.
					for (int32 BoneIndex = MaskBoneIndex; BoneIndex < NumBones; ++BoneIndex)
					{
						// if Depth == -1, it's not a child
						const int32 Depth = RefSkeleton.GetDepthBetweenBones(BoneIndex, MaskBoneIndex);
						if (Depth != -1)
						{
							// when you write to buffer, you'll need to match with BasePoses BoneIndex
							FPerBoneBlendWeight& BoneBlendWeight = BoneBlendWeights[BoneIndex];

							BoneBlendWeight.SourceIndex = PoseIndex;
							const float BlendIncrease = IncreaseWeightPerDepth * (float)(Depth + 1);
							BoneBlendWeight.BlendWeight = FMath::Clamp<float>(BoneBlendWeight.BlendWeight + BlendIncrease, 0.f, 1.f);
						}
					}
				}
			}
		}
	}
}

 

  • 4
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值