学习虚幻C++开发日志——基础案例

官方文档:虚幻引擎C++编程教程 | 虚幻引擎 5.5 文档 | Epic Developer Community | Epic Developer Community

提前告知(文章也有告知):对于创建新的类其初始具有的函数如果需对其进行override则需要进行SUPER:: 

1.物体上下起伏并旋转 

1.1第一种写法

创建一个继承于Actor的类,并为新的Actor命名为FloatingActor,然后点击Create Class

重新加载代码文件

在Games->(用户自定义工程文件名)->Source->FloatingActor.h

在头文件添加代码

public:	
	// 设置构造默认函数
	AFloatingActor();

	UPROPERTY(VisibleAnywhere)
//使用继承于UObject的指针UStaticMeshComponent*
	UStaticMeshComponent* VisualMesh;

在源文件:

//设置默认值
AFloatingActor::AFloatingActor()
{
	//将设置为每帧调用Tick()。如果你不需要它,你可以关闭它来提高性能。
	PrimaryActorTick.bCanEverTick = true;

    //创建Object,可在蓝图details查看
	VisualMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Mesh"));
	VisualMesh->SetupAttachment(RootComponent);//根组件
	//根组件另一种写法:RootComponent = VisualMesh;
	
	//不推荐此写法
	//静态网格体Copy Reference:/Script/Engine.StaticMesh'/Game/StarterContent/Shapes/Shape_Cone.Shape_Cone'
	static ConstructorHelpers::FObjectFinder<UStaticMesh> CubeVisualAsset(TEXT("/Game/StarterContent/Shapes/Shape_Cone.Shape_Cone"));

    //判断是否初始化成功
	if (CubeVisualAsset.Succeeded())
	{
		VisualMesh->SetStaticMesh(CubeVisualAsset.Object);
		VisualMesh->SetRelativeLocation(FVector(0.0f, 0.0f, 0.0f));
	}
}


void AFloatingActor::BeginPlay()
{
	Super::BeginPlay();
	//注意BeginPlay一定要调用Super::BeginPlay()
}


//调用每一帧
void AFloatingActor::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

    //初始化
	FVector NewLocation = GetActorLocation();
	FRotator NewRotation = GetActorRotation();
	float RunningTime = GetGameTimeSinceCreation();//得到在世界的时间从创建开始
	float DeltaHeight = (FMath::Sin(RunningTime + DeltaTime) - FMath::Sin(RunningTime));  //设置高度变化呈现正弦曲线变化
    float DeltaRotation = DeltaTime * 20.0f;	//Rotate by 20 degrees per second旋转变化	
    
    NewLocation.Z += DeltaHeight * 20.0f;       //高度变化,系数放大20倍
	NewRotation.Yaw += DeltaRotation;

	SetActorLocationAndRotation(NewLocation, NewRotation);
}

最后在编辑器创建蓝图子类,并将子类拖进场景即可。(下面示例最后一步与此操作相同就不在说明)

思路:在默认构造函数初始化网格体,运用引擎内置函数SetStaticMesh和SetRelativeLocation。在Tick时间函数内先初始化状态信息,并运用数学函数改变状态数值,最后用SetActorLocationAndRotation函数实现Actor位置变化。

1.2第二种写法(初始化网格体)

在上述头文件添加新的代码 :

public:
	UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Name")
	UStaticMesh* NewMesh;

	UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "FloatingActor")
	float FloatSpeed = 20.0f;

	UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "FloatingActor")
	float RotationSpeed = 20.0f;	

此写法是运用宏从而在蓝图进行快速修改 

从而不需要前一种方法默认构造函数的指定网格体的写法:

	//静态网格体Copy Reference:/Script/Engine.StaticMesh'/Game/StarterContent/Shapes/Shape_Cone.Shape_Cone'
	static ConstructorHelpers::FObjectFinder<UStaticMesh> CubeVisualAsset(TEXT("/Game/StarterContent/Shapes/Shape_Cone.Shape_Cone"));

在源文件的BeginPlay()函数处代码:

void AFloatingActor::BeginPlay()
{
	Super::BeginPlay();
	//注意BeginPlay一定要调用Super::BeginPlay()

    //将原默认构造函数的判断放在这里
	if (NewMesh)
	{
		VisualMesh->SetStaticMesh(NewMesh);
		VisualMesh->SetRelativeLocation(FVector(0.0f, 0.0f, 0.0f));
	}
}

2.相机自动切换

2.1第一种自定义相机切换

创建一个继承于Actor的类,并为新的Actor命名为LearnGameCamera,然后点击Create Class

重新加载代码文件

在Games->(用户自定义工程文件名)->Source->LearnGameCamera.h

在头文件添加代码

protected:
	UPROPERTY(EditAnywhere, Category = "learn")
	AActor* CameraOne;

	UPROPERTY(EditAnywhere, Category = "learn")
	AActor* CameraTwo;

	float TimeToNextCameraChange=0.f;

使用宏可以在details进行相机绑定

在源文件的Tick()函数处代码(引用帧参数):

注意Tick函数需要Super!

// Called every frame
void ALearnGameCamera::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);
	const float TimeBetweenCameraChanges = 2.0f;//硬编码写法,在摄像机停留2s
	const float SmoothBlendTime = 0.75f;// 视图混合平滑切换时间
	TimeToNextCameraChange -= DeltaTime;

    //下次更换相机的时间(判断是否触发相机切换机制)
	if (TimeToNextCameraChange <= 0.0f) 
	{
		TimeToNextCameraChange += TimeBetweenCameraChanges;

		//查找本地玩家控制的Actor
		APlayerController* OurPlayerController = UGameplayStatics::GetPlayerController(this, 0);
        判断玩家是否存在
		if (OurPlayerController)
		{
            //视角不是摄像机1的视角且摄像机1不是空指针
			if((OurPlayerController->GetViewTarget()!=CameraOne)&&(CameraOne!=nullptr))
			{
				//立即切换到摄像机1
				OurPlayerController->SetViewTarget(CameraOne);
			}
			else if ((OurPlayerController->GetViewTarget() != CameraTwo) && (CameraTwo != nullptr))
			{
				//平滑切换到摄像机2
				OurPlayerController->SetViewTargetWithBlend(CameraTwo, SmoothBlendTime);
			}
		}
	}
}

思路:在C++代码进行相机定义,用蓝图宏去将其暴露,从而可在details进行相机绑定,用自定义的浮点数TimeToNextCameraChange去判断是否可以触发相机切换,运用UGameplayStatics的GetPlayerController(const UObject* WorldContextObject, int32 PlayerIndex) 进行查找玩家是否存在,如果存在进一步用GetViewTarget()函数判断视角是否为指定的相机且相机指针要存在。切换到另一个相机用SetViewTargetWithBlend()函数进行切换。

引擎源码函数片段

GetPlayerController():

GetViewTarget():

SetViewTargetWithBlend():

 2.2遍历场景中的摄影机并依次显示

创建一个继承于Actor的类,并为新的Actor命名为LearnCameraDiectorModify,然后点击Create Class

重新加载代码文件

在Games->(用户自定义工程文件名)->Source->LearnCameraDiectorModify

在头文件添加代码

//定义结构体,用于后面容器存放摄像机的指针
USTRUCT()
struct FLearnToggleCamerInfo 
{
	GENERATED_BODY()
public:
	UPROPERTY(EditAnywhere, Category = "learn")
	AActor* CameraOne = nullptr;

	UPROPERTY(EditAnywhere, Category = "learn")
	float CameraBlendTime = 0.2f;//作为切换时间0.2s
};

