MyPawn.h部分
1 // Fill out your copyright notice in the Description page of Project Settings. 2 3 #pragma once 4 5 #include "CoreMinimal.h" 6 #include "GameFramework/Pawn.h" 7 #include "MyPawn.generated.h" 8 UCLASS() 9 class TEST4_API AMyPawn : public APawn 10 { 11 GENERATED_BODY() 12 13 public: 14 // Sets default values for this pawn's properties 15 AMyPawn(); 16 17 protected: 18 // Called when the game starts or when spawned 19 virtual void BeginPlay() override; 20 21 public: 22 // Called every frame 23 virtual void Tick(float DeltaTime) override; 24 25 // Called to bind functionality to input 26 virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override; 27 void fire(); 28 void MoveForward(float AxisValue); 29 void MoveRight(float AxisValue); 30 31 class UMyPawnMovementComponent* OurMovementComponent; 32 33 virtual UPawnMovementComponent* GetMovementComponent() const override; 34 /* 35 1.引入同一项目类请加入 class 36 2.如果补加入头文件 只能引入同一项目引用 而不能确定继承关系 37 38 */ 39 UParticleSystemComponent* OurParticleSystem; 40 private: 41 int32 coutFire = 0;//计数器 禁止外部对象和子对象访问 42 float RunningTime = 0.0f; 43 44 };
MyPawn.cpp部分
1 // Fill out your copyright notice in the Description page of Project Settings. 2 3 #include "MyPawn.h" 4 #include "Runtime/Engine/Classes/Components/BoxComponent.h" 5 #include "Runtime/Engine/Classes/Components/SphereComponent.h"// USphereComponent 引用 6 #include "Runtime/CoreUObject/Public/UObject/ConstructorHelpers.h" // ConstructorHelpers 引用 7 #include "Runtime/Engine/Classes/Particles/ParticleSystemComponent.h"//UParticleSystemComponent 引用 8 #include "Runtime/Engine/Classes/GameFramework/SpringArmComponent.h"//UStaticMeshComponent 引用 9 #include "Runtime/Engine/Classes/Camera/CameraComponent.h"//UCameraComponent 引用 10 #include "MyPawnMovementComponent.h" 11 #include "string" 12 using namespace std; 13 // Sets default values 14 AMyPawn::AMyPawn() 15 { 16 // Set this pawn to call Tick() every frame. You can turn this off to improve performance if you don't need it. 17 PrimaryActorTick.bCanEverTick = true; 18 AutoPossessPlayer = EAutoReceiveInput::Player0;//这行代码不加 无法实现用户操作 此时用户视角就是当前pawn视角 19 20 USphereComponent * SphereComponent = CreateDefaultSubobject<USphereComponent>("RootComponent"); 21 RootComponent = SphereComponent;//这里不一定非要用物体组件 22 23 24 25 // 创建静态网格物体 26 UStaticMeshComponent * SphereVisual = CreateDefaultSubobject<UStaticMeshComponent>("VisualRepresentation"); 27 SphereVisual->SetupAttachment(RootComponent); 28 SphereComponent->InitSphereRadius(40.f);// 实际物理 碰撞半径 29 SphereComponent->SetCollisionProfileName(TEXT("Pawn"));//碰撞设置 设置这个方法才可以实现物理碰撞 这里的名称必须为Pawn 30 //SetCollisionProfileName需要删除之前虚幻4场景中的pawn物体然后再重新加入才能实现物理碰撞 31 FName sComProName = SphereComponent->GetCollisionProfileName();// 得到 碰撞设置的名称 32 33 //打开素材库 34 static ConstructorHelpers::FObjectFinder<UStaticMesh> SphereVisualAssetWzh(TEXT("/Game/StarterContent/Shapes/Shape_Sphere.Shape_Sphere")); 35 if (SphereVisualAssetWzh.Succeeded()) { 36 SphereVisual->SetStaticMesh(SphereVisualAssetWzh.Object); 37 SphereVisual->SetRelativeLocation(FVector(0.0f, 0.0f, -40.0f));//设置位置0,0,0为初始位置 38 SphereVisual->SetWorldScale3D(FVector(0.8f));//SetWorldScale3D 设置组件在世界空间中的变换倍数。 倍数以原来模型大小为基准 39 } 40 41 // 创建一个可启用或停用的粒子系统 42 OurParticleSystem = CreateDefaultSubobject<UParticleSystemComponent>(TEXT("MovementParticles")); 43 OurParticleSystem->SetupAttachment(RootComponent);//直接将粒子系统添加到根组件上 44 OurParticleSystem->bAutoActivate = false;//在场景中激活 45 46 OurParticleSystem->SetRelativeLocation(FVector(-20.0f, 0.0f, 20.0f)); 47 OurParticleSystem->SetWorldScale3D(FVector(3.0f));//SetWorldScale3D 设置组件在世界空间中的变换倍数。 倍数以原来模型大小为基准 48 static ConstructorHelpers::FObjectFinder<UParticleSystem> ParticleAsset(TEXT("/Game/StarterContent/Particles/P_Fire.P_Fire")); 49 if (ParticleAsset.Succeeded()) 50 { 51 OurParticleSystem->SetTemplate(ParticleAsset.Object); 52 } 53 54 55 //加入个摄像头让视角看起来舒服点 当然不加也是可以看到 56 UCameraComponent* Camera = CreateDefaultSubobject<UCameraComponent>(TEXT("ActualCamera")); 57 Camera->SetupAttachment(RootComponent); 58 Camera->SetRelativeLocation(FVector(-250.f, 0.0f, 400));//设置位置0,0,0为初始位置 59 Camera->RelativeRotation = FRotator(-45.f, 0.f, 0.f);// y z x顺序旋转 一个旋转信息的容器 所有旋转值都以度数存储。 60 61 // 创建移动组件的一个实例,并告知其更新根组件。 62 //<UMyPawnMovementComponent>为自定义移动组件类 63 OurMovementComponent = CreateDefaultSubobject<UMyPawnMovementComponent>(TEXT("CustomMovementComponent"));//创建自定义移动组件类 如果没有这行代码无法实现物理碰撞无法使用自定义移动类移动球体 64 OurMovementComponent->UpdatedComponent = RootComponent;//这行代码不加也可以 65 66 } 67 68 // Called when the game starts or when spawned 69 void AMyPawn::BeginPlay() 70 { 71 Super::BeginPlay(); 72 73 74 } 75 76 // Called every frame 77 void AMyPawn::Tick(float DeltaTime)//没两帧之间的时间间隔 78 { 79 Super::Tick(DeltaTime); 80 81 82 } 83 84 // Called to bind functionality to input 85 void AMyPawn::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent) 86 { 87 Super::SetupPlayerInputComponent(PlayerInputComponent); 88 PlayerInputComponent->BindAction("fire", IE_Released, this, &AMyPawn::fire); 89 InputComponent->BindAxis("MoveRight", this, &AMyPawn::MoveRight); 90 InputComponent->BindAxis("MoveForward", this, &AMyPawn::MoveForward); 91 } 92 93 UPawnMovementComponent* AMyPawn::GetMovementComponent() const//得到移动组件 94 { 95 return OurMovementComponent; 96 } 97 98 void AMyPawn::fire() { 99 coutFire = !coutFire; 100 if (GEngine) 101 { 102 GEngine->AddOnScreenDebugMessage(-1, 0.2, FColor::Red, TEXT("火焰!")); 103 104 int32 active32 = OurParticleSystem->bIsActive; 105 //OurParticleSystem->ToggleActive(); //官方使用的ToggleActive()切换粒子状态 我建议不要使用这个函数 因为 106 //在快速按下键盘按键 调用事件函数fire时 无法执行里面的ToggleActive函数 但是可以打印文字“火焰“ 但是慢慢按就没问题 107 //我发现主要是 ToggleActive内部操作 bIsActive的问题 如果快速按下 bIsActive 就不会重新赋值 而是一直为1估计是虚幻4官方的bug, 慢慢按 才为0 我自己重新 定义一个外部变量coutFire 计数代替bIsActive 就没问题了不用ToggleActive实现 108 OurParticleSystem->SetActive(coutFire);//通过计数器 切换状态 109 } 110 111 } 112 113 void AMyPawn::MoveForward(float AxisValue)//移动前进 114 { 115 116 117 if (OurMovementComponent && (OurMovementComponent->UpdatedComponent == RootComponent)) 118 { 119 if (GEngine) 120 { 121 // TEXT只能接受字符串常量 122 123 FVector xyz1 = GetActorForwardVector(); 124 string str = to_string(xyz1.X) + " , " + to_string(xyz1.Y) + " , " + to_string(xyz1.Z) + " AxisValue = " + to_string(AxisValue); 125 FString fstr = FString(str.c_str()); 126 //按下s键AxisValue为-1 w键AxisValue为1 127 GEngine->AddOnScreenDebugMessage(-1, 0.5, FColor::Yellow, fstr); 128 } 129 130 //AddInputVector 设置每次移动的方向和距离 输入值 0.0 - 1.0之前 131 132 //GetActorForwardVector()得到当前视角永远向前的值 通过计算sin和鼠标转动的大小实现 就算视角变换也永远向前 133 //x大小就是当前sin大小 默认是1/2π 90度等于1 取值范围-1 -- 1, y z永远为0 134 135 //AxisValue ue4里按键绑定的值 设置输入的向量值移动的大小 136 137 OurMovementComponent->AddInputVector(GetActorForwardVector() * AxisValue);//AxisValue ue4里按键绑定的值 设置输入的向量值移动的大小 不按下时为0 138 139 if (GEngine) 140 { 141 // TEXT只能接受字符串常量 142 FVector xyz2 = OurMovementComponent->GetInputVector();//注意这里不是 GetActorForwardVector() 143 144 string str2 = to_string(xyz2.X) + " , " + to_string(xyz2.Y) + " , " + to_string(xyz2.Z) + " AxisValue = " + to_string(AxisValue) + " Speed = " + to_string(OurMovementComponent->GetMaxSpeed()); 145 FString fstr2 = FString(str2.c_str()); 146 GEngine->AddOnScreenDebugMessage(-1, 0.5, FColor::Red, fstr2); 147 148 } 149 150 } 151 } 152 153 void AMyPawn::MoveRight(float AxisValue)//移动向右 154 { 155 if (OurMovementComponent && (OurMovementComponent->UpdatedComponent == RootComponent)) 156 { 157 OurMovementComponent->AddInputVector(GetActorRightVector() * AxisValue); 158 } 159 }
MyPawnMovementComponent.h部分
1 // Fill out your copyright notice in the Description page of Project Settings. 2 3 #pragma once 4 5 #include "CoreMinimal.h" 6 #include "GameFramework/PawnMovementComponent.h" 7 #include "MyPawnMovementComponent.generated.h" 8 9 /** 10 * 11 */ 12 UCLASS() 13 class TEST4_API UMyPawnMovementComponent : public UPawnMovementComponent 14 { 15 GENERATED_BODY() 16 17 public: 18 virtual void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction) override; 19 20 21 22 };
MyPawnMovementComponent.cpp部分
1 // Fill out your copyright notice in the Description page of Project Settings. 2 3 #include "MyPawnMovementComponent.h" 4 void UMyPawnMovementComponent::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction) 5 { 6 Super::TickComponent(DeltaTime, TickType, ThisTickFunction); 7 8 // 确保所有内容仍然有效,并允许移动。 9 if (!PawnOwner || !UpdatedComponent || ShouldSkipUpdate(DeltaTime)) 10 { 11 return; 12 } 13 14 // 获取(然后清除)在 ACollidingPawn::Tick 设置的移动矢量。 15 FVector DesiredMovementThisFrame = ConsumeInputVector().GetClampedToMaxSize(1.0f) * DeltaTime * 150.0f; 16 if (!DesiredMovementThisFrame.IsNearlyZero()) 17 { 18 FHitResult Hit; 19 SafeMoveUpdatedComponent(DesiredMovementThisFrame, UpdatedComponent->GetComponentRotation(), true, Hit); 20 21 // 如碰到物体,尝试沿其滑动 22 if (Hit.IsValidBlockingHit()) 23 { 24 SlideAlongSurface(DesiredMovementThisFrame, 1.f - Hit.Time, Hit.Normal, Hit); 25 } 26 } 27 };