面向Unity开发者的虚幻引擎4

下面是Unity编辑器和虚幻编辑器的图片,用颜色编码以指示常用功能。每个块都经过标记,以显示等效的UE4术语。虚幻编辑器的布局完全可以通过拖放标签来自定义。

编辑资源

在 Unity 中,“检查器”选项卡用于编辑项目中的选定资源。在UE4中,“细节”面板会显示所选对象的属性,而较大的编辑任务会导致专用窗口或选项卡。将为每个编辑的资产打开新的选项卡式窗口,类似于 Web 浏览器。当然,您可以自由拖动选项卡或将它们作为独立窗口浮动。

快速词汇表

以下部分左侧包含常见的 Unity 术语,右侧包含其 UE4 等效项(或粗略等效项)。UE4关键词直接链接到虚幻引擎在线文档中更深入的信息。

类别

统一

标准箱

游戏类型

元件

元件

游戏对象

演员,典当

预 置

蓝图类

编辑器用户界面

层次结构面板

世界大纲

检查员

详细信息面板

项目浏览器

内容浏览器

场景视图

视窗

网 格

网孔

静态网格体

蒙皮网

骨架网格

材料

着色

材质、材质编辑器

材料

材质实例

影响

粒子效果

效果, 粒子, 级联

手里剑

级 联

游戏界面

用户界面

UMG(虚幻运动图形)

动画

动画

骨骼动画系统

梅卡尼姆

女神异闻录动画蓝图

二 维和

精灵编辑器

纸张2D

编程

C#

C++

脚本

蓝图

物理

光线投射

线描线、形状描线

刚体

碰撞, 物理

运行时平台

iOS 播放器、Web 播放器

平台

项目和文件

那么所有这些目录和文件是什么?

就像Unity项目一样,虚幻项目始终存在于自己的目录中,并拥有自己的项目文件。你可以双击.uproject文件将游戏加载到虚幻编辑器中,或右键单击以获取其他选项。项目文件夹包含各种子文件夹,其中包含游戏的内容和源以及各种配置文件和二进制文件。最重要的是“内容”和“源”子文件夹。

我应该把我的资产放在哪里?

在UE4中,每个项目都有一个内容文件夹。与 Unity 项目的“资源”文件夹类似,这是存储游戏资源的位置。要将资源导入游戏,只需将文件放入项目的内容目录中,它们就会自动导入并显示在内容浏览器中。当您使用外部程序更改文件时,编辑器中的资源将自动更新。

支持哪些常见的文件格式?

Unity 支持多种文件格式。UE4支持最常见的文件类型:

资产类型

支持的格式

二 维和

.fbx, .obj

质地

.png, .jpeg, .bmp ,.tga, .dds, .exr, .psd, .hdr

声音

。.wav

字体

.ttf, .otf

视频

.mov、.mp4.wmv

我的场景是如何存储的?

在 Unity 中,您可以将游戏对象放置在场景中,并将其另存为场景资源文件。虚幻引擎有一个类似于 Unity 场景的地图文件。地图文件存储有关关卡和关卡中对象的数据,以及光照数据和某些关卡特定设置。

如何更改项目的设置?

所有项目设置都可以从主菜单的编辑/项目设置下找到。与 Unity 的项目设置一样,这些设置允许您指定有关项目的信息(例如项目名称和图标)、配置游戏输入绑定以及定义引擎在运行项目时的行为方式。您可以在此处了解有关单个项目设置的更多信息。Unity 还具有所谓的“玩家设置”。在虚幻引擎中,这些是“平台设置”,可以在项目设置的“平台”类别下找到。

我的源文件去哪儿了?

在 Unity 中,您习惯于将 C# 源文件放在资产文件夹中。

UE4的工作方式不同。对于具有C++代码的项目,您将在项目目录下找到一个 Source 子文件夹,其中包含各种文件,包括C++源 (.cpp) 和头文件 (.h) 文件,以及一些构建脚本 (.构建.cs, .目标.cs)但是,仅蓝图项目将没有源文件夹。

在UE4中开始使用C++的最简单方法是使用编辑器将代码添加到项目(在主“文件”菜单中),或者从众多模板之一从头开始创建一个新的C++项目。您可以直接在内容浏览器中找到C++类,也可以通过双击其图标在Visual Studio或Xcode中打开文件。

从游戏对象到演员

我的游戏对象在哪里?

在 Unity 中,游戏对象是可以放置在世界中的“事物”。UE4 等效项是 Actor。在虚幻编辑器中,你可以将新的空Actor从“放置”面板拖到视口中:

您可以使用空Actor构建游戏,但UE4还包括具有内置功能的特殊类型的Actor,例如Pawn(用于玩家或AI对象)或角色(用于动画生物)。就像空Actor一样,你可以放下这些特殊类型的Actor,然后添加或自定义它们的属性和组件。稍后您将了解更多相关信息,但现在请记住,UE4有一个与这些特殊Actor配合使用的游戏框架

UE4中的Actor与Unity中的游戏对象略有不同。在 Unity 中,游戏对象是 C# 类,您无法直接扩展。在UE4中,Actor是一个C++类,你可以使用继承来扩展和自定义它。我们稍后会详细讨论这个问题!

我的组件在哪里?

在 Unity 中,您可以向游戏对象添加组件以赋予其功能。

在UE4中,您可以向Actor添加组件。在关卡中放置一个空Actor后,单击添加组件按钮(在细节面板中),然后选择要添加的组件。在这里,我们创建一个火炬,方法是放下一个空的Actor,然后为底座添加一个网格体组件,然后是一个光源,然后是一个粒子系统来创建它的火焰。

在Unity中,游戏对象包含组件的平面列表,但在UE4中,Actor实际上包含相互连接的组件层次结构。您可以在上面的示例中看到这一点,其中光源和粒子附加到网格体。这在后面的复杂Actor和游戏对象中讨论了一些重要的含义。

从 Unity 预制件到 UE4 蓝图类

Unity 的工作流程基于预制件。在 Unity 中,您可以使用组件构建一组游戏对象,然后从它们创建预制件。然后,您可以将预制件的实例放置在您的世界中,或在运行时实例化它们。

UE4的相应工作流程基于蓝图类。在UE4中,使用组件构建Actor,选择它,然后单击蓝图/添加脚本按钮(在细节面板中)。然后,选择一个位置来保存蓝图类,然后单击创建蓝图以保存新的蓝图类!

可以在内容浏览器中找到新的蓝图类。您可以双击直接编辑它们,也可以将它们拖放到任何级别中。

脚本组件和单体行为在哪里?

在 Unity 中,您可以将脚本组件拖放到游戏对象上以添加 C# 脚本。创建一个继承自 MonoBehavior 的类来定义该组件的作用。

UE4也有类似的东西。您可以创建自己的全新组件类,并将其拖放到任何Actor上。您可以使用蓝图脚本或C++创建组件类。

那么如何在UE4中创建自己的组件类呢?在“详细信息”面板的“添加组件”下拉列表中,可以看到可以创建新组件或选择现有组件:

在 Unity 中,当创建新的 MonoBehavior 时,您将获得一个包含 Start() 函数和 Update() 函数的框架类文件。

在UE4中,你还将获得一个带有InitializeComponent()函数和TickComponent()函数的骨架类,它们执行类似于Start和Update的功能。

如果创建蓝图脚本组件,您将获得与可视化节点相同的功能:

可编写脚本的Actor蓝图类

这是UE4中一个很酷的功能:你的新Actor蓝图类可以有自己的蓝图可视化脚本!这允许您向整个对象添加逻辑,而不仅仅是单个组件。结合继承(如下所述),这在设计游戏时提供了很大的灵活性。

除了支持可视化脚本的蓝图类外,UE4还支持使用代码实现的C++类。 以下是 Unity 和 UE4 代码的并排比较,然后是等效的 UE4 蓝图。

统一 C#

UE4 C++

`

    using UnityEngine;
    using System.Collections;

    public class MyComponent : MonoBehaviour
    {
        int Count;

        // Use this for initialization.
        void Start ()
        {
            Count = 0;
        }

        // Update is called once per frame.
        void Update () 
        {

            Count = Count + 1;
            Debug.Log(Count);
        }
    }`

`

    #pragma once
    #include "GameFramework/Actor.h"
    #include "MyActor.generated.h"

    UCLASS()
    class AMyActor : public AActor
    {
        GENERATED_BODY()
        int Count;

        // Sets default values for this actor's properties.
        AMyActor() 
        {
            // Allows Tick() to be called
            PrimaryActorTick.bCanEverTick = true;  
        }

        // Called when the game starts or when spawned.
        void BeginPlay()
        {
            Super::BeginPlay();
            Count = 0;
        }

        // Called every frame.
        void Tick(float DeltaSeconds)
        {
            Super::Tick(DeltaSeconds);
            Count = Count + 1;
            GLog->Log(FString::FromInt(Count));
        }
    };`

UE4蓝图

UE4蓝图类可以扩展

Unity 预制件和 UE4 蓝图类可以在游戏中类似地实例化。但是,Unity 存在与其他预制件嵌套预制件相关的复杂情况,这限制了它们作为可扩展构建块的作用。

在UE4中,您可以创建一个新的蓝图类,该类扩展了现有的蓝图类,并用新的属性、组件和可视化脚本功能对其进行扩充。

