Unreal Engine开发:Unreal Engine基础入门_蓝图基础

蓝图基础

蓝图概述

什么是蓝图?

蓝图(Blueprint)是Unreal Engine中的一个可视化脚本系统,允许开发者通过拖拽和连接节点来创建游戏逻辑、关卡脚本和自定义行为。蓝图使得非程序员也能轻松地进行游戏开发,同时也为程序员提供了一个快速迭代和调试的工具。蓝图系统基于C++的底层架构,因此可以实现与使用C++相同的功能,但更加直观和易于理解。

蓝图的类型

Unreal Engine中的蓝图主要有以下几种类型:

  1. 蓝图类(Blueprint Class):继承自某个现有的C++类(如Actor、Character等),用于创建自定义的游戏对象。

  2. 关卡蓝图(Level Blueprint):用于控制关卡内的逻辑,如触发事件、控制关卡进度等。

  3. 蓝图接口(Blueprint Interface):定义一组可以被多个蓝图类实现的方法,类似于C++中的接口。

  4. 蓝图宏(Blueprint Macro):用于创建可重用的逻辑片段,类似于C++中的宏定义。

  5. 蓝图函数库(Blueprint Function Library):包含一系列静态函数,可以在任何蓝图中调用。

蓝图的基本概念

  • 节点(Node):蓝图中的基本构建块,每个节点代表一个操作或事件。

  • 引脚(Pin):节点之间的连接点,用于传递数据或控制流。

  • 图表(Graph):蓝图中的逻辑结构,由节点和引脚组成。

  • 事件(Event):触发蓝图执行的起点,如按键事件、定时器事件等。

  • 变量(Variable):存储数据的容器,可以在蓝图中进行读写操作。

  • 函数(Function):封装一组节点,可以在蓝图中调用,类似于C++中的函数。

创建蓝图类

打开蓝图编辑器

  1. 在Unreal Engine编辑器中,点击“内容浏览器”(Content Browser)。

  2. 右键点击内容浏览器中的空白区域,选择“新建蓝图类”(New Blueprint Class)。

  3. 选择一个父类(如Actor、Character等),点击“选择”(Select)。

  4. 输入蓝图类的名称,点击“创建”(Create)。

添加和编辑变量

  1. 打开蓝图编辑器后,点击“变量”(Variables)选项卡。

  2. 点击“添加变量”(Add Variable)按钮,输入变量名称。

  3. 选择变量类型(如布尔值、整数、浮点数、字符串、向量等)。

  4. 设置变量的默认值和访问权限(如公共、私有、保护)。

示例:创建一个带有生命值的蓝图类

假设我们正在开发一个动作游戏,需要创建一个带有生命值的敌人角色。我们可以通过以下步骤来实现:

  1. 创建蓝图类

    • 在内容浏览器中右键点击空白区域,选择“新建蓝图类”。

    • 选择父类为Character,输入名称BP_Enemy,点击“创建”。

  2. 添加生命值变量

    • 打开BP_Enemy蓝图编辑器。

    • 点击“变量”选项卡,点击“添加变量”。

    • 输入变量名称Health,选择类型为Float,设置默认值为100.0,访问权限为公共。

  3. 创建和编辑函数

    • 点击“函数”(Functions)选项卡,点击“添加函数”(Add Function)。

    • 输入函数名称TakeDamage,点击“创建”。

    • TakeDamage函数图表中,添加一个Float类型的输入参数DamageAmount

    • 添加一个Set Health节点,将其与DamageAmount参数连接,使用Subtract节点计算新的生命值。


// TakeDamage 函数图表

EventGraph

{

    // 输入参数

    DamageAmount (Float)



    // 计算新的生命值

    Subtract (Float) (Health, DamageAmount) -> NewHealth



    // 设置新的生命值

    Set Health (NewHealth)

}

添加和编辑事件

  1. 打开事件图表

    • 在蓝图编辑器中,点击“事件图表”(Event Graph)选项卡。
  2. 添加事件

    • 搜索并拖拽事件节点(如Event BeginPlayEvent Tick等)到事件图表中。

    • 连接事件节点和逻辑节点,构建事件处理逻辑。