//在类内添加
private:
    //用容器存放摄像机指针
	TArray<FLearnToggleCamerInfo>CameraInfoList;
	float TimeToNextCameraChange = 0.f;

    //定义摄像机的索引
	int32 CameraIndex = 0;

在源文件的BeginPlay()函数处代码:

注意BeginPlay函数需要Super!

void ALearnCameraDirectorModify::BeginPlay()
{
	Super::BeginPlay();
    //存放摄像机
	TArray<AActor*>MyCameraActors;
    //获取ACameraActor类的对象然后将其输入到自定义的MyCameraActors容器
	UGameplayStatics::GetAllActorsOfClass(this,ACameraActor::StaticClass(),MyCameraActors);

	CameraInfoList.Empty();//容器元素清空初始化,但索引还在

	//下列代码可以单独抽取出来作为一个方法更新场景里相机信息
	check(MyCameraActors.Num() > 1);//用check判断如果不成立则用崩溃报错

    //遍历场景摄像机并给其添加索引
	for(int32 Index=0;Index<MyCameraActors.Num();Index++)
	{
        //向 CameraInfoList 添加一个新元素,并使用 FLearnToggleCamerInfo引用进行初始化。
		FLearnToggleCamerInfo& CameraInfo = CameraInfoList.AddDefaulted_GetRef();
		CameraInfo.CameraOne = MyCameraActors[Index];
	}
}

在源文件的Tick()函数处代码(引用帧参数):

注意Tick函数需要Super!

void ALearnCameraDirectorModify::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);
	const float TimeBetweenCameraChanges = 2.0f;//硬编码写法,在摄像机停留2s
	TimeToNextCameraChange -= DeltaTime;
	if (TimeToNextCameraChange <= 0.0f) 
	{
		TimeToNextCameraChange += TimeBetweenCameraChanges;
		++CameraIndex;
		if (CameraIndex > CameraInfoList.Num() - 1)//判断是否超出最大值 
		{
			CameraIndex = 0;//索引为0,再次重新进入循环
		}
	}
	//查找本地玩家控制的Actor
	APlayerController* OurPlayerController = UGameplayStatics::GetPlayerController(this, 0);

    //运用结构体,通过索引进行相机指定
	AActor* NextCamera = CameraInfoList[CameraIndex].CameraOne;
	float NextBlendTime = CameraInfoList[CameraIndex].CameraBlendTime;

	//判断玩家和相机是否存在
	if(OurPlayerController&&NextCamera)//此处也可以这样写(OurPlayerController->GetViewTarget()!=NextCamera)&&(NextCamera!=nullptr)
	{
		OurPlayerController->SetViewTargetWithBlend(NextCamera, NextBlendTime);
	}
}

获取场景摄像机思路:用结构体存放摄像机的指针,用TArray容器存放多个自定义结构体,并在BeginPlay函数内部创建TArray容器存放AActor*元素,通过GetAllActorsOfClass()获取ACameraActor类的对象然后将其输入到自定义存放AActor*元素的容器,然后用for循环,用FLearnToggleCamerInfo的类型的引用来获取CameraInfoLis容器t的索引,从而CameraInfo.CameraOne = MyCameraActors[Index]依次赋值

引擎源码函数片段

 GetAllActorsOfClass()

 AddDefaulted_GetRef()

3.控制摄像机(放大、缩小、旋转、同时控制Pawn移动)

3.1第一种写法(全部动作在一个类实现) 

先在编辑器进行映射绑定

Edit->Project Setting->Input(Engine)

注意:在MoveForward中-1.0表示反方向。 

创建一个继承于Pawn的类,并为新的Actor命名为LearnPawnWithCamera,然后点击Create Class

重新加载代码文件

在Games->(用户自定义工程文件名)->Source->LearnPawnWithCamera.h

在头文件添加代码

protected:
	// 输入函数(呈现承前启后的作用)处理动作映射
	void MoveForward(float AxisValue);
	void MoveRight(float AxisValue);
	void PitchCamera(float AxisValue);//摄像机俯仰
	void YawCamera(float AxisValue);//摄像机左右旋转
	void ZoomIn();
	void ZoomOut();