例如,在UE4中,您可以创建一个名为Monster的蓝图类,该类实现了基本的怪物功能,例如追逐人。然后,您可以创建进一步的蓝图类来扩展它,例如龙(一种添加喷火功能的怪物),Grue(一种在天黑时可能会吃掉你的怪物),例如其他 8 个。Monster的这些子类都继承了Monster的基本功能,并在上面添加了新功能。

在 Unity 中,您可以通过创建许多不同的游戏对象预制件来实现这一点:一个用于 Dragon,一个用于 Grue,依此类推。现在,假设您想为所有怪物添加一些新功能,例如使用新的说话组件说话的能力。在 Unity 中,您必须更新所有 10 个预制件,才能将新功能单独复制并粘贴到其中。

在UE4中,你可以简单地修改怪物蓝图类,添加这个新的说话能力。就这样!Dragon、Grue 和 Monster 的其他 8 个子职业会自动继承新的说话功能,您无需触摸它们。

但还有更多!我们在这里所说的关于蓝图类的所有内容也适用于C++类,Actor和组件也是如此。这些系统旨在支持可扩展功能的大规模开发,并且可以扩展到拥有 10 或 100 名开发人员的项目。

使用蓝图脚本、C++或同时使用两者

蓝图可视化脚本非常适合简单的游戏内逻辑流程和动作排序。对于设计师、美术师和面向视觉的程序员来说,这是一个很棒的系统,因为它很容易以视觉方式访问和控制游戏中的对象。您甚至可以仅使用蓝图创建小型独立游戏;有关完整示例,请参阅 Tappy Chicken 示例。

C++编程适用于更大规模的任务,例如构建游戏系统、复杂的 AI 和新的引擎功能。如果您已经有一些C++经验,请查看UE4中的C++编程简介页面。

大多数项目将混合使用蓝图和C++。许多开发者使用蓝图制作游戏功能原型,因为它非常简单有趣,后来为了性能和工程的严谨性,将部分或全部功能转移到C++。

蓝图类可以扩展C++类

UE4游戏开发的魔力很大程度上来自于程序员在C++中实现新功能之间的相互作用,设计师和美术师在蓝图中使用这些功能,然后要求更多!以下是团队如何构建基于 UE4 的射击游戏,同时使用 C++ 类系统编程以及用于行为和外观的蓝图类来实现拾取:

转换组件

在 Unity 中,每个游戏对象都有一个变换组件,该组件为游戏对象提供在世界中的位置、旋转和缩放。

同样,在UE4中,Actor有一个根组件,它可以是场景组件的任何子类。场景组件为Actor提供世界中的位置、旋转和比例,该位置和比例按层次结构应用于其下的所有组件。您将使用的许多组件都是从场景组件子类化的,因为有一个位置真的很有用!

即使您放置了一个空Actor,UE4也会为该Actor创建一个“默认场景根目录”,这只是一个普通的场景组件。如果将新的场景组件放入自己的组件中,它将替换默认场景根目录。

复合对象

在 Unity 中,您可以通过构建游戏对象的层次结构并一起设置其转换的父级来创建复合对象:

在UE4中,您可以通过分层嵌套组件来创建复合游戏对象:

从图中可以看出,可以通过将场景组件相互附加来创建嵌套层次结构,因为它们具有转换 - 类似于 Unity 中的父级转换。Actor 组件(所有组件的基类)只能直接附加到 Actor 本身。

 

我是否从组件中构建所有内容?

这实际上取决于您,但大多数情况下,您将使用自定义组件类型以及使用这些组件的 Actor 类的组合。我们之前提到过这一点,但UE4有许多特殊类型的Actor,它们保证了一定程度的功能,并且始终包含某些组件。例如,角色始终包含字符移动组件

在引擎中,您将很快遇到几种子类Actor类型,并且几乎在每种类型的游戏中都很有用。以下是我们最常见的内置Actor列表:

  • Pawn - 一种代表可控制游戏对象的Actor类型,通常是玩家的头像。棋子由玩家和AI通过拥有的控制器移动。

  • 角色 - Pawn的更专业版本,专为两足动物化身设计,可处理此类游戏对象的许多复杂性。

  • 控制器 - 拥有并控制棋子。通过将Pawn与控制器分离,您可以编写AI控制器,这些控制器可以使用与玩家相同的界面来操作Pawn。

  • 玩家控制器 - 一种更专业的控制器,用于从玩家的游戏手柄、触摸或鼠标/键盘获取输入,并使用该输入来驱动他们拥有的棋子或角色。

那么一切都是演员吗?

不是全部。Actor是UE4中用于游戏玩法的最常见职业,也是唯一可以生成到世界中的类型。所以你放在关卡中的所有东西都将是Actor。

另一个需要了解的重要类型是对象。对象实际上是所有虚幻类的基类,包括Actor和许多其他类。这是一个比Actor低得多的构造,但仍具有你期望从虚幻类中获得的功能,例如反射序列化。对象是一个非常基本的类,当我们需要定义一个不适合Actor模具的新类型时,我们使用。例如,Actor Component是所有组件的基类,派生自Object而不是Actor

UE4中的游戏框架是什么?

好吧,这就是事情变得有点疯狂的地方(以一种很棒的方式)。Unity 为你提供了一个全新的游戏开始设计,虚幻引擎也是如此。在Unity中,你可以用基本的游戏对象和组件构建所有内容,在虚幻引擎中,你可以用Actor和组件构建所有内容。

