Unreal Engine开发:Unreal Engine基础入门_(7).游戏对象与组件

游戏对象与组件

在Unreal Engine中,游戏对象和组件是构建游戏的基础。游戏对象(Actor)是游戏世界中的实体,可以是静态的环境物体、动态的角色、触发器等。组件(Component)则是游戏对象的构建块,每个游戏对象可以包含多个组件,这些组件负责游戏对象的不同方面,例如视觉表现、物理属性、碰撞检测等。

1. 游戏对象(Actor)

游戏对象是Unreal Engine中的基本单元,它们存在于游戏世界中,可以被移动、旋转、缩放等。每个游戏对象都是AActor类的实例。AActor类提供了一些基本的功能,例如位置、旋转和缩放属性,以及生命周期管理方法。

1.1 创建游戏对象

创建游戏对象可以通过继承AActor类来实现。以下是一个简单的例子,创建一个自定义的游戏对象:


// MyActor.h

#pragma once



#include "CoreMinimal.h"

#include "GameFramework/Actor.h"

#include "MyActor.generated.h"



UCLASS()

class MYGAME_API AMyActor : public AActor

{

    GENERATED_BODY()

    

public:    

    // 构造函数

    AMyActor();



protected:

    // 事件当Actor被添加到关卡时调用

    virtual void BeginPlay() override;



public:    

    // 事件每帧调用

    virtual void Tick(float DeltaTime) override;

};


// MyActor.cpp

#include "MyActor.h"

#include "Components/StaticMeshComponent.h"



AMyActor::AMyActor()

{

    // 设置该Actor是否以固定帧率进行Tick

    PrimaryActorTick.bCanEverTick = true;



    // 创建一个静态网格组件并添加到Actor

    UStaticMeshComponent* MeshComponent = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("MeshComponent"));

    MeshComponent->SetupAttachment(RootComponent);

}



void AMyActor::BeginPlay()

{

    Super::BeginPlay();

    

    // 在游戏开始时输出一条消息

    UE_LOG(LogTemp, Warning, TEXT("MyActor has begun play!"));

}



void AMyActor::Tick(float DeltaTime)

{

    Super::Tick(DeltaTime);

    

    // 每帧移动Actor

    FVector NewLocation = GetActorLocation();

    NewLocation.X += 100.0f * DeltaTime;

    SetActorLocation(NewLocation);

}

在这个例子中,我们创建了一个名为AMyActor的游戏对象,它包含一个静态网格组件。在BeginPlay方法中,我们输出了一条消息,表示游戏对象已经开始运行。在Tick方法中,我们每帧移动游戏对象的位置。

1.2 游戏对象的生命周期

游戏对象的生命周期包括以下阶段:

  • 构造:在游戏对象实例化时调用。

  • BeginPlay:在游戏对象被添加到关卡时调用。

  • Tick:每帧调用,用于更新游戏对象的状态。

  • Destroy:在游戏对象被销毁时调用。

以下是一个更详细的例子,展示了游戏对象的生命周期:


// MyActor.h

#pragma once



#include "CoreMinimal.h"

#include "GameFramework/Actor.h"

#include "MyActor.generated.h"



UCLASS()

class MYGAME_API AMyActor : public AActor

{

    GENERATED_BODY()

    

public:    

    AMyActor();



protected:

    virtual void BeginPlay() override;



public:    

    virtual void Tick(float DeltaTime) override;

    virtual void Destroyed() override;

};


// MyActor.cpp

#include "MyActor.h"

#include "Components/StaticMeshComponent.h"



AMyActor::AMyActor()

{

    PrimaryActorTick.bCanEverTick = true;



    UStaticMeshComponent* MeshComponent = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("MeshComponent"));

    MeshComponent->SetupAttachment(RootComponent);

}



void AMyActor::BeginPlay()

{

    Super::BeginPlay();

    

    UE_LOG(LogTemp, Warning, TEXT("MyActor has begun play!"));

}



void AMyActor::Tick(float DeltaTime)

