Unreal Engine 4 —— 常见Tips
2016-04-11 23:05
393 查看
算到现在使用UE4大概有两年了吧,从它每月还收费19美金的时候用到现在4.11都出来了。这是一款很强大的引擎,因此我也总结了方方面面的一些经验,这篇博客会时时更新。
在PCH中加入
如此即可
记得需要加入
在config/ConsoleVariables.ini中找到[Startup]
在其后加入:
针对项目的方法:
在DefaultEngine.ini中查找
其余的关于Vector, Color, FName等都同理可以进行输出。
可以使用GetOwningPlayerController函数:
使用GetPlayerCameraManager函数
其中的WorldContext是世界上下文参数。
如果这个值是灰色不可改变,那么需要在Edit->Project Settings->Physics->Simulation->Enable Async Scene设定为True
破碎后产生的小Chunks是默认与WorldDynamic无碰撞的,如果需要其有碰撞,那么需要将Large Chunk Threshold设定为一个比较大的数字:
千万不要进行缩放你的Destructible Mesh,会导致Chunks的碰撞计算出错。
UE4中只支持随机切片,如果要进行自定义的Destructible,你需要apex physx lab,非常酷的东西。
如果你在有布料的骨骼模型看到了一个奇怪的顶点,例如下面这个:
这种情况通常是你的Skinning出了问题,着重检查那些不该有蒙皮信息的骨骼。
若是出现了类似于
Classes inheriting from UObject are prefixed with the letter U.
Classes inheriting from AActor are prefixed with the letter A.
Classes inheriting from SWidget are prefixed with the letter S.
Abstract interface classes are prefixed with the letter I.
Most other classes are typically prefixed with the letter F.
UE4与Perforce简直是天生一对,我他娘的太喜欢这一对了。
当你每导入一个人形骨骼模型的时候,记得一定要在 Retarget Manager 中进行骨骼的设定。这样可以确保动画的Retargeting正常工作,而且可以节省很多工作量。
Components在CPP中的初始化:
只有在Event Graph中才能设定Timeline。
你每在Level中更改了一个Actor的信息,都会重新调用一次Construction Script。
想要摄像机Lag吗?在SpringArm中进行设定吧!
在C++中创建Interface
最基本代码如下:
.h
.cpp
使用
TMap的使用
注意与
也可以使用
可以使用
可以使用
我去……关于TMap都可以单独出一个博客了……
在C++中寻找BP中的物件或类:
GetGlobalShaderMap如何使用?
默认材质
在C++中调用Blueprint的函数
先吐槽,这个时候其实建议使用Interface来进行调用会清晰的多,以下方式只是Trick……
Build Error
InputCoreTypes.h如果出现各种syntax error.在PCH中加入
#include "Engine.h"即可。
Plugin
如果你要构建一个Function Lib Plugin,记得将LoadingPhase设定为PreDefault.Console Command
创建Console Command的方法:在GameMode中创建对应的函数,UFUNCTION的Category需要为ExecFunctions
创建无参数的Console Command
UFUNCTION(Exec, Category = ExecFunctions) void DoSomething();
创建带参数的Console Command
/*Function with one parameter*/ UFUNCTION(Exec, Category = ExecFunctions) void DoSomethingElse(float param);
如此即可
Android
获得Env
auto env = FAndroidApplication::GetJavaEnv();
GNativeAndroidApp
调用extern struct android_app* GNativeAndroidApp;
记得需要加入
#include <android_native_app_glue.h>
JNI
记得在.cs文件中的PrivateIncludePaths加入:
"Runtime/Launch/Private"
锁帧
直接修改引擎设置的方法:在config/ConsoleVariables.ini中找到[Startup]
在其后加入:
t.MaxFPS=30
针对项目的方法:
在DefaultEngine.ini中查找
[SystemSettings]的section,如果没有则新建一个,在其后加入:
t.MaxFPS=30
Log to screen
如果你想向屏幕上输出一些东西,可以使用如下代码:GEngine->AddOnScreenDebugMessage(-1, -1, FColor::Red, TEXT("阿妹你看,上帝压狗! "));
Log Category
如果你想要定义并且使用自己的Log,那么你应该这么做:// Decleare Log Category // General Log DECLARE_LOG_CATEGORY_EXTERN(YourLog, Log, All); // Logging during game startup DECLARE_LOG_CATEGORY_EXTERN(YourInit, Log, All); // Logging for your AI system DECLARE_LOG_CATEGORY_EXTERN(YourAI, Log, All); // Logging for Critical Errors that must always be addressed DECLARE_LOG_CATEGORY_EXTERN(YourCriticalErrors, Log, All); // Define Log Category // General Log DEFINE_LOG_CATEGORY(YourLog); // Logging during game startup DEFINE_LOG_CATEGORY(YourInit); // Logging for your AI system DEFINE_LOG_CATEGORY(YourAI); // Logging for Critical Errors that must always be addressed DEFINE_LOG_CATEGORY(YourCriticalErrors); // Using UE_LOG //"This is a message to yourself during runtime!" UE_LOG(YourLog,Warning,TEXT("This is a message to yourself during runtime!"));
格式化的Log
Log Message
//"阿妹你看,上帝压狗!" UE_LOG(YourLog,Warning,TEXT("阿妹你看,上帝压狗!"));
Log an FString
%s 字符串在Log中是使用TCHAR* 的, 所以我们要使用 *FString//"阿妹你看,上帝压狗!" UE_LOG(YourLog,Warning,TEXT("阿妹你看,上帝压%s!"), *TheDog->GetName() );
Log an Int
//"有了金坷垃,小麦亩产1800!" UE_LOG(YourLog,Warning,TEXT("有了金坷垃,小麦亩产%d!"), 1800);
Log a Float
//"有了金坷垃,小麦亩产1800.0f!" UE_LOG(YourLog,Warning,TEXT("有了金坷垃,小麦亩产%f!"), 1800.0f);
其余的关于Vector, Color, FName等都同理可以进行输出。
Current Camera
当前相机的获得可以通过两种方式:可以使用GetOwningPlayerController函数:
auto pc = GetOwningPlayerController(); auto *vt = pc->GetViewTarget(); ACameraActor* camera = Cast(vt); if (camera) { //do stuff }
使用GetPlayerCameraManager函数
auto camera = UGameplayStatics::GetPlayerCameraManager(WorldContext, 0);
其中的WorldContext是世界上下文参数。
Enumeration in C++
UENUM () namespace EBattleState { enum Type { CameraWander = 0 , // The camera is wandering around. ChooseCharacter , // Choose one character, and is going to choose location. CharacterMoving , // The character is moving, player input is not allowed. Count , }; } TEnumAsByte BattleStateEnum;
Apex Destruction
Destruction Mesh在还未破碎的情况下,是没有碰撞的,如果要启用,需要在Level中选中该Actor,将Use Async Scene设为False:如果这个值是灰色不可改变,那么需要在Edit->Project Settings->Physics->Simulation->Enable Async Scene设定为True
破碎后产生的小Chunks是默认与WorldDynamic无碰撞的,如果需要其有碰撞,那么需要将Large Chunk Threshold设定为一个比较大的数字:
千万不要进行缩放你的Destructible Mesh,会导致Chunks的碰撞计算出错。
UE4中只支持随机切片,如果要进行自定义的Destructible,你需要apex physx lab,非常酷的东西。
Animation&Rigging Tool
如果你不幸在ART中遇到了“Parent of end effector must be a joint”的错误,那么需要检查一下在你的骨骼模型中是否有double system,比如说头发啊或者裙摆之类的东西。如果你在有布料的骨骼模型看到了一个奇怪的顶点,例如下面这个:
这种情况通常是你的Skinning出了问题,着重检查那些不该有蒙皮信息的骨骼。
若是出现了类似于
No object matches name: ik_upperarm_fk_matcher_l的问题,则有可能是Rigging的版本太老。使用最新的ART代码重新Build一次整个Rigging系统。
Class名称的前缀
Template classes are prefixed with the letter T.Classes inheriting from UObject are prefixed with the letter U.
Classes inheriting from AActor are prefixed with the letter A.
Classes inheriting from SWidget are prefixed with the letter S.
Abstract interface classes are prefixed with the letter I.
Most other classes are typically prefixed with the letter F.
关于Unreal Engine 4的工作流程
当你在给你的场景进行光照布局的时候,记得一定要把眼球自适应关掉!UE4与Perforce简直是天生一对,我他娘的太喜欢这一对了。
当你每导入一个人形骨骼模型的时候,记得一定要在 Retarget Manager 中进行骨骼的设定。这样可以确保动画的Retargeting正常工作,而且可以节省很多工作量。
Components
Components一个很方便的作用是可以任意挂载,我用它来设计技能模块非常方便。Components在CPP中的初始化:
// Your .h file class USphereComponent* Sphere; // Your .cpp file Sphere = PCIP.CreateDefaultSubobject<USphereComponent>(this, TEXT("SphereComp"));
Blueprint
Bind一个event之后,要记得在event上点右键,选择RefreshNode。只有在Event Graph中才能设定Timeline。
你每在Level中更改了一个Actor的信息,都会重新调用一次Construction Script。
想要摄像机Lag吗?在SpringArm中进行设定吧!
Interface
在UE4的编程中,Interface非常重要。类之间只能进行单一继承,而针对于Interface则可以进行多继承。个人的经验中,它对于物品交互等的构建都非常方便。在C++中创建Interface
最基本代码如下:
.h
#pragma once #include "Interface.h" #include "InterfaceXBoxEvent.generated.h" /** Class needed to support InterfaceCast<IToStringInterface>(Object) */ UINTERFACE() class UInterfaceXBoxEvent : public UInterface { GENERATED_UINTERFACE_BODY() }; class IInterfaceXBoxEvent { GENERATED_IINTERFACE_BODY() public: UFUNCTION(BlueprintImplementableEvent, BlueprintCallable, Category = "Activate") void XboxEvent_KillAI(EAIType::Type type); };
.cpp
#include "MyGame.h" #include "InterfaceXBoxEvent.h" UInterfaceXBoxEvent::UInterfaceXBoxEvent(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { }
C++
避免Garbage Collection的做法:使用
UObjectBaseUtility::AddToRoot()可以达到该目的。
TMap的使用
TMap<int32, FString> FruitMap; FruitMap.Add(5, TEXT("Banana")); FruitMap.Add(2, TEXT("Grapefruit")); FruitMap.Add(7, TEXT("Pineapple")); // FruitMap == [ // { Key: 5, Value: "Banana" }, // { Key: 2, Value: "Grapefruit" }, // { Key: 7, Value: "Pineapple" } // ]
注意与
TMultiMap的区别,
TMap中的key都是唯一的,因此当插入一个重复键值时,原来的会被替换:
FruitMap.Add(2, TEXT("Pear")); // FruitMap == [ // { Key: 5, Value: "Banana" }, // { Key: 2, Value: "Pear" }, // { Key: 7, Value: "Pineapple" } // ]
也可以使用
Emplace函数来进行元素的替换或增加,这种方法可以避免临时变量的创建:
FruitMap.Emplace(3, TEXT("Orange")); // FruitMap == [ // { Key: 5, Value: "Banana" }, // { Key: 2, Value: "Pear" }, // { Key: 7, Value: "Pineapple" }, // { Key: 3, Value: "Orange" } // ]
可以使用
FindOrAdd来进行查找键值的查找,如TMap中没有这个键值,那么则会创建一个默认的值:
FString& Ref7 = FruitMap.FindOrAdd(7); // Ref7 == "Pineapple" // FruitMap == [ // { Key: 5, Value: "Mango" }, // { Key: 2, Value: "Pear" }, // { Key: 7, Value: "Pineapple" }, // { Key: 3, Value: "Orange" } // ] FString& Ref8 = FruitMap.FindOrAdd(8); // Ref8 == "" // FruitMap == [ // { Key: 5, Value: "Mango" }, // { Key: 2, Value: "Pear" }, // { Key: 7, Value: "Pineapple" }, // { Key: 3, Value: "Orange" }, // { Key: 8, Value: "" } // ]
可以使用
Remove函数,
RemoveAndCopyValue函数或者
FindAndRemoveChecked函数来进行元素的删除。
我去……关于TMap都可以单独出一个博客了……
在C++中寻找BP中的物件或类:
static ConstructorHelpers:: FObjectFinder<UStaticMesh > CubeMesh (TEXT( "StaticMesh'Content/TopDownBP/CubeMesh'" )); if ( CubeMesh.Object ) { Mesh ->SetStaticMesh (CubeMesh. Object ); }
GetGlobalShaderMap如何使用?
const auto FeatureLevel = GMaxRHIFeatureLevel; auto ShaderMap = GetGlobalShaderMap(FeatureLevel);
默认材质
if(Material == NULL) { Material = UMaterial:: GetDefaultMaterial(MD_Surface ); }
在C++中调用Blueprint的函数
先吐槽,这个时候其实建议使用Interface来进行调用会清晰的多,以下方式只是Trick……
// MainPlayerCharacter.cpp // By: Noah Zuo // Disc: Call functions in a blueprint from C++ #include "MainPlayerCharacter.h" AMainPlayerCharacter::AMainPlayerCharacter (const class FObjectInitializer& PCIP) : Super( PCIP) { // The BP is located at /Game/Blueprints/TestTest folder. static ConstructorHelpers ::FObjectFinder<UBlueprint> assetObject(TEXT( "Blueprint'/Game/Blueprints/TestTest'" )); if (assetObject.Succeeded()) { TestBlueprint = ( UClass*)assetObject .Object-> GeneratedClass; } } void AMainPlayerCharacter::BeginPlay() { // Spawn a Actor in the world. TestObjectActor = GWorld->SpawnActor<AActor >(TestBlueprint); } void AMainPlayerCharacter::Tick(float DeltaSeconds) { Super::Tick (DeltaSeconds); UFunction *tmp = TestObjectActor->FindFunction(TEXT ("TestPrint")); if (tmp != NULL) TestObjectActor ->ProcessEvent(tmp, nullptr); }
Particle
如果想在BP/C++中动态调整Particle的参数,需要添加Dynamic模块。然后将Distribution设定为ParticleParameter。Param Name设定为Material Editor中的名字,Parameter Name设定为BP中的名字。相关文章推荐
- 记一SQL部署问题
- 串口驱动
- MapReduce框架在Yarn上的详解
- 解决项目中无缘无故多出xxxxx.out.xml问题
- LeetCode155. Min Stack
- QGis二次开发基础 -- 矢量图层属性图表显示
- iOS学习笔记18-CoreData你懂的
- 稀疏矩阵的压缩存储与转置
- Statement以及PrparedStatement
- java线程池初识
- ThinkPHP单字母函数详解
- 生活中的小代码,每瓶汽水1元,两能喝多少瓶个空瓶可以置换一瓶汽水,现有20元,最多 能喝多少瓶汽水。(编程实现)
- 10.JDBC存取大对象BLOB类型
- Android调试系列之dumpsys命令
- PHP运算符陷阱
- 自定义View(View的绘制与测量)
- 整数数组中子数组的最大值2
- linux文件系统---10
- ZZuoj1865(贪心)
- Javascript中的装饰者模式以及AOP简介