mypro334 发表于 2023-4-11 23:10

Unreal Engine 4 道具捡拾教程 C++ 实现

Unreal Engine 4道具捡拾教程 C++ 实现
  物品捡拾是游戏比较常用的功能,这个教程讲解实现简单的物品捡拾的过程。
1、首先新建C++工程,输入好工程名称,注意选择C++页签


2. 先配置一下输入控制。选择Edit->ProjectSettings…


选择左侧Engine下的Input 配置键盘鼠标操作键


右侧显示Engine-Input, 点选Action Mappings 旁边的+号。


将NewActionMaping_0改名为Pickup,点选下面的输入设备选择鼠标右键Right Mouse Button






再增加一个Action Mapping,命名为Inventory, 输入方式设置为键盘I键







到这里输入方法设置完成,用鼠标右键拾取,用I键显示背包内容。
2、现在开始编码。首先创建父类为Actor的C++类Item。





Unreal Engine自动创建好了Item C++类




先编辑一下ItemPickup.Build.cs的内容,避免后面编译错误


public classItemPickup : ModuleRules
{
    public ItemPickup(TargetInfo Target)
    {
      PublicDependencyModuleNames.AddRange(newstring[] { "Core","CoreUObject", "Engine", "InputCore", "HeadMountedDisplay", "GameplayTasks"});
    }
}
主要代码在Item及ItemPickupPlayherController里,下面列出代码内容
Item.h

#include "GameFramework/Actor.h"
#include "Item.generated.h"


class AItemPickupCharacter;
class AItemPickupPlayerController;

UCLASS()
class ITEMPICKUP_API AItem : public AActor
{
    GENERATED_BODY()
   
public:
    // Sets default values for this actor's properties
    AItem();

    // Called when the game starts or when spawned
    virtual void BeginPlay() override;
   
    // Called every frame
    virtual void Tick( float DeltaSeconds ) override;

    UShapeComponent* TBox;
   
    UPROPERTY(EditAnyWhere)
      UStaticMeshComponent* SM_TBox;

    AItemPickupCharacter* MyPlayerController;

    AItemPickupPlayerController* PlCtl;

    UPROPERTY(EditAnyWhere)
      FString ItemName =FString(TEXT(""));

    void Pickup();

    void GetPlayer(AActor*Player);

    bool bItemIsWithinRange;

    UFUNCTION()
      void TriggerEnter(class UPrimitiveComponent*MyComp,class AActor * OtherActor,class UPrimitiveComponent*OtherComp,int32 OtherBodyIndex, bool bFromSweep,const FHitResult & SweepResult);

    UFUNCTION()
      void TriggerExit(class UPrimitiveComponent*MyComp,class AActor * OtherActor,class UPrimitiveComponent* OtherComp,int32OtherBodyIndex);

};

Item.cpp

// Fill out your copyright notice in theDescription page of Project Settings.

#include "ItemPickup.h"
#include "Item.h"
#include "Engine.h"

#include "ItemPickupCharacter.h"
#include "ItemPickupPlayerController.h"

// Sets default values
AItem::AItem()
{
    // Set this actor tocall Tick() every frame.You can turnthis off to improve performance if you don't need it.
    PrimaryActorTick.bCanEverTick= true;

    TBox=CreateDefaultSubobject<UBoxComponent>(TEXT("Box"));
    TBox->bGenerateOverlapEvents= true;
    TBox->OnComponentBeginOverlap.AddDynamic(this, &AItem::TriggerEnter);
    TBox->OnComponentEndOverlap.AddDynamic(this, &AItem::TriggerExit);
   
    RootComponent= TBox;

    SM_TBox =CreateDefaultSubobject<UStaticMeshComponent>(TEXT("BoxMesh"));

    SM_TBox->SetupAttachment(RootComponent);
}

// Called when the game starts or when spawned
void AItem::BeginPlay()
{
    Super::BeginPlay();
   
}

// Called every frame
void AItem::Tick( float DeltaTime )
{
    Super::Tick( DeltaTime );
    if (MyPlayerController != NULL)
    {
      PlCtl= Cast<AItemPickupPlayerController>(MyPlayerController->GetController());
      if (PlCtl->bIsPickingUP && bItemIsWithinRange)
      {
            Pickup();
      }
    }
}

