算到现在使用UE4大概有两年了吧,从它每月还收费19美金的时候用到现在4.11都出来了。这是一款很强大的引擎,因此我也总结了方方面面的一些经验,这篇博客会时时更新。
在config/ConsoleVariables.ini中找到[Startup]
在其后加入:
t.MaxFPS=30
[SystemSettings]
的section,如果没有则新建一个,在其后加入:t.MaxFPS=30
如果你想向屏幕上输出一些东西,可以使用如下代码:
GEngine->AddOnScreenDebugMessage(-1, -1, FColor::Red, TEXT("阿妹你看,上帝压狗! "));
如果你想要定义并且使用自己的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!"));
//"阿妹你看,上帝压狗!"
UE_LOG(YourLog,Warning,TEXT("阿妹你看,上帝压狗!"));
%s 字符串在Log中是使用TCHAR* 的, 所以我们要使用 *FString
//"阿妹你看,上帝压狗!"
UE_LOG(YourLog,Warning,TEXT("阿妹你看,上帝压%s!"), *TheDog->GetName() );
//"有了金坷垃,小麦亩产1800!"
UE_LOG(YourLog,Warning,TEXT("有了金坷垃,小麦亩产%d!"), 1800);
//"有了金坷垃,小麦亩产1800.0f!"
UE_LOG(YourLog,Warning,TEXT("有了金坷垃,小麦亩产%f!"), 1800.0f);
其余的关于Vector, Color, FName等都同理可以进行输出。
当前相机的获得可以通过两种方式:
auto pc = GetOwningPlayerController();
auto *vt = pc->GetViewTarget();
ACameraActor* camera = Cast(vt);
if (camera) {
//do stuff
}
auto camera = UGameplayStatics::GetPlayerCameraManager(WorldContext, 0);
其中的WorldContext是世界上下文参数。
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;
如果这个值是灰色不可改变,那么需要在Edit->Project Settings->Physics->Simulation->Enable Async Scene设定为True
破碎后产生的小Chunks是默认与WorldDynamic无碰撞的,如果需要其有碰撞,那么需要将Large Chunk Threshold设定为一个比较大的数字:
千万不要进行缩放你的Destructible Mesh,会导致Chunks的碰撞计算出错。
// Your .h file
class USphereComponent* Sphere;
// Your .cpp file
Sphere = PCIP.CreateDefaultSubobject<USphereComponent>(this, TEXT("SphereComp"));
在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)
{
}
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都可以单独出一个博客了……
static ConstructorHelpers:: FObjectFinder<UStaticMesh > CubeMesh (TEXT( "StaticMesh'Content/TopDownBP/CubeMesh'" ));
if ( CubeMesh.Object )
{
Mesh ->SetStaticMesh (CubeMesh. Object );
}
const auto FeatureLevel = GMaxRHIFeatureLevel;
auto ShaderMap = GetGlobalShaderMap(FeatureLevel);
if(Material == NULL)
{
Material = UMaterial:: GetDefaultMaterial(MD_Surface );
}
先吐槽,这个时候其实建议使用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);
}