{

    Super::Tick(DeltaTime);

    

    FVector NewLocation = GetActorLocation();

    NewLocation.X += 100.0f * DeltaTime;

    SetActorLocation(NewLocation);



    // 如果Actor移动到屏幕外,则销毁

    if (NewLocation.X > 10000.0f)

    {

        Destroy();

    }

}



void AMyActor::Destroyed()

{

    Super::Destroyed();

    

    UE_LOG(LogTemp, Warning, TEXT("MyActor has been destroyed!"));

}

在这个例子中,我们添加了Destroyed方法,在游戏对象被销毁时输出一条消息。同时,我们在Tick方法中添加了一个条件,当游戏对象移动到屏幕外时,自动销毁。

2. 组件(Component)

组件是游戏对象的构建块,每个游戏对象可以包含多个组件,这些组件负责游戏对象的不同方面。常见的组件类型包括:

  • 静态网格组件(StaticMeshComponent):用于显示静态的3D模型。

  • 骨骼网格组件(SkeletalMeshComponent):用于显示动画的3D模型。

  • 相机组件(CameraComponent):用于控制视角。

  • 光源组件(LightComponent):用于添加光源。

  • 碰撞组件(CollisionComponent):用于处理碰撞检测。

2.1 静态网格组件

静态网格组件用于显示静态的3D模型。以下是一个例子,创建一个静态网格组件并附加到游戏对象:


// MyActor.h

#pragma once



#include "CoreMinimal.h"

#include "GameFramework/Actor.h"

#include "MyActor.generated.h"



UCLASS()

class MYGAME_API AMyActor : public AActor

{

    GENERATED_BODY()

    

public:    

    AMyActor();



protected:

    virtual void BeginPlay() override;



public:    

    virtual void Tick(float DeltaTime) override;



private:

    UPROPERTY(VisibleAnywhere)

    UStaticMeshComponent* MeshComponent;

};


// MyActor.cpp

#include "MyActor.h"

#include "Components/StaticMeshComponent.h"



AMyActor::AMyActor()

{

    PrimaryActorTick.bCanEverTick = true;



    MeshComponent = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("MeshComponent"));

    MeshComponent->SetupAttachment(RootComponent);



    // 设置默认的静态网格

    static ConstructorHelpers::FObjectFinder<UStaticMesh> MeshAsset(TEXT("/Game/Models/MyModel"));

    if (MeshAsset.Succeeded())

    {

        MeshComponent->SetStaticMesh(MeshAsset.Object);

    }

}



void AMyActor::BeginPlay()

{

    Super::BeginPlay();

    

    UE_LOG(LogTemp, Warning, TEXT("MyActor has begun play!"));

}



void AMyActor::Tick(float DeltaTime)

{

    Super::Tick(DeltaTime);

    

    // 每帧旋转网格

    FRotator NewRotation = GetActorRotation();

    NewRotation.Yaw += 10.0f * DeltaTime;

    SetActorRotation(NewRotation);

}

在这个例子中,我们创建了一个静态网格组件,并在构造函数中设置了默认的静态网格。在Tick方法中,我们每帧旋转网格。

2.2 骨骼网格组件

骨骼网格组件用于显示动画的3D模型。以下是一个例子,创建一个骨骼网格组件并附加到游戏对象:


// MyCharacter.h

#pragma once



#include "CoreMinimal.h"

#include "GameFramework/Character.h"

#include "MyCharacter.generated.h"



UCLASS()

class MYGAME_API AMyCharacter : public ACharacter

{

    GENERATED_BODY()

    

public:    

    AMyCharacter();



protected:

    virtual void BeginPlay() override;



public:    

    virtual void Tick(float DeltaTime) override;



private:

    UPROPERTY(VisibleAnywhere)

    USkeletalMeshComponent* SkeletalMeshComponent;

};


// MyCharacter.cpp

#include "MyCharacter.h"

#include "Components/SkeletalMeshComponent.h"



AMyCharacter::AMyCharacter()