void AItem::Pickup()
{
    PlCtl =Cast<AItemPickupPlayerController>(MyPlayerController->GetController());
    PlCtl->Inventory.Add(*ItemName);
    GEngine->AddOnScreenDebugMessage(1,5.f, FColor::Green,TEXT("Pick Up the Item"));
    Destroy();
}

void AItem::GetPlayer(AActor * Player)
{
    MyPlayerController= Cast<AItemPickupCharacter>(Player);
}

void AItem::TriggerEnter(class UPrimitiveComponent*MyComp, class AActor * OtherActor, classUPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult & SweepResult)
{
    bItemIsWithinRange= true;

    GEngine->AddOnScreenDebugMessage(1,5.f,FColor::Green,FString::Printf(TEXT("Press Mouse Right ButtonTo Pickup %s"),*ItemName));

    GetPlayer(OtherActor);
}

void AItem::TriggerExit(class UPrimitiveComponent*MyComp, class AActor * OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex)
{
    bItemIsWithinRange= false;
}

ItemPickupPlayerController.h

// Copyright 1998-2016 Epic Games, Inc. All RightsReserved.
#pragma once
#include "GameFramework/PlayerController.h"
#include "ItemPickupPlayerController.generated.h"

UCLASS()
class AItemPickupPlayerController : public APlayerController
{
    GENERATED_BODY()

public:
    AItemPickupPlayerController();

protected:
    /** True if the controlled character should navigate to the mouse cursor.*/
    uint32 bMoveToMouseCursor : 1;

    // Begin PlayerController interface
    virtual void PlayerTick(float DeltaTime) override;
    virtual void SetupInputComponent() override;
    // End PlayerController interface

    /** Resets HMD orientation in VR. */
    void OnResetVR();

    /** Navigate player to the current mouse cursor location. */
    void MoveToMouseCursor();

    /** Navigate player to the current touch location. */
    void MoveToTouchLocation(constETouchIndex::Type FingerIndex,const FVector Location);
   
    /** Navigate player to the given world location. */
    void SetNewMoveDestination(constFVector DestLocation);

    /** Input handlers for SetDestination action. */
    void OnSetDestinationPressed();
    void OnSetDestinationReleased();

    void BeginPickup();
   
    void EndPickup();

    void ShowInventory();

public:
    bool bIsPickingUP = false;

    TArray<FString>Inventory;

};




ItemPickupPlayerController.cpp

// Copyright 1998-2016 Epic Games, Inc. All RightsReserved.

#include "ItemPickup.h"
#include "ItemPickupPlayerController.h"
#include "AI/Navigation/NavigationSystem.h"
#include "Runtime/Engine/Classes/Components/DecalComponent.h"
#include "Kismet/HeadMountedDisplayFunctionLibrary.h"
#include "ItemPickupCharacter.h"
#include "Engine.h"

AItemPickupPlayerController::AItemPickupPlayerController()
{
    bShowMouseCursor= true;
    DefaultMouseCursor= EMouseCursor::Crosshairs;
}

void AItemPickupPlayerController::PlayerTick(floatDeltaTime)
{
    Super::PlayerTick(DeltaTime);

    // keep updating the destination every tick while desired
    if (bMoveToMouseCursor)
    {
      MoveToMouseCursor();
    }
}

void AItemPickupPlayerController::SetupInputComponent()
{
    // set up gameplay key bindings
    Super::SetupInputComponent();

    InputComponent->BindAction("SetDestination",IE_Pressed, this, &AItemPickupPlayerController::OnSetDestinationPressed);
    InputComponent->BindAction("SetDestination",IE_Released, this, &AItemPickupPlayerController::OnSetDestinationReleased);

    // support touch devices
    InputComponent->BindTouch(EInputEvent::IE_Pressed,this, &AItemPickupPlayerController::MoveToTouchLocation);
    InputComponent->BindTouch(EInputEvent::IE_Repeat,this, &AItemPickupPlayerController::MoveToTouchLocation);

    InputComponent->BindAction("ResetVR",IE_Pressed, this, &AItemPickupPlayerController::OnResetVR);

    //Set Pickup Callback
    InputComponent->BindAction("Pickup",IE_Pressed, this, &AItemPickupPlayerController::BeginPickup);
    InputComponent->BindAction("Pickup",IE_Released, this, &AItemPickupPlayerController::EndPickup);

    InputComponent->BindAction("Inventory",IE_Pressed, this, &AItemPickupPlayerController::ShowInventory);
}

