您的位置:首页 > 其它

Unreal Engine 4 —— 常见Tips

2016-04-11 23:05 393 查看
算到现在使用UE4大概有两年了吧,从它每月还收费19美金的时候用到现在4.11都出来了。这是一款很强大的引擎,因此我也总结了方方面面的一些经验,这篇博客会时时更新。

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中的名字。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: