UE4 从无到有纯 C++ & Slate 开发沙盒游戏(十八) 添加玩家模型与相机
上一部分吧 GameMode 都绑定好了,现在把模型和相机放到 PlayerCharacter 上去
先做准备工作
如果我们写C++文件想要看到实时的效果,需要在 Content 下加个 Blueprint 文件夹,其下再创建个 Temp 文件夹,这个Temp 中保存写的一些蓝图,这些蓝图在项目完成以后是不需要的。
添加蓝图
由于我们是要一边写 PlayerCharacter 一边看他的效果,所以我们要选择创建一个继承自 PlayerCharacter 的蓝图,命名为 PlayerCharacterBP
这样便可以修改C++代码的同时动态的看到其实时效果
D:\UE4 Project\UE26.2\CourseProject\SlAiCourse\Source\SlAiCourse\Private\Player\SlAiPlayerCharacter.cpp
1 #include "Player/SlAiPlayerCharacter.h" 2 3 4 // Sets default values 5 ASlAiPlayerCharacter::ASlAiPlayerCharacter() 6 { 7 // Set this character to call Tick() every frame. You can turn this off to improve performance if you don't need it. 8 PrimaryActorTick.bCanEverTick = true; 9 10 /** 11 * 创建 Component(属性) 12 * CreateDefaultSubobject<T>() 在构造函数中创建使用 13 * NewObject<T> 如果要在其他位置的代码或者蓝图中创建,可以用 NewObject,用来创建 Uobject 类型 14 */ 15 16 /** 17 * 给默认 Mesh 添加骨骼模型 18 * 19 * Uobject 资源加载 20 * ConstructorHelpers::FObjectFinder<T>只能在构造函数使用 21 * LoadObiect<T>可以在任何地方使用 22 * 23 * 蓝图资源加载 24 * ConstructorHelpers::FClassFinder <T>只能在构造函数使用 25 * LoadClass<T>可以在任何地方加载 26 * 27 * 全局加载资源函数 28 * StaticLoadObject、StaticLoadClass 29 * 应该是早期的LoadObiect<T>和LoadClass<T>的版本 30 */ 31 static ConstructorHelpers::FObjectFinder<USkeletalMesh> StaticMeshThird(TEXT("SkeletalMesh'/Game/AssetsvilleTown/Meshes/Characters/SK_citizen_female_10.SK_citizen_female_10'")); 32 GetMesh()->SetSkeletalMesh(StaticMeshThird.Object); 33 GetMesh()->bOnlyOwnerSee = true; //如果该值为True,则该组件仅在视图参与者是该组件的所有者时才可见。直接或间接。 34 GetMesh()->bReceivesDecals = false; //是否接收光线反射 35 GetMesh()->SetCollisionObjectType(ECC_Pawn); //在骨架网格上设置碰撞对象类型 36 GetMesh()->SetCollisionEnabled(ECollisionEnabled::NoCollision); //我们的碰撞都会放到根组件的椭圆碰撞,这里设置无碰撞 37 GetMesh()->SetCollisionResponseToChannels(ECR_Ignore); //让这个Mesh忽略所有的碰撞 38 GetMesh()->SetRelativeLocation(FVector(0.f, 0.f, -95.f)); //设置位置 39 GetMesh()->SetRelativeRotation(FQuat::MakeFromEuler(FVector(0.f, 0.f, -90.f))); //设置旋转 40 } 41 42 // Called when the game starts or when spawned 43 void ASlAiPlayerCharacter::BeginPlay() 44 { 45 Super::BeginPlay(); 46 } 47 48 // Called every frame 49 void ASlAiPlayerCharacter::Tick(float DeltaTime) 50 { 51 Super::Tick(DeltaTime); 52 } 53 54 // Called to bind functionality to input 55 void ASlAiPlayerCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent) 56 { 57 Super::SetupPlayerInputComponent(PlayerInputComponent); 58 }
可以看到第三人称的模型已经放到了原点,拥有正的朝向和高度,碰撞属性也都配置好了
下面是第一人称的配置
d:\ue4 project\ue26.2\courseproject\slaicourse\Source\SlAiCourse\Public\Player\SlAiPlayerCharacter.h
1 #include "CoreMinimal.h" 2 #include "GameFramework/Character.h" 3 #include "SlAiPlayerCharacter.generated.h" 4 5 UCLASS() 6 class SLAICOURSE_API ASlAiPlayerCharacter : public ACharacter 7 { 8 GENERATED_BODY() 9 10 public: 11 // Sets default values for this character's properties 12 ASlAiPlayerCharacter(); 13 14 protected: 15 // Called when the game starts or when spawned 16 virtual void BeginPlay() override; 17 18 public: 19 // Called every frame 20 virtual void Tick(float DeltaTime) override; 21 22 // Called to bind functionality to input 23 virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override; 24 25 //第一人称的骨骼模型,VisibleDefaultsOnly 默认的, 26 UPROPERTY(VisibleDefaultsOnly, Category = "SlAi") 27 USkeletalMeshComponent* MeshFirst; 28 };
D:\UE4 Project\UE26.2\CourseProject\SlAiCourse\Source\SlAiCourse\Private\Player\SlAiPlayerCharacter.cpp
1 #include "Player/SlAiPlayerCharacter.h" 2 3 4 // Sets default values 5 ASlAiPlayerCharacter::ASlAiPlayerCharacter() 6 { 7 // Set this character to call Tick() every frame. You can turn this off to improve performance if you don't need it. 8 PrimaryActorTick.bCanEverTick = true; 9 10 /** 11 * 创建 Component(属性) 12 * CreateDefaultSubobject<T>() 在构造函数中创建使用 13 * NewObject<T> 如果要在其他位置的代码或者蓝图中创建,可以用 NewObject,用来创建 Uobject 类型 14 * 15 * 给默认 Mesh 添加骨骼模型 16 * 17 * Uobject 资源加载 18 * ConstructorHelpers::FObjectFinder<T>只能在构造函数使用 19 * LoadObiect<T>可以在任何地方使用 20 * 21 * 蓝图资源加载 22 * ConstructorHelpers::FClassFinder <T>只能在构造函数使用 23 * LoadClass<T>可以在任何地方加载 24 * 25 * 全局加载资源函数 26 * StaticLoadObject、StaticLoadClass 27 * 应该是早期的LoadObiect<T>和LoadClass<T>的版本 28 */ 29 30 //添加第一人称骨骼模型 31 static ConstructorHelpers::FObjectFinder<USkeletalMesh> StaticMeshFirst(TEXT("SkeletalMesh'/Game/AssetsvilleTown/Meshes/Characters/SK_citizen_female_10.SK_citizen_female_10'")); 32 MeshFirst = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("MeshFirst")); //实例化 33 MeshFirst->SetSkeletalMesh(StaticMeshFirst.Object); //设置骨骼模型 34 MeshFirst->SetupAttachment((USceneComponent*)GetCapsuleComponent()); //将Component添加到碰撞组件下 35 MeshFirst->bOnlyOwnerSee = true; //如果该值为True,则该组件仅在视图参与者是该组件的所有者时才可见。直接或间接。 36 //MeshFirst->bCastDynamicShadow = false; //是否渲染模型影子(如果你用的是两个手臂一样的模型,那就 false 屏蔽掉),默认是显示 37 MeshFirst->bReceivesDecals = false; //是否接收光线反射 38 //更新频率衰落 39 MeshFirst->MeshComponentUpdateFlag = EMeshComponentUpdateFlag::OnlyTickMontagesWhenNotRendered; 40 MeshFirst->PrimaryComponentTick.TickGroup = TG_PrePhysics; 41 //设置碰撞属性 42 MeshFirst->SetCollisionObjectType(ECC_Pawn); //在骨架网格上设置碰撞对象类型 43 MeshFirst->SetCollisionEnabled(ECollisionEnabled::NoCollision); //我们的碰撞都会放到根组件的椭圆碰撞,这里设置无碰撞 44 MeshFirst->SetCollisionResponseToAllChannels(ECR_Ignore); //让这个Mesh忽略所有的碰撞 45 //设置位移 46 MeshFirst->SetRelativeLocation(FVector(0.f, 0.f, -95.f)); //设置位置 47 MeshFirst->SetRelativeRotation(FQuat::MakeFromEuler(FVector(0.f, 0.f, -90.f))); //设置旋转 48 49 //添加第三人称骨骼模型 50 static ConstructorHelpers::FObjectFinder<USkeletalMesh> StaticMeshThird(TEXT("SkeletalMesh'/Game/AssetsvilleTown/Meshes/Characters/SK_citizen_female_10.SK_citizen_female_10'")); 51 GetMesh()->SetSkeletalMesh(StaticMeshThird.Object); 52 GetMesh()->bOnlyOwnerSee = true; 53 GetMesh()->bReceivesDecals = false; 54 GetMesh()->SetCollisionObjectType(ECC_Pawn); 55 GetMesh()->SetCollisionEnabled(ECollisionEnabled::NoCollision); 56 GetMesh()->SetCollisionResponseToAllChannels(ECR_Ignore); 57 GetMesh()->SetRelativeLocation(FVector(0.f, 0.f, -95.f)); 58 GetMesh()->SetRelativeRotation(FQuat::MakeFromEuler(FVector(0.f, 0.f, -90.f))); 59 } 60 61 // Called when the game starts or when spawned 62 void ASlAiPlayerCharacter::BeginPlay() 63 { 64 Super::BeginPlay(); 65 } 66 67 // Called every frame 68 void ASlAiPlayerCharacter::Tick(float DeltaTime) 69 { 70 Super::Tick(DeltaTime); 71 } 72 73 // Called to bind functionality to input 74 void ASlAiPlayerCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent) 75 { 76 Super::SetupPlayerInputComponent(PlayerInputComponent); 77 }
添加摄像机
d:\ue4 project\ue26.2\courseproject\slaicourse\Source\SlAiCourse\Public\Player\SlAiPlayerCharacter.h
1 #include "CoreMinimal.h" 2 #include "GameFramework/Character.h" 3 #include "SlAiPlayerCharacter.generated.h" 4 5 UCLASS() 6 class SLAICOURSE_API ASlAiPlayerCharacter : public ACharacter 7 { 8 GENERATED_BODY() 9 10 public: 11 // Sets default values for this character's properties 12 ASlAiPlayerCharacter(); 13 14 // Called every frame 15 virtual void Tick(float DeltaTime) override; 16 17 // Called to bind functionality to input 18 virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override; 19 20 public: 21 UPROPERTY(VisibleDefaultsOnly, Category = "SlAi") 22 class USpringArmComponent* CameraBoom; //相当于一个摄像机的摇杆 23 24 UPROPERTY(VisibleDefaultsOnly, Category = "SlAi") 25 class UCameraComponent* ThirdCamera; //第三人称摄像机组件 26 27 UPROPERTY(VisibleDefaultsOnly, Category = "SlAi") 28 UCameraComponent* FirstCamera; //第一人称摄像机组件 29 30 protected: 31 // Called when the game starts or when spawned 32 virtual void BeginPlay() override; 33 34 public: 35 //第一人称的骨骼模型,VisibleDefaultsOnly 默认的, 36 UPROPERTY(VisibleDefaultsOnly, Category = "SlAi") 37 USkeletalMeshComponent* MeshFirst; 38 };
D:\UE4 Project\UE26.2\CourseProject\SlAiCourse\Source\SlAiCourse\Private\Player\SlAiPlayerCharacter.cpp
1 #include "Player/SlAiPlayerCharacter.h" 2 #include "UObject/Object.h" 3 #include "GameFramework/SpringArmComponent.h" 4 #include "Camera/CameraComponent.h" 5 6 7 // Sets default values 8 ASlAiPlayerCharacter::ASlAiPlayerCharacter() 9 { 10 // Set this character to call Tick() every frame. You can turn this off to improve performance if you don't need it. 11 PrimaryActorTick.bCanEverTick = true; 12 13 /** 14 * 创建 Component(属性) 15 * CreateDefaultSubobject<T>() 在构造函数中创建使用 16 * NewObject<T> 如果要在其他位置的代码或者蓝图中创建,可以用 NewObject,用来创建 Uobject 类型 17 * 18 * 给默认 Mesh 添加骨骼模型 19 * 20 * Uobject 资源加载 21 * ConstructorHelpers::FObjectFinder<T>只能在构造函数使用 22 * LoadObiect<T>可以在任何地方使用 23 * 24 * 蓝图资源加载 25 * ConstructorHelpers::FClassFinder <T>只能在构造函数使用 26 * LoadClass<T>可以在任何地方加载 27 * 28 * 全局加载资源函数 29 * StaticLoadObject、StaticLoadClass 30 * 应该是早期的LoadObiect<T>和LoadClass<T>的版本 31 */ 32 33 //添加第一人称骨骼模型 34 static ConstructorHelpers::FObjectFinder<USkeletalMesh> StaticMeshFirst(TEXT("SkeletalMesh'/Game/AssetsvilleTown/Meshes/Characters/SK_citizen_female_10.SK_citizen_female_10'")); 35 MeshFirst = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("MeshFirst")); //实例化 36 MeshFirst->SetSkeletalMesh(StaticMeshFirst.Object); //设置骨骼模型 37 MeshFirst->SetupAttachment((USceneComponent*)GetCapsuleComponent()); //将Component添加到碰撞组件下 38 MeshFirst->bOnlyOwnerSee = true; //如果该值为True,则该组件仅在视图参与者是该组件的所有者时才可见。直接或间接。 39 //MeshFirst->bCastDynamicShadow = false; //是否渲染模型影子(如果你用的是两个手臂一样的模型,那就 false 屏蔽掉),默认是显示 40 MeshFirst->bReceivesDecals = false; //是否接收光线反射 41 //更新频率衰落 42 MeshFirst->MeshComponentUpdateFlag = EMeshComponentUpdateFlag::OnlyTickMontagesWhenNotRendered; 43 MeshFirst->PrimaryComponentTick.TickGroup = TG_PrePhysics; 44 //设置碰撞属性 45 MeshFirst->SetCollisionObjectType(ECC_Pawn); //在骨架网格上设置碰撞对象类型 46 MeshFirst->SetCollisionEnabled(ECollisionEnabled::NoCollision); //我们的碰撞都会放到根组件的椭圆碰撞,这里设置无碰撞 47 MeshFirst->SetCollisionResponseToAllChannels(ECR_Ignore); //让这个Mesh忽略所有的碰撞 48 //设置位移 49 MeshFirst->SetRelativeLocation(FVector(0.f, 0.f, -95.f)); //设置位置 50 MeshFirst->SetRelativeRotation(FQuat::MakeFromEuler(FVector(0.f, 0.f, -90.f))); //设置旋转 51 52 //添加第三人称骨骼模型 53 static ConstructorHelpers::FObjectFinder<USkeletalMesh> StaticMeshThird(TEXT("SkeletalMesh'/Game/AssetsvilleTown/Meshes/Characters/SK_citizen_female_10.SK_citizen_female_10'")); 54 GetMesh()->SetSkeletalMesh(StaticMeshThird.Object); 55 GetMesh()->bOnlyOwnerSee = true; 56 GetMesh()->bReceivesDecals = false; 57 GetMesh()->SetCollisionObjectType(ECC_Pawn); 58 GetMesh()->SetCollisionEnabled(ECollisionEnabled::NoCollision); 59 GetMesh()->SetCollisionResponseToAllChannels(ECR_Ignore); 60 GetMesh()->SetRelativeLocation(FVector(0.f, 0.f, -95.f)); 61 GetMesh()->SetRelativeRotation(FQuat::MakeFromEuler(FVector(0.f, 0.f, -90.f))); 62 63 //摄像机手臂 64 CameraBoom = CreateDefaultSubobject<USpringArmComponent>(TEXT("CameraBoom")); 65 CameraBoom->SetupAttachment(RootComponent); 66 //设置距离 67 CameraBoom->TargetArmLength = 300.f; 68 //设置偏移 69 CameraBoom->TargetOffset = FVector(0.f, 0.f, 60.f); 70 //绑定 Controller 的旋转 71 CameraBoom->bUsePawnControlRotation = true; 72 73 //初始化第三人称摄像机 74 ThirdCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("ThirdCamera")); 75 ThirdCamera->SetupAttachment(CameraBoom, USpringArmComponent::SocketName); 76 //设置 ThirdCamera 不跟随控制器的旋转 77 ThirdCamera->bUsePawnControlRotation = false; 78 79 //初始化第一人称摄像机 80 FirstCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("FirstCamera")); 81 FirstCamera->SetupAttachment((USceneComponent*)GetCapsuleComponent()); 82 //设置跟随 Controller 的旋转 83 FirstCamera->bUsePawnControlRotation = true; 84 85 //位置偏移 86 FirstCamera->AddLocalOffset(FVector(0.f, 0.f, 60.f)); 87 } 88 89 // Called when the game starts or when spawned 90 void ASlAiPlayerCharacter::BeginPlay() 91 { 92 Super::BeginPlay(); 93 } 94 95 // Called every frame 96 void ASlAiPlayerCharacter::Tick(float DeltaTime) 97 { 98 Super::Tick(DeltaTime); 99 } 100 101 // Called to bind functionality to input 102 void ASlAiPlayerCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent) 103 { 104 Super::SetupPlayerInputComponent(PlayerInputComponent); 105 }
添加完毕