protected:
    //对相机进行初始化定义
	//前向声明class可以避免头文件重复而导致的冲突,或者在UCLASS()上一行加class UStaticMeshComponent,这样就不用在UStaticMeshComponent前加class
	UPROPERTY(EditAnywhere)
	class UStaticMeshComponent* StaticMeshComp;

	UPROPERTY(EditAnywhere)
	class USpringArmComponent* SpringArmComp;

	UPROPERTY(EditAnywhere)
	class UCameraComponent* CameraComp;

	//输入变量
	FVector2D MovementInput;
	FVector2D CameraInput;
	float ZoomFactor=1.0f;
	bool bZoomingIn=false;
};

在类源文件中:

//添加头文件
#include "PlayerCamera/LearnPawnWithCamera.h"
#include "GameFramework/SpringArmComponent.h"
#include "Camera/CameraComponent.h"
#include"Components/StaticMeshComponent.h"
#include "LearnPawnWithCamera.h"

对函数声明

//对映射事件进行定义(此处还没与之前在编辑器设置的Input有关),此处只是对我们所命名的函数进行定义。
void ALearnPawnWithCamera::MoveForward(float AxisValue)
{
	MovementInput.X = FMath::Clamp<float>(AxisValue, -1.0f, 1.0f);
}

void ALearnPawnWithCamera::MoveRight(float AxisValue)
{
	MovementInput.Y = FMath::Clamp<float>(AxisValue, -1.0f, 1.0f);
}

void ALearnPawnWithCamera::PitchCamera(float AxisValue)
{
	CameraInput.Y = AxisValue;
}

void ALearnPawnWithCamera::YawCamera(float AxisValue)
{
	CameraInput.X = AxisValue;
}

void ALearnPawnWithCamera::ZoomIn()
{
	bZoomingIn = true;
}

void ALearnPawnWithCamera::ZoomOut()
{
	bZoomingIn = false;
}

将函数与我们在Input中设置的操作进行绑定: 

注意SetupPlayerInputComponent()函数需要Super!

void ALearnPawnWithCamera::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	Super::SetupPlayerInputComponent(PlayerInputComponent);

//承前操作{
	// 绑定"ZoomIn"的事件
	InputComponent->BindAction("ZoomIn", IE_Pressed, this, &ALearnPawnWithCamera::ZoomIn);
	InputComponent->BindAction("ZoomOut", IE_Released, this, &ALearnPawnWithCamera::ZoomOut);

	//为四条轴绑定事件(每帧调用)
	InputComponent->BindAxis("MoveForward", this, &ALearnPawnWithCamera::MoveForward);
	InputComponent->BindAxis("MoveRight", this, &ALearnPawnWithCamera::MoveRight);
	InputComponent->BindAxis("CameraPitch", this, &ALearnPawnWithCamera::PitchCamera);
	InputComponent->BindAxis("CameraYaw", this, &ALearnPawnWithCamera::YawCamera);
//}
}

此处绑定运用到引擎源码模板BindAxis(),观察此处的参数与我们在Input的命名,然后去看源码以理解参数。

 在Tick()函数进行调用

注意Tick函数需要Super!

