流程
1)创建GameState、PlayerController、Pawn(作为MainCamera)类,并在gameMode里加载;
2)创建继承自UObject类的全局配置类,将其设置为蓝图可编辑后,创建一个基于本C++类的蓝图配置类;
3)创建MainCamera类的组件(PikaGodStoneCamera类的构造函数);
4)创建PlayerState类,并在gameMode里加载;
5)在PlayerState类里引用蓝图里的全局配置(PlayerState类的构造函数);
6)在PlayerController类里加载PlayerState类的构造函数里,读取到的全局配置;
7)playerController类里用鼠标的移动方向控制主摄像机移动(PikaGodStonePlayerController::PikaCameraMove),鼠标滚轮控制主摄像机的缩放(移动和缩放的函数需要在UE4编辑器里提前设置好);
8)解决摄像机碰撞到同等高度的模型时,会产生重叠的问题,解决方法:创建继承自Actor的DisplaceTrigger类,类里创建一个碰撞Box,创建对应的蓝图类后,如果检测到Box与摄像机的碰撞,就拉高摄像机;
9)创建场景内角色移动的导航网格;
10)创建继承自Character类的角色基类CharacterBase和继承自UObject类的角色数据类CharacterData,在CharacterData里创建好角色属性并初始化后,在CharacterBase里创建一个指向CharacterData类的指针并在构造函数里进行实始化;
11)创建继承自角色类CharacterBase的怪物类Monster,和继承自AIController的行为控制类MonsterAIController,再创建一个继承自AIController类的行为控制类TowerAIController;
12)创建Monster类的蓝图,并将蓝图里的AIControllerClass设置为MonsterAIController;创建一个Monster类蓝图的子类蓝图,并将子类蓝图里添加一个方块组件,用于测试,子类蓝图的碰撞需要设置成NoCollision;
13)在创建Monster类的蓝图的上一层文件夹下创建一个Controller文件夹,并在里面创建AI相关的行为树MonsterBehaviorTree和黑板MonsterBlackboardData;
14)创建一个继承自BTService类的怪物寻找目标服务类MonsterBTServiceFindTarget,创建该类的时候会提示需要编译并报错,此时需要重写父类里的三个函数,重载后再次编译,成功后就可以在行为树的蓝图里选择刚刚创建的服务类MonsterBTServiceFindTarget;
15)在MonsterAIController类里创建行为树的指针,并运行行为树,编译后,创建基于本类的蓝图类MonsterAIControllerBP,再将角色蓝图基类PikaMonsterBaseBP的AIControllerClass切换为MonsterAIControllerBP,最后在蓝图MonsterAIControllerBP里加载已创建好的行为树MonsterBehaviorTree;
16)在MonsterAIController的C++类里编写寻找离自己最近的敌对目标的逻辑(PikaFindTarget函数);
17)创建继承自角色基类CharacterBase的塔的C++类Towers;
18)在行为树的服务c++类PikaMonsterBTServiceFindTarget里创建两个FBlackboardKeySelector,用来在黑板中存储目标塔和角色自身到目标塔之间的距离,这两个FBlackboardKeySelector需要在行为树的selector里选择和黑板里对应的变量值;
19)将MonsterAIController里返回的目标塔通过18里的FBlackboardKeySelector存储到黑板中,然后通过行为树的MoveTo,使PikaMonsterAIControllerBP自动移动到PikaTowersTestBP旁边;
20)创建Towers类的蓝图,并将蓝图里的AIControllerClass设置为TowerAIController;创建一个Towers类蓝图的子类蓝图,并将子类蓝图里添加一个方块组件,用于测试,子类蓝图的碰撞需要设置成NoCollision;
21)在CharacterBase里添加跟踪点,血条显示的组件及属性显示的组件,添加完后,需要在.Bulid.cs文件里添加UMG组件,否则会编译不过;
22)创建继承自Unreal Interface的攻击接口类AttackInterface,并在接口类定义一个接口函数PikaAttackTarget,接着在CharacterBase类多继承一个AttackInterface类,最后分别在Towers类和Monster类里重写PikaAttackTarget函数;
23)在Towers类里创建一个球形组件,用于设置塔的攻击范围,并将该组件绑定到根组件下;给球形组件绑定一个BeginOverlapping事件和一个EndOverlapping事件,用于检测进入本身攻击范围和离开攻击范围;
24)创建一个继承自Actor的子弹类BulletBase,在子弹类BulletBase里创建子弹类型的枚举,粒子等组件及碰撞事件,最后生成一个该子弹类的蓝图类,并在蓝图类中利用粒子组件装载攻击特效,并选择子弹的攻击类型;
25)CharacterBase类里增加一个可以蓝图里添加BulletBase类的属性,编译后,创建一个Towers的蓝图类,并在该蓝图里加载子弹蓝图类,完成后塔就会对进入其攻击范围的敌对目标进行攻击;
26)创建一个继承自BTTask Blackboard Base类的随机散步类PikaBTTask_RandomWalk(创建过程出现的重新编译的错误提示直接关闭就行,编译时需要重载父类里里三个方法),随机散步类PikaBTTask_RandomWalk中创建一个随机点,并将随机点传递到行为树蓝图中;
27)在行为树中,让怪物模型在26中创建的随机点上随机移动(没有找到目标时的逻辑);
28)创建一个继承自BTTaskNode类的移动类PikaBTTaskMoveToTarget;
29)创建一个继承自BTTaksNode类的攻击类PikaBTTaskAttackTarget;
30)在怪物的行为树里添加找到目标时的逻辑,和目标之间的距离大于800时调用PikaBTTaskMoveToTarget,朝目标移动,和目标之间的距离小于900时,开始调用PikaBTTaskAttackTarget,朝目标攻击;
31)自定义碰撞检测通道,修改子弹蓝图基类的碰撞类型,修改塔蓝图基类和怪物蓝图基类的碰撞类型为自定义的碰撞检测通道;
32)在子弹基类BulletBase里创建开火特效;
33)创建一个基于UserWeight类的UI基类PikaUIWidgetBase,创建一个基于UI基类的血条显示类PikaUIHealthShow,创建一个基于UI基类的属性显示类PikaUICharacterAttribute;
34)新建一个文件夹Content>HUD>GameUI,用来存储游戏UI;在GameUI里创建一个控件蓝图HealthShowBP,并将其父类设置为PikaUIHealthShow;
35)制作血条,并在塔的蓝图基类里载入,怪物的基类载入同塔基类;
36)在血条显示类UPikaUIHealthShow里创建两个变量用于控制血条栏和角色名称,编译后在控件蓝图HealthShowBP里将这两个变量绑定到控件蓝里对应的变量上;
37)在角色基类APikaCharacterBase里添加一个函数PikaGetHealthPercentage,用来获取角色当前生命的百分比;添加一个函数PikaGetDefenceDamage,用来计算伤害;添加一个函数PikaUpdateUMGHealth,用来更新血条栏;
38)伤害公式:对自身造成的伤害 = 敌人攻击力 / ((自身的防御力/10) + 1);
39)调整怪物行为树,使怪物攻击时会自动转向;
40)在Monster类和MonsterAIController类添加,将死亡信息传递到行为树的方法PikaDestoryCharacter和PikaSetCharacterDeathInfoSendBehaviorTree;
41)创建一个用于解析csv文件的DataTable类PikaCharacterInfoDataTable,修改PikaCharacterInfoDataTable类为结构体并让其继承自FTableRowBase;
42)导入csv数据;
43)添加线性攻击和范围攻击的相关代码;
44)制作范围攻击特效,并将特效中的参数暴露出来,用代码进行控制;
45)整合塔和怪物的攻击代码;
46)创建继承自Cheat Manager的GM命令类PikaGameManager;GM命令类可以在继承自PlayerController的玩家控制类(PikaGodStonePlayerController)里进行初始化,初始化完成后,还要在GM类的UCLASS里加上UCLASS(Within = PikaGodStonePlayerController);
47)创建继承自TargetPoint类的目标点类PikaAITargetPoint,该C++类可以直接拖拽到地图中以获取地图中的坐标点和方向;调用时可以先在PikaGodStonePlayerController里遍历场景中所有的目标点,然后将其添加到一个容器中以方便后续处理;
48)创建一个继承自Actor的类PikaToolRangeOfCharacter(该类里有一个类似范围攻击的搜索圈),并在角色基类里创建一个可以加载PikaToolRangeOfCharacter蓝图的属性,当塔或怪物死亡后,自动生成一个PikaToolRangeOfCharacter类的蓝图,用来搜索自己死亡后,附近的敌对目标,以便将自身的经验值加到敌对目标上;
49)在GM命令类PikaGameManager中添加一个添加塔的函数PikaAddTowers;
50)创建一个继承自Actor的伤害数值显示类PikaDamageValueText;创建一个继承自PikaUIWidgetBase的显示组件类PikaUI_InformationWeight;
51)创建一个控制蓝图UI_InformationWeightBP,并将该蓝图的基类设置为PikaUI_InformationWeight;创建一个继承自PikaDamageValueText类的蓝图类,将在蓝图类中载入控件蓝图UI_InformationWeightBP;
52)在和Button相关的引擎源码上添加新方法;
53)创建继承自PikaUIWidgetBase游戏主界面类PikaMainInterface;
54)在UE4编辑器中测试Button修改后的代码;
55)创建继承自HUD的HUD基类PikaHUDBase,并在PikaGodStoneGameModeBase里加载HUD;
56)创建继承自PikaUIWidgetBase的物品栏UI类PikaUI_Inventory;创建继承自PikaUIWidgetBase的菜单栏UI类PikaUI_InventorySlot;在UE4编辑器里创建两个控件蓝图,并将其父类分别指定为PikaUI_Inventory和PikaUI_InventorySlot;
57)在PikaUI_Inventory类中新增一个蓝图可编辑的属性,用来载入PikaUI_InventorySlot的蓝图实例;
58)创建一个继承自Object类的UI数据类PikaUIData,用来存储UI相关的数据,如物品栏的长宽高等;
59)创建物品栏,主界面类PikaMainInterface里加载PikaUI_Inventory,PikaUI_Inventory里加载PikaUI_InventorySlot;
60)在PikaUI_Inventory初始化物品栏图片,并在PikaUI_InventorySlot里进行图片的载入,载入后调整图片的大小及字体大小;
61)在PikaUI_InventorySlot里重载PikaOnClickedWidget,并通过UButton * UPikaUIWidgetBase::PikaGetButtonFromBlueprint(FName BlueprintWidgetName) const的方式获取Button,该方式获取Button会注册一个点击的按钮的事件,且事件的响应函数为上重载的PikaOnClickedWidget;最后在重载函数PikaOnClickedWidget里更新按钮上的文本;
62)制作CD材质,并将该材质导入到蓝图PikaUI_InventorySlotBP的CDImage里;
63)创建继承自SaveGame类的实例PikaGameSaveData,用来存储游戏存档;创建继承自GameInstance的实例PikaGodStoneGameInstance,GameInstance的实例在整个游戏中只存在一个,类里数据在关卡切换时,不会被销毁;创建完成后在游戏里加载该GameInstance实例;
64)PikaUI_InventorySlot里添加CD相关的逻辑;
65)创建一个继承自Actor类的替身类PikaTowerDoll,用来将特效中材质进行替换,如全部替换成红色,以便实现用鼠标将图标拖拽出来后的效果;
66)定制鼠标拖拽效果(PikaUI_InventorySlot类),实瑞该效果前需要先开启PikaGodStone.Build.cs文件中的Slate和SlateCore模块;
67)创建继承自DragDropOperation的拖拽类PikaDragDropOperation;创建继承自PikaUIWidgetBase的塔的图标类PikaTowerIcon;将蓝图PikaUI_InventoryBP复制一份,重命为PikaTowerIconBP,并将PikaTowerIconBP的父类设置为PikaTowerIcon;
68)PikaUI_InventorySlot类重写一个鼠标点击响应事件NativeOnMouseButtonDown,再通过FReply类的DetectDrag方法,在鼠标点击事件中再定义一个鼠标拖拽的响应事件,并重写拖拽的响应函数NativeOnDragDetected;重写响应函数NativeOnDrop,该函数会在用鼠标将物品栏的图标从一个位置挪到另一个位置时触发;
69)将PikaTowerIconBP蓝图里的Button替换成SizeBox;
70)在NativeOnDrop函数里完成物品栏移动和交换的逻辑,并解决图标移动后,背景颜色会变的问题;
71)在主屏幕类PikaMainInterface里重写NativeOnDrop函数,以接收将物品栏上的图标拖拽到物品栏之外的区域的事件;要触发NativeOnDrop事件的话,必须先设置主屏幕的蓝图类的canvas panel;
72)创建继承自Acotr的类PikaAllowBuildTrigger,用来在射线检测里设置允许建造的塔的区域;
73)创建一个PikaAllowBuildTrigger的蓝图类,并在项目设置里自定义一个通道类型(源码位置);修改PikaAllowBuildTrigger蓝图类里Box的碰撞类型;射线通道的类型为Trace Channels,且碰撞预设里一定要设置成Block,否则无法获取鼠标的坐标(UE4.18.3);
74)利用鼠标中键拖拽生成绿色替身模型,并利用射线通道设置替身模型的坐标(PikaGodStonePlayerController的Tick函数里);
75)修改模型空间位置并新建一个允许塔建造的对象通道 PikaAllowBuildTower以及一个通道预设PikaAllowBuild;在塔的替身类里创建一个组件,并将该组碰撞预设设置为PikaAllowBuild,用来控制塔的建造距离;
76)在PikaGodStonePlayerController添加一个Q键和E键的响应函数,用来控制替身模型的旋转;
77)UE4里创建一个控件蓝图CharacterAttributeBP,用来显示角色属性;
78)在塔的角色的蓝图基类里添加显示角色属性的控件蓝图CharacterAttributeBP;
79)新建一个踪迹通道PikaScanTrace和一个碰撞预设PikaScaning(射线代码在PikaGodStonePlayerController的Tick里);在角色基类PikaCharacterBase新增一个UBoxComponent组件来用捕捉踪迹通道PikaScanTrace的射线;
80)创建一个继承自PikaUIWidgetBase的类PikaUITowerInfo,用来显示物品栏上塔的信息;
81)复制CharacterAttributeBP重新命名为CharacterInfoBP,并将其父类修改为PikaUITowerInfo,用来作为PikaUITowerInfo的显示;
82)控件蓝图设置;
83)创建一个控件蓝图GameCountBP用来显示击杀数等信息;创建一个控件蓝图GameErrorHint用来显示错误提示;创建一个控件蓝图GameMenuBP;创建继承自PikaUIWidgetBase的C++类PikaUIGameCount,PikaGameErrorHint,PikaUIGameMenu,并将其指定为对应的蓝图控件的父类;
84)将蓝图GameCountBP、GameErrorHint、GameMenuBP加载到主界面,并更改主界上调出主菜单的按钮的样式;
85)(1)创建一个继承自PikaUIWidgetBase的类PikaUILoading;
(2)创建一个继承自PikaUIWidgetBase的类PikaUIMainHall,用来制作登录大厅;
(3)创建一个继承自PikaUIWidgetBase的类PikaUIReadAndWrite,用来读写存档;
(4)创建一个继承自PikaUIWidgetBase的类PikaUISaveLoadBar,用来作为存档时的单条存档记录;
(5)创建一个继承自PikaUIWidgetBase的类PikaUIGameWarning;
(6)创建一个继承自PikaUIWidgetBase的类PikaUIHallGameSetting,用来设置游戏参数;
(7)创建一个继承自PikaUIWidgetBase的类PikaUIHallKey,用来制作游戏开始,读取游戏,游戏设置等按钮;
(8)创建一个继承自GameModeBase的类PikaHallGameMode;
(9)创建一个继承自HUD的类PikaHallHUD(需要在PikaHallGameMode里创建);
(10)创建一个继承自Pawn的类APikaHallPawn(需要在PikaHallGameMode里创建);
86)在目标点类PikaAITargetPoint里创建一个特效组件,用来作为物怪生成点的特效;在关卡里设置目标点,并在目标点里每隔一段时间自动生成怪物(APikaGodStonePlayerController::Tick);
87)在塔的类APikaTowers增加一个蓝图可修改的属性PikaTowersType,用来标识塔为主塔还是普通塔;修改怪物寻找塔的逻辑,优先寻找主塔APikaMonsterAIController::PikaFindTarget;
88)子弹、塔、怪物的自定义碰撞整理;
89)通过设置PikaAITargetPoint(PikaTeam的值为1的点为主塔的生成点,值为0的点为怪物的生成点)类,在场景中生成主塔,并添加主塔的待机、攻击、出生、死亡的动画;
90)主塔动画逻辑整理;
91)创建加载资源的C++类PikaGameResource;创建PikaGameResource的蓝图类,并在蓝图类中加载小地图的图片;
92)创建一个继承自UE类TargetPoint的蓝图类MapPointBP,用来设置地图的坐标原点位置;
93)在PikaGameSaveData类创建一个结构体FPikaTemporaryCacheData,用来存储地图中塔和怪物的坐标、存活状态、生命值等信息;每个角色(塔或怪物)创建时,均会在该结构体里存储本角色信息,角色基类PikaCharacterBase里的PikaDestoryCharacter和Tick函数里会对每个角色的数据进行更新(Tick里只能对怪物数据进行更新,因为塔生成后不会移动);UPikaUI_Inventory::PikaSpawnTowerDollReleased里需要对塔的信息进行更新;
94)在APikaHUDBase::DrawHUD里用FPikaTemporaryCacheData里的角色数据绘制小地图;
95)创建继承自GameUserSettings的游戏设置类PikaGameUserSettings,用来设置和存储游戏的分辨率、窗口还是全屏等设置;
96)在资源加载类PikaGameResource里创建一个加载声音衰减体积框的属性;在UE4编辑器里创建一个声音的衰减体积框;
97)在子弹的基类PikaBulletBase里的BeginPlay里添加子弹发射时的声音;在角色的基类PikaCharacterBase里添加角色受伤时的声音;
98)添加音乐设置;
99)创建继承自WorldSettings的类PikaWorldSettings,用来设置关卡的条件,如怪物等级、数量等;编译代码后,在UE4编辑器里的项目设置里进行设置;
100)添加视频相关的设置;
101)关卡切换时,释放掉HUD和主界面类里相关资源;
102)创建继承自GameViewportClient的类PikaGameViewportClient,用来显示Loading界面;
注意事项
1)用鼠标控制屏幕移动时,可以设置一个误差范围,如移动在8px以内,就不对应的移动摄像机;
2)鼠标控制屏幕移动时,需要先勾选场景内的全部物体,并在全部物体的碰撞里去掉摄像机的碰撞;
3)鼠标滚轮控制主摄像机的缩放的函数在Camera类里,调用则在playerController里,鼠标移动控制摄像机移动则都是在playerController类里;
4)DisplaceTrigger类的碰撞只保留碰撞的Visibility和WorldDynamic通道;
5)需要通过GetWorld来获取实例的代码必须写在BeginPlay里,如果放在构造函数里,则有可能GetWorld后于构造函数执行,导致返回的UWorld为空;
6)TickNode函数不是Tick,不会每帧都会执行;
7)子弹类BulletBase是怪物类和塔类通用的,只不过两者的特效不同;
8)组件的创建和绑定可以放在构造函数里,但组件上的事件绑定必须放在BeginPlay里,以防止代码执行过程中,出现事件绑定的代码先于组件绑定的代码执行,导致事件绑定失败;
9)塔攻击敌对移动目标时,敌对目标位置的获取必须放在Tick里,否则会出现攻击打在移动目标前面位置上的现象;
10)行为树相关的代码中,BlackboardKey.SelectedKeyName表示在行为树的蓝图中,手动选择的变量;
11)碰撞事件被多次触发时,需要将碰撞类型设置为自定义,且只保留一个pawn;
12)修改了引擎后,除了Button,所有widget都可以用Cast进行强转;
13)UE4源码中,函数名加了Native的通常为蓝图调用的函数,没加的为C++函数,如下图所示;
14)UE4在执行时崩掉后,可以从调用堆栈里查看代码崩掉的位置;
15)控件蓝图的固定文本都可以指定为非变量;
16)标注栏设置为不可拖动
17)输出中文乱码的解决方法
18)游戏存档生成顺序:1.创建继承自SaveGame的存档类PikaGameSaveData--->2.在继承自GameInstance的类PikaGodStoneGameInstance里的构造函数里进行初始化--->3.在继承自PlayerState的类PikaGodStonePlayerState的构造函数里进行赋值等操作;
19)全局配置类说明:(1)全局配置类PikaGlobalConfig里包含了存档类PikaGameSaveData,并定义了PikaGameSaveData里各种结构体数据的指针;(2)PikaGodStonePlayerController类通过全局配置类的指针来对存档类PikaGameSaveData里的数据进行操作;(3)PikaGodStonePlayerController类的数据指针,如PikaGlobalConfigPre、PikaGameResourcePtr等,都是在PikaGodStonePlayerState的构造函数里进行初始化的;(4)全局配置类是在GameState里进行初始化的,因此,切换关卡,都会重新初始化;
20)角色数据(怪物和塔)说明:角色数据在初始化时有一个默认的初始值,然后在PikaGodStonePlayerController::PikaCreateAndDataImport里通过预先定义好的角色数据表,来对创建角色进行数据更新;
21)临时数据缓存说明:该数据缓存结构体FPikaTemporaryCacheData定义于PikaGameSaveData类里面,全局存在一个实例,结构体中每个属性均为数组,每次新增角色(塔或怪物时),每个属性数组里均会增加一个值,因此,额头相同的下标在每个属性数组里取出来值,就为该角色的属性值;另外,在新增角色时,角色基类PikaCharacterBase里会保存该角色的PikaCharacterSpawnID,用来获取该角色在结构体FPikaTemporaryCacheData里的属性下标;
22)关卡加载顺序:关卡对应的GameMode类--->GameMode类的构造函数里根据需求加载HUD,Pawn,PlayerController等类--->HUD,Pawn,PlayerController等类里分别加载对应的资源,如HUD的构造函数里加载主UI,打开鼠标等;
23)控件蓝图里,如果需要通过c++或蓝图访问的元素一定要设置成Is Variable,如button,checkbox等,不需要访问的则不用设置,如Text,Spacer等;
24)伤害显示的加载顺序:创建控件蓝图UI_InformationWeightBP,并让其继承自C++类PikaUI_InformationWeight--->创建一个继承自C++类 PikaDamageValueText的蓝图类PikaDamageValueTextBP,并在蓝图类PikaDamageValueTextBP中载入控件蓝图UI_InformationWeightBP--->在子弹类基类的蓝图类PikaBulletBaseBP里载入伤害蓝图类PikaDamageValueTextBP--->在子弹基类的碰撞检测里显示伤害蓝图类PikaDamageValueTextBP;
PikaDamageValueTextBP:
伤害显示的方式由下图中的曲线控制
PikaBulletBaseBP:
25)新关卡创建后,在世界设置里设置了GameMode就可以加载对应的HUD、PlayerContorller等类;
26)锚点位置表示该组件出现的位置;
27)UE4里在非透视图下面按鼠标中键,可以实例的地图大小;
28)UE43里一个关卡就是一个World,GetWorld获取的就是当前的关卡;
29)UE4里游戏存储说明:游戏在运行中时,将角色的血值、等级等数值,一有变动就实时传到GameInstance里,当玩家点击保存后,就将数据存储为文件;
30)寻找范围内的角色;
31)游戏载入后,各组件,如倒计时组件,在创建好后均为默认值,读取全局配置类里的相关数据后,才会有值;
32)添加背景音乐时,只需要导入如wav格式的音乐文件,然后将音乐文件拖入到关卡中,就能正常播放;
33)直接继承自UObject的类,如GameUserSettings,是没法使用GetWorld来获取当前的UWrold的,如果需要获取当前UWorld,则需要在GameUserSettings里重写GetWorld方法,并在关卡的GameMode里将当前UWorld保存在GameUserSettings类里;
34)UE4图像设置的5个等级:
创建指针变量后,需要在变量上面加上UPROPERTY(),以便让变量拥有回收机制
指针赋值前,一定要写一个是否为空的判断
camera类要加载到gameMode里,因此要继承自pawn
gameMode类里加载GameState、PlayerController、DefaultPawn
创建继承自UObject类的全局配置类,并将其设置为蓝图可编辑
UCLASS(Blueprintable)里一定要加上Blueprintable,否则不能从c++的类创建蓝图类
创建PlyaerController类
去掉物体的摄像机碰撞
勾选物体
设置鼠标滚轮的响应事件
DisplaceTrigger类的蓝图下只保留碰撞的Visibility和WorldDynamic通道
用DisplaceTrigger类的蓝图拉高摄像机
创建一条曲线控制主摄像机变化的平滑
PikaDisplaceTrigger类的蓝图中,创建一个时间轴,载入已经创建好的曲线,并将时间轴的长度改为曲线一样的1;
蓝图中逻辑
UE4里的导航
按P键后,编辑器会用绿色显示可以移动的位置,前提是模型必须设置碰撞面;
Nav Modifier Volume可以用来消除用不到的导航网格
蓝图方式的全局配置
需要通过GetWorld来获取实例的代码必须写在BeginPlay里示例
创建Monster类的蓝图,并将蓝图里的AIControllerClass设置为MonsterAIController
子类蓝图的碰撞需要设置成NoCollision
在创建Monster类的蓝图的上一层文件夹下创建一个Controller文件夹,并在里面创建AI相关的行为树和黑板
创建一个继承自BTService类的怪物寻找目标服务类MonsterBTServiceFindTarget,创建该类的时候会提示需要编译并报错,此时需要重写父类里的三个函数
重载后再次编译,成功后就可以在行为树的蓝图里选择刚刚创建的服务类MonsterBTServiceFindTarget
再将角色蓝图基类PikaMonsterBaseBP的AIControllerClass切换为MonsterAIControllerBP
最后在蓝图MonsterAIControllerBP里加载已创建好的行为树MonsterBehaviorTree
在行为树的服务c++类PikaMonsterBTServiceFindTarget里创建两个FBlackboardKeySelector
这两个FBlackboardKeySelector需要在行为树的selector里选择和黑板里对应的变量值
创建Towers类的蓝图,并将蓝图里的AIControllerClass设置为TowerAIController
需要在.Bulid.cs文件里添加UMG组件,否则会编译不过
创建一个Towers的蓝图类,并在该蓝图里加载子弹蓝图类,完成后塔就会对进入其攻击范围的敌对目标进行攻击
在行为树中,让怪物模型在26中创建的随机点上随机移动(没有找到目标时的逻辑)
注:Cooldown是系统函数,作用是冷却2秒再执行下面的逻辑,RandomWalk是自己定义的函数,作用创建随机点,并设置到黑板里的变量RandomPoint里,MoveTo是系统函数;
在怪物的行为树里添加找到目标时的逻辑
完整的怪物行为树,在上面的基础上增加了怪物是否死亡的判断
碰撞事件被多次触发时,需要将碰撞类型设置为自定义,且只保留一个pawn
自定义碰撞检测通道
修改子弹蓝图基类的碰撞类型
修改塔蓝图基类和怪物蓝图基类的碰撞类型为自定义的碰撞检测通道
在GameUI里创建一个控件蓝图HealthShowBP,并将其父类设置为PikaUIHealthShow
制作血条
半透明化血条背景
血条颜色设置
制作血条,并在塔的蓝图基类里载入,怪物的基类载入同塔基类
在血条显示类UPikaUIHealthShow里创建两个变量用于控制血条栏和角色名称,编译后在控件蓝图HealthShowBP里将这两个变量绑定到控件蓝里对应的变量上
调整怪物行为树,使怪物攻击时会自动转向;
在Monster类和MonsterAIController类添加,将死亡信息传递到行为树的方法PikaDestoryCharacter和PikaSetCharacterDeathInfoSendBehaviorTree;
创建一个用于解析csv文件的DataTable类PikaCharacterInfoDataTable,修改PikaCharacterInfoDataTable类为结构体并让其继承自FTableRowBase;
新建数据表格,用于导入数据(导入数据时不用新建,直接将csv文件拖入UE4编辑器后,并选择对应的数据结构就行);
导入塔和怪物csv数据;
怪物数据导入同塔数据
制作范围攻击特效,并将特效中的参数暴露出来,用代码进行控制;
子弹蓝图里载入该特效后,将初始速度和重力都更改为0;
创建继承自Cheat Manager的GM命令类PikaGameManager;GM命令类可以在继承自PlayerController的玩家控制类(PikaGodStonePlayerController)里进行初始化,初始化完成后,还要在GM类的UCLASS里加上UCLASS(Within = PikaGodStonePlayerController)
在游戏里按~调出命令行,执行自已定义的函数
创建继承自TargetPoint类的目标点类PikaAITargetPoint,该C++类可以直接拖拽到地图中以获取地图中的坐标点和方向;
创建一个继承自Actor的类PikaToolRangeOfCharacter
在GM命令类PikaGameManager中添加一个添加塔的函数PikaAddTowers;
创建一个控制蓝图,并将该蓝图的基类设置为PikaUI_InformationWeight;
创建一个继承自PikaDamageValueText类的蓝图类,将在蓝图类中载入控件蓝图UI_InformationWeightBP;
在和Button相关的引擎源码上添加新方法;
沿着button的父类一直找到UWidget类
---------------------------------------------------------------------------
---------------------------------------------------------------
---------------------------------------------------------------------------------
-----------------------------------------------------------------
--------------------------------------------------------------------
Image类修改
----------------------------------------------------------------
获取特效的尺寸,以控制生成替身模型的大小时的修改
-------------------------------------------------
checkBox修改
代码绑定位置
-------------------------------------------------
ComboBoxString
-------------------------------------------------
UserWidget添加获取动画的方法
定义一个动画枚举
动画状态
-------------------------------------------------
声音
-------------------------------------------------
GameUserSettings
-------------------------------------------------
将UserWidget的RemoveFromViewport函数改为虚函数,用于关卡切换时,HUD和主界面的资源释放
-------------------------------------------------
InputKeySelector(改键专用控件)
.h文件里的代理
.cpp文件里的调用
在UE4编辑器中测试Button修改后的代码
在UE4编辑器里创建两个控件蓝图,并将其父类分别指定为PikaUI_Inventory和PikaUI_InventorySlot;
PikaUI_InventorySlot
button切割
文本字体颜色
所有组件默认设置为隐藏
将按钮背景设置为黑色半透明
PikaUI_Inventory,Uniform Grid Panel通常用来制作物品栏
创建物品栏,主界面类PikaMainInterface里加载PikaUI_Inventory,PikaUI_Inventory里加载PikaUI_InventorySlot;
调节鼠标移动及点击时,按钮背景的颜色变化
在PikaUI_Inventory初始化物品栏图片,并在PikaUI_InventorySlot里进行图片的载入;载入后调整图片的大小;
在PikaUI_InventorySlot里重载PikaOnClickedWidget,并通过UButton * UPikaUIWidgetBase::PikaGetButtonFromBlueprint(FName BlueprintWidgetName) const的方式获取Button,该方式获取Button会注册一个点击的按钮的事件,且事件的响应函数为上重载的PikaOnClickedWidget;最后在重载函数PikaOnClickedWidget里更新按钮上的文本;
制作CD材质,并将该材质导入到蓝图PikaUI_InventorySlotBP的CDImage里;
Cooling
MaterialCooling,ControllerCD为该变量参数化后的变量名;
将材质导入Image,并调整Image设置
创建完成后在游戏里加载该GameInstance实例;
PikaUI_InventorySlot里添加CD相关的逻辑;
定制鼠标拖拽效果,实瑞该效果前需要先开启PikaGodStone.Build.cs文件中的Slate和SlateCore模块;
将PikaTowerIconBP蓝图里的Button替换成SizeBox;
sizebox里长和宽要设置
在NativeOnDrop函数里完成物品栏移动和交换的逻辑,并解决图标移动后,背景颜色会变的问题;
在主屏幕类PikaMainInterface里重写NativeOnDrop函数,以接收将物品栏上的图标拖拽到物品栏之外的区域的事件;要触发NativeOnDrop事件的话,必须先设置主屏幕的蓝图类的canvas panel;
Self Hit Test Invisible是接收点击的
创建一个PikaAllowBuildTrigger的蓝图类,并在项目设置里自定义一个通道类型(源码位置);修改PikaAllowBuildTrigger蓝图类里Box的碰撞类型;射线通道的类型为Trace Channels,且碰撞预设里一定要设置成Block,否则无法获取鼠标的坐标(UE4.18.3);
碰撞通道的源码位置,新增的通道信息会直接写在配置文件DefaultEngine.ini里,配置文件里最前面的+表示增加;
如上图,PikaAllowSpawnTrigger的通道名称为ECC_GameTraceChannel5,因此通过ECC_GameTraceChannel5这个枚举就可以进行通道的判断;
修改PikaAllowBuildTrigger蓝图类里Box的碰撞类型;
利用鼠标中键拖拽生成绿色替身模型,并利用射线通道设置替身模型的坐标(PikaGodStonePlayerController的Tick函数里);
修改模型空间位置并新建一个允许塔建造的对象通道 PikaAllowBuildTower以及一个通道预设PikaAllowBuild;在塔的替身类里创建一个组件,并将该组碰撞预设设置为PikaAllowBuild,用来控制塔的建造距离;
UE4里创建一个控件蓝图CharacterAttributeBP,用来显示角色属性;
image和vertical Box都需要拉伸,且image需要设置成半透明的全黑色;
多行文本如果修改字体大小和颜色和没有生效,需要编译后才能看到效果;
在塔的角色的蓝图基类里添加显示角色属性的控件蓝图CharacterAttributeBP;
新建一个踪迹通道PikaScanTrace和一个碰撞预设PikaScaning(射线代码在PikaGodStonePlayerController的Tick里);在角色基类PikaCharacterBase新增一个UBoxComponent组件来用捕捉踪迹通道PikaScanTrace的射线;
复制CharacterAttributeBP重新命名为CharacterInfoBP,并将其父类修改为PikaUITowerInfo,用来作为PikaUITowerInfo的显示;
控件蓝图设置;
PikaMainInterfaceBP
CharacterInfoBP
HealthShowBP
PikaTowerIconBP
PikaUI_InventoryBP
PikaUI_InventorySlotBP
CharacterAttributeBP
创建一个控件蓝图GameCountBP用来显示击杀数等信息;创建一个控件蓝图GameErrorHint用来显示错误提示;创建一个控件蓝图GameMenuBP;创建继承自PikaUIWidgetBase的C++类PikaUIGameCount,PikaGameErrorHint,PikaUIGameMenu,并将其指定为对应的蓝图控件的父类;
GameCountBP
GameErrorHint
GameMenuBP
将蓝图GameCountBP、GameErrorHint、GameMenuBP加载到主界面,并更改主界上调出主菜单的按钮的样式;
子弹、塔、怪物的自定义碰撞整理;
通用:
子弹:
塔:
怪物:
主塔动画逻辑整理;
1)主塔的动画播放,需要先在Mesh组件里载入主塔的动画蓝图类;
2)主塔动画图表的说明,状态机里有主塔待机和死亡的动画序列,插槽M_State里有主塔出生和攻击的蒙太奇动画;出生和攻击的蒙太奇动画是在,新建的蒙太奇动画里载入出生和攻击的动画序列;
3)状态机里通过变量MainDeath来控制,播放是否需要从待机Idle跳转到Death;MainDeath的值由蓝图里调用的C++函数来设置;
4)出生及攻击的蒙太奇动画需要和,动画蓝图里的插槽一致;
5)主塔生成的蒙太奇动画在PikaGodStonePlayerController里,用PikaSpawnTowers生成塔时调用;
6)主塔的攻击动画在APikaTowers::PikaAttackTarget函数里进行播放;
在资源加载类PikaGameResource里创建一个加载声音衰减体积框的属性;在UE4编辑器里创建一个声音的衰减体积框;
添加音乐设置;
查看引擎内配置的路径
添加自己的配置
创建继承自WorldSettings的类PikaWorldSettings,用来设置关卡的条件,如怪物等级、数量等;编译代码后,在UE4编辑器里的项目设置里进行设置;
设置成功后,ini文件里会自动出现该文件的路径
1