{

    PrimaryActorTick.bCanEverTick = true;



    SkeletalMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("SkeletalMeshComponent"));

    SkeletalMeshComponent->SetupAttachment(RootComponent);



    // 设置默认的骨骼网格

    static ConstructorHelpers::FObjectFinder<USkeletalMesh> SkeletalMeshAsset(TEXT("/Game/Models/MyCharacterMesh"));

    if (SkeletalMeshAsset.Succeeded())

    {

        SkeletalMeshComponent->SetSkeletalMesh(SkeletalMeshAsset.Object);

    }



    // 设置默认的动画

    static ConstructorHelpers::FObjectFinder<UAnimationAsset> AnimationAsset(TEXT("/Game/Animations/MyAnimation"));

    if (AnimationAsset.Succeeded())

    {

        SkeletalMeshComponent->SetAnimationMode(EAnimationMode::AnimationSingleNode);

        SkeletalMeshComponent->SetAnimation(AnimationAsset.Object);

    }

}



void AMyCharacter::BeginPlay()

{

    Super::BeginPlay();

    

    UE_LOG(LogTemp, Warning, TEXT("MyCharacter has begun play!"));

}



void AMyCharacter::Tick(float DeltaTime)

{

    Super::Tick(DeltaTime);

    

    // 每帧更新角色的位置

    FVector NewLocation = GetActorLocation();

    NewLocation.X += 100.0f * DeltaTime;

    SetActorLocation(NewLocation);

}

在这个例子中,我们创建了一个骨骼网格组件,并在构造函数中设置了默认的骨骼网格和动画。在Tick方法中,我们每帧更新角色的位置。

2.3 相机组件

相机组件用于控制游戏的视角。以下是一个例子,创建一个相机组件并附加到游戏对象:


// MyPlayerController.h

#pragma once



#include "CoreMinimal.h"

#include "GameFramework/PlayerController.h"

#include "MyPlayerController.generated.h"



UCLASS()

class MYGAME_API AMyPlayerController : public APlayerController

{

    GENERATED_BODY()

    

public:    

    AMyPlayerController();



protected:

    virtual void BeginPlay() override;



public:    

    virtual void Tick(float DeltaTime) override;



private:

    UPROPERTY(VisibleAnywhere)

    UCameraComponent* CameraComponent;

};


// MyPlayerController.cpp

#include "MyPlayerController.h"

#include "Components/CameraComponent.h"



AMyPlayerController::AMyPlayerController()

{

    PrimaryActorTick.bCanEverTick = true;



    CameraComponent = CreateDefaultSubobject<UCameraComponent>(TEXT("CameraComponent"));

    CameraComponent->SetupAttachment(RootComponent);



    // 设置相机的初始位置

    CameraComponent->SetRelativeLocation(FVector(0.0f, 0.0f, 100.0f));

}



void AMyPlayerController::BeginPlay()

{

    Super::BeginPlay();

    

    UE_LOG(LogTemp, Warning, TEXT("MyPlayerController has begun play!"));

}



void AMyPlayerController::Tick(float DeltaTime)

{

    Super::Tick(DeltaTime);

    

    // 每帧旋转相机

    FRotator NewRotation = CameraComponent->GetRelativeRotation();

    NewRotation.Yaw += 10.0f * DeltaTime;

    CameraComponent->SetRelativeRotation(NewRotation);

}

在这个例子中,我们创建了一个相机组件,并在构造函数中设置了相机的初始位置。在Tick方法中,我们每帧旋转相机。

2.4 光源组件

光源组件用于添加光源到游戏世界。以下是一个例子,创建一个光源组件并附加到游戏对象:


// MyLight.h

#pragma once



#include "CoreMinimal.h"

#include "GameFramework/Actor.h"

#include "MyLight.generated.h"



UCLASS()

class MYGAME_API AMyLight : public AActor

{

    GENERATED_BODY()

    

public:    

    AMyLight();



protected:

    virtual void BeginPlay() override;



public:    

    virtual void Tick(float DeltaTime) override;



private:

