Zack.Zhang Game Developer

UE4学习笔记2——简单的3C模块

2021-10-05
zack.zhang

本笔记的目的是学会基本的控制角色。入门示例成品

创建Character蓝图类

创建C++类继承于Character。命名为AMainPlayer,创建对应的蓝图,命名为BP_MainPlayer。

创建相机旋臂,且设置旋臂长度为600。旋臂本身不旋转,仅旋转其子项。

SpringArm = CreateDefaultSubobject<USpringArmComponent>(TEXT("SpringArm"));
SpringArm->SetupAttachment(GetRootComponent());
// 默认旋臂长度
SpringArm->TargetArmLength = 600.0f;

创建跟随角色的相机,并绑定到旋臂上,成为旋臂子项。

FollowCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("FollowCamera"));
FollowCamera->SetupAttachment(SpringArm, USpringArmComponent::SocketName);

控制相机旋转

设置旋臂使用Pawn控制旋转。旋臂在执行Pitch、Yaw、Roll时,相机能够沿着以旋臂长度为半径的球体表面,围绕着Pawn运动,并看向Pawn。

// 旋臂围绕着Pawn运动
SpringArm->bUsePawnControlRotation = true;

绑定鼠标的水平移动和垂直移动的轴操作映射。

PlayerInputComponent->BindAxis(TEXT("MouseYaw"), this, &AMainPlayer::MouseYaw);
PlayerInputComponent->BindAxis(TEXT("MousePitch"), this, &AMainPlayer::MousePitch);

void AMainPlayer::MouseYaw(float Value)
{
	// 这个函数每帧都会调用,也就是没有操作也会执行
	// Value为零就不用设置了,说明没有操作输入,节省性能
	if (FMath::IsNearlyZero(Value))
	{
		return;
	}
	AddControllerYawInput(Value);
}

void AMainPlayer::MousePitch(float Value)
{
	// 这个函数每帧都会调用,也就是没有操作也会执行
	// Value为零就不用设置了,说明没有操作输入,节省性能
	if (FMath::IsNearlyZero(Value))
	{
		return;
	}
	AddControllerPitchInput(Value);
}

如果想要角色朝向相机镜头Yaw方向,可以设置bUseControllerRotationYaw为true。当然如果是空战游戏,或者做角色飞行,需要角色Pitch和Roll也随着相机镜头改变,就可以设置bUseControllerRotationPitch和bUseControllerRotationRoll。这里我们角色转向所有轴向都不想要朝向相机方向。

// 角色所有轴向都不朝向相机朝向
bUseControllerRotationPitch = false;
bUseControllerRotationRoll = false;
bUseControllerRotationYaw = false;

// 角色朝向加速度方向
GetCharacterMovement()->bOrientRotationToMovement = true;
// 设置转身速度
GetCharacterMovement()->RotationRate = FRotator(0.0f, 500.0f, 0.0f);

如果三个bool值都设为true会出现以下诡异情景。

UE4-UseCtrlRot.png

控制角色移动

绑定键盘W、A、S、D键的轴操作映射。

PlayerInputComponent->BindAxis(TEXT("MoveForwardBack"), this, &AMainPlayer::MoveForwardBack);
PlayerInputComponent->BindAxis(TEXT("MoveLeftRight"), this, &AMainPlayer::MoveLeftRight);

void AMainPlayer::MoveForwardBack(float Value)
{
	if (Controller == nullptr || FMath::IsNearlyZero(Value))
	{
		return;
	}
	// AddMovementInput只在Character类有效
	//AddMovementInput(GetActorForwardVector(), Value);

	// 按下按钮的时候就朝向Cotroller的方向
	//if (Value != 0.0f)
	//{
	//	GetMesh()->SetRelativeRotation(YawRotator);
	//}
	// 注释掉,可以使用GetCharacterMovement()->bOrientRotationToMovement来实现

	FRotator Rotator = Controller->GetControlRotation(); // 获取控制器的欧拉角
	FRotator YawRotator(0.0f, Rotator.Yaw, 0.0f); // 欧拉角转矩阵
	FVector Direction = FRotationMatrix(YawRotator).GetUnitAxis(EAxis::X); // 取矩阵的m_01,m_02,m_03,也就是Controller的Forward
	AddMovementInput(Direction, Value);
}

void AMainPlayer::MoveLeftRight(float Value)
{
	if (Controller == nullptr || FMath::IsNearlyZero(Value))
	{
		return;
	}
	// AddMovementInput只在Character类有效
	//AddMovementInput(GetActorRightVector(), Value);

	// 按下按钮的时候就朝向Cotroller的方向
	//if (Value != 0.0f)
	//{
	//	GetMesh()->SetRelativeRotation(YawRotator);
	//}
	// 注释掉,可以使用GetCharacterMovement()->bOrientRotationToMovement来实现

	FRotator Rotator = Controller->GetControlRotation(); // 获取控制器的欧拉角
	FRotator YawRotator(0.0f, Rotator.Yaw, 0.0f); // 欧拉角转矩阵
	//FVector Direction = FRotationMatrix(YawRotator).GetUnitAxis(EAxis::X); // 取矩阵的m_01,m_02,m_03,也就是Controller的Forward
	//Direction = FVector::CrossProduct(FVector::UpVector, Direction);

	FVector Direction = FRotationMatrix(YawRotator).GetUnitAxis(EAxis::Y); // 取矩阵的m_11,m_12,m_13,也就是Controller的Right

	AddMovementInput(Direction, Value);
}