示例:敌人角色的生命值减少事件

  1. 打开事件图表

    • BP_Enemy蓝图编辑器中,点击“事件图表”选项卡。
  2. 添加Event BeginPlay

    • 搜索并拖拽Event BeginPlay节点到事件图表中。

    • 添加一个Print String节点,输入字符串Enemy Spawned,连接到Event BeginPlay节点。


// Event BeginPlay 事件图表

EventGraph

{

    Event BeginPlay

    {

        Print String (Enemy Spawned)

    }

}

  1. 添加Event Tick

    • 搜索并拖拽Event Tick节点到事件图表中。

    • 添加一个Is Alive节点,检查敌人是否存活。

    • 如果敌人存活,添加一个Take Damage节点,传递一个随机的伤害值。


// Event Tick 事件图表

EventGraph

{

    Event Tick (DeltaSeconds)

    {

        Is Alive (Health > 0)

        {

            Take Damage (Random Float (0, 10))

        }

    }

}

调用函数

  1. 在事件图表中调用函数

    • 搜索并拖拽Call Function节点到事件图表中。

    • 选择要调用的函数(如TakeDamage)。

    • 连接输入参数和输出结果。

示例:在敌人受到攻击时调用TakeDamage函数

  1. 添加Event Hit

    • 搜索并拖拽Event Hit节点到事件图表中。

    • 添加一个Call Function节点,选择TakeDamage函数。

    • 连接DamageAmount输入参数,传递一个常量值(如20.0)。


// Event Hit 事件图表

EventGraph

{

    Event Hit (OtherActor, OtherComponent, NormalImpulse, HitResult)

    {

        Call Function (TakeDamage)

        {

            DamageAmount (20.0)

        }

    }

}

蓝图类的继承

创建子类

  1. 创建新的蓝图类

    • 在内容浏览器中右键点击空白区域,选择“新建蓝图类”。

    • 选择父类为已经创建的蓝图类(如BP_Enemy),输入名称BP_Enemy_2,点击“创建”。

  2. 重写父类函数

    • 打开子类蓝图编辑器。

    • 点击“函数”选项卡,找到要重写的函数(如TakeDamage)。

    • 点击“重写”(Override)按钮,编辑子类中的函数逻辑。

示例:创建一个更强的敌人子类

假设我们需要创建一个更强的敌人子类,它的生命值减少速度更慢。我们可以通过以下步骤来实现:

  1. 创建子类

    • 在内容浏览器中右键点击空白区域,选择“新建蓝图类”。

    • 选择父类为BP_Enemy,输入名称BP_Enemy_2,点击“创建”。

  2. 重写TakeDamage函数

    • 打开BP_Enemy_2蓝图编辑器。

    • 点击“函数”选项卡,找到TakeDamage函数。

    • 点击“重写”按钮,编辑子类中的TakeDamage函数逻辑。

    • 在子类的TakeDamage函数中,使用Divide节点将传递的伤害值减半。


// BP_Enemy_2 中的 TakeDamage 函数图表

EventGraph

{

    // 输入参数

    DamageAmount (Float)



    // 计算新的生命值

    Divide (Float) (DamageAmount, 2) -> ReducedDamage

    Subtract (Float) (Health, ReducedDamage) -> NewHealth



    // 设置新的生命值

    Set Health (NewHealth)

}

蓝图接口

创建蓝图接口

  1. 新建蓝图接口

    • 在内容浏览器中右键点击空白区域,选择“新建蓝图接口”(New Blueprint Interface)。

    • 输入接口名称,点击“创建”。

  2. 添加接口方法

    • 打开蓝图接口编辑器。

    • 点击“添加函数”(Add Function)按钮,输入方法名称。

    • 设置方法的输入参数和返回类型。

示例:创建一个IDamageable接口