    UPROPERTY(VisibleAnywhere)

    UPointLightComponent* PointLightComponent;

};


// MyLight.cpp

#include "MyLight.h"

#include "Components/PointLightComponent.h"



AMyLight::AMyLight()

{

    PrimaryActorTick.bCanEverTick = true;



    PointLightComponent = CreateDefaultSubobject<UPointLightComponent>(TEXT("PointLightComponent"));

    PointLightComponent->SetupAttachment(RootComponent);



    // 设置光源的颜色

    PointLightComponent->SetLightColor(FLinearColor::Red);



    // 设置光源的强度

    PointLightComponent->SetIntensity(1000.0f);

}



void AMyLight::BeginPlay()

{

    Super::BeginPlay();

    

    UE_LOG(LogTemp, Warning, TEXT("MyLight has begun play!"));

}



void AMyLight::Tick(float DeltaTime)

{

    Super::Tick(DeltaTime);

    

    // 每帧改变光源的颜色

    FLinearColor NewColor = PointLightComponent->GetLightColor();

    NewColor.R = FMath::Fmod(NewColor.R + 0.01f, 1.0f);

    PointLightComponent->SetLightColor(NewColor);

}

在这个例子中,我们创建了一个点光源组件,并在构造函数中设置了光源的颜色和强度。在Tick方法中,我们每帧改变光源的颜色。

2.5 碰撞组件

碰撞组件用于处理游戏对象之间的碰撞检测。以下是一个例子,创建一个碰撞组件并附加到游戏对象:


// MyCollisionActor.h

#pragma once



#include "CoreMinimal.h"

#include "GameFramework/Actor.h"

#include "MyCollisionActor.generated.h"



UCLASS()

class MYGAME_API AMyCollisionActor : public AActor

{

    GENERATED_BODY()

    

public:    

    AMyCollisionActor();



protected:

    virtual void BeginPlay() override;



public:    

    virtual void Tick(float DeltaTime) override;



private:

    UPROPERTY(VisibleAnywhere)

    UBoxComponent* BoxComponent;



    UPROPERTY(VisibleAnywhere)

    UStaticMeshComponent* MeshComponent;



    void OnComponentHit(UPrimitiveComponent* HitComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit);

};


// MyCollisionActor.cpp

#include "MyCollisionActor.h"

#include "Components/BoxComponent.h"

#include "Components/StaticMeshComponent.h"



AMyCollisionActor::AMyCollisionActor()

{

    PrimaryActorTick.bCanEverTick = true;



    BoxComponent = CreateDefaultSubobject<UBoxComponent>(TEXT("BoxComponent"));

    BoxComponent->SetupAttachment(RootComponent);



    MeshComponent = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("MeshComponent"));

    MeshComponent->SetupAttachment(BoxComponent);



    // 设置默认的静态网格

    static ConstructorHelpers::FObjectFinder<UStaticMesh> MeshAsset(TEXT("/Game/Models/MyBoxMesh"));

    if (MeshAsset.Succeeded())

    {

        MeshComponent->SetStaticMesh(MeshAsset.Object);

    }



    // 启用碰撞

    BoxComponent->SetCollisionProfileName(UCollisionProfile::BlockAllDynamic_ProfileName);



    // 绑定碰撞事件

    BoxComponent->OnComponentHit.AddDynamic(this, &AMyCollisionActor::OnComponentHit);

}



void AMyCollisionActor::BeginPlay()

{

    Super::BeginPlay();

    

    UE_LOG(LogTemp, Warning, TEXT("MyCollisionActor has begun play!"));

}



void AMyCollisionActor::Tick(float DeltaTime)

{

    Super::Tick(DeltaTime);

    

    // 每帧移动Actor

    FVector NewLocation = GetActorLocation();

    NewLocation.X += 100.0f * DeltaTime;

    SetActorLocation(NewLocation);

}



void AMyCollisionActor::OnComponentHit(UPrimitiveComponent* HitComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit)