void ALearnPawnWithCamera::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

	//如果按下了放大按钮则放大,否则就缩小(启后的操作)

	if (bZoomingIn)
	{
		ZoomFactor += DeltaTime /0.5f;			//Zoom in over half a second
	}
	else
	{
		ZoomFactor -= DeltaTime /0.25f;		//Zoom out over a quarter of a second
	}
	ZoomFactor = FMath::Clamp<float>(ZoomFactor, 0.0f, 1.0f);//放大缩小视角限制

	//根据ZoomFactor来设置摄像机的视场和弹簧臂的长度
	CameraComp->FieldOfView = FMath::Lerp<float>(90.0f, 60.0f, ZoomFactor);
	SpringArmComp->TargetArmLength = FMath::Lerp<float>(400.0f, 300.0f, ZoomFactor);

    //此处花括号不能省去,否则会报错
	{
		//旋转Actor的偏转角度,这样摄像机也能旋转,因为摄像机与Actor相互绑定
		FRotator NewRotation = GetActorRotation();
		NewRotation.Yaw += CameraInput.X;
		SetActorRotation(NewRotation);
	}

	{
		// 旋转摄像机的俯仰角度,但要对其进行限制,这样我们就能始终俯视Actor
		FRotator NewRotation = SpringArmComp->GetComponentRotation();
		NewRotation.Pitch = FMath::Clamp(NewRotation.Pitch + CameraInput.Y, -80.0f, -15.0f);
		SpringArmComp->SetWorldRotation(NewRotation);
	}
	
	// 基于"MoveX"和 "MoveY"坐标轴来处理移动
	{
		if (!MovementInput.IsZero())
		{
			// 把移动轴的输入数值放大100倍
			MovementInput = MovementInput.GetSafeNormal() * 100.0f;
			FVector NewLocation = GetActorLocation();
			NewLocation += GetActorForwardVector() * MovementInput.X * DeltaTime;
			NewLocation += GetActorRightVector() * MovementInput.Y * DeltaTime;
			SetActorLocation(NewLocation);
		}
	}
}

此操作相当于三部分“声明——绑定——调用”(调用为承上启下的作用)

最后对相机组件进行定义:

ALearnPawnWithCamera::ALearnPawnWithCamera()
{
 	// Set this pawn to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

	//创建组件实例
	RootComponent = CreateDefaultSubobject<USceneComponent>(TEXT("RootComponent"));
	StaticMeshComp = CreateDefaultSubobject <UStaticMeshComponent>(TEXT("MeshComponent"));
	SpringArmComp = CreateDefaultSubobject<USpringArmComponent>(TEXT("SpringArmComponent"));
	CameraComp = CreateDefaultSubobject<UCameraComponent>(TEXT("CameraComponent"));

	//绑定组件,注意其之间的联系
	//在细节(Details)/子类蓝图处:LearnPawnWithCamera(Instance)->RootComponent(RootComponent)->StaticMeshComp(MeshComponent)->SpringArmComp(SpringArmComponent)->CameraComp(CameraComponent)
	StaticMeshComp->SetupAttachment(RootComponent);
	SpringArmComp->SetupAttachment(StaticMeshComp);
	CameraComp->SetupAttachment(SpringArmComp, USpringArmComponent::SocketName);

	//为SpringArm类的变量赋值。(设置弹簧臂)
	SpringArmComp->SetRelativeLocationAndRotation(FVector(0.0f, 0.0f, 50.0f), FRotator(-60.0f, 0.0f, 0.0f));//注意-60.f为Y轴
	SpringArmComp->TargetArmLength = 400.f;
	SpringArmComp->bEnableCameraLag = true;
	SpringArmComp->CameraLagSpeed = 3.0f;//延迟3s

	//控制默认玩家
	AutoPossessPlayer = EAutoReceiveInput::Player0;

}

此操作可在蓝图进行查看或修改:

思路:对摄像机进行属性定义,对移动映射进行定义绑定调用。

引擎源码片段

BindAction()

BindAxis()

FMath::Clamp<float>()

 FMath::Lerp<float>()

3.2将处理函数独立出来作为一个组件类 (功能多了一个空格显示特效)

先在编辑器进行映射绑定

Edit->Project Setting->Input(Engine)

注意:在MoveForward中-1.0表示反方向。 

创建一个继承于Pawn的类,并为新的Actor命名为LearnCollisionPawn,然后点击Create Class

重新加载代码文件

