-
如果遇到
原来写的创建类蓝图,需要暴露新的参数,但是创建类蓝图节点没有刷新,即暴露出来的参数没有显示,可以重新定位到创建蓝图,然后重新赋值Class,这样暴露出来的属性就可以看见了,我这里是参数IsDraw
-
当在调试动作或特效等局内表现的时候,需要放慢动作的播放,可以使用控制台命令slomo +时间(比如0.5),来实现放慢,好观察表现是否正确
-
宏函数库或者宏函数,如何设置参数类型为引用
-
见上图,通过使用
节点,通过鼠标左键从target参数向Input【输入】节点,出现上截图AddPinToNode,松开鼠标,即可添加引用参数,修改合适的名字即可
-
在界面上要控制浮点数显示的精度设置,关键节点:
,点击这个下拉倒三角形符号
ue4中,把浮点数,看成整数部分和分数部分,截图节点可以控制整数部分的最小位数和最大位数,也可以控制分数【小数】部分的最大和最小位数;RoundingMode可以设置浮点数在保留指定位数时,如何取舍值的方式,详情可以参考该结构体的定义;当UseGrouping=true时,将会把整数部分用","隔开
,当UseGroupingMode = false时,整数部分不会用“,”隔开,
AlwaysSign=true时,会把正负号加上,如:800,显示+800;否则,800,显示800【小结:遇到类似节点,可以类推】
-
在蓝图中,如何拼写换行的字符串:Shift+Enter键,即可添加换行【下面截图:是通过for循环,拼写带换行的字符串,其换行的关键节点就是Select节点】
-
当需要实现,特效与游戏伤害匹配时,需要动态改变粒子特效的生命周期,其本质就是动态修改粒子模块的控制参数:在粒子模块中,参数类型选择 Distribution Vector Particle Parameter,命好变量名称【LifeTime】,
代码控制截图:
PS:如果需要一个变量控制不同粒子模块,只需要变量名完全相同,且变量的类型和值的范围相同,即可。如本例中变量【LifeTime】同时控制2个粒子模块 -
在c++代码处打打断点,发现堆栈有如下截图时【即蓝图调用c++代码】:
可以在vs中的Immediate Widow,输入{,UE4Editor-Core}::PrintScriptCallstack(),查看具体蓝图调用的堆栈
-
项目中模块的管理是记录在:XXX.uproject文件里面,当模块出错,可以在这里暂时屏蔽
-
调试打包出来的debug/shiping包时,方法【前提都需要pdb调试文件在exe同目录】:
(1) 通过vs,attach to Process,调试
(2)通过打开工程,设置ue4为启动项,并设置ue4工程的属性如下【修改Working Directory:exe所在的目录和Command:完整的exe路径】 -
调试打包出来的debug/shiping包时,单步调试时,代码乱跳,可以将DebugGame改成Debug【前提:使用源码引擎,否则没有Debug选项】
. -
调试时防止变量被优化:通过PRAGMA_DISABLE_OPTIMIZATION和PRAGMA_ENABLE_OPTIMIZATION包裹自己代码部分,可以防止被包裹部分的代码变量被优化:
// Copyright Epic Games, Inc. All Rights Reserved.
#include "BoneControllers/AnimNode_CCDIK.h"
#include "Animation/AnimTypes.h"
#include "AnimationRuntime.h"
#include "DrawDebugHelpers.h"
#include "Animation/AnimInstanceProxy.h"
PRAGMA_DISABLE_OPTIMIZATION
/
// AnimNode_CCDIK
// Implementation of the CCDIK IK Algorithm
FAnimNode_CCDIK::FAnimNode_CCDIK()
: EffectorLocation(FVector::ZeroVector)
, EffectorLocationSpace(BCS_ComponentSpace)
, Precision(1.f)
, MaxIterations(10)
, bStartFromTail(true)
, bEnableRotationLimit(false)
{
}
FVector FAnimNode_CCDIK::GetCurrentLocation(FCSPose<FCompactPose>& MeshBases, const FCompactPoseBoneIndex& BoneIndex)
{
return MeshBases.GetComponentSpaceTransform(BoneIndex).GetLocation();
}
#if WITH_EDITOR
void FAnimNode_CCDIK::ResizeRotationLimitPerJoints(int32 NewSize)
{
if (NewSize == 0)
{
RotationLimitPerJoints.Reset();
}
else if (RotationLimitPerJoints.Num() != NewSize)
{
int32 StartIndex = RotationLimitPerJoints.Num();
RotationLimitPerJoints.SetNum(NewSize);
for (int32 Index = StartIndex; Index < RotationLimitPerJoints.Num(); ++Index)
{
RotationLimitPerJoints[Index] = 30.f;
}
}
}
#endif
void FAnimNode_CCDIK::InitializeBoneReferences(const FBoneContainer& RequiredBones)
{
DECLARE_SCOPE_HIERARCHICAL_COUNTER_ANIMNODE(InitializeBoneReferences)
TipBone.Initialize(RequiredBones);
RootBone.Initialize(RequiredBones);
EffectorTarget.InitializeBoneReferences(RequiredBones);
}
void FAnimNode_CCDIK::GatherDebugData(FNodeDebugData& DebugData)
{
DECLARE_SCOPE_HIERARCHICAL_COUNTER_ANIMNODE(GatherDebugData)
FString DebugLine = DebugData.GetNodeName(this);
DebugData.AddDebugItem(DebugLine);
ComponentPose.GatherDebugData(DebugData);
}
PRAGMA_ENABLE_OPTIMIZATION
-
使用Debug【可以避免断点乱跳问题】
通过命令启动调试游戏,出现
只需将打包引擎对应目录下dll,拷贝至打包游戏后对应的目录,即可解决
-
LineTraceByChannel节点可以直观debug
当DrawDebugType的值为:Persistent时,可以看到如下可视化的红线 -
将一个范围的值normal至0到1:【0-1可以用来驱动曲线资产】
-
限定输入和输出范围用【0-1去驱动】
-
粒子系统中的蓝图事件是:在非GPU发射器中,才能生效的,如果标识的是GPU Sprite将不会生效
并且可以设置事件触发的频率【如果时触发音效,可以防止因粒子的频率高,导致过多的音效生成】
-
通过粒子系统事件绑定实现声音时,由于节省性能,不在摄像机视口内的内容将不会渲染,因此在粒子系统中绑定的事件也不会触发,即声音不会播放,处理方法:点击非粒子发射器面板,将会出现设置粒子系统的面板,设置红圈中参数,则玩家在这个范围内就会听到声音
-
要想
这个事件触发,需要设置staticmeshcomponent的SimulationGeneratesHitEvent为true
20. 在ue4中,查看Verbose级别的日志:需要在自己工程下DefaultEngine.ini添加
[Core.Log]
global=Verbose
PS:该级别日志不会在控制台窗口打印,只能去对应的log文件里面去查看
21. 通过UFUNCTION(exec)这种声明的函数,可以直接输入命令启动,命令就是:函数名字;UFUNCTION(exec)
void ReportMatchResult();
调出命令输入ui,直接输入:ReportMatchResult即可
22. UObjectGlobals.h->FindObject:【Tries to find an object in memory】是在内存中找,而不是磁盘,所以当返回的指针是null时,表示在内存中没找到,并不代表在磁盘中没有相关信息,所以需要再在磁盘中加载
/**
* Find an optional object.
* @see StaticFindObject()
*/
template< class T >
inline T* FindObject( UObject* Outer, const TCHAR* Name, bool ExactClass=false )
{
return (T*)StaticFindObject( T::StaticClass(), Outer, Name, ExactClass );
}
/**
* Tries to find an object in memory. This will handle fully qualified paths of the form /path/packagename.object:subobject and resolve references for you.
*
* @param Class The to be found object's class
* @param InOuter Outer object to look inside. If this is ANY_PACKAGE it will search all in memory packages, if this is null then InName should start with a package name
* @param InName The object path to search for an object, relative to InOuter
* @param ExactClass Whether to require an exact match with the passed in class
*
* @return Returns a pointer to the found object or nullptr if none could be found
*/
COREUOBJECT_API UObject* StaticFindObject( UClass* Class, UObject* InOuter, const TCHAR* Name, bool ExactClass=false );