假设我们需要一个接口来统一处理所有可以受到伤害的对象。我们可以通过以下步骤来实现:

  1. 新建蓝图接口

    • 在内容浏览器中右键点击空白区域,选择“新建蓝图接口”。

    • 输入接口名称IDamageable,点击“创建”。

  2. 添加接口方法

    • 打开IDamageable蓝图接口编辑器。

    • 点击“添加函数”按钮,输入方法名称TakeDamage

    • 添加一个Float类型的输入参数DamageAmount


// IDamageable 接口

Interface

{

    Function TakeDamage (DamageAmount: Float)

}

实现蓝图接口

  1. 在蓝图类中实现接口

    • 打开需要实现接口的蓝图类编辑器。

    • 点击“类设置”(Class Settings)选项卡。

    • 在“接口”(Interfaces)部分,点击“添加”(Add)按钮,选择要实现的接口(如IDamageable)。

    • 点击“实现”(Implement)按钮,编辑实现逻辑。

示例:在BP_Enemy中实现IDamageable接口

  1. 实现接口

    • 打开BP_Enemy蓝图编辑器。

    • 点击“类设置”选项卡。

    • 在“接口”部分,点击“添加”按钮,选择IDamageable接口。

    • 点击“实现”按钮,编辑TakeDamage函数逻辑。


// BP_Enemy 中实现 TakeDamage 函数

EventGraph

{

    // 输入参数

    DamageAmount (Float)



    // 计算新的生命值

    Subtract (Float) (Health, DamageAmount) -> NewHealth



    // 设置新的生命值

    Set Health (NewHealth)

}

蓝图宏

创建蓝图宏

  1. 新建蓝图宏

    • 在内容浏览器中右键点击空白区域,选择“新建蓝图宏”(New Blueprint Macro)。

    • 输入宏名称,点击“创建”。

  2. 编辑宏逻辑

    • 打开蓝图宏编辑器。

    • 添加输入参数和输出参数。

    • 构建宏的逻辑图表。

示例:创建一个生命值检查宏

假设我们需要一个宏来检查对象的生命值是否低于某个阈值。我们可以通过以下步骤来实现:

  1. 新建蓝图宏

    • 在内容浏览器中右键点击空白区域,选择“新建蓝图宏”。

    • 输入宏名称BP_Macro_CheckHealth,点击“创建”。

  2. 编辑宏逻辑

    • 打开BP_Macro_CheckHealth蓝图宏编辑器。

    • 添加一个Float类型的输入参数Health

    • 添加一个布尔类型的输出参数IsLowHealth

    • 使用Less Than节点检查生命值是否低于50.0。


// BP_Macro_CheckHealth 宏图表

MacroGraph

{

    // 输入参数

    Health (Float)



    // 检查生命值是否低于50.0

    Less Than (Float) (Health, 50.0) -> IsLowHealth



    // 输出参数

    IsLowHealth (Boolean)

}

使用蓝图宏

  1. 在蓝图类中使用宏

    • 打开需要使用宏的蓝图类编辑器。

    • 点击“事件图表”选项卡。

    • 搜索并拖拽宏节点(如BP_Macro_CheckHealth)到事件图表中。

    • 连接输入参数和输出参数,构建使用宏的逻辑。

示例:在BP_Enemy中使用BP_Macro_CheckHealth

  1. 在事件图表中使用宏

    • 打开BP_Enemy蓝图编辑器。

    • 点击“事件图表”选项卡。

    • 搜索并拖拽BP_Macro_CheckHealth宏节点到事件图表中。

    • 连接Health变量作为输入参数。

    • 使用IsLowHealth输出参数来控制敌人是否需要进入防御状态。


// BP_Enemy 中使用 BP_Macro_CheckHealth 宏

EventGraph

{

    // 调用宏

    BP_Macro_CheckHealth (Health) -> IsLowHealth



    // 如果生命值低于50.0,进入防御状态

    If (IsLowHealth)

    {

        Set IsDefending (True)

    }

}

蓝图函数库

