Bootstrap

ue4 总结十一

1、对于多人游戏,AI控制只受服务端的管理,客户端无需进行寻路计算,所以这些逻辑全部放到服务端

 

2、有时候看不到某些actor效果很可能是由于立即Destroy造成的,这是很常见的bug

 

3、求出物体向目标点倒下30度

 

4、判断一个Tarray的某个元素是否存在

不对(程序会崩):

if (TOuterItemMgrArray[0])

正确(原因:万一TOuterItemMgrArray不存在就会崩,该函数做了判断):

if (TOuterItemMgrArray.IsValidIndex(0))

5、

TSubclassOf转UObject*:       使用->GetDefaultObject()方法

TSubclassOf转UClass*  :    前面加*

6、

UObject

为对象系统的基类。类层次为:

UObjectBase
     UObjectBaseUtility
          UObject

UClass

C++语言不像C#,Java那样提供完整的反射功能,我们需要定义一个数据结构(UClass)来描述C++中的类信息,这个数据结构也称为类的元数据。当然在UE4中UClass实例不仅仅用于描述C++(Native)类,也用来描述Blueprint生成的类。

类继承层次:

UObject
   UField
      UEnum
      UProperty
         UBoolProperty
         UEnumProperty
         UNumericProperty
         UObjectProperty
         ... 
      UStruct
         UClass
         UFunction
         UScriptStruct

链接:https://www.jianshu.com/p/1f2de6ea383c

 

7、

template <typename ElementType, typename IteratorType>
struct TDereferencingIterator
{
	explicit TDereferencingIterator(IteratorType InIter)
		: Iter(InIter)
	{
	}

	FORCEINLINE ElementType& operator*() const
	{
		return *(ElementType*)*Iter;
	}

}

 这里ElementType&是返回值类型,因此返回ElementType的指针前面加个*,也即返回类本身

 

8、EditAnyWhere和EditDefaultsOnly的区别

如果一个UPERPROTY设为EditAnyWhere,该蓝图类拖到场景中,修改蓝图的这个变量,场景中的变量不会改变,场景中的保存以前的变量,

如果一个UPERPROTY设为EditDefaultsOnly,该蓝图类拖到场景中,修改蓝图的这个变量,场景中不能配置该变量,全部读取蓝图中的变量

 

9、在BeginPlay设置一些变量可能失效

解决方法:

delay 0.2秒再设置

 

10、TimeLine在同步时记得勾选Replicated

 

11、用于防止同步抖动的骚方法

	//每一帧都更新rotation
	if (fDeltaTimeServer>0.0f)
	{
		float fTimeSecondsDelay = UGameplayStatics::GetGameState(GetWorld())->GetServerWorldTimeSeconds() - UGameplayStatics::GetTimeSeconds(GetWorld());
		fDeltaTimeServer = UKismetMathLibrary::FMax(fDeltaTimeServer, fTimeSecondsDelay);
	}
	else
	{
		fDeltaTimeServer = UGameplayStatics::GetGameState(GetWorld())->GetServerWorldTimeSeconds() - UGameplayStatics::GetTimeSeconds(GetWorld());
	}
	float fTimeSecondsAddTimeServer = UGameplayStatics::GetTimeSeconds(GetWorld()) + fDeltaTimeServer;

 

12、相机和物体发生碰撞bug:

解决方法:把物体对相机的碰撞改成overlap

 

13、SplineComponent

如果让一个物体沿着曲线轨迹运动,使用该组件,在场景中选中该组件的顶点,按alt+鼠标左键脱出下一段轨迹

在蓝图中,这样让物体沿轨迹运动

 

14、DestructiableComponent的Overlap事件和StaticMeshComponent的OverLap事件效果不太一样,

DestructiableComponent的Overlap事件:

人撞到物体触发

物体撞到人不触发

StaticMeshComponent的OverLap事件:

人撞到物体触发

物体撞到人触发

解决方法:在DestructiableComponent下面再放个StaticMeshComponent,触发事件全部调用StaticMeshComponent里的Overlap

 

15、对于可破碎物体,如果破碎后禁掉碰撞,记得一定在fracture回调函数中禁用碰撞,不能用自己函数多播禁

 

16、对于粒子特效,在播放时候调用SetActive函数

记得在粒子特效蓝图中取消勾选Auto Active,否则,特效一开始进入就播放

 

17、用vs编译热加载ue编辑器有时会出现一些bug,需要用vs启动

 

18、有时打开一个c++文件,显示已被删除或被remame,无法打开

解决方法:项目重新generate

 