然而,虚幻引擎在上面有一个额外的层,称为游戏框架。这在 Unity 中根本不存在。你不必在虚幻引擎中使用它,但它实际上非常酷!基本上,如果你使用一些基本的基元类并遵循某些既定的约定,你的游戏将自动获得一些很棒的功能,否则这些功能将很难实现或改造(例如完整的多人游戏支持!

无数精彩的游戏都是在虚幻引擎的游戏框架之上设计的,值得花一些时间来了解它是如何工作的。是的,你可以推出你自己的版本。如果你愿意,那完全没问题!但是,如今已有数百名出色的虚幻开发者在UE4中大量使用了这个框架,因此值得花一些时间学习。

要使用Gameplay框架,你实际上只需要学习虚幻引擎附带的自定义内置Actor类,例如PawnCharacterPlayer Controller,并最终了解虚幻复制和网络功能的工作原理。现在,让我们回到基础。

如何在UE4中编写代码

对于单开发程序员

对于蓝图脚本,你只需要虚幻编辑器——一切都是内置的!要用C++编写代码,请在Windows上下载免费版本的Visual Studio,或在Mac上安装Xcode。当您首次创建新项目(或向现有项目添加代码)时,UE4将自动为您创建Visual Studio项目文件。您可以通过双击内容浏览器中的C++类或单击主“文件”菜单中的“打开Visual Studio”按钮来打开 Visual Studio

UE4的一个重要区别是:有时必须手动刷新Visual Studio项目文件(例如,在下载新版本的UE4之后,或者手动更改磁盘上的源文件位置时)。可以通过单击主菜单中的“刷新 Visual Studio 项目”,或者右键单击项目目录中的 .uproject 文件并选择“生成 Visual Studio 项目文件”来执行此操作

Writing Event Functions (Start, Update, etc.)

If you are used to working with MonoBehaviors you are used to such methods as Start, Update, and OnDestroy. Here is a comparison between a Unity behavior and its counterpart in UE4 Actors and components.

In Unity, we might have a simple component that looks like this:

<span style="color:#000000"><code><span style="color:#153b65"><strong>public</strong></span> <span style="color:#153b65"><strong>class</strong></span> <span style="color:#153b65">MyComponent</span> <span style="color:#000000">:</span> <span style="color:#153b65">MonoBehaviour</span>
<span style="color:#000000">{</span>
    <span style="color:#153b65"><strong>void</strong></span> <span style="color:#153b65">Start</span><span style="color:#000000">()</span> <span style="color:#000000">{}</span>
    <span style="color:#153b65"><strong>void</strong></span> <span style="color:#153b65">OnDestroy</span><span style="color:#000000">()</span> <span style="color:#000000">{}</span>
    <span style="color:#153b65"><strong>void</strong></span> <span style="color:#153b65">Update</span><span style="color:#000000">()</span> <span style="color:#000000">{}</span>
<span style="color:#000000">}</span></code></span>

But remember, in UE4 you can write code right on the Actor itself rather than only coding new component types. This is actually very common and useful.

Similar to Unity's Start, OnDestroy, and Update functions, we have a similar set of methods for Actors in UE4:

C++ :

<span style="color:#000000"><code>UCLASS<span style="color:#000000">()</span>
<span style="color:#153b65"><strong>class</strong></span> <span style="color:#153b65">AMyActor</span> <span style="color:#000000">:</span> <span style="color:#153b65"><strong>public</strong></span> <span style="color:#153b65">AActor</span>
<span style="color:#000000">{</span>
    GENERATED_BODY<span style="color:#000000">()</span>

    <span style="color:#15653a">// Called at start of game.</span>
    <span style="color:#153b65"><strong>void</strong></span> <span style="color:#153b65">BeginPlay</span><span style="color:#000000">();</span>

    <span style="color:#15653a">// Called when destroyed.</span>
    <span style="color:#153b65"><strong>void</strong></span> <span style="color:#153b65">EndPlay</span><span style="color:#000000">(</span><span style="color:#153b65"><strong>const</strong></span> <span style="color:#153b65">EEndPlayReason</span><span style="color:#000000">::</span><span style="color:#153b65">Type</span> <span style="color:#153b65">EndPlayReason</span><span style="color:#000000">);</span>

    <span style="color:#15653a">// Called every frame to update this actor.</span>
    <span style="color:#153b65"><strong>void</strong></span> <span style="color:#153b65">Tick</span><span style="color:#000000">(</span><span style="color:#153b65"><strong>float</strong></span> <span style="color:#153b65">DeltaSeconds</span><span style="color:#000000">);</span>
<span style="color:#000000">};</span></code></span>

Blueprint :

Components in UE4 contain different functions. Here is a simple example:

C++ :

<span style="color:#000000"><code>UCLASS<span style="color:#000000">()</span>
<span style="color:#153b65"><strong>class</strong></span> <span style="color:#153b65">UMyComponent</span> <span style="color:#000000">:</span> <span style="color:#153b65"><strong>public</strong></span> <span style="color:#153b65">UActorComponent</span>
<span style="color:#000000">{</span>
    GENERATED_BODY<span style="color:#000000">()</span>

    <span style="color:#15653a">// Called after the owning Actor was created</span>
    <span style="color:#153b65"><strong>void</strong></span> <span style="color:#153b65">InitializeComponent</span><span style="color:#000000">();</span>

    <span style="color:#15653a">// Called when the component or the owning Actor is being destroyed</span>
    <span style="color:#153b65"><strong>void</strong></span> <span style="color:#153b65">UninitializeComponent</span><span style="color:#000000">();</span>

    <span style="color:#15653a">// Component version of Tick</span>
    <span style="color:#153b65"><strong>void</strong></span> <span style="color:#153b65">TickComponent</span><span style="color:#000000">(</span><span style="color:#153b65"><strong>float</strong></span> <span style="color:#153b65">DeltaTime</span><span style="color:#000000">,</span> <span style="color:#153b65"><strong>enum</strong></span> <span style="color:#153b65">ELevelTick</span> <span style="color:#153b65">TickType</span><span style="color:#000000">,</span> <span style="color:#153b65">FActorComponentTickFunction</span><span style="color:#000000">*</span> <span style="color:#153b65">ThisTickFunction</span><span style="color:#000000">);</span>
<span style="color:#000000">};</span></code></span>

Blueprint :

请记住,在UE4中,调用父类的方法版本非常重要。

例如,在 Unity C# 中,这称为 base。Update(),但在UE4 C++中,我们将使用Super::TickComponent():

<span style="color:#000000"><code><span style="color:#153b65"><strong>void</strong></span> <span style="color:#153b65">UMyComponent</span><span style="color:#000000">::</span><span style="color:#153b65">TickComponent</span><span style="color:#000000">(</span><span style="color:#153b65"><strong>float</strong></span> <span style="color:#153b65">DeltaTime</span><span style="color:#000000">,</span> <span style="color:#153b65"><strong>enum</strong></span> <span style="color:#153b65">ELevelTick</span> <span style="color:#153b65">TickType</span><span style="color:#000000">,</span> <span style="color:#153b65">FActorComponentTickFunction</span><span style="color:#000000">*</span> <span style="color:#153b65">ThisTickFunction</span><span style="color:#000000">)</span>
<span style="color:#000000">{</span>
    <span style="color:#15653a">// Custom tick stuff here</span>
    <span style="color:#153b65">Super</span><span style="color:#000000">::</span><span style="color:#153b65">TickComponent</span><span style="color:#000000">(</span><span style="color:#153b65">DeltaTime</span><span style="color:#000000">,</span> <span style="color:#153b65">TickType</span><span style="color:#000000">,</span> <span style="color:#153b65">ThisTickFunction</span><span style="color:#000000">);</span>
<span style="color:#000000">}</span></code></span>

您可能已经注意到,有些内容以“A”开头,而其他内容则以C++中的“U”开头。前缀“A”表示Actor子类,而前缀“U”表示对象子类。还有一些其他前缀,例如“F”用于大多数纯数据结构或非UObject类。

在UE4中编写游戏代码

好吧,从现在开始,事情会变得更深一些。我们将讨论对创建游戏至关重要的编程主题。因为您了解Unity,所以我们将针对学习虚幻C++的C#用户来解释功能,但如果需要,您可以将蓝图脚本用于几乎所有内容!我们尽可能在C++和蓝图中添加了示例。

让我们谈谈一些最常见的游戏编程模式,以及如何在虚幻引擎中处理它们。Unity 中的许多功能在虚幻引擎中都有类似的功能,看起来应该很熟悉。我们将一一介绍最常见的功能。

实例化游戏对象/生成Actor(生成角色)

在 Unity 中,我们使用实例化函数来创建对象的新实例。

此函数采用任何 UnityEngine.Object 类型(GameObject、MonoBehavior 等),并复制它。

<span style="color:#000000"><code><span style="color:#153b65"><strong>public</strong></span> <span style="color:#153b65">GameObject</span> <span style="color:#153b65">EnemyPrefab</span><span style="color:#000000">;</span>
<span style="color:#153b65"><strong>public</strong></span> <span style="color:#153b65">Vector3</span> <span style="color:#153b65">SpawnPosition</span><span style="color:#000000">;</span>
<span style="color:#153b65"><strong>public</strong></span> <span style="color:#153b65">Quaternion</span> <span style="color:#153b65">SpawnRotation</span><span style="color:#000000">;</span>

<span style="color:#153b65"><strong>void</strong></span> <span style="color:#153b65">Start</span><span style="color:#000000">()</span>
<span style="color:#000000">{</span>
    <span style="color:#153b65">GameObject</span> <span style="color:#153b65">NewGO</span> <span style="color:#000000">=</span> <span style="color:#000000">(</span><span style="color:#153b65">GameObject</span><span style="color:#000000">)</span><span style="color:#153b65">Instantiate</span><span style="color:#000000">(</span><span style="color:#153b65">EnemyPrefab</span><span style="color:#000000">,</span> <span style="color:#153b65">SpawnPosition</span><span style="color:#000000">,</span> <span style="color:#153b65">SpawnRotation</span><span style="color:#000000">);</span>
    <span style="color:#153b65">NewGO</span><span style="color:#000000">.</span>name <span style="color:#000000">=</span> <span style="color:#721d3b">"MyNewGameObject"</span><span style="color:#000000">;</span>
<span style="color:#000000">}</span></code></span>

在UE4中,有几个不同的函数可以实例化对象,具体取决于您的需求。NewObject 用于创建新的 UObject 类型,SpawnActor 用于生成 AActor 类型。

首先,我们将简要讨论UObjects和NewObject。在虚幻引擎中子类化UObject很像在Unity中子类化ScriptableObject。它们对于不需要生成到世界中或像Actor那样附加组件的游戏类很有用。

在 Unity 中,如果您创建了自己的 ScriptableObject 子类,则可以像这样实例化它:

<span style="color:#000000"><code><span style="color:#153b65">MyScriptableObject</span> <span style="color:#153b65">NewSO</span> <span style="color:#000000">=</span> <span style="color:#153b65">ScriptableObject</span><span style="color:#000000">.</span><span style="color:#153b65">CreateInstance</span><span style="color:#000000"><</span><span style="color:#153b65">MyScriptableObject</span><span style="color:#000000">>();</span></code></span>

在虚幻引擎中,如果你创建了自己的UObject派生类型,你可以像这样实例化它:

<span style="color:#000000"><code><span style="color:#153b65">UMyObject</span><span style="color:#000000">*</span> <span style="color:#153b65">NewObj</span> <span style="color:#000000">=</span> <span style="color:#153b65">NewObject</span><span style="color:#000000"><</span><span style="color:#153b65">UMyObject</span><span style="color:#000000">>();</span></code></span>

那么演员呢?Actor是使用SpawnActor方法在World(C++中的UWorld)对象上生成的。你如何获得世界对象?一些 UObjects 为你提供了一个 GetWorld 方法,例如,所有 Actor 都这样做。

你会注意到,我们不是传入另一个Actor,而是传入我们想要生成的Actor的“类”。在我们的示例中,类可以是 AMyEnemy 的任何子类。

但是,如果你想制作另一个对象的“副本”,就像 Instance iate 允许你做的事情一样,该怎么办?

NewObject 和 SpawnActor 函数也可以被赋予一个“模板”对象来使用。虚幻引擎将复制该对象,而不是“从头开始”制作。这将复制其所有 UPROPERTY 和组件。

<span style="color:#000000"><code><span style="color:#153b65">AMyActor</span><span style="color:#000000">*</span> <span style="color:#153b65">CreateCloneOfMyActor</span><span style="color:#000000">(</span><span style="color:#153b65">AMyActor</span><span style="color:#000000">*</span> <span style="color:#153b65">ExistingActor</span><span style="color:#000000">,</span> <span style="color:#153b65">FVector</span> <span style="color:#153b65">SpawnLocation</span><span style="color:#000000">,</span> <span style="color:#153b65">FRotator</span> <span style="color:#153b65">SpawnRotation</span><span style="color:#000000">)</span>
<span style="color:#000000">{</span>
    <span style="color:#153b65">UWorld</span><span style="color:#000000">*</span> <span style="color:#153b65">World</span> <span style="color:#000000">=</span> <span style="color:#153b65">ExistingActor</span><span style="color:#000000">-></span><span style="color:#153b65">GetWorld</span><span style="color:#000000">();</span>
    <span style="color:#153b65">FActorSpawnParameters</span> <span style="color:#153b65">SpawnParams</span><span style="color:#000000">;</span>
    <span style="color:#153b65">SpawnParams</span><span style="color:#000000">.</span><span style="color:#153b65">Template</span> <span style="color:#000000">=</span> <span style="color:#153b65">ExistingActor</span><span style="color:#000000">;</span>
    <span style="color:#153b65">World</span><span style="color:#000000">-></span><span style="color:#153b65">SpawnActor</span><span style="color:#000000"><</span><span style="color:#153b65">AMyActor</span><span style="color:#000000">>(</span><span style="color:#153b65">ExistingActor</span><span style="color:#000000">-></span><span style="color:#153b65">GetClass</span><span style="color:#000000">(),</span> <span style="color:#153b65">SpawnLocation</span><span style="color:#000000">,</span> <span style="color:#153b65">SpawnRotation</span><span style="color:#000000">,</span> <span style="color:#153b65">SpawnParams</span><span style="color:#000000">);</span>
<span style="color:#000000">}</span></code></span>

您可能想知道在这种情况下“从头开始”是什么意思。您创建的每个对象类都有一个默认模板,其中包含其属性和组件的默认值。如果你不覆盖这些属性,也不提供自己的模板,虚幻将使用这些默认值来构造你的对象。为了帮助说明这一点,让我们首先看一个 MonoBehavior,例如:

<span style="color:#000000"><code><span style="color:#153b65"><strong>public</strong></span> <span style="color:#153b65"><strong>class</strong></span> <span style="color:#153b65">MyComponent</span> <span style="color:#000000">:</span> <span style="color:#153b65">MonoBehaviour</span>
<span style="color:#000000">{</span>
    <span style="color:#153b65"><strong>public</strong></span> <span style="color:#153b65"><strong>int</strong></span> <span style="color:#153b65">MyIntProp</span> <span style="color:#000000">=</span> <span style="color:#153b65">42</span><span style="color:#000000">;</span>
    <span style="color:#153b65"><strong>public</strong></span> <span style="color:#153b65">SphereCollider</span> <span style="color:#153b65">MyCollisionComp</span> <span style="color:#000000">=</span> <span style="color:#153b65"><strong>null</strong></span><span style="color:#000000">;</span>

    <span style="color:#153b65"><strong>void</strong></span> <span style="color:#153b65">Start</span><span style="color:#000000">()</span>
    <span style="color:#000000">{</span>
        <span style="color:#15653a">// Create the collision component if we don't already have one</span>
        <span style="color:#153b65"><strong>if</strong></span> <span style="color:#000000">(</span><span style="color:#153b65">MyCollisionComp</span> <span style="color:#000000">==</span> <span style="color:#153b65"><strong>null</strong></span><span style="color:#000000">)</span>
        <span style="color:#000000">{</span>
            <span style="color:#153b65">MyCollisionComp</span> <span style="color:#000000">=</span> gameObject<span style="color:#000000">.</span><span style="color:#153b65">AddComponent</span><span style="color:#000000"><</span><span style="color:#153b65">SphereCollider</span><span style="color:#000000">>();</span>
            <span style="color:#153b65">MyCollisionComp</span><span style="color:#000000">.</span>center <span style="color:#000000">=</span> <span style="color:#153b65">Vector3</span><span style="color:#000000">.</span>zero<span style="color:#000000">;</span>
            <span style="color:#153b65">MyCollisionComp</span><span style="color:#000000">.</span>radius <span style="color:#000000">=</span> <span style="color:#153b65">20.0f</span><span style="color:#000000">;</span>
        <span style="color:#000000">}</span>
    <span style="color:#000000">}</span>
<span style="color:#000000">}</span></code></span>

在上面的例子中,我们有一个默认为 42 的 int 属性和一个默认半径为 20 的 SphereCollider 组件。

我们可以在虚幻引擎中使用对象的构造函数实现同样的事情。

<span style="color:#000000"><code>UCLASS<span style="color:#000000">()</span>
<span style="color:#153b65"><strong>class</strong></span> <span style="color:#153b65">AMyActor</span> <span style="color:#000000">:</span> <span style="color:#153b65"><strong>public</strong></span> <span style="color:#153b65">AActor</span>
<span style="color:#000000">{</span>
    GENERATED_BODY<span style="color:#000000">()</span>

    UPROPERTY<span style="color:#000000">()</span>
    int32 <span style="color:#153b65">MyIntProp</span><span style="color:#000000">;</span>

    UPROPERTY<span style="color:#000000">()</span>
    <span style="color:#153b65">USphereComponent</span><span style="color:#000000">*</span> <span style="color:#153b65">MyCollisionComp</span><span style="color:#000000">;</span>

    <span style="color:#153b65">AMyActor</span><span style="color:#000000">()</span>
    <span style="color:#000000">{</span>
        <span style="color:#153b65">MyIntProp</span> <span style="color:#000000">=</span> <span style="color:#153b65">42</span><span style="color:#000000">;</span>

        <span style="color:#153b65">MyCollisionComp</span> <span style="color:#000000">=</span> <span style="color:#153b65">CreateDefaultSubobject</span><span style="color:#000000"><</span><span style="color:#153b65">USphereComponent</span><span style="color:#000000">>(</span><span style="color:#153b65">FName</span><span style="color:#000000">(</span>TEXT<span style="color:#000000">(</span><span style="color:#721d3b">"CollisionComponent"</span><span style="color:#000000">));</span>
        <span style="color:#153b65">MyCollisionComp</span><span style="color:#000000">-></span><span style="color:#153b65">RelativeLocation</span> <span style="color:#000000">=</span> <span style="color:#153b65">FVector</span><span style="color:#000000">::</span><span style="color:#153b65">ZeroVector</span><span style="color:#000000">;</span>
        <span style="color:#153b65">MyCollisionComp</span><span style="color:#000000">-></span><span style="color:#153b65">SphereRadius</span> <span style="color:#000000">=</span> <span style="color:#153b65">20.0f</span><span style="color:#000000">;</span>
    <span style="color:#000000">}</span>
<span style="color:#000000">};</span></code></span>

在 AMyActor 的构造函数中,我们为类设置了默认属性值。请注意 CreateDefaultSubobject 函数的使用。我们可以使用它来创建组件并为它们分配默认属性。我们使用此函数创建的所有子对象都充当默认模板,因此我们可以在子类或蓝图中修改它们。

从一种类型转换为另一种类型

在这种情况下,我们得到一个我们知道我们拥有的组件,然后将其转换为特定类型并有条件地执行某些操作。

Unity C#:

<span style="color:#000000"><code><span style="color:#153b65">Collider</span> collider <span style="color:#000000">=</span> gameObject<span style="color:#000000">.</span><span style="color:#153b65">GetComponent</span><span style="color:#000000"><</span><span style="color:#153b65">Collider</span><span style="color:#000000">>;</span>
<span style="color:#153b65">SphereCollider</span> sphereCollider <span style="color:#000000">=</span> collider <span style="color:#153b65"><strong>as</strong></span> <span style="color:#153b65">SphereCollider</span><span style="color:#000000">;</span>
<span style="color:#153b65"><strong>if</strong></span> <span style="color:#000000">(</span>sphereCollider <span style="color:#000000">!=</span> <span style="color:#153b65"><strong>null</strong></span><span style="color:#000000">)</span>
<span style="color:#000000">{</span>
        <span style="color:#15653a">// ...</span>
<span style="color:#000000">}</span></code></span>

UE4 C++:

<span style="color:#000000"><code><span style="color:#153b65">UPrimitiveComponent</span><span style="color:#000000">*</span> <span style="color:#153b65">Primitive</span> <span style="color:#000000">=</span> <span style="color:#153b65">MyActor</span><span style="color:#000000">-></span><span style="color:#153b65">GetComponentByClass</span><span style="color:#000000">(</span><span style="color:#153b65">UPrimitiveComponent</span><span style="color:#000000">::</span><span style="color:#153b65">StaticClass</span><span style="color:#000000">());</span>
<span style="color:#153b65">USphereComponent</span><span style="color:#000000">*</span> <span style="color:#153b65">SphereCollider</span> <span style="color:#000000">=</span> <span style="color:#153b65">Cast</span><span style="color:#000000"><</span><span style="color:#153b65">USphereComponent</span><span style="color:#000000">>(</span><span style="color:#153b65">Primitive</span><span style="color:#000000">);</span>
<span style="color:#153b65"><strong>if</strong></span> <span style="color:#000000">(</span><span style="color:#153b65">SphereCollider</span> <span style="color:#000000">!=</span> <span style="color:#153b65"><strong>nullptr</strong></span><span style="color:#000000">)</span>
<span style="color:#000000">{</span>
        <span style="color:#15653a">// ...</span>
<span style="color:#000000">}</span></code></span>

销毁游戏对象/演员

统一

C++

蓝图

销毁(我的游戏对象);

MyActor->Destroy();

销毁游戏对象/演员(延迟 1 秒)

统一

C++

蓝图

销毁(MyGameObject, 1);

MyActor->SetLifeSpan(1);

单击查看完整视图。

禁用游戏对象/角色

统一

C++

蓝图

MyGameObject.SetActive(false);

隐藏可见组件

<span style="color:#000000"><span style="background-color:#ffffff"><code>    <span style="color:#153b65">MyActor</span><span style="color:#000000">-></span><span style="color:#153b65">SetActorHiddenInGame</span><span style="color:#000000">(</span><span style="color:#153b65"><strong>true</strong></span><span style="color:#000000">);</span>

    <span style="color:#15653a">// Disables collision components</span>
    <span style="color:#153b65">MyActor</span><span style="color:#000000">-></span><span style="color:#153b65">SetActorEnableCollision</span><span style="color:#000000">(</span><span style="color:#153b65"><strong>false</strong></span><span style="color:#000000">);</span>

    <span style="color:#15653a">// Stops the Actor from ticking</span>
    <span style="color:#153b65">MyActor</span><span style="color:#000000">-></span><span style="color:#153b65">SetActorTickEnabled</span><span style="color:#000000">(</span><span style="color:#153b65"><strong>false</strong></span><span style="color:#000000">);</span></code></span></span>

单击查看完整视图。

从组件访问游戏对象/Actor(角色)

统一

C++

蓝图

游戏对象父GO =

<span style="color:#000000"><span style="background-color:#ffffff"><code>    <span style="color:#153b65">MyComponent</span><span style="color:#000000">.</span>gameObject<span style="color:#000000">;</span></code></span></span>

AActor* 父演员 =

<span style="color:#000000"><span style="background-color:#ffffff"><code>     <span style="color:#153b65">MyComponent</span><span style="color:#000000">-></span><span style="color:#153b65">GetOwner</span><span style="color:#000000">();</span></code></span></span>

单击查看完整视图。

从游戏对象/Actor访问组件

统一

<span style="color:#000000"><code><span style="color:#153b65">MyComponent</span> <span style="color:#153b65">MyComp</span> <span style="color:#000000">=</span> gameObject<span style="color:#000000">.</span><span style="color:#153b65">GetComponent</span><span style="color:#000000"><</span><span style="color:#153b65">MyComponent</span><span style="color:#000000">>();</span></code></span>

C++

<span style="color:#000000"><code><span style="color:#153b65">UMyComponent</span><span style="color:#000000">*</span> <span style="color:#153b65">MyComp</span> <span style="color:#000000">=</span> <span style="color:#153b65">MyActor</span><span style="color:#000000">-></span><span style="color:#153b65">FindComponentByClass</span><span style="color:#000000"><</span><span style="color:#153b65">UMyComponent</span><span style="color:#000000">>();</span></code></span>

蓝图

查找游戏对象/角色

<span style="color:#000000"><code><span style="color:#15653a">// Find GameObject by name</span>
<span style="color:#153b65">GameObject</span> <span style="color:#153b65">MyGO</span> <span style="color:#000000">=</span> <span style="color:#153b65">GameObject</span><span style="color:#000000">.</span><span style="color:#153b65">Find</span><span style="color:#000000">(</span><span style="color:#721d3b">"MyNamedGameObject"</span><span style="color:#000000">);</span>

<span style="color:#15653a">// Find Objects by type</span>
<span style="color:#153b65">MyComponent</span><span style="color:#000000">[]</span> <span style="color:#153b65">Components</span> <span style="color:#000000">=</span> <span style="color:#153b65">Object</span><span style="color:#000000">.</span><span style="color:#153b65">FindObjectsOfType</span><span style="color:#000000">(</span><span style="color:#153b65"><strong>typeof</strong></span><span style="color:#000000">(</span><span style="color:#153b65">MyComponent</span><span style="color:#000000">))</span> <span style="color:#153b65"><strong>as</strong></span> <span style="color:#153b65">MyComponent</span><span style="color:#000000">[];</span>
<span style="color:#153b65"><strong>foreach</strong></span> <span style="color:#000000">(</span><span style="color:#153b65">MyComponent</span> <span style="color:#153b65">Component</span> <span style="color:#153b65"><strong>in</strong></span> <span style="color:#153b65">Components</span><span style="color:#000000">)</span>
<span style="color:#000000">{</span>
        <span style="color:#15653a">// ...</span>
<span style="color:#000000">}</span>

<span style="color:#15653a">// Find GameObjects by tag</span>
<span style="color:#153b65">GameObject</span><span style="color:#000000">[]</span> <span style="color:#153b65">GameObjects</span> <span style="color:#000000">=</span> <span style="color:#153b65">GameObject</span><span style="color:#000000">.</span><span style="color:#153b65">FindGameObjectsWithTag</span><span style="color:#000000">(</span><span style="color:#721d3b">"MyTag"</span><span style="color:#000000">);</span>
<span style="color:#153b65"><strong>foreach</strong></span> <span style="color:#000000">(</span><span style="color:#153b65">GameObject</span> GO <span style="color:#153b65"><strong>in</strong></span> <span style="color:#153b65">GameObjects</span><span style="color:#000000">)</span>
<span style="color:#000000">{</span>
        <span style="color:#15653a">// ...</span>
<span style="color:#000000">}</span>

<span style="color:#15653a">// Find Actor by name (also works on UObjects)</span>
<span style="color:#153b65">AActor</span><span style="color:#000000">*</span> <span style="color:#153b65">MyActor</span> <span style="color:#000000">=</span> <span style="color:#153b65">FindObject</span><span style="color:#000000"><</span><span style="color:#153b65">AActor</span><span style="color:#000000">>(</span><span style="color:#153b65"><strong>nullptr</strong></span><span style="color:#000000">,</span> TEXT<span style="color:#000000">(</span><span style="color:#721d3b">"MyNamedActor"</span><span style="color:#000000">));</span>

<span style="color:#15653a">// Find Actors by type (needs a UWorld object)</span>
<span style="color:#153b65"><strong>for</strong></span> <span style="color:#000000">(</span><span style="color:#153b65">TActorIterator</span><span style="color:#000000"><</span><span style="color:#153b65">AMyActor</span><span style="color:#000000">></span> <span style="color:#153b65">It</span><span style="color:#000000">(</span><span style="color:#153b65">GetWorld</span><span style="color:#000000">());</span> <span style="color:#153b65">It</span><span style="color:#000000">;</span> <span style="color:#000000">++</span><span style="color:#153b65">It</span><span style="color:#000000">)</span>
<span style="color:#000000">{</span>
        <span style="color:#153b65">AMyActor</span><span style="color:#000000">*</span> <span style="color:#153b65">MyActor</span> <span style="color:#000000">=</span> <span style="color:#000000">*</span><span style="color:#153b65">It</span><span style="color:#000000">;</span>
        <span style="color:#15653a">// ...</span>
<span style="color:#000000">}</span></code></span>

<span style="color:#000000"><code><span style="color:#15653a">// Find UObjects by type</span>
<span style="color:#153b65"><strong>for</strong></span> <span style="color:#000000">(</span><span style="color:#153b65">TObjectIterator</span><span style="color:#000000"><</span><span style="color:#153b65">UMyObject</span><span style="color:#000000">></span> <span style="color:#153b65">It</span><span style="color:#000000">;</span> <span style="color:#153b65">It</span><span style="color:#000000">;</span> <span style="color:#000000">++</span>it<span style="color:#000000">)</span>
<span style="color:#000000">{</span>
    <span style="color:#153b65">UMyObject</span><span style="color:#000000">*</span> <span style="color:#153b65">MyObject</span> <span style="color:#000000">=</span> <span style="color:#000000">*</span><span style="color:#153b65">It</span><span style="color:#000000">;</span>
    <span style="color:#15653a">// ...</span>
<span style="color:#000000">}</span>

<span style="color:#15653a">// Find Actors by tag (also works on ActorComponents, use TObjectIterator instead)</span>
<span style="color:#153b65"><strong>for</strong></span> <span style="color:#000000">(</span><span style="color:#153b65">TActorIterator</span><span style="color:#000000"><</span><span style="color:#153b65">AActor</span><span style="color:#000000">></span> <span style="color:#153b65">It</span><span style="color:#000000">(</span><span style="color:#153b65">GetWorld</span><span style="color:#000000">());</span> <span style="color:#153b65">It</span><span style="color:#000000">;</span> <span style="color:#000000">++</span><span style="color:#153b65">It</span><span style="color:#000000">)</span>
<span style="color:#000000">{</span>
    <span style="color:#153b65">AActor</span><span style="color:#000000">*</span> <span style="color:#153b65">Actor</span> <span style="color:#000000">=</span> <span style="color:#000000">*</span><span style="color:#153b65">It</span><span style="color:#000000">;</span>
    <span style="color:#153b65"><strong>if</strong></span> <span style="color:#000000">(</span><span style="color:#153b65">Actor</span><span style="color:#000000">-></span><span style="color:#153b65">ActorHasTag</span><span style="color:#000000">(</span><span style="color:#153b65">FName</span><span style="color:#000000">(</span>TEXT<span style="color:#000000">(</span><span style="color:#721d3b">"Mytag"</span><span style="color:#000000">))))</span>
    <span style="color:#000000">{</span>
        <span style="color:#15653a">// ...</span>
    <span style="color:#000000">}</span>
<span style="color:#000000">}</span></code></span>

向游戏对象/演员添加标签

<span style="color:#000000"><code><span style="color:#153b65">MyGameObject</span><span style="color:#000000">.</span>tag <span style="color:#000000">=</span> <span style="color:#721d3b">"MyTag"</span><span style="color:#000000">;</span>

<span style="color:#15653a">// Actors can have multiple tags</span>
<span style="color:#153b65">MyActor</span><span style="color:#000000">.</span><span style="color:#153b65">Tags</span><span style="color:#000000">.</span><span style="color:#153b65">AddUnique</span><span style="color:#000000">(</span>TEXT<span style="color:#000000">(</span><span style="color:#721d3b">"MyTag"</span><span style="color:#000000">));</span></code></span>

为单体行为/角色组件添加标签

<span style="color:#000000"><code><span style="color:#15653a">// This changes the tag on the GameObject it is attached to</span>
<span style="color:#153b65">MyComponent</span><span style="color:#000000">.</span>tag <span style="color:#000000">=</span> <span style="color:#721d3b">"MyTag"</span><span style="color:#000000">;</span>

<span style="color:#15653a">// Components have their own array of tags</span>
<span style="color:#153b65">MyComponent</span><span style="color:#000000">.</span><span style="color:#153b65">ComponentTags</span><span style="color:#000000">.</span><span style="color:#153b65">AddUnique</span><span style="color:#000000">(</span>TEXT<span style="color:#000000">(</span><span style="color:#721d3b">"MyTag"</span><span style="color:#000000">));</span></code></span>

比较游戏对象/角色和单一行为/参与者组件上的标签

<span style="color:#000000"><code><span style="color:#153b65"><strong>if</strong></span> <span style="color:#000000">(</span><span style="color:#153b65">MyGameObject</span><span style="color:#000000">.</span><span style="color:#153b65">CompareTag</span><span style="color:#000000">(</span><span style="color:#721d3b">"MyTag"</span><span style="color:#000000">))</span>
<span style="color:#000000">{</span>
    <span style="color:#15653a">// ...</span>
<span style="color:#000000">}</span>

<span style="color:#15653a">// Checks the tag on the GameObject it is attached to</span>
<span style="color:#153b65"><strong>if</strong></span> <span style="color:#000000">(</span><span style="color:#153b65">MyComponent</span><span style="color:#000000">.</span><span style="color:#153b65">CompareTag</span><span style="color:#000000">(</span><span style="color:#721d3b">"MyTag"</span><span style="color:#000000">))</span>
<span style="color:#000000">{</span>
    <span style="color:#15653a">// ...</span>
<span style="color:#000000">}</span>

<span style="color:#15653a">// Checks if an Actor has this tag</span>
<span style="color:#153b65"><strong>if</strong></span> <span style="color:#000000">(</span><span style="color:#153b65">MyActor</span><span style="color:#000000">-></span><span style="color:#153b65">ActorHasTag</span><span style="color:#000000">(</span><span style="color:#153b65">FName</span><span style="color:#000000">(</span>TEXT<span style="color:#000000">(</span><span style="color:#721d3b">"MyTag"</span><span style="color:#000000">))))</span>
<span style="color:#000000">{</span>
    <span style="color:#15653a">// ...</span>
<span style="color:#000000">}</span></code></span>

<span style="color:#000000"><code><span style="color:#15653a">// Checks if an ActorComponent has this tag</span>
<span style="color:#153b65"><strong>if</strong></span> <span style="color:#000000">(</span><span style="color:#153b65">MyComponent</span><span style="color:#000000">-></span><span style="color:#153b65">ComponentHasTag</span><span style="color:#000000">(</span><span style="color:#153b65">FName</span><span style="color:#000000">(</span>TEXT<span style="color:#000000">(</span><span style="color:#721d3b">"MyTag"</span><span style="color:#000000">))))</span>
<span style="color:#000000">{</span>
    <span style="color:#15653a">// ...</span>
<span style="color:#000000">}</span></code></span>

物理:刚体与原始组件

在 Unity 中,要赋予任何游戏对象物理特性,请先为其指定一个刚体组件。在虚幻中,任何原始组件(C++中的UPrimitiveComponent)都可以是物理对象。一些常见的基元组件是形状组件(胶囊体、球体、盒子)、静态网格组件和骨架网格组件。

与 Unity 不同,Unity 将碰撞和可视化的职责分离到单独的组件中。虚幻引擎将潜在物理和潜在可见的概念结合到PrimitiveComponent中。在世界上具有任何几何体的任何组件,可以渲染或与 PrimitiveComponent 中的物理子类交互。

层与通道

在 Unity 中,它们被称为“层”。UE4使用碰撞通道,它们的工作方式类似。你可以在这里阅读它们。

RayCast vs RayTrace

Unity C#:

<span style="color:#000000"><code><span style="color:#153b65">GameObject</span> <span style="color:#153b65">FindGOCameraIsLookingAt</span><span style="color:#000000">()</span>
<span style="color:#000000">{</span>
    <span style="color:#153b65">Vector3</span> <span style="color:#153b65">Start</span> <span style="color:#000000">=</span> <span style="color:#153b65">Camera</span><span style="color:#000000">.</span>main<span style="color:#000000">.</span>transform<span style="color:#000000">.</span>position<span style="color:#000000">;</span>
    <span style="color:#153b65">Vector3</span> <span style="color:#153b65">Direction</span> <span style="color:#000000">=</span> <span style="color:#153b65">Camera</span><span style="color:#000000">.</span>main<span style="color:#000000">.</span>transform<span style="color:#000000">.</span>forward<span style="color:#000000">;</span>
    <span style="color:#153b65"><strong>float</strong></span> <span style="color:#153b65">Distance</span> <span style="color:#000000">=</span> <span style="color:#153b65">100.0f</span><span style="color:#000000">;</span>
    <span style="color:#153b65"><strong>int</strong></span> <span style="color:#153b65">LayerBitMask</span> <span style="color:#000000">=</span> <span style="color:#153b65">1</span> <span style="color:#000000"><<</span> <span style="color:#153b65">LayerMask</span><span style="color:#000000">.</span><span style="color:#153b65">NameToLayer</span><span style="color:#000000">(</span><span style="color:#721d3b">"Pawn"</span><span style="color:#000000">);</span>

    <span style="color:#153b65">RaycastHit</span> <span style="color:#153b65">Hit</span><span style="color:#000000">;</span>
    <span style="color:#153b65"><strong>bool</strong></span> bHit <span style="color:#000000">=</span> <span style="color:#153b65">Physics</span><span style="color:#000000">.</span><span style="color:#153b65">Raycast</span><span style="color:#000000">(</span><span style="color:#153b65">Start</span><span style="color:#000000">,</span> <span style="color:#153b65">Direction</span><span style="color:#000000">,</span> <span style="color:#153b65"><strong>out</strong></span> <span style="color:#153b65">Hit</span><span style="color:#000000">,</span> <span style="color:#153b65">Distance</span><span style="color:#000000">,</span> <span style="color:#153b65">LayerBitMask</span><span style="color:#000000">);</span>

    <span style="color:#153b65"><strong>if</strong></span> <span style="color:#000000">(</span>bHit<span style="color:#000000">)</span>
    <span style="color:#000000">{</span>
        <span style="color:#153b65"><strong>return</strong></span> <span style="color:#153b65">Hit</span><span style="color:#000000">.</span>collider<span style="color:#000000">.</span>gameObject<span style="color:#000000">;</span>
    <span style="color:#000000">}</span>

    <span style="color:#153b65"><strong>return</strong></span> <span style="color:#153b65"><strong>null</strong></span><span style="color:#000000">;</span>
<span style="color:#000000">}</span></code></span>

UE4 C++:

<span style="color:#000000"><code><span style="color:#153b65">APawn</span><span style="color:#000000">*</span> <span style="color:#153b65">AMyPlayerController</span><span style="color:#000000">::</span><span style="color:#153b65">FindPawnCameraIsLookingAt</span><span style="color:#000000">()</span>
<span style="color:#000000">{</span>
    <span style="color:#15653a">// You can use this to customize various properties about the trace</span>
    <span style="color:#153b65">FCollisionQueryParams</span> <span style="color:#153b65">Params</span><span style="color:#000000">;</span>
    <span style="color:#15653a">// Ignore the player's pawn</span>
    <span style="color:#153b65">Params</span><span style="color:#000000">.</span><span style="color:#153b65">AddIgnoredActor</span><span style="color:#000000">(</span><span style="color:#153b65">GetPawn</span><span style="color:#000000">());</span>

    <span style="color:#15653a">// The hit result gets populated by the line trace</span>
    <span style="color:#153b65">FHitResult</span> <span style="color:#153b65">Hit</span><span style="color:#000000">;</span>

    <span style="color:#15653a">// Raycast out from the camera, only collide with pawns (they are on the ECC_Pawn collision channel)</span>
    <span style="color:#153b65">FVector</span> <span style="color:#153b65">Start</span> <span style="color:#000000">=</span> <span style="color:#153b65">PlayerCameraManager</span><span style="color:#000000">-></span><span style="color:#153b65">GetCameraLocation</span><span style="color:#000000">();</span>
    <span style="color:#153b65">FVector</span> <span style="color:#153b65">End</span> <span style="color:#000000">=</span> <span style="color:#153b65">Start</span> <span style="color:#000000">+</span> <span style="color:#000000">(</span><span style="color:#153b65">PlayerCameraManager</span><span style="color:#000000">-></span><span style="color:#153b65">GetCameraRotation</span><span style="color:#000000">().</span><span style="color:#153b65">Vector</span><span style="color:#000000">()</span> <span style="color:#000000">*</span> <span style="color:#153b65">1000.0f</span><span style="color:#000000">);</span>
    <span style="color:#153b65"><strong>bool</strong></span> bHit <span style="color:#000000">=</span> <span style="color:#153b65">GetWorld</span><span style="color:#000000">()-></span><span style="color:#153b65">LineTraceSingle</span><span style="color:#000000">(</span><span style="color:#153b65">Hit</span><span style="color:#000000">,</span> <span style="color:#153b65">Start</span><span style="color:#000000">,</span> <span style="color:#153b65">End</span><span style="color:#000000">,</span> ECC_Pawn<span style="color:#000000">,</span> <span style="color:#153b65">Params</span><span style="color:#000000">);</span>

    <span style="color:#153b65"><strong>if</strong></span> <span style="color:#000000">(</span>bHit<span style="color:#000000">)</span>
    <span style="color:#000000">{</span>
        <span style="color:#15653a">// Hit.Actor contains a weak pointer to the Actor that the trace hit</span>
        <span style="color:#153b65"><strong>return</strong></span> <span style="color:#153b65">Cast</span><span style="color:#000000"><</span><span style="color:#153b65">APawn</span><span style="color:#000000">>(</span><span style="color:#153b65">Hit</span><span style="color:#000000">.</span><span style="color:#153b65">Actor</span><span style="color:#000000">.</span><span style="color:#153b65">Get</span><span style="color:#000000">());</span>
    <span style="color:#000000">}</span>

    <span style="color:#153b65"><strong>return</strong></span> <span style="color:#153b65"><strong>nullptr</strong></span><span style="color:#000000">;</span>
<span style="color:#000000">}</span></code></span>

UE4蓝图:

单击查看完整视图。

触发器

Unity C#:

<span style="color:#000000"><code><span style="color:#153b65"><strong>public</strong></span> <span style="color:#153b65"><strong>class</strong></span> <span style="color:#153b65">MyComponent</span> <span style="color:#000000">:</span> <span style="color:#153b65">MonoBehaviour</span>
<span style="color:#000000">{</span>
    <span style="color:#153b65"><strong>void</strong></span> <span style="color:#153b65">Start</span><span style="color:#000000">()</span>
    <span style="color:#000000">{</span>
        collider<span style="color:#000000">.</span>isTrigger <span style="color:#000000">=</span> <span style="color:#153b65"><strong>true</strong></span><span style="color:#000000">;</span>
    <span style="color:#000000">}</span>
    <span style="color:#153b65"><strong>void</strong></span> <span style="color:#153b65">OnTriggerEnter</span><span style="color:#000000">(</span><span style="color:#153b65">Collider</span> <span style="color:#153b65">Other</span><span style="color:#000000">)</span>
    <span style="color:#000000">{</span>
        <span style="color:#15653a">// ...</span>
    <span style="color:#000000">}</span>
    <span style="color:#153b65"><strong>void</strong></span> <span style="color:#153b65">OnTriggerExit</span><span style="color:#000000">(</span><span style="color:#153b65">Collider</span> <span style="color:#153b65">Other</span><span style="color:#000000">)</span>
    <span style="color:#000000">{</span>
        <span style="color:#15653a">// ...</span>
    <span style="color:#000000">}</span>
<span style="color:#000000">}</span></code></span>

UE4 C++:

<span style="color:#000000"><code>UCLASS<span style="color:#000000">()</span>
<span style="color:#153b65"><strong>class</strong></span> <span style="color:#153b65">AMyActor</span> <span style="color:#000000">:</span> <span style="color:#153b65"><strong>public</strong></span> <span style="color:#153b65">AActor</span>
<span style="color:#000000">{</span>
    GENERATED_BODY<span style="color:#000000">()</span>

    <span style="color:#15653a">// My trigger component</span>
    UPROPERTY<span style="color:#000000">()</span>
    <span style="color:#153b65">UPrimitiveComponent</span><span style="color:#000000">*</span> <span style="color:#153b65">Trigger</span><span style="color:#000000">;</span>

    <span style="color:#153b65">AMyActor</span><span style="color:#000000">()</span>
    <span style="color:#000000">{</span>
        <span style="color:#153b65">Trigger</span> <span style="color:#000000">=</span> <span style="color:#153b65">CreateDefaultSubobject</span><span style="color:#000000"><</span><span style="color:#153b65">USphereComponent</span><span style="color:#000000">>(</span>TEXT<span style="color:#000000">(</span><span style="color:#721d3b">"TriggerCollider"</span><span style="color:#000000">));</span>

        <span style="color:#15653a">// Both colliders need to have this set to true for events to fire</span>
        <span style="color:#153b65">Trigger</span><span style="color:#000000">.</span>bGenerateOverlapEvents <span style="color:#000000">=</span> <span style="color:#153b65"><strong>true</strong></span><span style="color:#000000">;</span>

        <span style="color:#15653a">// Set the collision mode for the collider</span>
        <span style="color:#15653a">// This mode will only enable the collider for raycasts, sweeps, and overlaps</span>
        <span style="color:#153b65">Trigger</span><span style="color:#000000">.</span><span style="color:#153b65">SetCollisionEnabled</span><span style="color:#000000">(</span><span style="color:#153b65">ECollisionEnabled</span><span style="color:#000000">::</span><span style="color:#153b65">QueryOnly</span><span style="color:#000000">);</span>
    <span style="color:#000000">}</span>

    <span style="color:#153b65"><strong>virtual</strong></span> <span style="color:#153b65"><strong>void</strong></span> <span style="color:#153b65">NotifyActorBeginOverlap</span><span style="color:#000000">(</span><span style="color:#153b65">AActor</span><span style="color:#000000">*</span> <span style="color:#153b65">Other</span><span style="color:#000000">)</span> <span style="color:#153b65"><strong>override</strong></span><span style="color:#000000">;</span>

    <span style="color:#153b65"><strong>virtual</strong></span> <span style="color:#153b65"><strong>void</strong></span> <span style="color:#153b65">NotifyActorEndOverlap</span><span style="color:#000000">(</span><span style="color:#153b65">AActor</span><span style="color:#000000">*</span> <span style="color:#153b65">Other</span><span style="color:#000000">)</span> <span style="color:#153b65"><strong>override</strong></span><span style="color:#000000">;</span>
<span style="color:#000000">};</span></code></span>

UE4蓝图:

您可以在此处阅读有关设置碰撞响应的更多信息。

运动学刚体

Unity C#:

<span style="color:#000000"><code><span style="color:#153b65"><strong>public</strong></span> <span style="color:#153b65"><strong>class</strong></span> <span style="color:#153b65">MyComponent</span> <span style="color:#000000">:</span> <span style="color:#153b65">MonoBehaviour</span>
<span style="color:#000000">{</span>
    <span style="color:#153b65"><strong>void</strong></span> <span style="color:#153b65">Start</span><span style="color:#000000">()</span>
    <span style="color:#000000">{</span>
        rigidbody<span style="color:#000000">.</span>isKinimatic <span style="color:#000000">=</span> <span style="color:#153b65"><strong>true</strong></span><span style="color:#000000">;</span>
        rigidbody<span style="color:#000000">.</span>velocity <span style="color:#000000">=</span> transform<span style="color:#000000">.</span>forward <span style="color:#000000">*</span> <span style="color:#153b65">10.0f</span><span style="color:#000000">;</span>
    <span style="color:#000000">}</span>
<span style="color:#000000">}</span></code></span>

在UE4中,碰撞组件和刚体组件是一体的。它的基类是UPrimitiveComponent,它有许多子类(USphereComponent,UCapsuleComponent等)以满足您的需求。

UE4 C++:

<span style="color:#000000"><code>UCLASS<span style="color:#000000">()</span>
<span style="color:#153b65"><strong>class</strong></span> <span style="color:#153b65">AMyActor</span> <span style="color:#000000">:</span> <span style="color:#153b65"><strong>public</strong></span> <span style="color:#153b65">AActor</span>
<span style="color:#000000">{</span>
    GENERATED_BODY<span style="color:#000000">()</span>

    UPROPERTY<span style="color:#000000">()</span>
    <span style="color:#153b65">UPrimitiveComponent</span><span style="color:#000000">*</span> <span style="color:#153b65">PhysicalComp</span><span style="color:#000000">;</span>

    <span style="color:#153b65">AMyActor</span><span style="color:#000000">()</span>
    <span style="color:#000000">{</span>
        <span style="color:#153b65">PhysicalComp</span> <span style="color:#000000">=</span> <span style="color:#153b65">CreateDefaultSubobject</span><span style="color:#000000"><</span><span style="color:#153b65">USphereComponent</span><span style="color:#000000">>(</span>TEXT<span style="color:#000000">(</span><span style="color:#721d3b">"CollisionAndPhysics"</span><span style="color:#000000">));</span>
        <span style="color:#153b65">PhysicalComp</span><span style="color:#000000">-></span><span style="color:#153b65">SetSimulatePhysics</span><span style="color:#000000">(</span><span style="color:#153b65"><strong>false</strong></span><span style="color:#000000">);</span>
        <span style="color:#153b65">PhysicalComp</span><span style="color:#000000">-></span><span style="color:#153b65">SetPhysicsLinearVelocity</span><span style="color:#000000">(</span><span style="color:#153b65">GetActorRotation</span><span style="color:#000000">().</span><span style="color:#153b65">Vector</span><span style="color:#000000">()</span> <span style="color:#000000">*</span> <span style="color:#153b65">100.0f</span><span style="color:#000000">);</span>
    <span style="color:#000000">}</span>
<span style="color:#000000">};</span></code></span>

输入事件

Unity C#:

<span style="color:#000000"><code><span style="color:#153b65"><strong>public</strong></span> <span style="color:#153b65"><strong>class</strong></span> <span style="color:#153b65">MyPlayerController</span> <span style="color:#000000">:</span> <span style="color:#153b65">MonoBehaviour</span>
<span style="color:#000000">{</span>
    <span style="color:#153b65"><strong>void</strong></span> <span style="color:#153b65">Update</span><span style="color:#000000">()</span>
    <span style="color:#000000">{</span>
        <span style="color:#153b65"><strong>if</strong></span> <span style="color:#000000">(</span><span style="color:#153b65">Input</span><span style="color:#000000">.</span><span style="color:#153b65">GetButtonDown</span><span style="color:#000000">(</span><span style="color:#721d3b">"Fire"</span><span style="color:#000000">))</span>
        <span style="color:#000000">{</span>
            <span style="color:#15653a">// ...</span>
        <span style="color:#000000">}</span>
        <span style="color:#153b65"><strong>float</strong></span> <span style="color:#153b65">Horiz</span> <span style="color:#000000">=</span> <span style="color:#153b65">Input</span><span style="color:#000000">.</span><span style="color:#153b65">GetAxis</span><span style="color:#000000">(</span><span style="color:#721d3b">"Horizontal"</span><span style="color:#000000">);</span>
        <span style="color:#153b65"><strong>float</strong></span> <span style="color:#153b65">Vert</span> <span style="color:#000000">=</span> <span style="color:#153b65">Input</span><span style="color:#000000">.</span><span style="color:#153b65">GetAxis</span><span style="color:#000000">(</span><span style="color:#721d3b">"Vertical"</span><span style="color:#000000">);</span>
        <span style="color:#15653a">// ...</span>
    <span style="color:#000000">}</span>
<span style="color:#000000">}</span></code></span>

UE4 C++:

<span style="color:#000000"><code>UCLASS<span style="color:#000000">()</span>
<span style="color:#153b65"><strong>class</strong></span> <span style="color:#153b65">AMyPlayerController</span> <span style="color:#000000">:</span> <span style="color:#153b65"><strong>public</strong></span> <span style="color:#153b65">APlayerController</span>
<span style="color:#000000">{</span>
    GENERATED_BODY<span style="color:#000000">()</span>

    <span style="color:#153b65"><strong>void</strong></span> <span style="color:#153b65">SetupInputComponent</span><span style="color:#000000">()</span>
    <span style="color:#000000">{</span>
        <span style="color:#153b65">Super</span><span style="color:#000000">::</span><span style="color:#153b65">SetupInputComponent</span><span style="color:#000000">();</span>

        <span style="color:#153b65">InputComponent</span><span style="color:#000000">-></span><span style="color:#153b65">BindAction</span><span style="color:#000000">(</span><span style="color:#721d3b">"Fire"</span><span style="color:#000000">,</span> IE_Pressed<span style="color:#000000">,</span> <span style="color:#153b65"><strong>this</strong></span><span style="color:#000000">,</span> <span style="color:#000000">&</span><span style="color:#153b65">AMyPlayerController</span><span style="color:#000000">::</span><span style="color:#153b65">HandleFireInputEvent</span><span style="color:#000000">);</span>
        <span style="color:#153b65">InputComponent</span><span style="color:#000000">-></span><span style="color:#153b65">BindAxis</span><span style="color:#000000">(</span><span style="color:#721d3b">"Horizontal"</span><span style="color:#000000">,</span> <span style="color:#153b65"><strong>this</strong></span><span style="color:#000000">,</span> <span style="color:#000000">&</span><span style="color:#153b65">AMyPlayerController</span><span style="color:#000000">::</span><span style="color:#153b65">HandleHorizontalAxisInputEvent</span><span style="color:#000000">);</span>
        <span style="color:#153b65">InputComponent</span><span style="color:#000000">-></span><span style="color:#153b65">BindAxis</span><span style="color:#000000">(</span><span style="color:#721d3b">"Vertical"</span><span style="color:#000000">,</span> <span style="color:#153b65"><strong>this</strong></span><span style="color:#000000">,</span> <span style="color:#000000">&</span><span style="color:#153b65">AMyPlayerController</span><span style="color:#000000">::</span><span style="color:#153b65">HandleVerticalAxisInputEvent</span><span style="color:#000000">);</span>
    <span style="color:#000000">}</span>

    <span style="color:#153b65"><strong>void</strong></span> <span style="color:#153b65">HandleFireInputEvent</span><span style="color:#000000">();</span>
    <span style="color:#153b65"><strong>void</strong></span> <span style="color:#153b65">HandleHorizontalAxisInputEvent</span><span style="color:#000000">(</span><span style="color:#153b65"><strong>float</strong></span> <span style="color:#153b65">Value</span><span style="color:#000000">);</span>
    <span style="color:#153b65"><strong>void</strong></span> <span style="color:#153b65">HandleVerticalAxisInputEvent</span><span style="color:#000000">(</span><span style="color:#153b65"><strong>float</strong></span> <span style="color:#153b65">Value</span><span style="color:#000000">);</span>
<span style="color:#000000">};</span></code></span>

UE4蓝图:

以下是项目设置中的输入属性可能的样子:

您可以在此处阅读有关如何设置输入的更多信息。

常见问题

如何自动加载我的最后一个项目?

如果您习惯于Unity自动加载您正在处理的最后一个项目,那么在UE4中也可以这样做。要启用,请在打开项目时选中“始终在启动时加载最后一个项目”。您也可以随时从主编辑菜单的编辑/编辑器首选项/加载和保存/启动下切换设置。

在哪里为我的游戏设置输入绑定?

在 Unity 中,您习惯于使用项目的输入管理器设置来设置默认绑定。在UE4中,它的工作方式类似。您将打开项目设置,然后选择输入类别。在那里,您可以添加各种按钮(动作)和模拟控件(轴)。为每个控件指定名称和默认绑定。然后,您可以在触发输入事件时获取对游戏 Pawn 的回调。有关详细信息,请查看输入文档页面

如何更改项目的起始场景?

您可以从项目设置选项卡更改项目的启动图。从主菜单中选择编辑/项目设置->地图和模式以更改起始地图。

如何运行我的游戏?

运行游戏的最简单方法是单击主编辑器工具栏上的“Play”按钮,这将直接在编辑器进程中运行游戏。如果要将其作为独立应用程序运行,请单击“播放”旁边的下拉箭头,然后选择“独立游戏”。最后,如果要在移动设备或 Web 浏览器中运行,将使用工具栏上的“启动”按钮(在安装该平台所需的任何先决条件后)。

这些是什么单位?

在 Unity 中,主要测量单位是一米。在UE4中,主要测量单位是一厘米。

因此,如果你在 UE1 中整体移动 100 个单位(米)的东西,相当于在 UE4 中移动 <> 个单位(厘米)的东西。

如果你想在Unity中移动2英尺的东西,那就是0.61个单位(米),而在UE4中是61个单位(厘米)。

这个坐标系是怎么回事?哪条路是向上的?

Unity 和 UE4 都使用左手坐标系,但轴会互换。在UE4中,正X是“前进”,正Y是“右”,正Z是“向上”。

如何查看游戏的日志输出?

在UE4编辑器中,您可以从“窗口->开发者工具”菜单中打开“输出日志”。您还可以使用“-log”命令行参数运行游戏,以在游戏旁边调用专用的日志窗口,这非常有用!

说到日志输出,我的Debug.Log在哪里?

UE4中的日志记录是高度可定制的。在此处阅读如何记录消息。

如何引发异常?

在 Unity 中,您习惯于在出现问题时引发异常。UE4不使用异常处理。相反,请使用“check()”函数来触发严重断言错误。您可以传入错误消息。如果要报告错误但不停止程序,请改用“ensure()”。这将记录完整调用堆栈的错误,但程序执行将继续。如果附加了调试器,则这两个函数都将中断到调试器中。

.NET Framework在哪里?

与Unity不同,UE4不使用.NET框架。UE4有自己的一套容器类和库。常见的容器比较:

.Net 框架

标准箱

字符串

FString, FText

列表

塔雷

字典

马普

哈希集

目录

您可以在此处了解有关其他UE4容器的更多信息。

虚幻会自动重新加载代码更改吗?

是的!您可以在编写代码时使编辑器保持打开状态。只需在完成代码编辑后从Visual Studio开始编译,编辑器将自动“热重载”您的更改。您也可以单击编辑器主工具栏上的“编译”按钮。当您附加了Visual Studio调试器时,这可能很有用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
虚幻引擎Unity都有许多经典的书籍和电子书,这里列举一些比较优秀的书籍供参考: 虚幻引擎书籍推荐: 1. 《虚幻引擎官方文档》:虚幻引擎官方文档是学习虚幻引擎的必备资料,包含了虚幻引擎的各个方面,从入门到高级技巧都有详细的讲解。 2. 《虚幻引擎4游戏开发实战》:本书是一本虚幻引擎4的实战教程,通过实践项目的方式讲解了虚幻引擎4的各个方面,从场景制作到物理模拟,从UI设计到人工智能都有涉及。 3. 《虚幻引擎4游戏设计基础》:本书是一本适合初学者的虚幻引擎4入门教程,从基础概念到实践操作都有详细的讲解,适合快速入门。 Unity书籍推荐: 1. 《Unity官方文档》:Unity官方文档是学习Unity的必备资料,包含了Unity的各个方面,从入门到高级技巧都有详细的讲解。 2. 《Unity 5.x游戏开发实战》:本书是一本Unity 5.x的实战教程,通过实践项目的方式讲解了Unity 5.x的各个方面,从场景制作到物理模拟,从UI设计到人工智能都有涉及。 3. 《Unity 5.x游戏开发从入门到精通》:本书是一本适合初学者的Unity 5.x入门教程,从基础概念到实践操作都有详细的讲解,适合快速入门。 以上是一些较为优秀的虚幻引擎Unity书籍,供开发者参考。当然,随着游戏引擎的不断更新和发展,也会有越来越多的优秀学习资料问世。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值