{

    // 当发生碰撞时输出一条消息

    UE_LOG(LogTemp, Warning, TEXT("MyCollisionActor hit by %s"), *OtherActor->GetName());

}

在这个例子中,我们创建了一个碰撞盒组件和一个静态网格组件,并将静态网格组件附加到碰撞盒组件上。我们启用了碰撞,并绑定了碰撞事件。当发生碰撞时,我们输出一条消息。

3. 组件的组合

游戏对象通常包含多个组件,这些组件协同工作以实现复杂的行为。以下是一个例子,创建一个包含多个组件的游戏对象:


// MyComplexActor.h

#pragma once



#include "CoreMinimal.h"

#include "GameFramework/Actor.h"

#include "MyComplexActor.generated.h"



UCLASS()

class MYGAME_API AMyComplexActor : public AActor

{

    GENERATED_BODY()

    

public:    

    AMyComplexActor();



protected:

    virtual void BeginPlay() override;



public:    

    virtual void Tick(float DeltaTime) override;



private:

    UPROPERTY(VisibleAnywhere)

    UStaticMeshComponent* MeshComponent;



    UPROPERTY(VisibleAnywhere)

    UBoxComponent* BoxComponent;



    UPROPERTY(VisibleAnywhere)

    UPointLightComponent* PointLightComponent;



    void OnComponentHit(UPrimitiveComponent* HitComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit);

};


// MyComplexActor.cpp

#include "MyComplexActor.h"

#include "Components/StaticMeshComponent.h"

#include "Components/BoxComponent.h"

#include "Components/PointLightComponent.h"



AMyComplexActor::AMyComplexActor()

{

    PrimaryActorTick.bCanEverTick = true;



    // 创建静态网格组件

    MeshComponent = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("MeshComponent"));

    MeshComponent->SetupAttachment(RootComponent);



    // 创建碰撞盒组件

    BoxComponent = CreateDefaultSubobject<UBoxComponent>(TEXT("BoxComponent"));

    BoxComponent->SetupAttachment(MeshComponent);



    // 创建点光源组件

    PointLightComponent = CreateDefaultSubobject<UPointLightComponent>(TEXT("PointLightComponent"));

    PointLightComponent->SetupAttachment(BoxComponent);



    // 设置默认的静态网格

    static ConstructorHelpers::FObjectFinder<UStaticMesh> MeshAsset(TEXT("/Game/Models/MyComplexMesh"));

    if (MeshAsset.Succeeded())

    {

        MeshComponent->SetStaticMesh(MeshAsset.Object);

    }



    // 启用碰撞

    BoxComponent->SetCollisionProfileName(UCollisionProfile::BlockAllDynamic_ProfileName);



    // 绑定碰撞事件

    BoxComponent->OnComponentHit.AddDynamic(this, &AMyComplexActor::OnComponentHit);



    // 设置光源的颜色

    PointLightComponent->SetLightColor(FLinearColor::Green);



    // 设置光源的强度

    PointLightComponent->SetIntensity(500.0f);

}



void AMyComplexActor::BeginPlay()

{

    Super::BeginPlay();

    

    UE_LOG(LogTemp, Warning, TEXT("MyComplexActor has begun play!"));

}



void AMyComplexActor::Tick(float DeltaTime)

{

    Super::Tick(DeltaTime);

    

    // 每帧移动Actor

    FVector NewLocation = GetActorLocation();

    NewLocation.X += 100.0f * DeltaTime;

    SetActorLocation(NewLocation);



    // 每帧改变光源的颜色

    FLinearColor NewColor = PointLightComponent->GetLightColor();

    NewColor.G = FMath::Fmod(NewColor.G + 0.01f, 1.0f);

    PointLightComponent->SetLightColor(NewColor);

}



void AMyComplexActor::OnComponentHit(UPrimitiveComponent* HitComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit)

{

    // 当发生碰撞时输出一条消息

    UE_LOG(LogTemp, Warning, TEXT("MyComplexActor hit by %s"), *OtherActor->GetName());



    // 当发生碰撞时改变光源的颜色

    PointLightComponent->SetLightColor(FLinearColor::Red);

}