创建蓝图函数库

  1. 新建蓝图函数库

    • 在内容浏览器中右键点击空白区域,选择“新建蓝图函数库”(New Blueprint Function Library)。

    • 输入函数库名称,点击“创建”。

  2. 添加函数

    • 打开蓝图函数库编辑器。

    • 点击“添加函数”(Add Function)按钮,输入函数名称。

    • 设置函数的输入参数和返回类型。

    • 构建函数的逻辑图表。

示例:创建一个计算伤害的函数库

假设我们需要一个函数库来计算敌人受到的伤害。我们可以通过以下步骤来实现:

  1. 新建蓝图函数库

    • 在内容浏览器中右键点击空白区域,选择“新建蓝图函数库”。

    • 输入函数库名称BP_FunctionLibrary_Damage,点击“创建”。

  2. 添加计算伤害函数

    • 打开BP_FunctionLibrary_Damage蓝图函数库编辑器。

    • 点击“添加函数”按钮,输入函数名称CalculateDamage

    • 添加一个Float类型的输入参数BaseDamage

    • 添加一个Float类型的输入参数Armor

    • 添加一个Float类型的返回参数FinalDamage

    • 使用Multiply节点和Subtract节点计算最终伤害值。


// BP_FunctionLibrary_Damage 中的 CalculateDamage 函数

FunctionGraph

{

    // 输入参数

    BaseDamage (Float)

    Armor (Float)



    // 计算最终伤害值

    Multiply (Float) (BaseDamage, 0.5) -> HalfDamage

    Subtract (Float) (HalfDamage, Armor) -> FinalDamage



    // 返回最终伤害值

    Return (FinalDamage)

}

在蓝图类中调用函数库

  1. 在蓝图类中调用函数库

    • 打开需要调用函数库的蓝图类编辑器。

    • 点击“事件图表”选项卡。

    • 搜索并拖拽函数库节点(如CalculateDamage)到事件图表中。

    • 连接输入参数和输出参数,构建使用函数库的逻辑。

示例:在BP_Enemy中调用CalculateDamage函数

  1. 在事件图表中调用函数库

    • 打开BP_Enemy蓝图编辑器。

    • 点击“事件图表”选项卡。

    • 搜索并拖拽CalculateDamage函数库节点到事件图表中。

    • 连接BaseDamageArmor变量作为输入参数。

    • 使用FinalDamage输出参数来更新敌人生命值。


// BP_Enemy 中调用 CalculateDamage 函数

EventGraph

{

    // 输入参数

    BaseDamage (Float)

    Armor (Float)



    // 调用函数库

    CalculateDamage (BaseDamage, Armor) -> FinalDamage



    // 更新敌人生命值

    Subtract (Float) (Health, FinalDamage) -> NewHealth

    Set Health (NewHealth)

}

蓝图与C++的交互

在C++中调用蓝图函数

  1. 在C++中声明蓝图可调用函数

    • 在C++类中,使用UFUNCTION宏声明蓝图可调用函数。

    • 使用BlueprintCallable标签来指定函数可以在蓝图中调用。


// Enemy.h

#pragma once



#include "CoreMinimal.h"

#include "GameFramework/Character.h"

#include "Enemy.generated.h"



UCLASS()

class MYGAME_API AEnemy : public ACharacter

{

    GENERATED_BODY()



public:

    // 蓝图可调用函数

    UFUNCTION(BlueprintCallable, Category = "Damage")

    void TakeDamage(float DamageAmount);



private:

    // 生命值变量

    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Health")

    float Health;

};

  1. 在C++中实现蓝图可调用函数

    • 在C++类的CPP文件中,实现声明的蓝图可调用函数。

// Enemy.cpp

#include "Enemy.h"



void AEnemy::TakeDamage(float DamageAmount)

{

    Health -= DamageAmount;

}

在蓝图中调用C++函数

  1. 在蓝图中调用C++函数

    • 打开需要调用C++函数的蓝图类编辑器。

    • 点击“事件图表”选项卡。

    • 搜索并拖拽C++函数节点(如TakeDamage)到事件图表中。

    • 连接输入参数和输出参数,构建使用C++函数的逻辑。

