UE小技巧怕忘掉
- 鼠标左键操作时固定视角
- Game启动角色控制问题
- Pawn使用SpringArm
- Game模式射线碰撞获取多维子材质
- TextRender应用中文
- 蓝图中应用Touch现实单指滑动,双指缩放
- 多人联机NavData在Client不存在
- VR模式运行画面模糊
- 编辑器蓝图工具获取Asset类型并放置Actor到场景
- 程序窗口失去焦点,没有声音
- C++声明,蓝图调用静态函数WorldContextObject免传参
- C++声明,蓝图调用函数TMap免传参
- C++声明,变量暴露编辑器和Spawn节点
- C++ FSlateDrawElement 绘制旋转文字
- C++ 多播代理属性供给蓝图绑定
- C++ 指定蓝图调用函数返回子类类型
- C++ 异步任务
- C++ 字符串与其他类型互转
- 编辑器Actor执行Tick函数
- C++ 插件模块使用Editor模块
- UE插件加载第三方dll并打包项目在其他电脑运行时崩溃
- UE编译第三方库插件代码报错
- UE打包后无法切换ViewMode
鼠标左键操作时固定视角
- 说明:UE默认鼠标左键或右键按住时滑动鼠标则可旋转视角,如果鼠标左键做了其他拖拽功能又不想旋转视角
- 方法:可设置是否忽略LookInput
Game启动角色控制问题
- 启动Game后需要鼠标点击一下才能进入控制问题
- 说明:启动Game后想要直接进入控制,但出现需要鼠标点击一下才能进入控制
- 方法:进入Editor Preferences/Play,设置GameGetsMouseControl为true
- 启动Game后视角会自动跟随鼠标移动而旋转问题
- 说明:视图添加了UMG,启用了Controller的ShowMouseCursor,想要进入场景时需要按住鼠标键滑动来控制视角旋转,但是启动Game后发现不按鼠标键,视角旋转也自动跟随鼠标滑动控制了
- 方法:BeginPlay时使用SetInputModeGameAndUI
Pawn使用SpringArm
- 旋转控制问题
- 说明:默认Pawn没有勾选UseControllerRotationPitch/Yaw/Roll,使用了SpringArm后,无法旋转控制
- 方法:勾选SpringArm组件中的UsePawnControlRotation选项
- 视角突然拉近目标问题
- 说明:当有碰撞体距离Pawn的Camera距离在SpringArm组件设置的ProbeSize数值内将发生拉近目标问题
- 方法:取消勾选SpringArm组件中的DoCollisionTest选项
Game模式射线碰撞获取多维子材质
- 说明:Game模式下,使用鼠标射线碰撞来获取模型中多个材质槽中对应的材质
- 方法:通过LineTraceByChannel(取消勾选TraceComplex)来获得HitResult,此HitResult的TraceStart与TraceEnd作为参数再使用LineTraceByChannel(勾选TraceComplex)来获得HitResult,此HitResult中的HitComponent调用GetMaterialFromCollisionFaceIndex(FaceIndex作为参数)来获取对应材质槽Index和对应的材质
TextRender应用中文
- 说明:默认TextRender应用的字体不支持中文字符
- 方法:通过创建字体并设置字体缓存类型为离线,设置Import Options属性(不使用UnicodeRange也可以手动添加Chars),设置完成后重新导入
AlphaOnly: true
Unicode Range: 4E00-9FA5
蓝图中应用Touch现实单指滑动,双指缩放
- 说明:触摸屏多指滑动会导致FingerIndex的累加,如果判断FingerIndex来处理逻辑会出问题
- 方法:通过组数来管理激活的FingerIndex,超过2个则清空数组来做限制,后面通过数据数量来判断逻辑,
在Moved分支中判断数组中更改FingerIndex对应的Location,最后调用对应的事件,以便自定义功能的实现 - PlayerController(蓝图类)
- TouchIndexInfo(结构体)
- CheckFingerIndexs(宏)
- UpdateTouchLocation(函数)
多人联机NavData在Client不存在
- 说明:多人联机中,使用了Nav寻路系统,在Client端无效,Play状态下使用控制台命令Show Navigation显示NavData,发现NavData只存在于Server而不存在与Client
- 方法:进入Project Settings/Navigation System,设置Allow Client Side Navigation为true
VR模式运行画面模糊
- 说明:在VR模式下运行,头显显示的画面较模糊
- 方法:使用控制台命令
//确保开启VR模式
Stereo On
//设置分辨率
vr.PixelDensity 1.4
//或者
r.Screenpercentage 140
编辑器蓝图工具获取Asset类型并放置Actor到场景
- 说明:在编辑器工具类中获取自定义的Actor资产Class,并SpawnActor到场景
- 方法:先在项目设置里添加一项PrimaryAssetTypesToScan,然后再蓝图工具中通过AsyncLoadClassAsset导入AssetClass并转换成ActorClass,提供给SpawnActor节点。
程序窗口失去焦点,没有声音
- 说明:当程序窗口失去了焦点,默认会没有声音
- 方法1:在其中一个配置文件中设置音量为1.0(打包前:YourProject/Config/DefaultEngine.ini ; 打包后:WindowsNoEditor/YourProject/Saved/Config/WindowsNoEditor/Engine.ini)
[Audio] UnfocusedVolumeMultiplier=1.0
- 方法2:C++中开放蓝图功能设置音量1.0
UFUNCTION(BlueprintCallable, Category = MiscUtil, meta = (WorldContext = "WorldContextObject")) static void SetUnfocusedVolumeMultiplier(UObject* WorldContextObject, float Value) { FApp::SetUnfocusedVolumeMultiplier(Value); }
C++声明,蓝图调用静态函数WorldContextObject免传参
- 说明:C++继承蓝图函数库时,静态方法中需要传入WorldContextObject上下文对象,蓝图每次调用需要传参很麻烦
- 方法:通过反射宏声明 meta = (WorldContext = “WorldContextObject”),蓝图中可免传参WorldContextObject
UFUNCTION(BlueprintPure, Category = CourseManager, meta = (WorldContext = "WorldContextObject"))
static FString GetCourseMode(UObject* WorldContextObject, int32 InMode);
C++声明,蓝图调用函数TMap免传参
- 说明:C++ 函数使用TMap参数,蓝图每次调用需要Make传参,不然无法编译通过
- 方法:通过反射宏声明 meta = (AutoCreateRefTerm = “Headers”),蓝图中可免传参Headers
UFUNCTION(BlueprintCallable, meta = (BlueprintInternalUseOnly = "true",AutoCreateRefTerm = "Headers", WorldContext = "WorldContextObject"))
static UHttp* CreateHttpRequest(UObject* WorldContextObject, FString Url, const TMap<FString, FString>& Headers, FString Body);
C++声明,变量暴露编辑器和Spawn节点
- 说明:C++声明类的变量暴露给蓝图,且变量需要暴露给编辑器和Spawn节点
- 方法:通过反射宏声明 meta=(InstanceEditable=true, ExposeOnSpawn=true)
UPROPERTY(EditAnywhere, meta=(InstanceEditable=true, ExposeOnSpawn=true))
FString ID;
C++ FSlateDrawElement 绘制旋转文字
- 说明:在OnPaint中使用FSlateDrawElement绘制旋转文字
- 方法:通过旋转Transform构建文字绘制的Geometry
//主要记录Geometry与Transform的处理,部分变量声明不在
int32 SGraphBase::DrawLabelText(const FOnPaintHandlerParams& InParams) const
{
int32 DrawLayer = InParams.Layer + 1;
//获取对应控件,文字绘制在此控件中心位置
TSharedPtr<SWidget> WidgetPtr;
FChildren* Children = HorBox->GetChildren();
for (int32 Index = 0; Index < Children->Num(); ++Index)
{
WidgetPtr = Children->GetChildAt(Index);
FVector2D WidgetSize = WidgetPtr->GetPaintSpaceGeometry().GetAbsoluteSize();
FVector2D WidgetPos = WidgetPtr->GetPaintSpaceGeometry().GetAbsolutePosition() + WidgetSize * 0.5;
//获取文字内容
const FString LabelString = Labels[Index];
//测量文字尺寸
const TSharedRef< FSlateFontMeasure > FontMeasureService = FSlateApplication::Get().GetRenderer()->GetFontMeasureService();
FVector2D TextSize = FontMeasureService->Measure(LabelString, TextFont);
//创建旋转Geometry
FSlateRenderTransform TextRenderTransform = TransformCast<FSlateRenderTransform>(FQuat2D(FMath::DegreesToRadians(LableTextRot)));
const FGeometry TextRenderGeometry = InParams.Geometry.MakeChild(TextRenderTransform);
FVector2D PaintPos = TextRenderGeometry.AbsoluteToLocal(WidgetPos);
//绘制文字
FSlateDrawElement::MakeText
(
InParams.OutDrawElements,
InParams.Layer,
TextRenderGeometry.ToPaintGeometry(FVector2D(PaintPos.X, PaintPos.Y - TextSize.Y * 0.5), TextSize),
LabelString,
LabelFont,
ESlateDrawEffect::None,
LabelColor.GetSpecifiedColor()
);
}
return DrawLayer;
}
C++ 多播代理属性供给蓝图绑定
- 说明:多播代理属性有数组数据时在蓝图绑定代理事件使用时会出现:No value will be returned by reference
- 方法:在UPROPERTY中添加:meta = (AllowPrivateAccess = true)
DECLARE_DYNAMIC_MULTICAST_DELEGATE_FourParams(FAlarmInfoRequestCompleteDelegate, bool, bSuccess, int32, Code, FString, Message, const TArray<FAlarmInfo>&, AlarmInfos);
UPROPERTY(BlueprintAssignable, Category = "NetworkManager", meta = (AllowPrivateAccess = true))
FAlarmInfoRequestCompleteDelegate AlarmInfoCompleteDelegate;
C++ 指定蓝图调用函数返回子类类型
- 说明:提供给蓝图调佣,UE管理父类对象时,有时需要接口返回参数中指定的子类类型
- 方法:在UPROPERTY中添加:meta = (DeterminesOutputType= “ManagerClass”)
UFUNCTION(BlueprintCallable, Category = "ManagerManager", meta = (DeterminesOutputType = "ManagerClass"))
AManagerActor* GetManager(TSubclassOf<AManagerActor> ManagerClass);
C++ 异步任务
- 说明:可以将一些简单的任务扔到UE的线程池中去进行,不必关心具体的线程同步问题
- 方法:AsyncTask
AsyncTask(ENamedThreads::GameThread, [=]()
{
//具体任务
});
C++ 字符串与其他类型互转
- 说明:不同场景下需要把字符串类型与其他类型互转
- 方法:使用特定代码转换
//std::string 转 FString
{
std::string msg= "HelloWorld";
FString Result (msg.c_str());
}
//FString转 std::string
{
FString Message = TEXT("HelloWorld");
std::string Result (TCHAR_TO_UTF8(*Message));
}
//FString 转 const char*
{
FString Message = TEXT("HelloWorld");
std::string msg(TCHAR_TO_UTF8(*Message));
const char* Result = msg.c_str();
}
//const char* 转 FString
{
const char* msg = "HelloWorld";
FString Result = FString(UTF8_TO_TCHAR(msg));
}
//FString 转 FName
{
FString Message = TEXT("HelloWorld");
FName Result = FName(*Message );
}
//FString 转 Integer
{
FString Message = TEXT("123.456");
int32 Result = FCString::Atoi(*Message );
}
//FString 转 Float
{
FString Message = TEXT("123.456");
float Result = FCString::Atof(*Message );
}
//Integer 转 FString
{
int32 Data = 123;
FString Result = FString::FromInt(Data);
}
//Float 转 FString
{
float Data = 123.456;
FString Result = FString::SanitizeFloat(Data);
}
//Array<uint8> 转 FString
{
TArray<uint8> Data;
const std::string msg(reinterpret_cast<const char*>(Data.GetData()), Data.Num());
FString Result = msg.c_str();
}
//FArrayReaderPtr 转 FString
{
uint8 Data[512];
FMemory::Memzero(Data, 512);
FMemory::Memcpy(Data, ArrayReaderPtr->GetData(), ArrayReaderPtr->Num());
FString Result = ((const char*)Data);
}
//Enum 转 FString
{
UENUM(BlueprintType)
enum class EImageFmt : uint8
{
JPG UMETA(DisplayName = "JPG"),
PNG UMETA(DisplayName = "PNG")
};
/* 获取枚举值的字符串*/
template<class EnumType>
FString GetEnumAsString(EnumType InEnumValue)
{
UEnum* Enum = StaticEnum<EnumType>();
return Enum->GetNameStringByValue((uint8)InEnumValue);
}
//使用
EImageFmt ImageFmt = EImageFmt::JPG;
FString Result = GetEnumAsString<EImageFmt>(ImageFmt );
}
//中文字符转码
{
std::string ConvertTCHARToChar(const TCHAR* Ptr)
{
std::string strOut;
if (Ptr != NULL)
{
int nInputStrLen = wcslen(Ptr);
int nOutputStrLen = WideCharToMultiByte(CP_ACP, 0, Ptr, nInputStrLen, NULL, 0, 0, 0) + 2;
strOut.resize(nOutputStrLen, 0);
char* pBuffer = (char*)strOut.c_str();
WideCharToMultiByte(CP_ACP, 0, Ptr, nInputStrLen, pBuffer, nOutputStrLen, 0, 0);
}
return strOut;
}
}
编辑器Actor执行Tick函数
- 说明:默认Actor在编辑器下不执行Tick函数
- 方法:重写方法ShouldTickIfViewportsOnly,并设置PrimaryActorTick.bCanEverTick = true;
TestActor.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "TestActor.generated.h"
UCLASS()
class ATestActor : public AActor
{
GENERATED_BODY()
public:
ATestActor();
UPROPERTY(EditAnywhere, Category = "Debug")
bool bUpdateInEditor = true;
UPROPERTY(EditAnywhere, Category = "Debug")
float TickCount;
public:
virtual bool ShouldTickIfViewportsOnly() const override;
virtual void Tick(float DeltaTime) override;
};
//TestActor.cpp
#include "TestActor.h"
ATestActor::ATestActor()
{
PrimaryActorTick.bCanEverTick = true;
PrimaryActorTick.TickGroup = ETickingGroup::TG_PostUpdateWork;
}
bool ATestActor::ShouldTickIfViewportsOnly() const
{
return this->bUpdateInEditor;
}
void ATestActor::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
TickCount += DeltaTime;
}
C++ 插件模块使用Editor模块
- 说明:Runtime插件模块使用Editor模块功能时编译会报无法解析外部符号错误
- 方法:加入UnrealEd模块,并在使用位置引入对应头文件,并用宏判断包裹
//xx.Build.cs
if (Target.bBuildEditor == true)
{
PublicDependencyModuleNames.AddRange(
new string[] {
"UnrealEd",
}
);
}
//ACustomActor.cpp
#if WITH_EDITOR
#include "Editor.h"
#include "EditorViewportClient.h"
#include "LevelEditorViewport.h"
#endif
#if WITH_EDITOR
bool ACustomActor::GetEditorActivedCamera(FOsgbCamera& OsgbCamera) {
if (!GEditor) {return false;}
UWorld* pWorld = this->GetWorld();
if (!IsValid(pWorld)) {return false;}
// Do not include editor cameras when running in a game world (which includes Play-in-Editor)
if (pWorld->IsGameWorld()) {
return false;
}
return true;
}
#endif
UE插件加载第三方dll并打包项目在其他电脑运行时崩溃
- 说明:插件加载了其他dll打包后,在其他电脑上运行崩溃(开发环境与运行环境不同)
- 方法:
- 下载VisualStudioSetup2022并安装组件 MSVC v143 -VS 2022 C++ x64/x86 生成工具(最新版)
- 若第一步安装后无效,则下载安装DirectX
- 下载VisualStudioSetup2022并安装组件 MSVC v143 -VS 2022 C++ x64/x86 生成工具(最新版)
UE编译第三方库插件代码报错
说明:UE编译第三方库代码报错
方法:在插件Build.cs中添加对应的宏
//报错 error C4668: 没有将“......”定义为预处理器宏,用“0”替换“#if/#elif”
bEnableUndefinedIdentifierWarnings
UE打包后无法切换ViewMode
说明:打包后需要切换线框模式、无光模式、仅光照模式等
方法:项目的DefaultEngine.ini配置添加 r.ForceDebugViewModes=1后重新打包
控制台切换模式命令
//线框
viewmode wireframe
//光照
viewmode lit
//无光照
viewmode unlit
//细节光照
viewmode lit_detaillighting
//仅光照
viewmode lightingonly
//光照复杂度
viewmode lightcomplexity
//着色器复杂度
viewmode shadercomplexity