经过在公司半个月的工作,主要学习以下内容:
1.第三方库(ThirdParty)
第三方库是在做SDK对接中学习到的,第三方库主要分为三个文件,分别是include,lib,redist。
其中include中存放的是第三方库的头文件,后缀为.h
lib为静态库,后缀为.lib
redist为动态库,后缀为.dll
在做UE4程序之前需要引入第三方库。
2.引入第三方库
首先将第三方库放入与工程文件.Build.cs同一级目录下
然后在.Build.cs中加入以下代码:
private string ModulePath
{
get
{
return ModuleDirectory;
}
}
private string ThirdPartyPath
{
get
{
return Path.GetFullPath(Path.Combine(ModulePath, "ThirdParty"));
}
}
需要注意的是要在.Bulid.cs中加上这个:
using System.IO;
接下来为头文件 ,静态库,动态库的引入:
PublicIncludePaths.Add(Path.Combine(ThirdPartyPath, "include"));
PublicAdditionalLibraries.Add(Path.Combine(ThirdPartyPath, "lib", "imos_sdk.lib"));
PublicAdditionalLibraries.Add(Path.Combine(ThirdPartyPath, "lib", "xp_frame.lib"));
PublicAdditionalLibraries.Add(Path.Combine(ThirdPartyPath, "lib", "xp_player.lib"));
string dllPath = Path.Combine(ThirdPartyPath, "redist");
RuntimeDependencies.Add("$(BinaryOutputDir)/imos_sdk.dll", Path.Combine(dllPath, "imos_sdk.dll"));
RuntimeDependencies.Add("$(BinaryOutputDir)/xp_frame.dll", Path.Combine(dllPath, "xp_frame.dll"));
RuntimeDependencies.Add("$(BinaryOutputDir)/xp_player.dll", Path.Combine(dllPath, "xp_player.dll"));
动态库要是多的话直接把redist中的动态库拷入到Binaries/Win64中(不知道对不对,我弄反正是可以)。
以上就算把第三方库引入到工程中了,接下来就是第三方库的引用了。
下面是在UE4C++编写过程中用到知识点
3.UE4C++用到的宏
在编写过程中代码中的宏我觉得是最烦人了,实在看不明白
下面记一下这次用到的一些宏:
1,UCLASS类说明符,声明包含一个类的标准 C++ 类声明。在标准声明之上,描述符(如类说明符和元数据)将被传递到 UCLASS 宏 ,UE4中的类是以A开头的。
UCLASS()
class IMOS_UEF_1_API AMyActor: public AActor
{
GENERATED_BODY()
};
2, 类中的一个,也不清楚具体作用是啥
GENERATED_BODY() //class
GENERATED_USTRUCT_BODY() //struct
3.UPROPERTY 作用是定义能够被UE垃圾回收机制自动回收的属性变量
UPROPERTY(Editanywhere, BlueprintReadWrite) //定义一个可以显示面板的变量,而且蓝图可读写
FString a; //需要注意的是定义的变量必须是蓝图认可的变量
UPROPERTY(Editanywhere, BlueprintReadOnly) //定义蓝图只读的变量
4.UFUNCTION 定义能被UE识别的函数
UFUNCTION(BlueprintCallable) //定义一个函数可以在蓝图调用
void Function();
5.USTRUCT() 结构体的类说明符,定义结构体需要用到,定义结构体时候需要注意,UE4的结构体名称必须以F开头,必须以F开头。
USTRUCT(BlueprintType) //能在蓝图中使用
struct Fstruct
{
GENERATED_USTRUCT_BODY()
};
6.UFUNCTION(BlueprintImplementableEvent) 蓝图中event事件
UFUNCTION(BlueprintImplementableEvent)
void OnUpdateCamera();
4.编写C++时遇到的问题
1.在编写一个可在蓝图中调用的函数时,函数的返回值和形参必须是蓝图认识的类型,在使用时需要做类型转化,还可以用函数封装的方法来实现,写一个例子:
.h文件
class Actor:public AActor{
public:
UFUNCTION(BlueprintCallable)
void Box();
void Function(CHAR a); //CHAR类型蓝图不认识,所以不可以用UFUNCTION(BlueprintCallable)
public:
CHAR a;
};
.cpp文件
void Actor::Box()
{
Function(a);
}
void Actor::Function(CHAR a)
{
//函数实现
}
2.在c++中使用Tarry容器
定义一个结构体
USTRUCT(BlueprintType)
struct FSTRUCT
{
GENERATED_BODY()
public:
UPROPERTY(Editanywhere, BlueprintReadWrite)
FString sName;
UPROPERTY(Editanywhere, BlueprintReadWrite)
FString sCode;
UPROPERTY(Editanywhere, BlueprintReadWrite)
int CameraState;
};
在类中做一个存储 FSTRUCT的TArray容器
class Actor:public AActor{
public:
UFUNCTION(BlueprintCallable)
void GetBox();
UFUNCTION(BlueprintCallable)//获取列表
const TArray<FCAMINFO>& getCameraList()
{
return cif;
}
UFUNCTION(BlueprintCallable) //返回容器元素个数
int getCount();
public:
UPROPERTY(Editanywhere, BlueprintReadOnly)
TArray<FSTRUCT> Box;
};
void Actor::GetBox()
{
for(int i=0;i<100;i++)
{
FSTRUCT cItem; //我犯的错误,直接就用Box了;
cItem.sName=a;
cItem.sCode=b;
cItem.CameraState=1;
Box.Add(cItem);
}
}
int Actor::getCount()
{
int count=0;
for (int i = 0; i < cif.Num(); i++) //注意不是<=
{
count++;
}
return count;
}
目前用到关于TArry的应该就是这些知识点,以后用到别的再记录。
3.递归的使用递归函数以前有了解但是只是看看别人写的代码印象不深刻,经过这次教训对递归的印象加深了不少,在分页遍历中用到的,递归的用法很灵活,现在的能力无法掌握。。。
void DiGui(FString a,int b,int nlevel)
{
if(nleve>=4) //限制调用次数
return;
for(int i=0;i<10;i++)
{
if(条件)
{
遍历内容
}
else
{
DiGui(c,d,nlevel+1); //自己调用自己
}
}
return;
}
4.写window窗口
window窗口的编写是调用一些接口,网上能查到,但是看不太明白
记录一下公司同事提供的编写代码
//创建窗口
void AMyActor_Window::CreateVideoWindow()
{
if (pHwnd)
return;
HWND parentHandel = (HWND)GEngine->GameViewport->GetWindow()->GetNativeWindow()->GetOSWindowHandle();
uint32 extyle = WS_EX_WINDOWEDGE; //1
uint32 winstyle = WS_POPUPWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;//2,4,8
TCHAR winName[] = TEXT("DHSDK_Window");
TCHAR className[] = TEXT("UnrealWindow");
HINSTANCE tpinsHandle = (HINSTANCE)GetModuleHandle(NULL);
HWND oldTypeWind = CreateWindowEx(extyle, className, winName, winstyle, 300, 300, 600, 600, parentHandel, NULL, tpinsHandle, NULL);
::ShowWindow(oldTypeWind, SW_HIDE ); //SW_HIDE是创建时隐藏窗口 SW_SHOW是创建时显示窗口,这个根据自己的需求来定
pHwnd = oldTypeWind; //pHwnd是在头文件中定义的窗口句柄,类型是HWND
}
//销毁窗口
void AMyActor_Window::CloseVideoWindow()
{
if (pHwnd)
{
::SendMessageA((HWND)pHwnd, WM_CLOSE, 0, 0);
pHwnd = NULL;
}
}
//调整窗口尺寸
void AMyActor_Window::ReSize(FVector2D imgPos, FVector2D imgSize)
{
if (pHwnd)
{
int32 WindowX = imgPos.X;
int32 WindowY = imgPos.Y;
int32 NewWidth = imgSize.X;
int32 NewHeight = imgSize.Y;
::SetWindowPos((HWND)pHwnd, nullptr, WindowX, WindowY, NewWidth, NewHeight, SWP_NOZORDER | SWP_NOACTIVATE);
}
}
//判断窗口显示与隐藏
void AMyActor_Window::ShowWindow(bool IsShow)
{
if (pHwnd)
{
::ShowWindow(pHwnd, IsShow ? SW_SHOW : SW_HIDE);
}
}
5.创建C++的Actor类时,官方提供的默认函数 ,在这里要记住如果要使用tick函数那么就不要删掉构造函数,因为类中的构造函数内容是设置tick函数可以执行,默认是不执行的。而且c++中的BeginPlay要比蓝图中的好,因为他好像涉及到一个执行先后的问题。
UCLASS()
class IMOS_UEF_1_API AMyActor_Window : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
AMyActor_Window();
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
// Called when the game starts or when destroy
virtual void BeginDestroy() override;
//public:
// // Called every frame
virtual void Tick(float DeltaTime) override;
}
AMyActor_Window::AMyActor_Window()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
}
void AMyActor_Window::BeginPlay()
{
Super::BeginPlay();
//CreateVideoWindow();
}
/ Called when the game starts or when destroy
void AMyActor_Window::BeginDestroy()
{
Super::BeginDestroy();
//CloseVideoWindow();
}
void AMyActor_Window::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
6.两个Actor之间的调用
如果要需要调用其它Actor中的函数时,需要包含要调用的Actor的头文件,然后在自己Actor的类中写一个要调用的Actor的指针。
#include“Actor1.h”
UCLASS()
class Actor2 : public AActor
{
GENERATED_BODY()
public:
UPROPERTY(Editanywhere, BlueprintReadWrite)
class Actor1* A1 = nullptr; //这样就可以通过A1调用Actor1中的函数了
}
7.UE4中的模块
UE4是一堆模块组成的,在使用相应模块中的内容时不要忘了在.bulid.cs中引入该模块,目前我用到了两个需要自己开启的,slate和slateCore是和窗口有关的,UMG是创建UImage时用到的
PrivateDependencyModuleNames.AddRange(new string[] { "Slate", "SlateCore", "UMG" });
UPROPERTY(EditAnywhere, BlueprintReadWrite)
class UImage* m_pAnchorSizeImg; //这里需要开启UMG模块
8.FString类型转char*
FString FNum
string Snum = TCHAR_TO_UTF8(*Fnum);
char* Cnum = (char*)malloc(sizeof(char) * (Snum.length() + 1));
strncpy_s(Cnum, Snum.length() + 1, Snum.c_str(), Snum.length());
9.开空间
int* Num = (int*)malloc(10 * sizeof(int));
free(Num);
10.检测内存泄漏(还没用过,先记录一下,用F5调试才会出现结果,而且应该只能在VS中用)
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
目前好像就这些,剩下等有在记。
如果有大神看到的话希望帮我补充一下或者指出我上面可能写错的地方(可能我理解上出了错误),菜鸟一枚多多包涵