• 虚幻C+++基础 day2


    角色移动与视角控制

    Character类与相关API

    • 创建Character子类
    • MainPlayer.h
    // Fill out your copyright notice in the Description page of Project Settings.
    
    #pragma once
    
    #include "CoreMinimal.h"
    #include "GameFramework/Character.h"
    #include "MainPlayer.generated.h"
    
    UCLASS()
    class UEGAME_API AMainPlayer : public ACharacter
    {
    	GENERATED_BODY()
    
    public:
    	// Sets default values for this character's properties
    	AMainPlayer();
    
    	//新建一个SpringArm
    	UPROPERTY(visibleAnywhere,BlueprintReadOnly)
    	class USpringArmComponent* SpringArm;
    	//新建一个Camera
    	UPROPERTY(visibleAnywhere, BlueprintReadOnly)
    	class UCameraComponent* FollowCamera;
    
    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;
    
    };
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • MianPlayer.cpp
    // Fill out your copyright notice in the Description page of Project Settings.
    
    
    #include "MainPlayer.h"
    #include "GameFramework/SpringArmComponent.h"
    #include "Camera/CameraComponent.h"
    
    // Sets default values
    AMainPlayer::AMainPlayer()
    {
     	// Set this character to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
    	PrimaryActorTick.bCanEverTick = true;
    
    	SpringArm = CreateDefaultSubobject<USpringArmComponent>(TEXT("SpringArm"));
    	SpringArm->SetupAttachment(GetRootComponent());
    	//设置SPringArm无碰撞臂长
    	SpringArm->TargetArmLength = 600.f;
        
    	FollowCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("FollowCamera"));
    	FollowCamera->SetupAttachment(SpringArm, NAME_None);
    
    }
    
    // Called when the game starts or when spawned
    void AMainPlayer::BeginPlay()
    {
    	Super::BeginPlay();
    	
    }
    
    // Called every frame
    void AMainPlayer::Tick(float DeltaTime)
    {
    	Super::Tick(DeltaTime);
    
    }
    
    // Called to bind functionality to input
    void AMainPlayer::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
    {
    	Super::SetupPlayerInputComponent(PlayerInputComponent);
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 运行结果
      在这里插入图片描述

    指定骨骼模型并调整胶囊体

    • 指定骨骼模型

    在这里插入图片描述

    • C++硬编码给出默认值

    • 头文件胶囊体#include “Components/CapsuleComponent.h”

    //设置胶囊体的默认宽高
    GetCapsuleComponent()->SetCapsuleSize(35.f, 100.f);
    
    • 1
    • 2

    在这里插入图片描述

    创建轴映射与GameMode

    • 创建关卡GameMode子类

    在这里插入图片描述

    • 设置玩家使用默认类

    在这里插入图片描述

    在这里插入图片描述

    • 轴映射

    在这里插入图片描述

    基本简单移动与旋转控制

    • AddMovementInput:沿着给定的世界方向向量(通常是标准化的)添加移动输入,并按“ScaleValue”进行缩放。如果ScaleValue < 0,则移动方向相反。基础Pawn类不会自动应用移动,这取决于用户在Tick事件中这样做。像Character和DefaultPawn这样的子类会自动处理这些输入并移动。

    在这里插入图片描述

    • GetActorForwardVector:获取Actor,X轴正向的向量

    • GetActorRightVector:获取Actor,Y轴正向的向量

    MainPlayer.cpp

    // Fill out your copyright notice in the Description page of Project Settings.
    
    
    #include "MainPlayer.h"
    #include "GameFramework/SpringArmComponent.h"
    #include "Camera/CameraComponent.h"
    #include "Components/CapsuleComponent.h"
    #include "Components/InputComponent.h"
    // Sets default values
    AMainPlayer::AMainPlayer()
    {
     	// Set this character to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
    	PrimaryActorTick.bCanEverTick = true;
    
    	SpringArm = CreateDefaultSubobject<USpringArmComponent>(TEXT("SpringArm"));
    	SpringArm->SetupAttachment(GetRootComponent());
    	//设置SPringArm无碰撞臂长
    	SpringArm->TargetArmLength = 600.f;
    	SpringArm->bUsePawnControlRotation = true;//硬编码SpringArm继承controlller旋转为真
    
    	FollowCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("FollowCamera"));
    	FollowCamera->SetupAttachment(SpringArm, NAME_None);
    	FollowCamera->bUsePawnControlRotation = false;//硬编码FollowCamera继承controlller旋转为假
    
    	//设置胶囊体的默认宽高
    	GetCapsuleComponent()->SetCapsuleSize(35.f, 100.f);
    }
    
    // Called when the game starts or when spawned
    void AMainPlayer::BeginPlay()
    {
    	Super::BeginPlay();
    	
    }
    
    // Called every frame
    void AMainPlayer::Tick(float DeltaTime)
    {
    	Super::Tick(DeltaTime);
    
    }
    
    // Called to bind functionality to input
    void AMainPlayer::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
    {
    	Super::SetupPlayerInputComponent(PlayerInputComponent);
    	//检查PlayerInputComponent指针,check函数只能在这使用
    	check(PlayerInputComponent);
    
    	//绑定轴映射事件
    	PlayerInputComponent->BindAxis("MoveForward", this, &AMainPlayer::MoveForward);
    	PlayerInputComponent->BindAxis("MoveRigth", this, &AMainPlayer::MoveRigth);
    
    	//绑定Controller控制器去管理视角旋转
    	PlayerInputComponent->BindAxis("Turn", this, &ACharacter::AddControllerYawInput);
    	PlayerInputComponent->BindAxis("LookUp", this, &ACharacter::AddControllerPitchInput);
    
    
    }
    
    void AMainPlayer::MoveForward(float value)
    {
        //沿着给定的世界方向向量(通常是标准化的)添加移动输入
    	AddMovementInput(GetActorForwardVector(), value);
    }
    
    void AMainPlayer::MoveRigth(float value)
    {
    	AddMovementInput(GetActorRightVector(), value);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71

    控制角色旋转

    • 相机的选择和角色的旋转应该是两个独立的事件
    • 我们需要分离控制相机的鼠标控制旋转(ControlRotation)和角色旋转(Pawn Rotation)。
    • 在UE中XYZ轴的正向分别对应前方、右方和上方,显示的箭头颜色分别为红色、绿色和蓝色(三基色的习惯顺序)。
    • 头文件 #include “GameFramework/PlayerController.h”
    • Controller:这是Character类中自己声明的AController* 属性,用与获取该Actor的控制器
      在这里插入图片描述
    // Fill out your copyright notice in the Description page of Project Settings.
    
    
    #include "MainPlayer.h"
    #include "GameFramework/SpringArmComponent.h"
    #include "Camera/CameraComponent.h"
    #include "Components/CapsuleComponent.h"
    #include "Components/InputComponent.h"
    #include "GameFramework/PlayerController.h"
    
    // Sets default values
    AMainPlayer::AMainPlayer()
    {
     	// Set this character to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
    	PrimaryActorTick.bCanEverTick = true;
    
    	SpringArm = CreateDefaultSubobject<USpringArmComponent>(TEXT("SpringArm"));
    	SpringArm->SetupAttachment(GetRootComponent());
    	//设置SPringArm无碰撞臂长
    	SpringArm->TargetArmLength = 600.f;
    	SpringArm->bUsePawnControlRotation = true;//硬编码SpringArm继承controlller旋转为真
    
    	FollowCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("FollowCamera"));
    	FollowCamera->SetupAttachment(SpringArm, NAME_None);
    	FollowCamera->bUsePawnControlRotation = false;//硬编码FollowCamera继承controlller旋转为假
    
    	//设置胶囊体的默认宽高
    	GetCapsuleComponent()->SetCapsuleSize(35.f, 100.f);
    
    	//对Character的Pawn进行硬编码
    	bUseControllerRotationPitch = false;
    	bUseControllerRotationYaw = false;
    	bUseControllerRotationRoll = false;
    
    }
    
    // Called when the game starts or when spawned
    void AMainPlayer::BeginPlay()
    {
    	Super::BeginPlay();
    	
    }
    
    // Called every frame
    void AMainPlayer::Tick(float DeltaTime)
    {
    	Super::Tick(DeltaTime);
    
    }
    
    // Called to bind functionality to input
    void AMainPlayer::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
    {
    	Super::SetupPlayerInputComponent(PlayerInputComponent);
    	//检查PlayerInputComponent指针,check函数只能在这使用
    	check(PlayerInputComponent);
    
    	//绑定轴映射事件
    	PlayerInputComponent->BindAxis("MoveForward", this, &AMainPlayer::MoveForward);
    	PlayerInputComponent->BindAxis("MoveRigth", this, &AMainPlayer::MoveRigth);
    
    	//绑定Controller控制器去管理视角旋转
    	PlayerInputComponent->BindAxis("Turn", this, &ACharacter::AddControllerYawInput);
    	PlayerInputComponent->BindAxis("LookUp", this, &ACharacter::AddControllerPitchInput);
    
    
    }
    
    void AMainPlayer::MoveForward(float value)
    {
    	//获取到Control旋转
    	FRotator Rotation = Controller->GetControlRotation();
    	//转向只关注水平Yaw方向,因此置0防止影响
    	FRotator YowRotation = FRotator(0.0f, Rotation.Yaw, 0.0f);
    	//获取相机(鼠标控制器的朝向),并且朝这个轴的方向移动
    	FVector Direction = FRotationMatrix(YowRotation).GetUnitAxis(EAxis::X);
    	AddMovementInput(Direction, value);
    }
    
    void AMainPlayer::MoveRigth(float value)
    {
    	//获取到Controller旋转
    	FRotator Rotation = Controller->GetControlRotation();
    	//转向只关注水平Yaw方向,因此置0防止影响
    	FRotator YowRotation = FRotator(0.0f, Rotation.Yaw, 0.0f);
    	//获取相机(鼠标控制器的朝向),并且朝这个轴的方向移动
    	FVector Direction = FRotationMatrix(YowRotation).GetUnitAxis(EAxis::Y);
    	AddMovementInput(Direction, value);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90

    使角色自动面向移动方向

    • CharacterMovement非常强大,我们打开CharacterMovement的Orient Rotation to Movement就开启自动面向旋转

    在这里插入图片描述

    • 头文件:#include “GameFramework/CharacterMovementComponent.h”
    	//硬编码orient Rotation to Movement,给个默认转向速率
    	GetCharacterMovement()->bOrientRotationToMovement = true;
    	GetCharacterMovement()->RotationRate = FRotator(0.f, 500.f, 0.f);
    
    • 1
    • 2
    • 3
    • 运行结果

    在这里插入图片描述

    创建键盘与手柄使用的视角与旋转函数

    • 新建两个float变量来控制上下左右转向的速率,注意旋转时要乘以DeltaTime避免高低性能差值
    	float BaseTurnRate;		//使用键盘X转向的速率
    	float BaseLookUpRate;	//使用键盘Y转向的速率
    
    	//给键盘控制转向的速率变量赋初值
    	BaseTurnRate = 21.f;
    	BaseLookUpRate = 21.f;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 因为可能要修改视角限制,新建Turn与LookUp绑定Controller控制器去管理视角旋转函数,新建绑定键盘鼠标轴映射事件函数
    private:
    	void MoveForward(float value);
    	void MoveRight(float value);
    
    	void Turn(float Value);
    	void LookUp(float Value);
    
    	void TurnRate(float Rate);
    	void LookUpRate(float Rate);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    // Called to bind functionality to input
    void AMainPlayer::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
    {
    	Super::SetupPlayerInputComponent(PlayerInputComponent);
    	//检查PlayerInputComponent指针,check函数只能在这使用
    	check(PlayerInputComponent);
    
    	//绑定移动轴映射事件
    	PlayerInputComponent->BindAxis("MoveForward", this, &AMainPlayer::MoveForward);
    	PlayerInputComponent->BindAxis("MoveRight", this, &AMainPlayer::MoveRight);
    
    	//绑定Controller控制器去管理视角旋转
    	PlayerInputComponent->BindAxis("Turn", this, &AMainPlayer::Turn);
    	PlayerInputComponent->BindAxis("LookUp", this, &AMainPlayer::LookUp);
    
    	//绑定键盘鼠标轴映射事件
    	PlayerInputComponent->BindAxis("TurnRate", this, &AMainPlayer::TurnRate);
    	PlayerInputComponent->BindAxis("LookUpRate", this, &AMainPlayer::LookUpRate);
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    void AMainPlayer::Turn(float Value)
    {
    	if (Value != 0.f)
    	{
    		AddControllerYawInput(Value);
    	}
    	
    }
    
    void AMainPlayer::LookUp(float Value)
    {
    	if (Value != 0.f)
    	{
    		AddControllerPitchInput(Value);
    	}
    	
    }
    
    void AMainPlayer::TurnRate(float Rate)
    {
    	//要乘以一个DeltaTime这样就可以避免高帧底帧差值问题
    	float Value = Rate * BaseTurnRate * GetWorld()->GetDeltaSeconds();
    	if (Value != 0.f)
    	{
    		AddControllerYawInput(Value);
    	}
    }
    
    void AMainPlayer::LookUpRate(float Rate)
    {
    	//要乘以一个DeltaTime这样就可以避免高帧底帧差值问题
    	float Value = Rate * BaseLookUpRate * GetWorld()->GetDeltaSeconds();
    	if (Value != 0.f)
    	{
    		AddControllerPitchInput(Value);
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    限制角色上下视角旋转的范围

    • 思路当旋转区域不是理想的范围就直接不要

    在这里插入图片描述

    void AMainPlayer::LookUp(float Value)
    {
    	//UE_LOG(LogTemp, Warning, TEXT("%f"), GetControlRotation().Pitch);
    	// 
    	//控制视角
    	if (GetControlRotation().Pitch < 270.f && GetControlRotation().Pitch >180.f && Value > 0.f)
    	{
    		return;
    	}
    	else if (GetControlRotation().Pitch < 180.f && GetControlRotation().Pitch >45.f && Value < 0.f)
    	{
    		return;
    	}
    	AddControllerPitchInput(Value);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • MainPlayer.cpp
    // Fill out your copyright notice in the Description page of Project Settings.
    
    
    #include "MainPlayer.h"
    #include "GameFramework/SpringArmComponent.h"
    #include "Camera/CameraComponent.h"
    #include "Components/CapsuleComponent.h"
    #include "Components/InputComponent.h"
    #include "GameFramework/PlayerController.h"
    #include "GameFramework/CharacterMovementComponent.h"
    
    // Sets default values
    AMainPlayer::AMainPlayer()
    {
     	// Set this character to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
    	PrimaryActorTick.bCanEverTick = true;
    
    	SpringArm = CreateDefaultSubobject<USpringArmComponent>(TEXT("SpringArm"));
    	SpringArm->SetupAttachment(GetRootComponent());
    	//设置SPringArm无碰撞臂长
    	SpringArm->TargetArmLength = 600.f;
    	SpringArm->bUsePawnControlRotation = true;//硬编码SpringArm继承controlller旋转为真
    
    	FollowCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("FollowCamera"));
    	FollowCamera->SetupAttachment(SpringArm, NAME_None);
    	FollowCamera->bUsePawnControlRotation = false;//硬编码FollowCamera继承controlller旋转为假
    
    	//设置胶囊体的默认宽高
    	GetCapsuleComponent()->SetCapsuleSize(35.f, 100.f);
    
    	//对Character的Pawn进行硬编码
    	bUseControllerRotationPitch = false;
    	bUseControllerRotationYaw = false;
    	bUseControllerRotationRoll = false;
    
    	//硬编码orient Rotation to Movement,给个默认转向速率
    	GetCharacterMovement()->bOrientRotationToMovement = true;
    	GetCharacterMovement()->RotationRate = FRotator(0.f, 500.f, 0.f);
    
    	//给键盘控制转向的速率变量赋初值
    	BaseTurnRate = 21.f;
    	BaseLookUpRate = 21.f;
    }
    
    // Called when the game starts or when spawned
    void AMainPlayer::BeginPlay()
    {
    	Super::BeginPlay();
    	
    }
    
    // Called every frame
    void AMainPlayer::Tick(float DeltaTime)
    {
    	Super::Tick(DeltaTime);
    
    }
    
    // Called to bind functionality to input
    void AMainPlayer::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
    {
    	Super::SetupPlayerInputComponent(PlayerInputComponent);
    	//检查PlayerInputComponent指针,check函数只能在这使用
    	check(PlayerInputComponent);
    
    	//绑定移动轴映射事件
    	PlayerInputComponent->BindAxis("MoveForward", this, &AMainPlayer::MoveForward);
    	PlayerInputComponent->BindAxis("MoveRight", this, &AMainPlayer::MoveRight);
    
    	//绑定Controller控制器去管理视角旋转
    	PlayerInputComponent->BindAxis("Turn", this, &AMainPlayer::Turn);
    	PlayerInputComponent->BindAxis("LookUp", this, &AMainPlayer::LookUp);
    
    	//绑定键盘鼠标轴映射事件
    	PlayerInputComponent->BindAxis("TurnRate", this, &AMainPlayer::TurnRate);
    	PlayerInputComponent->BindAxis("LookUpRate", this, &AMainPlayer::LookUpRate);
    
    }
    
    void AMainPlayer::MoveForward(float value)
    {
    	if (Controller != nullptr && value != 0.f)
    	{
    		//获取到Control旋转
    		FRotator Rotation = Controller->GetControlRotation();
    		//转向只关注水平Yaw方向,因此置0防止影响
    		FRotator YowRotation = FRotator(0.0f, Rotation.Yaw, 0.0f);
    		//获取相机(鼠标控制器的朝向),并且朝这个轴的方向移动
    		FVector Direction = FRotationMatrix(YowRotation).GetUnitAxis(EAxis::X);
    		AddMovementInput(Direction, value);
    	}
    
    }
    
    void AMainPlayer::MoveRight(float value)
    {
    	if (Controller != nullptr && value != 0.f)
    	{
    		//获取到Controller旋转
    		FRotator Rotation = Controller->GetControlRotation();
    		//转向只关注水平Yaw方向,因此置0防止影响
    		FRotator YowRotation = FRotator(0.0f, Rotation.Yaw, 0.0f);
    		//获取相机(鼠标控制器的朝向),并且朝这个轴的方向移动
    		FVector Direction = FRotationMatrix(YowRotation).GetUnitAxis(EAxis::Y);
    		AddMovementInput(Direction, value);
    	}
    }
    
    void AMainPlayer::Turn(float Value)
    {
    	if (Value != 0.f)
    	{
    		AddControllerYawInput(Value);
    	}
    	
    }
    
    void AMainPlayer::LookUp(float Value)
    {
    	//UE_LOG(LogTemp, Warning, TEXT("%f"), GetControlRotation().Pitch);
    	// 
    	//控制视角
    	if (GetControlRotation().Pitch < 270.f && GetControlRotation().Pitch >180.f && Value > 0.f)
    	{
    		return;
    	}
    	else if (GetControlRotation().Pitch < 180.f && GetControlRotation().Pitch >45.f && Value < 0.f)
    	{
    		return;
    	}
    	AddControllerPitchInput(Value);
    }
    
    void AMainPlayer::TurnRate(float Rate)
    {
    	//要乘以一个DeltaTime这样就可以避免高帧底帧差值问题
    	float Value = Rate * BaseTurnRate * GetWorld()->GetDeltaSeconds();
    	if (Value != 0.f)
    	{
    		AddControllerYawInput(Value);
    	}
    }
    
    void AMainPlayer::LookUpRate(float Rate)
    {
    	//要乘以一个DeltaTime这样就可以避免高帧底帧差值问题
    	float Value = Rate * BaseLookUpRate * GetWorld()->GetDeltaSeconds();
    	//控制视角
    	if (GetControlRotation().Pitch < 270.f && GetControlRotation().Pitch >180.f && Value > 0.f)
    	{
    		return;
    	}
    	else if (GetControlRotation().Pitch < 180.f && GetControlRotation().Pitch >45.f && Value < 0.f)
    	{
    		return;
    	}
    	AddControllerPitchInput(Value);
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159

    角色跳跃与空中控制

    • 直接重写Character类中的Jump方法,然后绑定轴映射到空格跳跃

    在这里插入图片描述

    在这里插入图片描述
    在这里插入图片描述

    	//重新Character类中的Jump方法
    	void Jump() override;
    
    • 1
    • 2
    	//绑定跳跃轴映射事件
    	PlayerInputComponent->BindAction("Jump", IE_Pressed, this, &AMainPlayer::Jump);//按下空格
    	PlayerInputComponent->BindAction("Jump", IE_Released, this, &ACharacter::StopJumping);//抬起空格
    
    • 1
    • 2
    • 3
    void AMainPlayer::Jump()
    {
    	//继承父类的方法
    	Super::Jump();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 设置跳跃的默认跳跃初始值与在空中的坠落时横向运动控制量(硬编码)
    	//设置跳跃初始值与在空中的坠落时横向运动控制量
    	GetCharacterMovement()->JumpZVelocity = 600.f;
    	GetCharacterMovement()->AirControl = 0.15f;
    
    • 1
    • 2
    • 3

    在这里插入图片描述

    • MainPlayer.h
    // Fill out your copyright notice in the Description page of Project Settings.
    
    #pragma once
    
    #include "CoreMinimal.h"
    #include "GameFramework/Character.h"
    #include "MainPlayer.generated.h"
    
    UCLASS()
    class UEGAME_API AMainPlayer : public ACharacter
    {
    	GENERATED_BODY()
    
    public:
    	// Sets default values for this character's properties
    	AMainPlayer();
    
    	//新建一个SpringArm
    	UPROPERTY(visibleAnywhere,BlueprintReadOnly)
    	class USpringArmComponent* SpringArm;
    	//新建一个Camera
    	UPROPERTY(visibleAnywhere, BlueprintReadOnly)
    	class UCameraComponent* FollowCamera;
    
    	
    	float BaseTurnRate;		//使用键盘X转向的速率
    	float BaseLookUpRate;	//使用键盘Y转向的速率
    
    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;
    
    	//重新Character类中的Jump方法
    	void Jump() override;
    
    	void MoveForward(float value);
    	void MoveRight(float value);
    
    	void Turn(float Value);
    	void LookUp(float Value);
    
    	void TurnRate(float Rate);
    	void LookUpRate(float Rate);
    };
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • MainPlayer.cpp
    // Fill out your copyright notice in the Description page of Project Settings.
    
    
    #include "MainPlayer.h"
    #include "GameFramework/SpringArmComponent.h"
    #include "Camera/CameraComponent.h"
    #include "Components/CapsuleComponent.h"
    #include "Components/InputComponent.h"
    #include "GameFramework/PlayerController.h"
    #include "GameFramework/CharacterMovementComponent.h"
    
    // Sets default values
    AMainPlayer::AMainPlayer()
    {
     	// Set this character to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
    	PrimaryActorTick.bCanEverTick = true;
    
    	SpringArm = CreateDefaultSubobject<USpringArmComponent>(TEXT("SpringArm"));
    	SpringArm->SetupAttachment(GetRootComponent());
    	//设置SPringArm无碰撞臂长
    	SpringArm->TargetArmLength = 600.f;
    	SpringArm->bUsePawnControlRotation = true;//硬编码SpringArm继承controlller旋转为真
    
    	FollowCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("FollowCamera"));
    	FollowCamera->SetupAttachment(SpringArm, NAME_None);
    	FollowCamera->bUsePawnControlRotation = false;//硬编码FollowCamera继承controlller旋转为假
    
    	//设置胶囊体的默认宽高
    	GetCapsuleComponent()->SetCapsuleSize(35.f, 100.f);
    
    	//对Character的Pawn进行硬编码
    	bUseControllerRotationPitch = false;
    	bUseControllerRotationYaw = false;
    	bUseControllerRotationRoll = false;
    
    	//硬编码orient Rotation to Movement,给个默认转向速率
    	GetCharacterMovement()->bOrientRotationToMovement = true;
    	GetCharacterMovement()->RotationRate = FRotator(0.f, 500.f, 0.f);
    
    	//设置跳跃初始值与在空中的坠落时横向运动控制量
    	GetCharacterMovement()->JumpZVelocity = 600.f;
    	GetCharacterMovement()->AirControl = 0.15f;
    
    	//给键盘控制转向的速率变量赋初值
    	BaseTurnRate = 21.f;
    	BaseLookUpRate = 21.f;
    }
    
    // Called when the game starts or when spawned
    void AMainPlayer::BeginPlay()
    {
    	Super::BeginPlay();
    	
    }
    
    // Called every frame
    void AMainPlayer::Tick(float DeltaTime)
    {
    	Super::Tick(DeltaTime);
    
    }
    
    // Called to bind functionality to input
    void AMainPlayer::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
    {
    	Super::SetupPlayerInputComponent(PlayerInputComponent);
    	//检查PlayerInputComponent指针,check函数只能在这使用
    	check(PlayerInputComponent);
    
    	//绑定跳跃轴映射事件
    	PlayerInputComponent->BindAction("Jump", IE_Pressed, this, &AMainPlayer::Jump);//按下空格
    	PlayerInputComponent->BindAction("Jump", IE_Released, this, &ACharacter::StopJumping);//抬起空格
    
    	//绑定移动轴映射事件
    	PlayerInputComponent->BindAxis("MoveForward", this, &AMainPlayer::MoveForward);
    	PlayerInputComponent->BindAxis("MoveRight", this, &AMainPlayer::MoveRight);
    
    	//绑定Controller控制器去管理视角旋转
    	PlayerInputComponent->BindAxis("Turn", this, &AMainPlayer::Turn);
    	PlayerInputComponent->BindAxis("LookUp", this, &AMainPlayer::LookUp);
    
    	//绑定键盘鼠标轴映射事件
    	PlayerInputComponent->BindAxis("TurnRate", this, &AMainPlayer::TurnRate);
    	PlayerInputComponent->BindAxis("LookUpRate", this, &AMainPlayer::LookUpRate);
    
    }
    
    void AMainPlayer::Jump()
    {
    	//继承父类的方法
    	Super::Jump();
    }
    
    void AMainPlayer::MoveForward(float value)
    {
    	if (Controller != nullptr && value != 0.f)
    	{
    		//获取到Control旋转
    		FRotator Rotation = Controller->GetControlRotation();
    		//转向只关注水平Yaw方向,因此置0防止影响
    		FRotator YowRotation = FRotator(0.0f, Rotation.Yaw, 0.0f);
    		//获取相机(鼠标控制器的朝向),并且朝这个轴的方向移动
    		FVector Direction = FRotationMatrix(YowRotation).GetUnitAxis(EAxis::X);
    		AddMovementInput(Direction, value);
    	}
    
    }
    
    void AMainPlayer::MoveRight(float value)
    {
    	if (Controller != nullptr && value != 0.f)
    	{
    		//获取到Controller旋转
    		FRotator Rotation = Controller->GetControlRotation();
    		//转向只关注水平Yaw方向,因此置0防止影响
    		FRotator YowRotation = FRotator(0.0f, Rotation.Yaw, 0.0f);
    		//获取相机(鼠标控制器的朝向),并且朝这个轴的方向移动
    		FVector Direction = FRotationMatrix(YowRotation).GetUnitAxis(EAxis::Y);
    		AddMovementInput(Direction, value);
    	}
    }
    
    void AMainPlayer::Turn(float Value)
    {
    	if (Value != 0.f)
    	{
    		AddControllerYawInput(Value);
    	}
    	
    }
    
    void AMainPlayer::LookUp(float Value)
    {
    	//UE_LOG(LogTemp, Warning, TEXT("%f"), GetControlRotation().Pitch);
    	// 
    	//控制视角
    	if (GetControlRotation().Pitch < 270.f && GetControlRotation().Pitch >180.f && Value > 0.f)
    	{
    		return;
    	}
    	else if (GetControlRotation().Pitch < 180.f && GetControlRotation().Pitch >45.f && Value < 0.f)
    	{
    		return;
    	}
    	AddControllerPitchInput(Value);
    }
    
    void AMainPlayer::TurnRate(float Rate)
    {
    	//要乘以一个DeltaTime这样就可以避免高帧底帧差值问题
    	float Value = Rate * BaseTurnRate * GetWorld()->GetDeltaSeconds();
    	if (Value != 0.f)
    	{
    		AddControllerYawInput(Value);
    	}
    }
    
    void AMainPlayer::LookUpRate(float Rate)
    {
    	//要乘以一个DeltaTime这样就可以避免高帧底帧差值问题
    	float Value = Rate * BaseLookUpRate * GetWorld()->GetDeltaSeconds();
    	//控制视角
    	if (GetControlRotation().Pitch < 270.f && GetControlRotation().Pitch >180.f && Value > 0.f)
    	{
    		return;
    	}
    	else if (GetControlRotation().Pitch < 180.f && GetControlRotation().Pitch >45.f && Value < 0.f)
    	{
    		return;
    	}
    	AddControllerPitchInput(Value);
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173

    混合空间(BlendSpace)

    • 创建BlendSpace1D,并给出相应的骨骼

    在这里插入图片描述

    • 将相应的行走、奔跑、动画添加上去

    在这里插入图片描述

    动画蓝图的创建

    • 创建动画蓝图,选择自己的骨骼
      在这里插入图片描述
      在这里插入图片描述

    创建给动画蓝图提供逻辑的AnimInstance子类

    • 创建AnimInstance子类
      在这里插入图片描述
    • 写入判断是否奔跑与跳跃的变量,MainPlayer类的指针方便到时候好获取参数参与UE反射,重写NativeInitializeAnimation,这个函数类似与BeginPlay,然后加入一个实时更新的函数在Animation蓝图中使用
    • MainPlayerAnimation.h
    // Fill out your copyright notice in the Description page of Project Settings.
    
    #pragma once
    
    #include "CoreMinimal.h"
    #include "Animation/AnimInstance.h"
    #include "MainPlayerAnimInstance.generated.h"
    
    /**
     * 
     */
    UCLASS()
    class UEGAME_API UMainPlayerAnimInstance : public UAnimInstance
    {
    	GENERATED_BODY()
    
    public:
    	UPROPERTY(VisibleAnywhere,BlueprintReadOnly,Category="Animation Properties")
    	float Speed;//判断速度是否达到奔跑
    	
    	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Animation Properties")
    	bool bIsAir;//判断是否跳跃
    
    	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Animation Properties")
    	class AMainPlayer* Player;
    
    	virtual void NativeInitializeAnimation() override; //类似与BeginPlay
    
    	UFUNCTION(BlueprintCallable, Category = "Animation Properties")
    	void UpdataAnimationProperties();//实时更新
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • MainPlayerAnimtion.cpp
    // Fill out your copyright notice in the Description page of Project Settings.
    
    
    #include "MainPlayerAnimInstance.h"
    
    void UMainPlayerAnimInstance::NativeInitializeAnimation()
    {
    
    }
    
    void UMainPlayerAnimInstance::UpdataAnimationProperties()
    {
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    编写动画参数更新逻辑并给动画蓝图指定父类

    • MainPlayerAnimtion.cpp
    • TryGetPawnOwner:获取角色的Pawn类
    • GetVelocity:获取速度
    // Fill out your copyright notice in the Description page of Project Settings.
    
    
    #include "MainPlayerAnimInstance.h"
    #include "Characters/Player/MainPlayer.h"
    #include "GameFramework/CharacterMovementComponent.h"
    void UMainPlayerAnimInstance::NativeInitializeAnimation()
    {
    	
    	Player = Cast<AMainPlayer>(TryGetPawnOwner());//获取角色的Pawn类
    }
    
    void UMainPlayerAnimInstance::UpdataAnimationProperties()
    {
    	//防御性编程
    	if (Player)
    	{
    		//移动只需要平面的速度
    		FVector SpeedVector = Player->GetVelocity();
    		FVector PlanarSpeed = FVector(SpeedVector.X, SpeedVector.Y, 0.f);
    		//将移动的向量传给speed即可
    		Speed = PlanarSpeed.Size();
    
    		bIsAir = Player->GetMovementComponent()->IsFalling();//判断Player是否在下落
    	}
    	else 
    	{
    		Player = Cast<AMainPlayer>(TryGetPawnOwner());//获取角色的Pawn类
    	}
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 给动画蓝图指定父类
      在这里插入图片描述

    制作移动动画设置到角色

    • 连接我们的更新函数
      在这里插入图片描述
    • 新建一个状态机
      在这里插入图片描述
    • 在状态机里面在添加一个状态
      在这里插入图片描述
    • 然后再到此状态里面把混合空间与编码的speed加上
      在这里插入图片描述
    • 返回最开始的动画图表连接上最终动画
      在这里插入图片描述
    • 最后将混合空间添加到角色蓝图Mesh的Animation中就可
      在这里插入图片描述

    制作跳跃动画设置到角色

    • 将跳跃的三个状态添加到状态机
      在这里插入图片描述

    • 首先判断是否起跳,用C++编写好的变量进行判断
      在这里插入图片描述

    • 监测起跳动作,当跳跃动作快播放完了的时候就得开始切换,一般我们常用这个Timer Remaining(ratio):剩余计时器(比例)来进行使用判断监测
      在这里插入图片描述

    • 判断是否落下
      在这里插入图片描述

    • 监测落下动作,当跳跃动作快播放完了的时候就得开始切换,一般我们常用这个Timer Remaining(ratio):剩余计时器(比例)来进行使用判断监测
      在这里插入图片描述

    • 运行结果
      请添加图片描述

  • 相关阅读:
    你真知道交换机、路由器和防火墙的区别吗?
    00 后搞视频号月入过万,怎么做?
    dubbo-admin配置及使用
    李宏毅2022机器学习HW3 Image Classification
    嵌入式开发从入门到精通之第三十节:NFC射频天线设计及调测
    【FreeRTOS】【STM32】06.1 FreeRTOS的使用1(对06的补充)
    Ubuntu18.04 系统安装Anaconda
    数据可视化ECharts:静态页面制作--主体
    Vue3 el-tooltip 根据内容控制宽度大小换行和并且内容太短不显示
    算法力扣刷题记录 十三【242. 有效的字母异位词】
  • 原文地址:https://blog.csdn.net/qq_44924388/article/details/134207597