在Games->(用户自定义工程文件名)->Source->LearnCollisionPawn.h

LearnCollisionPawn头文件添加代码

public:
	virtual UPawnMovementComponent* GetMovementComponent() const override;

public:	
	UPROPERTY()
	class UParticleSystemComponent* OurParticleSystem;
	UPROPERTY()
	class UCollisionPawnMovementComponent* OurMovementComponent;

	//绑定方法
	void MoveForward(float AxisValue);
	void MoveRight(float AxisValue);
	void Turn(float AxisValue);
	void ParticleToggle();

创建一个继承于PawnMovementComponent的类,并为新的PawnMovementComponent命名为CollisionPawnMovementComponent,然后点击Create Class

重新加载代码文件

在Games->(用户自定义工程文件名)->Source->CollisionPawnMovementComponent.h

在CollisionPawnMovementComponent头文件添加代码:

public:
	UPROPERTY()
	class UParticleSystemComponent* OurParticleSystem;

	UPROPERTY()
	class UCollisionPawnMovementComponent* OurMovementComponent;

此组件相当于第一种写法示例的“处理函数”。

 注意TickComponent函数需要Super!

//此函数相当于一个处理组件
void UCollisionPawnMovementComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
	Super::TickComponent(DeltaTime, TickType, ThisTickFunction);

	// 确保所有事物持续有效,以便进行移动。
	if (!PawnOwner || !UpdatedComponent || ShouldSkipUpdate(DeltaTime))
	{
		return;
	}

	// 获取(然后清除)ACollidingPawn::Tick中设置的移动向量
	FVector DesiredMovementThisFrame = ConsumeInputVector().GetClampedToMaxSize(1.0f) * DeltaTime * 150.0f;
	if (!DesiredMovementThisFrame.IsNearlyZero())
	{
		FHitResult Hit;
		SafeMoveUpdatedComponent(DesiredMovementThisFrame, UpdatedComponent->GetComponentRotation(), true, Hit);

		// 若发生碰撞,尝试滑过去
		if (Hit.IsValidBlockingHit())
		{
			SlideAlongSurface(DesiredMovementThisFrame, 1.f - Hit.Time, Hit.Normal, Hit);
		}
	}
}

 在LearnCollisionPawn类源文件中,先确保组件头文件存在

#include "ComponentAndCollision/LearnCollisionPawn.h"
#include "UObject/ConstructorHelpers.h"
#include "Particles/ParticleSystemComponent.h"
#include "Components/SphereComponent.h"
#include "Camera/CameraComponent.h"
#include "GameFramework/SpringArmComponent.h"
#include"CollisionPawnMovementComponent.h"