示例:在BP_Enemy中调用C++的TakeDamage函数

  1. 在事件图表中调用C++函数

    • 打开BP_Enemy蓝图编辑器。

    • 点击“事件图表”选项卡。

    • 搜索并拖拽TakeDamageC++函数节点到事件图表中。

    • 连接输入参数和输出参数,构建使用C++函数的逻辑。


// BP_Enemy 中调用 C++ 的 TakeDamage 函数

EventGraph

{

    // 输入参数

    DamageAmount (Float)



    // 调用 C++ 函数

    TakeDamage (DamageAmount)

}

蓝图与C++的变量交互

  1. 在C++中声明蓝图可读写变量

    • 在C++类中,使用UPROPERTY宏声明蓝图可读写变量。

    • 使用VisibleAnywhereBlueprintReadWrite等标签来指定变量的可见性和访问权限。


// Enemy.h

#pragma once



#include "CoreMinimal.h"

#include "GameFramework/Character.h"

#include "Enemy.generated.h"



UCLASS()

class MYGAME_API AEnemy : public ACharacter

{

    GENERATED_BODY()



public:

    // 蓝图可读写变量

    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Health")

    float Health;



    // 蓝图可调用函数

    UFUNCTION(BlueprintCallable, Category = "Damage")

    void TakeDamage(float DamageAmount);



private:

    // 其他私有变量和函数

};

  1. 在蓝图中读写C++变量

    • 打开需要读写C++变量的蓝图类编辑器。

    • 点击“变量”选项卡,可以看到C++类中声明的变量。

    • 使用这些变量进行读写操作。

示例:在BP_Enemy中读写C++的Health变量

  1. 在蓝图中读取和设置C++变量

    • 打开BP_Enemy蓝图编辑器。

    • 点击“变量”选项卡,可以看到Health变量。

    • 在事件图表中,使用Get HealthSet Health节点来读取和设置生命值。


// BP_Enemy 中读取和设置 C++ 的 Health 变量

EventGraph

{

    // 获取当前生命值

    Get Health -> CurrentHealth



    // 打印当前生命值

    Print String (CurrentHealth)



    // 设置新的生命值

    Set Health (NewHealth)

}

蓝图与C++的事件交互

  1. 在C++中声明蓝图可调用事件

    • 在C++类中,使用UFUNCTION宏声明蓝图可调用事件。

    • 使用BlueprintImplementableEvent标签来指定事件可以在蓝图中实现。


// Enemy.h

#pragma once



#include "CoreMinimal.h"

#include "GameFramework/Character.h"

#include "Enemy.generated.h"



UCLASS()

class MYGAME_API AEnemy : public ACharacter

{

    GENERATED_BODY()



public:

    // 蓝图可读写变量

    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Health")

    float Health;



    // 蓝图可调用事件

    UFUNCTION(BlueprintImplementableEvent, Category = "Damage")

    void OnTakeDamage(float DamageAmount);



    // 蓝图可调用函数

    UFUNCTION(BlueprintCallable, Category = "Damage")

    void TakeDamage(float DamageAmount);



private:

    // 其他私有变量和函数

};

  1. 在C++中触发蓝图事件

    • 在C++类的CPP文件中,实现触发蓝图事件的函数。

// Enemy.cpp

#include "Enemy.h"



void AEnemy::TakeDamage(float DamageAmount)

{

    Health -= DamageAmount;

    OnTakeDamage(DamageAmount);

}

  1. 在蓝图中实现C++事件

    • 打开需要实现C++事件的蓝图类编辑器。

    • 点击“事件图表”选项卡。

    • 搜索并拖拽C++事件节点(如OnTakeDamage)到事件图表中。

    • 连接输入参数和输出参数,构建事件处理逻辑。

示例:在BP_Enemy中实现C++的OnTakeDamage事件

  1. 在蓝图中实现C++事件

    • 打开BP_Enemy蓝图编辑器。

    • 点击“事件图表”选项卡。

    • 搜索并拖拽OnTakeDamageC++事件节点到事件图表中。

    • 连接输入参数DamageAmount,添加逻辑节点来处理事件(如播放受伤动画、播放受伤声音等)。


