Unity3D to Unreal Engine 4

文章先作为笔记记录,待整理
文章主要参考:官方文档http://api.unrealengine.com/CHN/GettingStarted/FromUnity/index.html

推荐几个不错的UE入门教程:
《Inside UE4》
《Unreal新手笔记(二)——编程架构》

类图

视频教程:
《Unreal Engine 4 喵喵教程 (中文)》
《虚幻4游戏引擎官方入门自学到提高全218集(中文字幕)上部》
《虚幻4入门到精通教程【全集】》


什么是蓝图?

蓝图通常包含2部分:

  • 蓝图资源:类似于Unity的Prefab
  • 蓝图脚本:可视化的游戏脚本系统
    一般我们所指的蓝图是狭义的蓝图,即可视化脚本系统。

       对于开发者来说,我们可以把它理解为一种可视化的高级语言(C#等),它有基本的变量、函数、类型转换,支持继承、多态等。通过使用连线把节点、事件、函数及变量连接到一起,这样就可以创建复杂的游戏性元素。蓝图通过各种用途的节点构成图来进行工作,这些节点包括针对蓝图每个实例的对象构建、独立的函数、一般的游戏性事件,从而实现各种行为及其它功能。

中文 英文
蓝图其实是可视化的类
Blueprint is visual script

蓝图核心类:

  • UObject:
  • Actor:物件;类似于Unity的GameObject
  • Pawn:棋子(由玩家或AI控制的游戏对象),士兵(由于UE是从FPS游戏进化来的缘故)
  • Character:角色
  • Controller:控制器,有些类似于Unity的MonoBehavior
  • Component:组件


    组件

蓝图:
蓝图,BluePrint,简称BP,是游戏的可视化脚本系统,Visual Scripting.
使用蓝图所定义的对象通常被直接称为“蓝图”。

问题:

  1. 蓝图类似于Unity的Prefab.
  2. 蓝图的逻辑节点其实跟Unity行为树的节点比较类似?
  3. 如何定义蓝图的一个节点?
  4. 蓝图的变量与行为树的黑板有什么区别吗?
  5. 如何将Prefab批量改为蓝图?

在虚幻 4 中编写游戏逻辑代码
好了,现在开始稍微深入一些。我们将谈论一下创建游戏所需要的编程话题。因为您了解 Unity,我们来面向 C# 的用户解释 C++ 的功能,当然您也可以使用蓝图来完成几乎所有的事情!我们尽可能的为范例提供 C++ 的同时也提供蓝图。

先说一下一些通用的游戏逻辑编程模式,以及如何在虚幻中实现。许多在 Unity 中的函数在虚幻中都有类似的函数。我们先从最常见的开始。

Instantiating GameObject / Spawning Actor
在 Unity 中,我们使用 Instantiate 函数来新建物体的实例。

该函数使用任意的 UnityEngine.Object 类型(GameObject,MonoBehaviour 等),并创建它的拷贝。

public GameObject EnemyPrefab;
public Vector3 SpawnPosition;
public Quaternion SpawnRotation;

void Start()
{
    GameObject NewGO = (GameObject)Instantiate(EnemyPrefab, SpawnPosition, SpawnRotation);
    NewGO.name = "MyNewGameObject";
}

在虚幻 4 中,根据不同的需要,有一些不同的函数用于创建物体。NewObject 用于创建新的 UObject 类型实例,而 SpawnActor 用于创建新的 AActor 类型实例。

首先我们总体说一下 UObject 和 NewObject。在虚幻中 UObject 的子类很像 Unity 中 ScriptableObject 的子类。对于游戏过程中,它们是那些不需要在游戏世界中创建并看见的存在。

在 Unity 中,如果要创建自己的 ScriptableObject 子类,可能会像下面这样的初始化:

MyScriptableObject NewSO = ScriptableObject.CreateInstance();

在虚幻中,如果要创建 UObject 的继承类,是像下面这样的初始化:

UMyObject* NewObj = NewObject();

那么 Actor 呢?Actor 的在世界(C++ 中的 UWorld)中生成是通过 SpawnActor 方法。如何获取 World 对象?有些 UObject 会提供一个 GetWorld 的方法,所有的 Actor 则都具有这个方法。

您可能已经注意到,并没有传递一个 Actor,我们传递了一个 Actor 的 “class” 来作为生成 Actor 的参数。在我们的范例中,是一个 AMyEnemy 类的任意子类。

但如果想要创建某个东西的“拷贝”,就像 Unity 的 Instantiate 函数那样,该怎么做呢?

NewObject 和 SpawnActor 函数也能通过给一个 “模板” 对象来工作。虚幻引擎会创建该一个对象的拷贝,而不是从零创建一个新的对象。这将会拷贝该对象的所有属性(UPROPERTY)和组件。

AMyActor* CreateCloneOfMyActor(AMyActor* ExistingActor, FVector SpawnLocation, FRotator SpawnRotation)
{
    UWorld* World = ExistingActor->GetWorld();
    FActorSpawnParameters SpawnParams;
    SpawnParams.Template = ExistingActor;
    World->SpawnActor(ExistingActor->GetClass(), SpawnLocation, SpawnRotation, SpawnParams);
}

您也许想知道“从零开始创建”在这里具体是什么意思。每个对象类在创建时都有一个默认模板,包含了它的默认属性和组件。在创建时如果您并不像修改这些默认属性,并没有提供你自己的模板,虚幻将使用这些默认值来创建该对象。为了更好的说明这个,我们先来看一下 MonoBehaviour 的例子:

public class MyComponent : MonoBehaviour
{
    public int MyIntProp = 42;
    public SphereCollider MyCollisionComp = null;

    void Start()
    {
        // Create the collision component if we don't already have one
        if (MyCollisionComp == null)
        {
            MyCollisionComp = gameObject.AddComponent();
            MyCollisionComp.center = Vector3.zero;
            MyCollisionComp.radius = 20.0f;
        }
    }
}

在上面这个例子中,有一个 int 属性,默认是 42,并有一个 SphereCollider 组件默认半径是 20。

在虚幻 4 中,利用对象的构造函数也能达到同样的效果。

UCLASS()
class AMyActor : public AActor
{
    GENERATED_BODY()

    UPROPERTY()
    int32 MyIntProp;

    UPROPERTY()
    USphereComponent* MyCollisionComp;

    AMyActor()
    {
        MyIntProp = 42;

        MyCollisionComp = CreateDefaultSubobject(FName(TEXT("CollisionComponent"));
        MyCollisionComp->RelativeLocation = FVector::ZeroVector;
        MyCollisionComp->SphereRadius = 20.0f;
    }
};

在 AMyActor 的构造函数中,我们为这个类设置了属性的默认值。请注意 CreateDefaultSubobject 函数。我们可以用它来创建组件并赋予组件默认值。所有子对象都将使用这个函数作为默认模板来创建,也可以在子类或者蓝图中对它进行修改。


通过 GameObject / Actor 访问组件
Unity

MyComponent MyComp = gameObject.GetComponent();

C++

UMyComponent* MyComp = MyActor->FindComponentByClass();

类型转换
在这个例子中,获取了一个已知的组件,并将它转换为一个特定类型并有条件的做一些事情。

Unity C#:

Collider collider = gameObject.GetComponent;
SphereCollider sphereCollider = collider as SphereCollider;
if (sphereCollider != null)
{
        // ...
}

虚幻 4 C++:

UPrimitiveComponent* Primitive = MyActor->GetComponentByClass(UPrimitiveComponent::StaticClass());
USphereComponent* SphereCollider = Cast(Primitive);
if (SphereCollider != nullptr)
{
        // ...
}

RayCast vs RayTrace
Unity C#:

GameObject FindGOCameraIsLookingAt()
{
    Vector3 Start = Camera.main.transform.position;
    Vector3 Direction = Camera.main.transform.forward;
    float Distance = 100.0f;
    int LayerBitMask = 1 << LayerMask.NameToLayer("Pawn");

    RaycastHit Hit;
    bool bHit = Physics.Raycast(Start, Direction, out Hit, Distance, LayerBitMask);

    if (bHit)
    {
        return Hit.collider.gameObject;
    }

    return null;
}

虚幻 4 C++:

APawn* AMyPlayerController::FindPawnCameraIsLookingAt()
{
    // You can use this to customize various properties about the trace
    FCollisionQueryParams Params;
    // Ignore the player's pawn
    Params.AddIgnoredActor(GetPawn());

    // The hit result gets populated by the line trace
    FHitResult Hit;

    // Raycast out from the camera, only collide with pawns (they are on the ECC_Pawn collision channel)
    FVector Start = PlayerCameraManager->GetCameraLocation();
    FVector End = Start + (PlayerCameraManager->GetCameraRotation().Vector() * 1000.0f);
    bool bHit = GetWorld()->LineTraceSingle(Hit, Start, End, ECC_Pawn, Params);

    if (bHit)
    {
        // Hit.Actor contains a weak pointer to the Actor that the trace hit
        return Cast(Hit.Actor.Get());
    }

    return nullptr;
}

  1. Prefab vs 蓝图
    Unity 的Prefab,在虚幻中的蓝图有着类似的功能。
    但蓝图具有可扩展性,或者称为可继承性。(因为蓝图的本质其实是一个可视化的C++类?)
    --
    比如,在虚幻 4 中,可以创建一个蓝图类叫做 Monster,实现基本的怪物功能,比如追击人类。然后可以创建一个叫做 Dragon 的蓝图类来扩展它(某种特定的怪物,添加了火焰吐息的功能),再有一个 Grue(一种当它变黑是就有可能吃人的怪物),以及其他 8 种类型。这样一些 Monster 的子类都继承了基础的 Monster 类的功能,并在此基础上添加新的能力。
    在 Unity 中,则需要创建很多不同的 GameObject 的 prefabs:为 Dragon 创建一个,为 Grue 创建一个,等等。假设这时希望为所有的怪物添加某个功能,比如使用一个 Speak 组件来说话,在 Unity 中则需要更新所有的 10 个 prefabs,拷贝粘贴到每个中。
    在虚幻 4 中,只需简单的修改 Monster 的蓝图类,并为它添加新的 Speak 的能力,便做完了!Dragon,Grue 以及其他 8 种 Monster 的子类都会自动的继承这个说话的新功能,并不需要去修改这些子类。
  • 旋转示意图
  1. 如何为蓝图绑定脚本/添加脚本/AddComponent?
  • 新建C++类:Monster,父类选择Character
  • 新建蓝图类:BPMonster,分类选择Actor
  • 双击蓝图类BPMonster,打开蓝图编辑器
  • BPMonster(自身)相当于Unity的transform:选择BPMonster(自身),然后视口面板选择类设置,细节窗口选择父类为Monster完成脚本绑定。


    image.png

你可能感兴趣的:(Unity3D to Unreal Engine 4)