在这个例子中,我们创建了一个包含多个组件的游戏对象 AMyComplexActor,这些组件包括:

  • 静态网格组件(StaticMeshComponent):用于显示静态的3D模型。

  • 碰撞盒组件(BoxComponent):用于处理碰撞检测。

  • 点光源组件(PointLightComponent):用于添加光源。

3.1 静态网格组件

静态网格组件 MeshComponent 被创建并附加到游戏对象的根组件 RootComponent。我们还设置了一个默认的静态网格模型,使其在游戏开始时显示。

3.2 碰撞盒组件

碰撞盒组件 BoxComponent 被创建并附加到静态网格组件 MeshComponent。我们启用了碰撞,并绑定了碰撞事件 OnComponentHit,当发生碰撞时,会输出一条消息并改变光源的颜色。

3.3 点光源组件

点光源组件 PointLightComponent 被创建并附加到碰撞盒组件 BoxComponent。我们设置了光源的颜色为绿色,并在每帧改变其颜色,使其产生动画效果。

4. 游戏对象与组件的交互

游戏对象和组件之间可以通过各种方式交互,以实现更复杂的游戏逻辑。以下是一些常见的交互方式:

  • 设置组件属性:在游戏对象的代码中直接设置组件的属性。

  • 调用组件方法:调用组件的方法来改变其行为。

  • 事件绑定:将组件的事件绑定到游戏对象的方法上,以便在事件发生时执行特定的逻辑。

4.1 设置组件属性

设置组件属性是最常见的交互方式之一。以下是一个例子,展示如何在游戏对象中设置组件的属性:


// MyActor.h

#pragma once



#include "CoreMinimal.h"

#include "GameFramework/Actor.h"

#include "MyActor.generated.h"



UCLASS()

class MYGAME_API AMyActor : public AActor

{

    GENERATED_BODY()

    

public:    

    AMyActor();



protected:

    virtual void BeginPlay() override;



public:    

    virtual void Tick(float DeltaTime) override;



private:

    UPROPERTY(VisibleAnywhere)

    UStaticMeshComponent* MeshComponent;



    UPROPERTY(VisibleAnywhere)

    UPointLightComponent* PointLightComponent;

};


// MyActor.cpp

#include "MyActor.h"

#include "Components/StaticMeshComponent.h"

#include "Components/PointLightComponent.h"



AMyActor::AMyActor()

{

    PrimaryActorTick.bCanEverTick = true;



    MeshComponent = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("MeshComponent"));

    MeshComponent->SetupAttachment(RootComponent);



    PointLightComponent = CreateDefaultSubobject<UPointLightComponent>(TEXT("PointLightComponent"));

    PointLightComponent->SetupAttachment(MeshComponent);



    // 设置默认的静态网格

    static ConstructorHelpers::FObjectFinder<UStaticMesh> MeshAsset(TEXT("/Game/Models/MyModel"));

    if (MeshAsset.Succeeded())

    {

        MeshComponent->SetStaticMesh(MeshAsset.Object);

    }



    // 设置光源的颜色

    PointLightComponent->SetLightColor(FLinearColor::Blue);



    // 设置光源的强度

    PointLightComponent->SetIntensity(500.0f);

}



void AMyActor::BeginPlay()

{

    Super::BeginPlay();

    

    UE_LOG(LogTemp, Warning, TEXT("MyActor has begun play!"));

}



void AMyActor::Tick(float DeltaTime)

{

    Super::Tick(DeltaTime);

    

    // 每帧改变光源的颜色

    FLinearColor NewColor = PointLightComponent->GetLightColor();

    NewColor.B = FMath::Fmod(NewColor.B + 0.01f, 1.0f);

    PointLightComponent->SetLightColor(NewColor);

}

在这个例子中,我们创建了一个静态网格组件和一个点光源组件,并在构造函数中设置了它们的属性。在 Tick 方法中,我们每帧改变光源的颜色。