控制跳跃

绑定键盘的Space键的按下和抬起事件。

PlayerInputComponent->BindAction(TEXT("Jump"), EInputEvent::IE_Pressed, this, &AMainPlayer::Jump);
PlayerInputComponent->BindAction(TEXT("Jump"), EInputEvent::IE_Released, this, &ACharacter::StopJumping);

void AMainPlayer::Jump()
{
	Super::Jump();
}

动画

新建BlendSpace

类似Unity的BlendTree的概念,不同的是UE4里BlendSpace作为一个资源存在在文件夹里。工作原理同样是根据某个参数,来混合动画。文件夹里想要创建BlendSpace的地方右键,如下图菜单选择创建。这里我们希望根据移动速度来差值Idle动画和Walk动画,所以创建一个1D的BlendSpace就可以了。命名为BS_Player_Movement。

UE4-BlendSpace.png

双击打开BlendSpace的编辑窗口,按下图方式拖拽动画到插值轴的两端,即可设置BlendSpace的需要混合的两个动画了。

UE4-EditBlendTree1.png

设置插值轴的名称,也就是靠什么参数来插值混合两个动画的,同时可以设置轴的分段数,也就是“网格分区数量”。

UE4-EditBlendTree2.png

新建动画蓝图类

动画蓝图类都是继承于UAnimInstance的,所以新建一个类继承于UAnimInstance,用来取得其所属角色身上的移动速度信息和是否浮空信息,并在蓝图里使用。

UCLASS()
class TEST2_API UMainPlayerAnimInstance : public UAnimInstance
{
	GENERATED_BODY()
	
public:

	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Animation Properties")
	float Speed;

	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Animation Properties")
	bool bIsInAir;

	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Animation Properties")
	class AMainPlayer* PlayerRef;

public:
	// 继承于UAnimInstance的初始化方法
	virtual void NativeInitializeAnimation() override;

	// 每帧执行,用来获取所属角色的速度和浮空信息
	UFUNCTION(BlueprintCallable, Category = "Animation Properties")
	void UpdateAnimationProperties();
};

void UMainPlayerAnimInstance::NativeInitializeAnimation()
{
	PlayerRef = Cast<AMainPlayer>(TryGetPawnOwner());
}

void UMainPlayerAnimInstance::UpdateAnimationProperties()
{
	if (PlayerRef == nullptr)
	{
		PlayerRef = Cast<AMainPlayer>(TryGetPawnOwner());
	}
	if (PlayerRef == nullptr)
	{
		return;
	}

	FVector SpeedVector = PlayerRef->GetVelocity();
	FVector PlannarSpeed = FVector(SpeedVector.X, SpeedVector.Y, 0.0f);
	Speed = PlannarSpeed.Size();

	bIsInAir = PlayerRef->GetMovementComponent()->IsFalling();
}

主要添加了Speed和bIsInAir属性来保存玩家速度和浮空信息。用PlayerRef来保存所属角色的指针。

文件夹里右键创建动画蓝图类,继承于UMainPlayerAnimInstance,命名为ABP_MainPlayer。

UE4-CreateAnimBlueprint.png

编辑动画蓝图

蓝图里设置每帧执行上文创建的UpdateAnimationProperties函数。

UE4-EditABP1.png

在AnimGraph里创建一个状态机,类似于Unity的Animator中的动画控制器一样的概念。

UE4-EditABP2.png

双击状态机,编辑状态机。状态机初始状态Entry类似于Unity中Animator的Any State的概念。从Entry连一条线,创建一个状态命名为Movement。

UE4-EditABP3.png
UE4-EditABP4.png

双击Movement状态,编辑状态。获取UpdateAnimationProperties类中的Speed属性作为BlendSpace的输入,来混合Idle和Walk动画。

UE4-EditABP5.png

同理创建JumpingStart、Jumping和JumpingEnd三个状态。

UE4-EditABP6.png

分别将Jumping_Up、Jumping和Jumping_Down三个动画拖入到JumpingStart、Jumping和JumpingEnd三个状态里。

UE4-EditABP6.png

设置状态之间的跳转条件,例如Jumping到Jumping_End就是当bIsInAir为false时跳转。

UE4-EditABP8.png
UE4-EditABP9.png

至此动画蓝图编辑完成,点击动画蓝图的左上角“编译”和“保存”按钮完成动画蓝图的编辑。

使用动画蓝图

打开角色蓝图BP_MainPlayer,选中“网格体”,“细节”窗口里找到动画设置,如下进行设置。

UE4-ABPApply.png


Similar Posts

评论