// BP_Enemy 中实现 OnTakeDamage 事件

EventGraph

{

    // 输入参数

    DamageAmount (Float)



    // 播放受伤动画

    Play Animation (InjuredAnimation)



    // 播放受伤声音

    Play Sound (InjuredSound)

}

蓝图与C++的接口交互

  1. 在C++中声明蓝图接口

    • 在C++类中,使用UINTERFACE宏声明蓝图接口。

    • 使用UCLASS宏声明接口的实现类。


// IDamageable.h

#pragma once



#include "CoreMinimal.h"

#include "Engine/EngineTypes.h"

#include "IDamageable.generated.h"



UINTERFACE(MinimalAPI, meta = (CannotImplementInterfaceInBlueprint))

class UDamageableInterface : public UInterface

{

    GENERATED_BODY()

};



class MYGAME_API IDamageableInterface

{

    GENERATED_BODY()



public:

    // 蓝图可调用接口方法

    UFUNCTION(BlueprintCallable, Category = "Damage")

    virtual void TakeDamage(float DamageAmount) = 0;

};

  1. 在C++中调用蓝图接口方法

    • 在C++类中,使用CastExecute方法来调用蓝图接口方法。

// EnemyManager.h

#pragma once



#include "CoreMinimal.h"

#include "GameFramework/Actor.h"

#include "IDamageable.h"

#include "EnemyManager.generated.h"



UCLASS()

class MYGAME_API AEnemyManager : public AActor

{

    GENERATED_BODY()



public:

    // 蓝图可调用函数

    UFUNCTION(BlueprintCallable, Category = "Damage")

    void ApplyDamageToAllEnemies(float DamageAmount);



private:

    // 所有敌人的引用

    TArray<AEnemy*> Enemies;

};



// EnemyManager.cpp

#include "EnemyManager.h"

#include "IDamageable.h"



void AEnemyManager::ApplyDamageToAllEnemies(float DamageAmount)

{

    for (AEnemy* Enemy : Enemies)

    {

        if (IDamageableInterface* DamageableEnemy = Cast<IDamageableInterface>(Enemy))

        {

            DamageableEnemy->TakeDamage(DamageAmount);

        }

    }

}

  1. 在蓝图中实现C++接口

    • 打开需要实现接口的蓝图类编辑器。

    • 点击“类设置”选项卡。

    • 在“接口”部分,点击“添加”按钮,选择要实现的接口(如IDamageable)。

    • 点击“实现”按钮,编辑实现逻辑。

示例:在BP_Enemy中实现C++的IDamageable接口

  1. 实现接口

    • 打开BP_Enemy蓝图编辑器。

    • 点击“类设置”选项卡。

    • 在“接口”部分,点击“添加”按钮,选择IDamageable接口。

    • 点击“实现”按钮,编辑TakeDamage函数逻辑。


// BP_Enemy 中实现 TakeDamage 函数

EventGraph

{

    // 输入参数

    DamageAmount (Float)



    // 计算新的生命值

    Subtract (Float) (Health, DamageAmount) -> NewHealth



    // 设置新的生命值

    Set Health (NewHealth)



    // 播放受伤动画

    Play Animation (InjuredAnimation)



    // 播放受伤声音

    Play Sound (InjuredSound)

}

总结

通过上述内容,我们了解了Unreal Engine中蓝图的基本概念、创建和编辑蓝图类、实现蓝图接口、使用蓝图宏和函数库,以及蓝图与C++的交互。蓝图系统为游戏开发提供了强大的可视化脚本工具,使得开发者可以快速地创建和调试游戏逻辑。同时,通过与C++的交互,蓝图系统可以充分利用底层的性能优势,实现更复杂和高效的游戏功能。

希望这些内容能帮助你更好地理解和使用蓝图系统,从而提高你的游戏开发效率。如果你有任何问题或需要进一步的帮助,请参考Unreal Engine的官方文档或社区资源。
在这里插入图片描述

你可能感兴趣的:(游戏开发2,虚幻,游戏引擎,java,前端,网络)