4.2 调用组件方法

调用组件的方法可以改变其行为或状态。以下是一个例子,展示如何在游戏对象中调用组件的方法:


// MyCharacter.h

#pragma once



#include "CoreMinimal.h"

#include "GameFramework/Character.h"

#include "MyCharacter.generated.h"



UCLASS()

class MYGAME_API AMyCharacter : public ACharacter

{

    GENERATED_BODY()

    

public:    

    AMyCharacter();



protected:

    virtual void BeginPlay() override;



public:    

    virtual void Tick(float DeltaTime) override;



    UFUNCTION()

    void MoveForward(float Value);



private:

    UPROPERTY(VisibleAnywhere)

    USkeletalMeshComponent* SkeletalMeshComponent;



    UPROPERTY(VisibleAnywhere)

    UCameraComponent* CameraComponent;

};


// MyCharacter.cpp

#include "MyCharacter.h"

#include "Components/SkeletalMeshComponent.h"

#include "Components/CameraComponent.h"

#include "GameFramework/CharacterMovementComponent.h"



AMyCharacter::AMyCharacter()

{

    PrimaryActorTick.bCanEverTick = true;



    SkeletalMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("SkeletalMeshComponent"));

    SkeletalMeshComponent->SetupAttachment(RootComponent);



    CameraComponent = CreateDefaultSubobject<UCameraComponent>(TEXT("CameraComponent"));

    CameraComponent->SetupAttachment(RootComponent);

    CameraComponent->SetRelativeLocation(FVector(0.0f, 0.0f, 100.0f));



    // 设置默认的骨骼网格

    static ConstructorHelpers::FObjectFinder<USkeletalMesh> SkeletalMeshAsset(TEXT("/Game/Models/MyCharacterMesh"));

    if (SkeletalMeshAsset.Succeeded())

    {

        SkeletalMeshComponent->SetSkeletalMesh(SkeletalMeshAsset.Object);

    }



    // 设置默认的动画

    static ConstructorHelpers::FObjectFinder<UAnimationAsset> AnimationAsset(TEXT("/Game/Animations/MyAnimation"));

    if (AnimationAsset.Succeeded())

    {

        SkeletalMeshComponent->SetAnimationMode(EAnimationMode::AnimationSingleNode);

        SkeletalMeshComponent->SetAnimation(AnimationAsset.Object);

    }

}



void AMyCharacter::BeginPlay()

{

    Super::BeginPlay();

    

    UE_LOG(LogTemp, Warning, TEXT("MyCharacter has begun play!"));

}



void AMyCharacter::Tick(float DeltaTime)

{

    Super::Tick(DeltaTime);

    

    // 每帧更新角色的位置

    FVector NewLocation = GetActorLocation();

    NewLocation.X += 100.0f * DeltaTime;

    SetActorLocation(NewLocation);

}



void AMyCharacter::MoveForward(float Value)

{

    if (Value != 0.0f)

    {

        // 调用CharacterMovementComponent的方法来移动角色

        AddMovementInput(GetActorForwardVector(), Value);

    }

}

在这个例子中,我们创建了一个骨骼网格组件和一个相机组件。我们还定义了一个 MoveForward 方法,该方法调用 CharacterMovementComponentAddMovementInput 方法来移动角色。

4.3 事件绑定

事件绑定允许你将组件的事件与游戏对象的方法关联起来,以便在事件发生时执行特定的逻辑。以下是一个例子,展示如何在游戏对象中绑定组件的事件:


// MyTriggerActor.h

#pragma once



#include "CoreMinimal.h"

#include "GameFramework/Actor.h"

#include "MyTriggerActor.generated.h"



UCLASS()

class MYGAME_API AMyTriggerActor : public AActor

{

    GENERATED_BODY()

    

public:    

    AMyTriggerActor();



protected:

    virtual void BeginPlay() override;



public:    

    virtual void Tick(float DeltaTime) override;



private:

    UPROPERTY(VisibleAnywhere)

    UBoxComponent* TriggerComponent;