void AItemPickupPlayerController::OnResetVR()
{
    UHeadMountedDisplayFunctionLibrary::ResetOrientationAndPosition();
}

void AItemPickupPlayerController::MoveToMouseCursor()
{
    if (UHeadMountedDisplayFunctionLibrary::IsHeadMountedDisplayEnabled())
    {
      if (AItemPickupCharacter* MyPawn= Cast<AItemPickupCharacter>(GetPawn()))
      {
            if (MyPawn->GetCursorToWorld())
            {
                UNavigationSystem::SimpleMoveToLocation(this, MyPawn->GetCursorToWorld()->GetComponentLocation());
            }
      }
    }
    else
    {
      // Trace to see what is under the mouse cursor
      FHitResult Hit;
      GetHitResultUnderCursor(ECC_Visibility,false, Hit);

      if (Hit.bBlockingHit)
      {
            // We hit something, move there
            SetNewMoveDestination(Hit.ImpactPoint);
      }
    }
}

void AItemPickupPlayerController::MoveToTouchLocation(constETouchIndex::TypeFingerIndex, constFVector Location)
{
    FVector2D ScreenSpaceLocation(Location);

    // Trace to see what is under the touch location
    FHitResult HitResult;
    GetHitResultAtScreenPosition(ScreenSpaceLocation,CurrentClickTraceChannel,true,HitResult);
    if (HitResult.bBlockingHit)
    {
      // We hit something, move there
      SetNewMoveDestination(HitResult.ImpactPoint);
    }
}

void AItemPickupPlayerController::SetNewMoveDestination(constFVector DestLocation)
{
    APawn* const MyPawn= GetPawn();
    if (MyPawn)
    {
      UNavigationSystem*const NavSys = GetWorld()->GetNavigationSystem();
      float const Distance = FVector::Dist(DestLocation,MyPawn->GetActorLocation());

      // We need to issue move command only if far enough in order for walkanimation to play correctly
      if (NavSys && (Distance > 120.0f))
      {
            NavSys->SimpleMoveToLocation(this,DestLocation);
      }
    }
}

void AItemPickupPlayerController::OnSetDestinationPressed()
{
    // set flag to keep updating destination until released
    bMoveToMouseCursor= true;
}

void AItemPickupPlayerController::OnSetDestinationReleased()
{
    // clear flag to indicate we should stop updating the destination
    bMoveToMouseCursor= false;
}

void AItemPickupPlayerController::BeginPickup()
{
    GEngine->AddOnScreenDebugMessage(-1,5.f,FColor::Blue,TEXT("Begin Pickup"));
    bIsPickingUP= true;
}

void AItemPickupPlayerController::EndPickup()
{
    GEngine->AddOnScreenDebugMessage(-1,5.f, FColor::Blue, TEXT("End Pickup"));
    bIsPickingUP= false;
}

void AItemPickupPlayerController::ShowInventory()
{
    GEngine->AddOnScreenDebugMessage(-1,5.f, FColor::Blue, TEXT("Show Inventory"));
    for (auto& Item : Inventory)
    {
      GEngine->AddOnScreenDebugMessage(-1,5.f, FColor::Blue, FString::Printf(TEXT("Item: %s"),*Item));
    }
}
3、基于Item创建Blueprint 对象,先在Content主目录下创建一个Pickup子目录


建立New Folder, 命名为Pickup



在C++ Classes 下的ItemPickup找到Item对象,点鼠标右键选择Create Blueprint class based on Item.


命名为BP_PickItem,选择存放在Pickup下。


4、编辑BP_PickItem,首先要为BP_PickItem创建一个Mesh,先选中RootComponent,然后点击Add Component




出现下拉列表后选择Static Mesh



命名为PickBox



选中PickBox,在右侧Static Mesh选中SM_Rock模型



缩小一下这个模型


选择编译Compile并存储一下,完成后关闭这个窗口。


6、将这个BP_PickItem拖拽到场景中。


将ItemPickup及ItemPickup1分别命名为Box1和Box2




7、编译一下游戏,选择运行游戏,移动到拾取物体上,按鼠标右键。


物品消失,被我们拾取到了。



按I键,显示背包内容。


8、这个教程比较相对比较简单,主要目的是理解如果用C++实现游戏的简单交互。
页: [1]
查看完整版本: Unreal Engine 4 道具捡拾教程 C++ 实现