19、检测墙后面的玩家不受到爆炸伤害

做法:


使用LineTraceForObejct方法,检测两点之间(人物和爆炸桶)做一条射线是否有物体ObjectType为某个枚举,比如墙的ObjectType设为WorldStatic,就会返回true,输出的hit保存射线碰撞点的相关信息,可以获取到碰撞到碰撞到的actor,component等相关信息。

Obeject Type在这里设:

 

20、将碰撞通道转换为ObjectType:

TArray <TEnumAsByte<EObjectTypeQuery>> WorldStaticObjectTypes;
WorldStaticObjectTypes.Add(UEngineTypes::ConvertToObjectType(ECollisionChannel::ECC_WorldStatic));

也即这句话

UEngineTypes::ConvertToObjectType(ECollisionChannel::ECC_WorldStatic

 

21、测试时绘制的线一般是在服务端绘制

 

22、使用TimeLine时候

输出的新建轨迹0,在c++中是float DeltaTime,输出的DeltaTime是曲线轨迹的值

而这个值根据Tick()函数传入的float DeltaTime来计算,在编辑器中控制台通过t.MaxFPS 来控制想要的FPS,如果FPS很低,那么TimeLine采样频率就少,如果特别低,那么就会只采曲线的初值和终值,如果FPS很高,那么会取曲线中的许多点,输出的

曲线轨迹的值也就更平滑。

 

23、子父类component的碰撞可能发生矛盾,建议不要一个block,一个overlap,否则有时会屏蔽一个

可以两个都设为一样的,不同的在代码里面设

//让可破碎component对地面产生碰撞,有破碎效果
DestructibleComponent->SetCollisionResponseToChannel(ECC_WorldStatic, ECollisionResponse::ECR_Block);
DestructibleComponent->SetCollisionResponseToChannel(ECC_WorldDynamic, ECollisionResponse::ECR_Block);

 

24、通过replicated movement可以让客户端物体复制服务端的位置,但是通过childActor方式的actor,不能通过replicated movement可以让客户端物体复制服务端的位置,只能多播,服务端和客户端同时set Location

 

25、IsValidLowLevel():

 指针不为空,但内容出现NULL或者异常。(此情况一般是,对这个对象的多处指针引用,但是在A处销毁了,之后在B处继续调用)。牵扯到内存管理,如果此对象的类是属于UE4的,那可以 yourObject!=nullptr&&_yourObject->IsValidLowLevel()。

参见UE4UObjectBase这个底层基类

bool UObjectBase::IsValidLowLevel() const;

bool UObjectBase::IsValidLowLevelFast(bool bRecursive /*= true*/) const
 

26、在Subclass类中有一个函数

	/** Implicit conversion to UClass */
	FORCEINLINE operator UClass* () const
	{
		return **this;
	}

这里*this表示当前类本身,又加了一个*表示调用了该类里面的重载*操作符的函数,该函数是这样定义的:

	/** Dereference back into a UClass, does runtime type checking */
	FORCEINLINE UClass* operator*() const
	{
		if (!Class || !Class->IsChildOf(TClass::StaticClass()))
		{
			return nullptr;
		}
		return Class;
	}
	

这里第二个函数Operator作用是重载运算符,第一个函数Operator作用是隐式转换,自动将Subclass类转换成UClass类。

 

27、beginplay里面判断ROLE_AutonomousProxy,是有可能会出现错误,

应重写actor的PostNetReceive虚函数,把判断ROLE_AutonomousProxy的逻辑放到该函数里面
 

28、在beginPlay写逻辑,一定要延迟一段时间,这样客户端才能保证同步,否则有些逻辑在服务端执行了,没时间通过rpc传到客户端

 

29、

http://www.cppblog.com/Herbert/archive/2009/01/08/70479.html

void AGOASmelterLava::TakeDamageToPlayerEverySecond()
{
    for (int i = 0; i < AllOverLapPlayer.Num();)
    {
        //UKismetSystemLibrary::PrintString(this, TEXT("受伤"));
        if (IsValid(AllOverLapPlayer[i]))
        {
            FHitResult hitResult;
            IGOATakeDamageInterface::Execute_TakeDamage(AllOverLapPlayer[i], EGOADamageType::OrganMelee, DamageDataEverySecond, hitResult, CurrentInstigateActor, this, CurrentInstigatePlayerController);
            if (AllOverLapPlayer[i]->IsDead())
            {
                AllOverLapPlayer.Remove(Cast<AGladiator>(AllOverLapPlayer[i]));
                continue;
            }
        }
        i++;
    }
}

 

;