    UPROPERTY(VisibleAnywhere)

    UStaticMeshComponent* MeshComponent;



    void OnTriggerOverlapBegin(UPrimitiveComponent* OverlappedComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);

    void OnTriggerOverlapEnd(UPrimitiveComponent* OverlappedComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex);

};


// MyTriggerActor.cpp

#include "MyTriggerActor.h"

#include "Components/BoxComponent.h"

#include "Components/StaticMeshComponent.h"



AMyTriggerActor::AMyTriggerActor()

{

    PrimaryActorTick.bCanEverTick = true;



    // 创建触发器组件

    TriggerComponent = CreateDefaultSubobject<UBoxComponent>(TEXT("TriggerComponent"));

    TriggerComponent->SetupAttachment(RootComponent);

    TriggerComponent->SetCollisionProfileName(UCollisionProfile::OverlapAllDynamic_ProfileName);



    // 创建静态网格组件

    MeshComponent = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("MeshComponent"));

    MeshComponent->SetupAttachment(TriggerComponent);



    // 绑定触发器事件

    TriggerComponent->OnComponentBeginOverlap.AddDynamic(this, &AMyTriggerActor::OnTriggerOverlapBegin);

    TriggerComponent->OnComponentEndOverlap.AddDynamic(this, &AMyTriggerActor::OnTriggerOverlapEnd);



    // 设置默认的静态网格

    static ConstructorHelpers::FObjectFinder<UStaticMesh> MeshAsset(TEXT("/Game/Models/MyTriggerMesh"));

    if (MeshAsset.Succeeded())

    {

        MeshComponent->SetStaticMesh(MeshAsset.Object);

    }

}



void AMyTriggerActor::BeginPlay()

{

    Super::BeginPlay();

    

    UE_LOG(LogTemp, Warning, TEXT("MyTriggerActor has begun play!"));

}



void AMyTriggerActor::Tick(float DeltaTime)

{

    Super::Tick(DeltaTime);

    

    // 每帧更新Actor的位置

    FVector NewLocation = GetActorLocation();

    NewLocation.X += 100.0f * DeltaTime;

    SetActorLocation(NewLocation);

}



void AMyTriggerActor::OnTriggerOverlapBegin(UPrimitiveComponent* OverlappedComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)

{

    // 当其他Actor进入触发器区域时输出一条消息

    UE_LOG(LogTemp, Warning, TEXT("MyTriggerActor triggered by %s"), *OtherActor->GetName());



    // 改变触发器的颜色

    MeshComponent->SetMaterial(0, nullptr); // 假设你有一个材料可以改变颜色

}



void AMyTriggerActor::OnTriggerOverlapEnd(UPrimitiveComponent* OverlappedComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex)

{

    // 当其他Actor离开触发器区域时输出一条消息

    UE_LOG(LogTemp, Warning, TEXT("MyTriggerActor untriggered by %s"), *OtherActor->GetName());



    // 恢复触发器的颜色

    MeshComponent->SetMaterial(0, nullptr); // 假设你有一个默认材料

}

在这个例子中,我们创建了一个触发器组件 TriggerComponent 和一个静态网格组件 MeshComponent。我们启用了触发器的碰撞,并绑定了 OnComponentBeginOverlapOnComponentEndOverlap 事件。当其他游戏对象进入或离开触发器区域时,我们会输出一条消息并改变触发器的颜色。

5. 总结

在Unreal Engine中,游戏对象和组件是构建游戏的基础。游戏对象是游戏世界中的实体,可以包含多个组件,这些组件负责游戏对象的不同方面。通过设置组件属性、调用组件方法和绑定组件事件,你可以实现复杂的交互和行为。组件的组合使得游戏对象能够执行多种功能,从而构建出丰富多样的游戏世界。

希望这些例子能帮助你更好地理解和使用Unreal Engine中的游戏对象和组件。如果你有任何问题或需要进一步的帮助,请随时查阅Unreal Engine的官方文档或社区资源。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值