蓝图视觉脚本基础
蓝图概述
蓝图(Blueprints)是Unreal Engine中的一种可视化脚本系统,允许开发者通过拖拽节点和连接线来创建游戏逻辑、行为和交互。蓝图简化了游戏开发过程,使得没有编程背景的开发者也能轻松上手。蓝图可以用于创建游戏对象的行为、关卡逻辑、UI界面、动画逻辑等。
蓝图的类型
Unreal Engine中的蓝图主要分为以下几种类型:
-
蓝图类(Blueprint Class):这是最常见的蓝图类型,用于创建游戏中的可实例化对象,如角色、道具、敌人等。
-
蓝图宏库(Blueprint Macro Library):用于创建可重用的逻辑块,可以在多个蓝图中调用。
-
关卡蓝图(Level Blueprint):用于控制关卡中的全局逻辑,如玩家的初始位置、游戏事件等。
-
数据表蓝图(Data Table Blueprint):用于管理游戏中的数据表格,如角色属性、物品数据等。
-
动画蓝图(Animation Blueprint):用于创建和管理角色的动画逻辑。
创建蓝图类
创建蓝图类的步骤
-
打开Unreal Engine编辑器:启动Unreal Engine编辑器并打开您的项目。
-
创建蓝图类:
-
在内容浏览器(Content Browser)中,右键点击空白处,选择“新建”(New) > “蓝图类”(Blueprint Class)。
-
选择一个父类(Parent Class),例如“Actor”(用于创建一般的游戏对象)、“Character”(用于创建角色)等。
-
为蓝图类命名并点击“创建”(Create)按钮。
-
蓝图类的基本结构
创建蓝图类后,您将看到一个蓝图编辑器窗口,其中包含以下几个主要部分:
-
事件图表(Event Graph):用于编辑蓝图的逻辑。
-
组件(Components):用于添加和编辑蓝图的组件,如静态网格体(Static Mesh)、碰撞组件(Collision Component)等。
-
变量(Variables):用于定义蓝图的属性和数据。
-
函数(Functions):用于创建可重用的逻辑块。
示例:创建一个简单的Actor蓝图
假设我们要创建一个简单的游戏对象,该对象在被玩家碰撞时播放一个音效。
-
创建蓝图类:
-
在内容浏览器中右键点击空白处,选择“新建” > “蓝图类”。
-
选择“Actor”作为父类。
-
命名为“SimpleActor”。
-
-
添加组件:
-
打开蓝图编辑器。
-
在“组件”部分,点击“添加组件”(Add Component)按钮。
-
选择“Static Mesh”组件,用于显示物体的模型。
-
选择“Sphere Collision”组件,用于检测碰撞。
-
-
配置组件:
-
选择“Static Mesh”组件,在细节(Details)面板中选择一个静态网格体(例如一个立方体)。
-
选择“Sphere Collision”组件,在细节面板中调整碰撞半径(例如设置为100)。
-
-
创建变量:
-
在蓝图编辑器中,点击“变量”(Variables)标签。
-
点击“+添加变量”(+Add Variable)按钮。
-
命名为“SoundEffect”,类型选择“Sound Base”。
-
点击“编译”(Compile)按钮。
-
-
编写逻辑:
-
点击“事件图表”(Event Graph)标签。
-
右键点击空白处,选择“添加事件”(Add Event) > “碰撞”(Collision) > “Begin Overlap”。
-
从“Begin Overlap”事件中拖出一条线,选择“播放声音”(Play Sound)节点。
-
将“SoundEffect”变量连接到“播放声音”节点的“Sound”引脚。
-
// 事件图表逻辑
Event BeginOverlap(OtherActor, OtherComp)
Play Sound (SoundEffect)
蓝图类的实例化
-
将蓝图类放入关卡:
-
在关卡编辑器(Level Editor)中,点击“添加演员”(Add Actor)按钮。
-
选择您刚刚创建的“SimpleActor”蓝图类。
-
将其放置在关卡中。
-
-
设置变量:
-
选中关卡中的“SimpleActor”实例。
-
在细节面板中,找到“SoundEffect”变量。
-
选择一个音效资源(例如“WAV”文件)并拖放到变量中。
-
事件图表(Event Graph)
事件概述
事件图表是蓝图中用于编辑逻辑的主要区域。事件(Event)是蓝图中的一种特殊节点,用于触发一系列逻辑操作。常见的事件包括:
-
BeginPlay:当游戏开始时触发。
-
Tick:每帧触发一次,用于更新游戏逻辑。
-
Input Events:当玩家输入时触发,例如按键、触摸等。
-
Collision Events:当对象发生碰撞时触发,例如BeginOverlap、EndOverlap等。
事件的使用
-
BeginPlay事件:
-
在事件图表中右键点击空白处,选择“添加事件” > “BeginPlay”。
-
从“BeginPlay”事件中拖出一条线,选择“打印字符串”(Print String)节点。
-
在“Print String”节点中输入“Game Started!”。
-
// BeginPlay事件
Event BeginPlay
Print String ("Game Started!")
-
Tick事件:
-
在事件图表中右键点击空白处,选择“添加事件” > “Tick”。
-
从“Tick”事件中拖出一条线,选择“设置演员位置”(Set Actor Location)节点。
-
在“Set Actor Location”节点中,设置一个新的位置,例如将对象沿着X轴移动100个单位。
-
// Tick事件
Event Tick (DeltaSeconds)
Set Actor Location (NewLocation = Get Actor Location + (X = 100, Y = 0, Z = 0) * DeltaSeconds)
-
输入事件:
-
在事件图表中右键点击空白处,选择“添加事件” > “输入” > “跳跃”(Jump)。
-
从“Jump”事件中拖出一条线,选择“播放动画”(Play Animation)节点。
-
在“Play Animation”节点中,选择一个跳跃动画。
-
// 跳跃输入事件
Event Jump
Play Animation (JumpAnimation)
-
碰撞事件:
-
在事件图表中右键点击空白处,选择“添加事件” > “碰撞” > “BeginOverlap”。
-
从“BeginOverlap”事件中拖出一条线,选择“播放声音”(Play Sound)节点。
-
将“SoundEffect”变量连接到“播放声音”节点的“Sound”引脚。
-
// BeginOverlap碰撞事件
Event BeginOverlap (OtherActor, OtherComp)
Play Sound (SoundEffect)
变量(Variables)
变量概述
变量是蓝图中用于存储数据的容器。变量可以是各种类型,如整数、浮点数、字符串、布尔值、对象引用等。变量可以在事件图表中使用,也可以在组件中配置。
变量的创建和使用
-
创建变量:
-
在蓝图编辑器中,点击“变量”(Variables)标签。
-
点击“+添加变量”(+Add Variable)按钮。
-
命名为“Health”,类型选择“整数”(Integer)。
-
点击“编译”(Compile)按钮。
-
-
在事件图表中使用变量:
-
在事件图表中右键点击空白处,选择“添加事件” > “BeginPlay”。
-
从“BeginPlay”事件中拖出一条线,选择“设置变量”(Set Variable)节点。
-
选择“Health”变量。
-
在“Set Variable”节点中,设置“Health”的初始值为100。
-
// BeginPlay事件设置Health变量
Event BeginPlay
Set Health (100)
-
更新和读取变量:
-
在事件图表中右键点击空白处,选择“添加事件” > “输入” > “攻击”(Attack)。
-
从“Attack”事件中拖出一条线,选择“获取变量”(Get Variable)节点。
-
选择“Health”变量。
-
从“Get Variable”节点拖出一条线,选择“整数操作”(Integer Operation)节点。
-
选择“减法”(Subtract)操作。
-
从“Subtract”节点拖出一条线,选择“设置变量”(Set Variable)节点。
-
选择“Health”变量。
-
在“Subtract”节点中,设置减去的值为10。
-
// Attack输入事件减少Health变量
Event Attack
Get Health
Subtract (Health, 10)
Set Health (Result)
函数(Functions)
函数概述
函数是蓝图中用于封装可重用逻辑的节点。通过创建函数,您可以将复杂的逻辑拆分为多个独立的模块,提高代码的可读性和可维护性。
函数的创建和使用
-
创建函数:
-
在蓝图编辑器中,点击“函数”(Functions)标签。
-
点击“+添加函数”(+Add Function)按钮。
-
命名为“TakeDamage”,点击“创建”(Create)按钮。
-
-
编写函数逻辑:
-
在事件图表中右键点击空白处,选择“添加事件” > “自定义事件”(Custom Event)。
-
命名为“TakeDamage”。
-
从“TakeDamage”事件中拖出一条线,选择“获取变量”(Get Variable)节点。
-
选择“Health”变量。
-
从“Get Variable”节点拖出一条线,选择“整数操作”(Integer Operation)节点。
-
选择“减法”(Subtract)操作。
-
从“Subtract”节点拖出一条线,选择“设置变量”(Set Variable)节点。
-
选择“Health”变量。
-
在“Subtract”节点中,设置减去的值为10。
-
// TakeDamage函数逻辑
Event TakeDamage
Get Health
Subtract (Health, 10)
Set Health (Result)
-
调用函数:
-
在事件图表中右键点击空白处,选择“添加事件” > “输入” > “攻击”(Attack)。
-
从“Attack”事件中拖出一条线,选择“调用函数”(Call Function)节点。
-
选择“TakeDamage”函数。
-
// Attack输入事件调用TakeDamage函数
Event Attack
Call Function TakeDamage
蓝图的继承和多态
继承概述
蓝图支持继承,您可以创建一个父蓝图,并在其基础上创建多个子蓝图。子蓝图可以重写或扩展父蓝图的属性和逻辑。
继承的步骤
-
创建父蓝图:
-
在内容浏览器中右键点击空白处,选择“新建” > “蓝图类”。
-
选择“Actor”作为父类。
-
命名为“BaseActor”。
-
-
添加父蓝图的变量和逻辑:
-
在“BaseActor”蓝图中,创建一个变量“Health”。
-
在事件图表中添加“TakeDamage”函数。
-
-
创建子蓝图:
-
在内容浏览器中右键点击空白处,选择“新建” > “蓝图类”。
-
选择“BaseActor”作为父类。
-
命名为“ChildActor”。
-
-
重写或扩展父蓝图的逻辑:
-
在“ChildActor”蓝图中,打开事件图表。
-
右键点击空白处,选择“添加事件” > “调用父类函数”(Call Parent Function)。
-
选择“TakeDamage”函数。
-
从“Call Parent Function”节点拖出一条线,选择“打印字符串”(Print String)节点。
-
在“Print String”节点中输入“Health decreased!”。
-
// ChildActor蓝图中重写TakeDamage函数
Event TakeDamage
Call Parent Function TakeDamage
Print String ("Health decreased!")
蓝图的通信
通信概述
蓝图之间的通信可以通过事件派遣(Event Dispatchers)和接口(Interfaces)来实现。事件派遣可以用于在蓝图之间发送事件,而接口可以用于定义蓝图之间的方法调用。
事件派遣的使用
-
创建事件派遣:
-
在“BaseActor”蓝图中,点击“变量”(Variables)标签。
-
点击“+添加变量”(+Add Variable)按钮。
-
命名为“OnHealthChanged”,类型选择“事件派遣”(Event Dispatcher)。
-
点击“编译”(Compile)按钮。
-
-
在函数中使用事件派遣:
-
在“BaseActor”蓝图的“TakeDamage”函数中,从“Set Health”节点拖出一条线,选择“触发事件派遣”(Trigger Event Dispatcher)节点。
-
选择“OnHealthChanged”事件派遣。
-
// TakeDamage函数中触发OnHealthChanged事件派遣
Event TakeDamage
Get Health
Subtract (Health, 10)
Set Health (Result)
Trigger Event Dispatcher OnHealthChanged
-
在子蓝图中监听事件派遣:
-
在“ChildActor”蓝图中,打开事件图表。
-
右键点击空白处,选择“添加事件” > “事件派遣” > “OnHealthChanged”。
-
从“OnHealthChanged”事件中拖出一条线,选择“打印字符串”(Print String)节点。
-
在“Print String”节点中输入“Health changed to: ”。
-
使用“获取变量”(Get Variable)节点获取“Health”变量,并将其连接到“Print String”节点的“Text”引脚。
-
// ChildActor蓝图中监听OnHealthChanged事件
Event OnHealthChanged
Get Health
Print String ("Health changed to: " + Health.ToString())
接口的使用
-
创建接口:
-
在内容浏览器中右键点击空白处,选择“新建” > “蓝图接口”(Blueprint Interface)。
-
命名为“HealthInterface”。
-
打开“HealthInterface”蓝图,点击“+添加函数”(+Add Function)按钮。
-
命名为“TakeDamage”,点击“创建”(Create)按钮。
-
点击“编译”(Compile)按钮。
-
-
实现接口:
-
在“BaseActor”蓝图中,点击“类设置”(Class Settings)标签。
-
在“接口”(Interfaces)部分,点击“+添加接口”(+Add Interface)按钮。
-
选择“HealthInterface”接口。
-
点击“编译”(Compile)按钮。
-
在事件图表中右键点击空白处,选择“添加事件” > “接口” > “HealthInterface” > “TakeDamage”。
-
编写“TakeDamage”函数的逻辑。
-
// BaseActor蓝图中实现TakeDamage接口
Event TakeDamage
Get Health
Subtract (Health, 10)
Set Health (Result)
Trigger Event Dispatcher OnHealthChanged
-
在其他蓝图中调用接口函数:
-
在内容浏览器中创建一个新的蓝图类,例如“HealthManager”。
-
在“HealthManager”蓝图中,添加一个变量“TargetActor”,类型选择“Actor”。
-
在事件图表中右键点击空白处,选择“添加事件” > “输入” > “减少目标血量”(ReduceTargetHealth)。
-
从“ReduceTargetHealth”事件中拖出一条线,选择“调用接口函数”(Call Interface Function)节点。
-
选择“TargetActor”变量和“HealthInterface”接口。
-
选择“TakeDamage”函数。
-
// HealthManager蓝图中调用TargetActor的TakeDamage接口函数
Event ReduceTargetHealth
Call Interface Function (TargetActor, HealthInterface, TakeDamage)
蓝图的调试
调试概述
蓝图提供了一些调试工具,帮助您在开发过程中查找和修复问题。常见的调试工具包括:
-
打印字符串(Print String):在事件图表中添加“Print String”节点,可以在游戏运行时在屏幕上显示调试信息。
-
断点(Breakpoints):在事件图表中右键点击节点,选择“添加断点”(Add Breakpoint),可以在节点处暂停游戏运行,以便检查变量和逻辑。
-
蓝图调试器(Blueprint Debugger):通过蓝图调试器可以查看蓝图的执行过程和变量值。
调试示例
假设我们在“BaseActor”蓝图中有一个“TakeDamage”函数,我们希望在调用该函数时打印调试信息。
-
添加打印字符串节点:
-
在“BaseActor”蓝图的“TakeDamage”函数中,从“Set Health”节点拖出一条线,选择“打印字符串”(Print String)节点。
-
在“Print String”节点中输入“Health decreased to: ”。
-
使用“获取变量”(Get Variable)节点获取“Health”变量,并将其连接到“Print String”节点的“Text”引脚。
-
// TakeDamage函数中添加打印字符串节点
Event TakeDamage
Get Health
Subtract (Health, 10)
Set Health (Result)
Get Health
Print String ("Health decreased to: " + Health.ToString())
-
添加断点:
-
在“TakeDamage”函数的“Set Health”节点上右键点击,选择“添加断点”(Add Breakpoint)。
-
在游戏运行时,当“TakeDamage”函数被调用时,游戏将在断点处暂停。
-
使用蓝图调试器查看变量值和执行过程。
-
蓝图的性能优化
性能优化概述
虽然蓝图提供了强大的可视化脚本功能,但在大型项目中,不当的使用方式可能会导致性能问题。性能优化是确保游戏运行流畅、响应迅速的关键步骤。以下是一些常见的蓝图性能优化技巧:
优化技巧
-
减少事件图表中的节点数量:
-
尽量将复杂的逻辑拆分为多个函数,避免在事件图表中堆积大量的节点。
-
使用蓝图宏库(Blueprint Macro Library)创建可重用的逻辑块,减少重复代码。
-
-
使用事件派遣和委托:
-
事件派遣(Event Dispatchers)和委托(Delegates)可以减少蓝图之间的直接调用,提高性能。
-
例如,可以在一个蓝图中触发事件派遣,而不是在多个蓝图中直接调用函数。
-
-
优化动画逻辑:
-
动画蓝图(Animation Blueprint)中,尽量使用动画混合(Blend)和动画蒙版(Mask)来减少动画状态机的复杂性。
-
使用动画通知(Anim Notifies)来触发特定的事件,而不是在每一帧中进行检查。
-
-
避免频繁的Tick事件:
-
Tick事件每帧触发,如果处理不当,可能会导致性能下降。
-
尽量在需要时使用事件或函数,而不是依赖频繁的Tick事件。
-
如果必须使用Tick事件,确保在不必要时禁用它,例如通过条件判断来控制。
-
-
使用C++实现关键逻辑:
-
对于性能要求较高的逻辑,可以使用C++来实现,然后在蓝图中调用。
-
C++代码通常比蓝图更高效,尤其是在处理大量数据或复杂计算时。
-
优化示例
假设我们有一个角色蓝图,该角色在每帧中进行复杂的计算来更新其位置和状态。我们可以对以下方面进行优化:
-
减少事件图表中的节点数量:
- 将复杂的逻辑拆分为多个函数,例如“UpdatePosition”和“UpdateState”。
-
使用事件派遣:
- 创建一个事件派遣“OnUpdate”来通知其他蓝图更新。
-
优化动画逻辑:
- 在动画蓝图中使用动画混合和蒙版来减少状态机的复杂性。
-
避免频繁的Tick事件:
- 使用条件判断来控制Tick事件的执行频率。
-
使用C++实现关键逻辑:
- 创建一个C++类来处理角色的位置更新,然后在蓝图中调用该类的方法。
示例:优化角色蓝图
-
创建C++类:
-
在Unreal Engine中创建一个新的C++类,例如“CharacterMovement”。
-
编写一个方法来更新角色的位置和状态。
-
// CharacterMovement.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "CharacterMovement.generated.h"
UCLASS()
class YOURGAME_API ACharacterMovement : public AActor
{
GENERATED_BODY()
public:
ACharacterMovement();
protected:
virtual void BeginPlay() override;
public:
virtual void Tick(float DeltaTime) override;
UFUNCTION()
void UpdatePosition(float DeltaTime);
UFUNCTION()
void UpdateState();
};
// CharacterMovement.cpp
#include "CharacterMovement.h"
ACharacterMovement::ACharacterMovement()
{
PrimaryActorTick.bCanEverTick = true;
}
void ACharacterMovement::BeginPlay()
{
Super::BeginPlay();
}
void ACharacterMovement::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
if (ShouldUpdatePosition())
{
UpdatePosition(DeltaTime);
}
if (ShouldUpdateState())
{
UpdateState();
}
}
void ACharacterMovement::UpdatePosition(float DeltaTime)
{
// 更新角色位置的逻辑
}
void ACharacterMovement::UpdateState()
{
// 更新角色状态的逻辑
}
-
在蓝图中调用C++方法:
-
创建一个角色蓝图,例如“PlayerCharacter”。
-
在角色蓝图中添加一个变量“CharacterMovement”,类型选择“CharacterMovement”。
-
在事件图表中调用“CharacterMovement”的“UpdatePosition”和“UpdateState”方法。
-
// PlayerCharacter蓝图中调用C++方法
Event Tick (DeltaSeconds)
Get CharacterMovement
Call Function UpdatePosition (DeltaSeconds)
Call Function UpdateState
优化效果
通过这些优化技巧,我们可以显著提高角色蓝图的性能。例如,将复杂的计算逻辑移到C++类中,可以减少蓝图的节点数量和执行时间。使用事件派遣和委托可以减少蓝图之间的直接调用,提高代码的可维护性和性能。
总结
蓝图是Unreal Engine中一种强大的可视化脚本系统,使得游戏开发变得更加直观和简单。然而,为了确保游戏的高性能和稳定性,我们需要在开发过程中注意性能优化。通过减少节点数量、使用事件派遣、优化动画逻辑、避免频繁的Tick事件以及使用C++实现关键逻辑,我们可以有效地提高蓝图的性能,为玩家提供更好的游戏体验。
509

被折叠的 条评论
为什么被折叠?



