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 };