写在前面
这里主要是记录一下Visual Studio和Editor之间的关系和如何使用它们进行UE4协同开发。
一、启动
1. 先启动Visual Studio再启动Editor
-
(1) 打开项目根目录下的
xxx.sln
解决方案,即可启动Visual Studio,这个是和普通的C++项目打开方式相同的;
-
(2) 在打开的C++项目中,点击本地Windows调试器编译程序即可启动Editor;
-
但这样一来,修改的代码就不能在Editor中生效了,需要停止调试再重新编译调试启动Editor才能将修改的代码生效;
-
所以这种方式不太推荐使用的;
2. 先启动Editor再启动Visual Studio
-
(1) 启动Editor的方式有四种:
-
打开已有UE4项目:
-
如果是已有UE4项目,则可以打开项目根目录的
xxx.uproject
,即可启动项目对应的Editor;
-
新建UE4项目或者打开已有UE4项目:
-
如果之前并没有已经创建的UE4项目,或者需要新建一个UE4项目,则可以点击UE4 Unreal Engine快捷方式(一般按官方途径安装之后在桌面就会有)启动Editor,然后按照指引新建一个UE4项目;
-
[推荐] 当然也可以点击UE4 Epic Games Launcher快捷方式,在库中启动对应版本的引擎,也可以进入Editor新建项目指引,一般是更推荐这种方式,因为可以管理不同版本的引擎;
-
另外,如果是通过源码编译得到的Unreal Engine,则需要在源码中打开
UE4.sln
,先调用Visual Studio打开Unreal Engine,然后右键UE4项目->Debug->Start new instance即可调出Editor界面,这样也可以进入Editor新建项目指引; -
当然上面的三种方法除了新建UE4项目之外,也可以打开已有的UE4项目,只要启动了Editor基本上就比较容易操作了;
-
(2) 在Editor中新建项目或者打开已有项目之后,在工具栏点击文件->打开Visual Studio即可用Visual Studio打开项目对应的UE4项目代码;
-
注意,项目的Editor和新建项目时启动的Editor是不一样的,后者可以视为一个引导程序,而前者才是
xxx.uproject
对应的Editor;
二、目录结构
1. C++项目文件目录结构
- 一个基本的UE4项目的项目文件结构如下:
- 各个文件夹对应的含义如下:
Binaries
:可执行文件和DLL文件;Config
:配置文件,包含了项目设置,键盘输入之类的配置文件;Content
:存放引擎或者游戏的内容文件,包括地图、贴图、模型、材质和蓝图等;Intermediate
:临时构造文件,包含了在编译引擎或者游戏时生成的临时文件;Saved
:保存的内容,包括自动保存的文件、本地配置文件(*.ini
文件)、截图和日志文件;Source
:源代码,包括项目的所有源代码;
- 其中最重要的文件夹是
Content
和Source
,前者用于管理各种内容文件,后者用于管理源代码,是C++项目和Editor沟通的桥梁;
2. Editor内容浏览器文件目录结构
-
一个基本的Editor内容浏览器的文件目录结构如下:
-
(1)
内容
文件夹和C++项目中的Content
文件夹基本上是完全对应的,里面的资源文件均可以通过文件资源管理器在Content
文件夹中找到,而且目录结构一致; -
(2)
C++类
文件夹和Source
文件夹基本上是完全对应的,所有出现的C++类均可以在文件资源管理器的Source
文件夹中找到,而且目录结构一致; -
一个简单的示例如下:
-
TestCppGameModeBase
这个类在Source
文件夹中有对应的.cpp
和.h
,在内容浏览器中也有对应的映射;
- 如果发现内容浏览器中少了某些文件夹,可以点击右下角的视图选项勾选需要的内容,就可以在内容浏览器中看到了;
三、C++类和蓝图的相互协作
- Visual Studio负责管理C++类源码,Editor则负责蓝图和资源的组织管理,它们之间最重要的沟通桥梁就是C++类和蓝图之间协作;
- 这里将介绍如何创建一个最基本的
UObject
类,然后在蓝图中调用它;
1. 创建C++类
- C++类要在Editor中创建,在内容浏览器的C++类->工程文件夹目录下右键,点击新建C++类即可;
- 勾选显示所有类可显示所有的已有类;
- 点击下一步,检查当前类是否创建于项目文件夹下;
- 勾选公有按钮,会自动将该类的
.h
文件放到Public文件夹下,将.cpp
文件放到Private文件夹下; - 修改类的命名,注意要用大驼峰式,所有首字母均大写,不需要加前缀,因为这个是类文件名,真正的类名UE4会自动帮我们加上的;
- 如果新建类后,在内容浏览器中没有显示,可以:
- 使用Editor的编译按钮编译;
- 在Visual Studio中生成解决方案编译;
- 或者尝试重新进入对应的目录中,刷新界面显示内容;
2. 创建C++类对应的蓝图类
- 使用
UObject
为父类创建的类是最基本的类,类内的内容十分简洁; - 它的头文件包括类的声明、类成员变量和类成员函数声明,如下:
- 它的
cpp
仅包含一行头文件,内容如下:
- 此时的
PrintOnScreenObject
类是无法在Editor中创建蓝图类的,需要给它加上Blueprintable
说明符,如下:
- 回到Editor中,在C++类上右键创建基于xxx的蓝图类,即可创建对应的蓝图类,如下:
- 蓝图是资源的一种,因此创建的蓝图类会在
Content
文件夹下; - 创建了蓝图类之后还要把它移动到合适的文件夹中,做好分类,如下:
3. 实现C++成员函数
- 为了能让
PrintOnScreenObject
类的成员变量和函数均能在蓝图中可见,需要为它们增加对应的宏说明符,如下:
- 然后,在
.cpp
文件中实现打印的功能,参考博客:UE4 C++ 之 打印; - (1) UE4打印到日志:
// 日志实现的格式如下
UE_LOG(日志变量名, 日志级别, 日志内容);
// 日志的级别有三种:Log, Warning, Error
// 输出文本
UE_LOG(LogTemp, Log, TEXT("This Log is grey text."));
// 输出含普通类型字符串
int32 ID = 5;
UE_LOG(LogTemp, Warning, TEXT("This Log's id = %d"), ID);
- (2) UE4打印到屏幕:
// 打印到屏幕的实现格式如下
GEngine->AddOnScreenDebugMessage(-1, 显示持续时间, 显示颜色, 显示内容);
// 打印文本
GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Red, TEXT("Hello world!"));
// 打印含普通类型的字符串
FString MyName = "Jeremy";
GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Red, FString::Printf(TEXT("My name is: %s."), *MyName));
float Height = 179.0f
GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Red, FString::Printf(TEXT("I am %f cm tall."), Height));
- 因此,实现的成员函数如下:
4. 构建调用C++类的蓝图
- 因为只有Actor才能放进地图里面,而前面创建的类是
UObject
类型的,所以还要额外创建一个Actor蓝图类,如下:
- 双击Actor蓝图类,打开蓝图编辑界面,并搭建调用蓝图
PrintOnScreenObject
类的蓝图,如下:
- 一些注意的点如下:
- 首先要让当前Actor类有一个
PrintOnScreenObject
类成员变量,在左下方的我的蓝图->变量中新加即可; - 蓝图的逻辑是:构建一个
PrintOnScreenObject
类对象,拥有者是当前Actor类,然后把构造的对象赋给PrintOnScreenObject
变量,然后通过该变量调用PrintOnScreenObject
类的成员函数PrintToScreen
; - 白色点的连接表示执行过程的传递,其余点的连接表示变量数据的传递;
- 如果在C++代码中修改了成员函数或者变量的名字,则蓝图中的对应气泡需要重新构建;
- 右键气泡节点可以进行快速节点注释;
- 编译C++项目不通过的时候,可以先去Editor进行编译,然后再回到Visual Studio中编译;
- 首先要让当前Actor类有一个
- 搭建好蓝图后,点击左上角的编译按钮;
- 然后回到主面板,将
BP_PrintOnScreenActor
拖入地图中生成实例,否则蓝图无法生效;
- 最后点击编译和播放即可;
- 效果是在屏幕上有5秒的内容打印,在日志中有输出warning级别日志信息;
5. 删除类
-
删除蓝图类:
- 在内容浏览器中右键选择要删除的蓝图,选择删除即可;
- 删除时,如果选择替换引用,则替换所有的该蓝图类实例,如果选择强制删除,则强制删除所有的该蓝图类实例;
-
删除C++类要稍微麻烦一点:
- 关闭所有Editor和Visual Studio窗口;
- 删除类对应的
.cpp
和.h
文件; - 删除Binaries文件夹;
- 右键
.uproject
文件,选择Generate Visual Studio project files,重新生成vs项目文件;
四、遇到的问题及处理
1. 调用类成员变量时有红色波浪线报错,但编译能通过
- 情景:在创建C++类时勾选了公有按钮,
.h
文件被放到了Public文件夹下,在.cpp
中调用类内成员时有大量的红色波浪线报错,Visual Studio无法识别变量类型,也无法给出类的函数提示,虽然编译能够通过,但这样编程就会很难受,既无提示也很难判断是否有拼写错误; - 原因:代码的目录结构过于复杂,Visual Studio没有将当前代码所需的声明文件包含在搜索路径下;
- 解决方法:
- 右键项目属性;
- 在NMake中包含搜索路径下,新增声明文件所在的路径,更具体一点的,是当前代码中显示了红色波浪线的变量或者函数所在的声明文件(通常是
.h
文件)的路径;
2. 调用系统类函数时有红色波浪线报错,但编译能通过
- 场景:调用别的一些UE4自带的类时,提示找不到该类声明,或者提示不允许指针指向不完整的类类型,无函数提示,但编译能够通过;
- 原因:因为没有引入和该类对应的头文件,但UE4有某些修复机制,导致编译能够通过;
- 解决方法:在代码中右键该类名称,点击转到声明,这时编辑器会给出所有包含该变量声明的头文件位置,选择合适的头文件引入到当前代码中即可;
3. 在Visual Studio中编译不成功但无法定位错误
- 一种解决方法:可以在Editor中编译,给出的错误信息会比较详细,方便定位错误;
- 其实在Editor中编译等价于在Visual Studio中生成解决方案;
4. 头文件中类提示未定义标识符
- 场景:如果是需要在头文件中使用一些UE4的类,则有可能提示未定义标识符而报错,因为头文件中确实没有引入这个类对应的头文件,而且也不适合在头文件中引入别的类的头文件,一般只在
.cpp
文件中才引入,头文件只作声明; - 解决方法:在类名前增加
class
关键字,当然也可以在头文件的下面直接将所有用到的类都用class
关键字声明一遍,这样就不用每次写类名都声明了;
5. 修改C++类后,在对应的蓝图类面板上没有实时更新信息
- 场景:用C++类派生蓝图类后,如果修改了C++类的内容,则蓝图类可能不能实时同步更新;
- 解决方法:在类设置->父类中修改为其他类,然后再修改回原来的类,即可刷新C++类中的信息到蓝图类中;