在 LearnCollisionPawn类源文件中,先在默认构造函数进行网格体、摄像机、粒子系统等声明定义

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

	// 根组件将成为对物理反应的球体(此写法没有在头文件声明,不建议这样写)
	USphereComponent* SphereComponent = CreateDefaultSubobject<USphereComponent>(TEXT("RootComponent"));
	RootComponent = SphereComponent;
	SphereComponent->InitSphereRadius(40.0f);
	SphereComponent->SetCollisionProfileName(TEXT("Pawn"));

	// 创建并放置网格体组件,以便查看球体位置
	UStaticMeshComponent* SphereVisual = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("VisualRepresentation"));
	SphereVisual->SetupAttachment(RootComponent);

	//基于硬编码的资产路径一般不太推荐,例如这个示例中的球体静态网格体的路径;
	static ConstructorHelpers::FObjectFinder<UStaticMesh> SphereVisualAsset(TEXT("/Game/StarterContent/Shapes/Shape_Sphere.Shape_Sphere"));
	
	if (SphereVisualAsset.Succeeded())
	{
		SphereVisual->SetStaticMesh(SphereVisualAsset.Object);
		SphereVisual->SetRelativeLocation(FVector(0.0f, 0.0f, -40.0f));
		SphereVisual->SetWorldScale3D(FVector(0.8f));
	}

	// 创建可激活或停止的粒子系统
	OurParticleSystem = CreateDefaultSubobject<UParticleSystemComponent>(TEXT("MovementParticles"));
	OurParticleSystem->SetupAttachment(SphereVisual);
	OurParticleSystem->bAutoActivate = false;
	OurParticleSystem->SetRelativeLocation(FVector(-20.0f, 0.0f, 20.0f));
	static ConstructorHelpers::FObjectFinder<UParticleSystem> ParticleAsset(TEXT("/Game/StarterContent/Particles/P_Fire.P_Fire"));
	if (ParticleAsset.Succeeded())
	{
		OurParticleSystem->SetTemplate(ParticleAsset.Object);
	}

	// 使用弹簧臂给予摄像机平滑自然的运动感。
	USpringArmComponent* SpringArm = CreateDefaultSubobject<USpringArmComponent>(TEXT("CameraAttachmentArm"));
	SpringArm->SetupAttachment(RootComponent);
	SpringArm->SetRelativeRotation(FRotator(-45.f, 0.f, 0.f));
	SpringArm->TargetArmLength = 400.0f;
	SpringArm->bEnableCameraLag = true;
	SpringArm->CameraLagSpeed = 3.0f;

	// 创建摄像机并附加到弹簧臂
	UCameraComponent* Camera = CreateDefaultSubobject<UCameraComponent>(TEXT("ActualCamera"));
	Camera->SetupAttachment(SpringArm, USpringArmComponent::SocketName);

	// 创建移动组件的实例,并要求其更新根组件。
	OurMovementComponent = CreateDefaultSubobject<UCollisionPawnMovementComponent>(TEXT("CustomMovementComponent"));
	OurMovementComponent->UpdatedComponent = RootComponent;

	// 控制默认玩家
	AutoPossessPlayer = EAutoReceiveInput::Player0;
}

同时对移动函数进行声明定义

void ALearnCollisionPawn::MoveForward(float AxisValue)
{
	if (OurMovementComponent && (OurMovementComponent->UpdatedComponent == RootComponent))
	{
		OurMovementComponent->AddInputVector(GetActorForwardVector() * AxisValue);
	}
}

void ALearnCollisionPawn::MoveRight(float AxisValue)
{
	if (OurMovementComponent && (OurMovementComponent->UpdatedComponent == RootComponent))
	{
		OurMovementComponent->AddInputVector(GetActorRightVector() * AxisValue);
	}
}

void ALearnCollisionPawn::Turn(float AxisValue)
{
	FRotator NewRotation = GetActorRotation();
	NewRotation.Yaw += AxisValue;
	SetActorRotation(NewRotation);
}

//粒子系统
void ALearnCollisionPawn::ParticleToggle()
{
	if (OurParticleSystem && OurParticleSystem->Template)
	{
		OurParticleSystem->ToggleActive();
	}
}

然后进行移动映射绑定:

// Called to bind functionality to input
void ALearnCollisionPawn::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	Super::SetupPlayerInputComponent(PlayerInputComponent);

	//作为中间连接
	PlayerInputComponent->BindAction("ParticleToggle", IE_Pressed, this, &ALearnCollisionPawn::ParticleToggle);
	PlayerInputComponent->BindAxis("MoveForward", this, &ALearnCollisionPawn::MoveForward);
	PlayerInputComponent->BindAxis("MoveRight", this, &ALearnCollisionPawn::MoveRight);
	PlayerInputComponent->BindAxis("Turn", this, &ALearnCollisionPawn::Turn);
}

对获取移动组件添加返回值即可

UPawnMovementComponent* ALearnCollisionPawn::GetMovementComponent() const
{
	return OurMovementComponent;
}

大致思路和第一种写法类似,只是将移动处理函数独立出来作为移动组件,这种做法使得多个类可使用此移动组件。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值