本文將介紹用C++實現一個簡單的玩家可通過WASD控制移動,Shift進行加速,鼠標控制視角旋轉和縮放的小球。
本人也只是一個UE4初學者,大佬勿噴。
一、技術難點
- 小球通過角速度控制旋轉,因此想實現自由視角相機,它就不能作爲小球的子物體。
- 小球的移動方向始終要保持與視野前方相同。
二、最終效果圖
- 模型資源鏈接:https://pan.baidu.com/s/1e2bavPacWwA6_pDHlcM0Tw 密碼:na24
- UE4項目以及源碼:https://download.csdn.net/download/qq_31788759/10565311
三、核心代碼模塊
在此先將模塊分類,使結構清晰明瞭,最後有完整代碼,可具體查看。
1、首先創建組件
- SphereBase.h(自己創建的C++類)下
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "RootComp")
class USceneComponent * RootComp;//聲明根節點組件
UPROPERTY(EditAnywhere, BlueprintReadWrite,Category = "SphereMeshComp")
class UStaticMeshComponent * SphereMeshComp;//小球Mesh組件
UPROPERTY(EditAnywhere, BlueprintReadWrite,Category = "CameraArmComp")
class USpringArmComponent * CameraArmComp;//相機臂組件
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "CameraComp")
class UCameraComponent * CameraComp;//相機組件
- SphereBase.cpp
//創建組件
RootComp = CreateDefaultSubobject<USceneComponent>(TEXT("RootComp"));
SphereMeshComp = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("SphereBaseComp"));
CameraArmComp = CreateDefaultSubobject<USpringArmComponent>(TEXT("CameraArmComp"));
CameraComp = CreateDefaultSubobject<UCameraComponent>(TEXT("CameraComp"));
//添加組件父子關係
SphereMeshComp->SetupAttachment(RootComp);
CameraArmComp->SetupAttachment(RootComp);
CameraComp->SetupAttachment(CameraArmComp);
//設置小球物理效果爲真
SphereMeshComp->SetSimulatePhysics(true);
- 創建藍圖類繼承該C++類後,組件已創建
2、綁定按鍵輸入
//綁定前後左右移動
PlayerInputComponent->BindAxis("MoveForward", this, &ASphereBase::MoveForward);
PlayerInputComponent->BindAxis("MoveRight", this, &ASphereBase::MoveRight);
//Shift按下與擡起
PlayerInputComponent->BindAction("MoveQuick", IE_Pressed, this, &ASphereBase::MoveQuick);
PlayerInputComponent->BindAction("MoveQuick", IE_Released, this, &ASphereBase::MoveNormal);
//相機上下左右旋轉
PlayerInputComponent->BindAxis("CameraYaw", this, &ASphereBase::YawCamera);
PlayerInputComponent->BindAxis("CameraPitch", this, &ASphereBase::PitchCamera);
//相機縮放
PlayerInputComponent->BindAction("ZoomIn", IE_Pressed, this, &ASphereBase::ZoomIn);
PlayerInputComponent->BindAction("ZoomIn", IE_Released, this, &ASphereBase::ZoomStop);
PlayerInputComponent->BindAction("ZoomOut", IE_Pressed, this, &ASphereBase::ZoomOut);
PlayerInputComponent->BindAction("ZoomIn", IE_Released, this, &ASphereBase::ZoomStop);
具體函數請查看完整代碼
3、相機自由視角
建議採用世界座標系函數修改值,不要使用相對座標系Relative函數,否則會遇到很多問題。
- 小球移動控制
if (!AngularVector.IsZero())
{
FVector NewVector = FVector(0, 0, 0);
NewVector += AngularVector.X * CameraArmComp->GetForwardVector() * SphereSpeed;
NewVector += AngularVector.Y * CameraArmComp->GetRight Vector() * SphereSpeed;
SphereMeshComp->SetPhysicsAngularVelocity(NewVector);//給小球施加角速度向量
}
- 相機臂左右旋轉
FRotator LRRotation = CameraArmComp->GetComponentRotation();
LRRotation.Yaw += CameraInput.X;
CameraArmComp->SetWorldRotation(LRRotation);
- 相機臂上下旋轉
FRotator UDRotation = CameraArmComp->GetComponentRotation();
UDRotation.Pitch = FMath::Clamp(UDRotation.Pitch + CameraInput.Y, -80.0f, -15.0f);//控制上下視野範圍
CameraArmComp->SetWorldRotation(UDRotation);
- 相機臂跟隨小球
FVector NewLocation = SphereMeshComp->GetComponentLocation();
CameraArmComp->SetWorldLocation(NewLocation);
4、相機縮放
ZoomValue = FMath::Clamp<float>(ZoomValue, 0.0f, 1.0f);
//基於ZoomFActor來混合控制相機的視域和彈簧臂的長度 0.0f對應90.0f 1500.0f
CameraComp->FieldOfView = FMath::Lerp<float>(90.0f, 60.0f, ZoomValue);
CameraArmComp->TargetArmLength = FMath::Lerp<float>(1500.0f, 500.0f, ZoomValue);
滾輪控制ZoomValue值的變化
四、完整代碼
- Sphere.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Pawn.h"
#include "SphereBase.generated.h"//必須放在頭文件最後
UCLASS()
class BILICODE_API ASphereBase : public APawn//APawn 繼承 Actor
{
GENERATED_BODY()
public:
// Sets default values for this pawn's properties
ASphereBase();
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "RootComp")
class USceneComponent * RootComp;
UPROPERTY(EditAnywhere, BlueprintReadWrite,Category = "SphereMeshComp")
class UStaticMeshComponent * SphereMeshComp;//class聲明
UPROPERTY(EditAnywhere, BlueprintReadWrite,Category = "CameraArmComp")
class USpringArmComponent * CameraArmComp;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "CameraComp")
class UCameraComponent * CameraComp;
public:
FVector AngularVector;
float SphereSpeed;
float SpeedMin;
float SpeedMax;
FVector CameraInput;
float ZoomValue;
UPROPERTY(EditAnyWhere, BlueprintReadWrite)
bool IsInput;//控制是否能輸入按鍵
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
// Called to bind functionality to input
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
UFUNCTION(BlueprintCallable)
void MoveForward(float AxisValue);
UFUNCTION(BlueprintCallable)
void MoveRight(float AxisValue);
UFUNCTION(BlueprintCallable)
void MoveQuick();
UFUNCTION(BlueprintCallable)
void MoveNormal();
void PitchCamera(float AxisValue);
void YawCamera(float AxisValue);
void StartJump();
void StopJump();
void ZoomIn();
void ZoomStop();
void ZoomOut();
};
- Sphere.cpp
// Fill out your copyright notice in the Description page of Project Settings.
#include "SphereBase.h"
#include "Components/StaticMeshComponent.h"//Mesh頭文件
#include "GameFramework/SpringArmComponent.h"//攝像機手臂頭文件
#include "Camera/CameraComponent.h"
#include "Components/SceneComponent.h"
#include "Components/InputComponent.h"//輸入按鍵綁定頭文件
#include "Engine.h"
// Sets default values
ASphereBase::ASphereBase()
{
// 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;
IsInput = true;
SphereSpeed = 300.0f;
SpeedMin = SphereSpeed;
SpeedMax = 500.0f;
ZoomValue = 0.5f;
//創建組件
RootComp = CreateDefaultSubobject<USceneComponent>(TEXT("RootComp"));
SphereMeshComp = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("SphereBaseComp"));
CameraArmComp = CreateDefaultSubobject<USpringArmComponent>(TEXT("CameraArmComp"));
CameraComp = CreateDefaultSubobject<UCameraComponent>(TEXT("CameraComp"));
//組件關係
SphereMeshComp->SetupAttachment(RootComp);
CameraArmComp->SetupAttachment(RootComp);
CameraComp->SetupAttachment(CameraArmComp);
//設置物理效果爲真
SphereMeshComp->SetSimulatePhysics(true);
}
// Called when the game starts or when spawned
void ASphereBase::BeginPlay()
{
Super::BeginPlay();
}
// Called every frame
void ASphereBase::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
if (!AngularVector.IsZero())
{
FVector NewVector = FVector(0, 0, 0);
NewVector += AngularVector.X * CameraArmComp->GetForwardVector() * SphereSpeed;
NewVector += AngularVector.Y * CameraArmComp->GetRightVector() * SphereSpeed;
SphereMeshComp->SetPhysicsAngularVelocity(NewVector);//小球向一個向量方向旋轉移動
}
{//相機臂左右旋轉(相機臂與小球是兄弟關係
FRotator LRRotation = CameraArmComp->GetComponentRotation();
LRRotation.Yaw += CameraInput.X;
CameraArmComp->SetWorldRotation(LRRotation);
}
{//相機臂跟隨小球
FVector NewLocation = SphereMeshComp->GetComponentLocation();
CameraArmComp->SetWorldLocation(NewLocation);
//兩種方便的調試方法
//GEngine->AddOnScreenDebugMessage(-1, 3.f, FColor::Purple, NewLocation.ToString());
/*DrawDebugLine(
GetWorld(),
SphereBeginLocation,
SphereMeshComp->GetComponentLocation(),
FColor::Red,
false, -1, 0,
3.
);*/
}
{//相機臂上下旋轉
FRotator UDRotation = CameraArmComp->GetComponentRotation();
UDRotation.Pitch = FMath::Clamp(UDRotation.Pitch + CameraInput.Y, -80.0f, -15.0f);//控制旋轉範圍
CameraArmComp->SetWorldRotation(UDRotation);
}
{//相機縮放
ZoomValue = FMath::Clamp<float>(ZoomValue, 0.0f, 1.0f);
//基於ZoomFActor來混合相機的視域和彈簧臂的長度
CameraComp->FieldOfView = FMath::Lerp<float>(90.0f, 60.0f, ZoomValue);
CameraArmComp->TargetArmLength = FMath::Lerp<float>(1500.0f, 500.0f, ZoomValue);
}
}
// Called to bind functionality to input
void ASphereBase::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)//pawn不同於actor的地方,用於綁定按鍵
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
PlayerInputComponent->BindAxis("MoveForward", this, &ASphereBase::MoveForward);//綁定 前後移動映射 的函數
PlayerInputComponent->BindAxis("MoveRight", this, &ASphereBase::MoveRight);//綁定左右
PlayerInputComponent->BindAction("MoveQuick", IE_Pressed, this, &ASphereBase::MoveQuick);
PlayerInputComponent->BindAction("MoveQuick", IE_Released, this, &ASphereBase::MoveNormal);
PlayerInputComponent->BindAxis("CameraYaw", this, &ASphereBase::YawCamera);
PlayerInputComponent->BindAxis("CameraPitch", this, &ASphereBase::PitchCamera);
PlayerInputComponent->BindAction("ZoomIn", IE_Pressed, this, &ASphereBase::ZoomIn);
PlayerInputComponent->BindAction("ZoomIn", IE_Released, this, &ASphereBase::ZoomStop);
PlayerInputComponent->BindAction("ZoomOut", IE_Pressed, this, &ASphereBase::ZoomOut);
PlayerInputComponent->BindAction("ZoomIn", IE_Released, this, &ASphereBase::ZoomStop);
}
//前後左右輸入控制
void ASphereBase::MoveForward(float AxisValue)
{
if (IsInput)
{
AngularVector.Y = FMath::Clamp<float>(AxisValue, -1.0f, 1.0f);
}
}
void ASphereBase::MoveRight(float AxisValue)
{
if (IsInput)
{
AngularVector.X = FMath::Clamp<float>(AxisValue, -1.0f, 1.0f);
}
}
//shift輸入控制
void ASphereBase::MoveQuick()
{
SphereSpeed = SpeedMax;
}
void ASphereBase::MoveNormal()
{
SphereSpeed = SpeedMin;
}
//相機旋轉輸入控制
void ASphereBase::PitchCamera(float AxisValue)
{
CameraInput.Y = AxisValue;
}
void ASphereBase::YawCamera(float AxisValue)
{
CameraInput.X = AxisValue;
}
void ASphereBase::ZoomIn()
{
ZoomValue += 0.1f;
}
//相機縮放輸入控制
void ASphereBase::ZoomStop()
{
}
void ASphereBase::ZoomOut()
{
ZoomValue -= 0.1f;
}