【UEC++游戏案例】向上的小松饼

一. 效果与资源准备

1.1 游戏演示效果

 

 

1.2 游戏资产素材与源码

 

 

1.3 前期准备

  1. 创建无初学者内容的空项目

  2. 将素材文件拷贝到项目 Content 文件夹下

 

  1. 搭建场景(用 3D 场景模拟 2D 游戏效果)

 

 

二. 创建角色类与全局相机

2.1 创建角色类

  1. 创建C++类(Character),重命名 Cake(Public)

 

  1. 创建继承自 Cake 的蓝图(实例化),重命名 BP_Cake,并存放在 Blueprints 文件夹下

 

  1. 设置 BP_Cake 模型资产,并调整胶囊体覆盖模型

 

  1. 创建 BP_GameModeBase 游戏模式(GameModeBase),并和 BP_Cake 一起挂载到项目设置,那么在场景中放置玩家出生点 Player Start 后,运行时会自动生成 BP_Cake 的玩家出生点位置

 

 

2.2 创建全局相机

  1. 创建C++类(Actor),重命名 Camera(Public)

 

  1. 创建继承自 Camera 的蓝图(实例化),重命名 BP_Camera,并存放在 Blueprints 文件夹下

 

  1. 指定默认相机

 

  1. 调整相机正交模式

 

 

三. 移动逻辑

3.1 角色水平方向跟随鼠标移动

  1. 获取 PlayerController,运行时显示鼠标

 

  1. 角色随鼠标移动

 

  1. 防止角色出画,添加阻挡体积

 

  1. 运行效果:

 

 

3.2 角色垂直方向跳跃

  1. 角色垂直方向跳跃

 

  1. 绑定操作映射

 

  1. 运行效果:

 

 

3.4 设置角色速度

  1. 设置角色在空中/落地 2种状态下的不同速度

 

  1. 设置角色 BP_Cake 蓝图物理细节参数

 

 

3.4 全局相机垂直跟随

  1. 相机左右并不移动,只需调整 Z 轴跟随

 

  1. 设置背景板和阻挡体积为可移动,随摄像机移动

 

  1. 运行效果:

 

 

 

 

四. 创建云朵类

4.1 创建云朵类

  1. 创建C++类(Actor),重命名 Cloud(Public)

 

  1. 创建继承自 Cloud 的蓝图(实例化),重命名 BP_Cloud,并存放在 Blueprints 文件夹下

 

  1. 添加盒体检测组件和云朵组件

 

4.2 随机云贴图生成

  1. 通过修改材质中的,随机生成云显示

 

  1. 设置云朵的显示,并添加材质数组

 

  1. 运行效果(拖放多个 BP_Cloud 到场景中运行测试):

 

  1. 调整修改云朵的大小

 

 

 

 

4.3 角色触碰云朵则触发弹跳

  1. 重写碰撞函数,检测到角色则调用弹跳函数

 

  1. 运行效果(小球触碰到云朵就起飞):

 

 

4.4 云朵随机下雨

  1. 添加云朵雨组件并绑定,随机显示云朵雨

 

  1. 设置云朵雨的位置,并添加材质

 

  1. 运行效果(随机生成云朵雨):

 

 

五. 云朵生成器

5.1 创建云朵生成器

  1. 创建C++类(Actor),重命名 SpawnCloud(Public)

 

  1. 创建继承自 SpawnCloud 的蓝图(实例化),重命名 BP_SpawnCloud,存放在 Blueprints 文件夹下

 

  1. 云朵生成器的原理:在高处设置一块云朵生成区 SpawnArea,低处设置一块碰撞检测区 TriggerArea,当角色跳跃碰撞到检测区 TriggerArea,则整体上移,并在生成区 SpawnArea 随机位置生成云朵

 

 

5.2 随机位置生成云朵

  1. 添加云朵生成区域组件和检测生成区域组件

 

  1. 随机位置生成云朵

 

 

5.3 碰撞检测与初始化上升

  1. 检测是否与角色产生碰撞

 

  1. 云朵生成器的初始化与上升

 

  1. 在 BP_SpawnCloud 中调整参数

 

 

六. 计分系统与云朵销毁

6.1 计分系统

  1. 在角色中添加分数和计分方法

 

  1. 在云朵中添加分数文本,并显示分数

 

  1. 调整分数文本的字体位置大小

 

 

6.2 TimeLine 云朵销毁

  1. 结合蓝图中 Timeline 实现云朵淡入淡出效果

 

  1. 销毁相机视角外的多余云朵

 

  1. 在场景中调整销毁碰撞检测区域的位置

 

  1. 运行效果(销毁时显示计数并变化淡出,落下区域无云朵):

 

 

七. 游戏结束与重开

7.1 游戏结束的判定

  1. 结合蓝图中 Timeline (计数 2s )判断角色是否持续下落,如果持续下落则直接降落到地面

 

  1. 游戏结束的判定

 

 

7.2 游戏重开按钮

  1. 创建 UMG 蓝图,直接设计游戏重开按钮 UI(不建议在C++里面用代码创建UI按钮,是一件非常费力不讨好的事情)

 

  1. 设置 UI 动画

 

  1. 结合蓝图,在游戏结束后显示游戏重开按钮

 

 

7.3 点击事件游戏重开

  1. 添加按钮点击事件

 

  1. 重开则重新生成云朵

 

  1. 点击重开后,移除UI,调用 C++ 中 GameReset 函数

 

 

 

 

 

八. 游戏音乐

8.1 背景音乐

  1. 将音乐文件拖入场景,设置循环播放

 

 

8.2 角色接触云朵音乐

  1. 按云朵按位置播放音乐

 

  1. 设置音乐

 

 

8.3 云朵雨音乐

  1. 添加云朵雨的声音组件,并播放

 

  1. 创建雨声音频的 Cue 文件并打开,设置雨声衰减

 

  1. 在蓝图中设置云朵雨的音效

 

 

附录:C++文件提要

1. Cake.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/Character.h"
 7 #include "Cake.generated.h"
 8 
 9 UCLASS()
10 class PROJECT_UPUPCAKE_API ACake : public ACharacter
11 {
12     GENERATED_BODY()
13 
14 public:
15     // Sets default values for this character's properties
16     ACake();
17 
18 protected:
19     // Called when the game starts or when spawned
20     virtual void BeginPlay() override;
21     
22     //声明一个玩家控制器
23     APlayerController* PlayerController;
24     
25     //角色在空中的速度
26     UPROPERTY(EditAnywhere,Category="Speed")
27     float AirSpeed;
28 
29     //角色落地的速度
30     UPROPERTY(EditAnywhere,Category="Speed")
31     float GroundSpeed;
32     
33     //计分
34     int Score;
35 
36     //判断是否死亡
37     bool bDeath;
38 
39     //判断游戏是否开始
40     bool bGamestart;
41 
42 public:    
43     // Called every frame
44     virtual void Tick(float DeltaTime) override;
45 
46     // Called to bind functionality to input
47     virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
48 
49     //声明角色跟随鼠标移动的函数
50     void FollowMouseCursorMoving();
51     
52     //声明跳跃,游戏启动时跳跃
53     void BeginJump();
54 
55     //声明跳跃,碰到云彩时跳跃
56     void Jump();
57 
58     //判断角色所在的场景,设置速度
59     void SetSpeed();
60 
61     //加分
62     void IncreaseScore();
63 
64     //获取分数
65     int GetScore() const;
66 
67     //判断角色是否持续下落
68     void IsFalling();
69 
70     //刷新时间轴
71     UFUNCTION(BlueprintImplementableEvent)
72     void UpdateTimer();
73 
74     //重置时间轴
75     UFUNCTION(BlueprintImplementableEvent)
76     void ResetTimer();
77 
78     //游戏结束
79     UFUNCTION(BlueprintCallable)
80     void GameOver();
81 
82     //游戏重开
83     UFUNCTION(BlueprintCallable)
84     void GameReset();
85     
86     //显示重开按钮
87     UFUNCTION(BlueprintImplementableEvent)
88     void ResetUI();
89 };
复制代码

 

2. Cake.cpp

复制代码
  1 // Fill out your copyright notice in the Description page of Project Settings.
  2 
  3 #include "Cake.h"
  4 #include "GameFramework/CharacterMovementComponent.h" //判断角色是否运动
  5 
  6 // Sets default values
  7 ACake::ACake()
  8 {
  9      // Set this character to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
 10     PrimaryActorTick.bCanEverTick = true;
 11 
 12     //速度初始化
 13     AirSpeed = 3500.0f;
 14     GroundSpeed = 300.0f;
 15 
 16     //分数初始化
 17     Score = 0;
 18 
 19     //判断是否死亡(初始化)
 20     bDeath = false;
 21     //判断游戏是否开始(初始化)
 22     bGamestart = false;
 23 }
 24 
 25 // Called when the game starts or when spawned
 26 void ACake::BeginPlay()
 27 {
 28     Super::BeginPlay();
 29 
 30     //获取 PlayerController(因为继承自 Character,可以直接 GetController()获取)
 31     PlayerController = Cast<APlayerController>(GetController());
 32 
 33     //获取鼠标显示
 34     PlayerController->bShowMouseCursor = true;
 35 
 36     //调用游戏重开
 37     GameReset();
 38 }
 39 
 40 // Called every frame
 41 void ACake::Tick(float DeltaTime)
 42 {
 43     Super::Tick(DeltaTime);
 44 
 45     if(!bDeath)
 46     {
 47         FollowMouseCursorMoving();  //每帧判断角色朝鼠标方向移动
 48     
 49         SetSpeed();  //每帧判断角色所在的场景,设置速度
 50     
 51         IsFalling();  //每帧判断角色是否持续下落
 52     }
 53 }
 54 
 55 // Called to bind functionality to input
 56 void ACake::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
 57 {
 58     Super::SetupPlayerInputComponent(PlayerInputComponent);
 59 
 60     //跳跃绑定
 61     PlayerInputComponent->BindAction("Jump", IE_Pressed, this, &ACake::BeginJump);
 62 }
 63 
 64 void ACake::FollowMouseCursorMoving()
 65 {
 66     //获取鼠标在世界坐标下的位置(方向暂用不到)
 67     FVector MouseCursorLocation;
 68     FVector MouseCursorDirection;
 69     PlayerController->DeprojectMousePositionToWorld(MouseCursorLocation, MouseCursorDirection);
 70 
 71     //角色朝鼠标方向移动
 72     //获取 Y方向(左右方向)的偏移:鼠标位置-小球位置,用 Clamp()函数限定范围为 -1到 1
 73     float YDirection = FMath::Clamp(MouseCursorLocation.Y - GetActorLocation().Y, -1.0f ,1.0f);
 74     FVector Direction = FVector(0,YDirection,0);  //转换为向量
 75     AddMovementInput(Direction);
 76     
 77 }
 78 
 79 void ACake::BeginJump()
 80 {
 81     if(!bGamestart && GetActorLocation().Z != 0)
 82     {
 83         bGamestart = true;  //游戏开始
 84         Jump();
 85     }
 86 }
 87 
 88 void ACake::Jump()
 89 {
 90     //LaunchCharacter(发射方向,false:XY方向,true:Z方向),弹跳函数只对角色有效
 91     //false/true:是否替换原发射速度(true一直保持 1500)
 92     LaunchCharacter(FVector(0,0,1500),false, true);    
 93 }
 94 
 95 void ACake::SetSpeed()
 96 {
 97     //判断角色是否下落
 98     if(GetCharacterMovement()->IsFalling())
 99     {
100         GetCharacterMovement()->MaxWalkSpeed = AirSpeed;  //在空中
101     }
102     else
103     {
104         if(bGamestart)
105         {
106             GameOver();
107         }
108         GetCharacterMovement()->MaxWalkSpeed = GroundSpeed;  //在地面
109     }
110 }
111 
112 void ACake::IncreaseScore()
113 {
114     Score++;
115 }
116 
117 int ACake::GetScore() const
118 {
119     return Score;
120 }
121 
122 void ACake::IsFalling()
123 {
124     //如果 Z方向小于0,则表示准备开始下落了
125     if(GetCharacterMovement()->Velocity.Z < 0)
126     {
127         //持续性下落,刷新时间轴
128         UpdateTimer();
129     }
130     else
131     {
132         //短暂性下落,重置时间轴
133         ResetTimer();
134 
135     }
136 }
137 
138 void ACake::GameOver()
139 {
140     bDeath = true;
141     SetActorRotation(FRotator::ZeroRotator);  //旋转归零
142     EnableInput(PlayerController);  //启用输入
143 
144     //显示重开按钮
145     UE_LOG(LogTemp,Warning, TEXT("GameOver"));
146     
147     ResetUI();
148 
149 }
150 
151 void ACake::GameReset()
152 {
153     Score = 0;
154     bDeath = false;
155     bGamestart = false;
156 }
复制代码

 

3.Camera.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 "Camera/CameraComponent.h"
 7 #include "GameFramework/Actor.h"
 8 #include "Cake.h"  //角色
 9 #include "Components/BoxComponent.h"  //盒体检测
10 #include "Camera.generated.h"
11 
12 UCLASS()
13 class PROJECT_UPUPCAKE_API ACamera : public AActor
14 {
15     GENERATED_BODY()
16     
17 public:    
18     // Sets default values for this actor's properties
19     ACamera();
20 
21 protected:
22     // Called when the game starts or when spawned
23     virtual void BeginPlay() override;
24 
25     //声明一个相机组件
26     UPROPERTY(VisibleAnywhere)
27     UCameraComponent* CameraComponent;
28 
29     //声明一个玩家控制器
30     APlayerController* PlayerController;
31 
32     //声明角色
33     ACake* Cake;
34 
35     //销毁相机视角外的多余云朵
36     UPROPERTY(VisibleAnywhere, Category = "Component")
37     UBoxComponent* DestroyArea;
38 
39 public:    
40     // Called every frame
41     virtual void Tick(float DeltaTime) override;
42 
43     //全局相机垂直跟随
44     void CameraMoving();
45 
46     //检测销毁区是否与多余云朵产生碰撞
47     virtual void NotifyActorBeginOverlap(AActor* OtherActor) override;  //重写碰撞函数
48 };
复制代码

 

4. Camera.cpp

复制代码
 1 // Fill out your copyright notice in the Description page of Project Settings.
 2 
 3 #include "Camera.h"
 4 #include "Camera/CameraComponent.h"  //相机组件
 5 #include "Kismet/GameplayStatics.h"  //玩家控制器
 6 #include "Cloud.h"  //销毁相机视角外的多余云朵
 7 
 8 // Sets default values
 9 ACamera::ACamera()
10 {
11      // Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
12     PrimaryActorTick.bCanEverTick = true;
13 
14     //定义一个相机组件
15     CameraComponent = CreateDefaultSubobject<UCameraComponent>(TEXT("CameraComponent"));
16     //将相机组件设置为默认根组件
17     CameraComponent->SetupAttachment(RootComponent);
18 
19     //销毁相机视角外的多余云朵
20     DestroyArea = CreateDefaultSubobject<UBoxComponent>(TEXT("DestroyArea"));
21     //绑定到根组件
22     DestroyArea->SetupAttachment(RootComponent);
23 
24 }
25 
26 // Called when the game starts or when spawned
27 void ACamera::BeginPlay()
28 {
29     Super::BeginPlay();
30 
31     //获取玩家控制器
32     PlayerController = UGameplayStatics::GetPlayerController(this, 0);
33     //切换视角(立刻对齐)
34     PlayerController->SetViewTargetWithBlend(this, 0);
35 
36     //获取角色
37     Cake = Cast<ACake>(UGameplayStatics::GetPlayerPawn(this,0));
38     
39 }
40 
41 // Called every frame
42 void ACamera::Tick(float DeltaTime)
43 {
44     Super::Tick(DeltaTime);
45 
46     CameraMoving();  //每帧调用全局相机垂直跟随
47 }
48 
49 void ACamera::CameraMoving()
50 {
51     //(相机的 X,相机的 Y,角色的 Z)组成跟随坐标
52     FVector TargetLoaction = FVector(GetActorLocation().X, GetActorLocation().Y, Cake->GetActorLocation().Z);
53     //设置相机当前位置
54     SetActorLocation(TargetLoaction);
55 }
56 
57 void ACamera::NotifyActorBeginOverlap(AActor* OtherActor)
58 {
59     Super::NotifyActorBeginOverlap(OtherActor);
60 
61     //类型转换
62     ACloud* Cloud = Cast<ACloud>(OtherActor);
63     if(Cloud)
64     {
65         //检测到多余云朵则调用销毁
66         Cloud->Destroy();
67     }
68 }
复制代码

 

5. Cloud.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 "Components/BoxComponent.h"
 7 #include "GameFramework/Actor.h"
 8 #include "Cake.h"  //角色
 9 #include "Components/TextRenderComponent.h"  //文本
10 #include "Sound/SoundWave.h"  //播放音乐
11 #include "Cloud.generated.h"
12 
13 UCLASS()
14 class PROJECT_UPUPCAKE_API ACloud : public AActor
15 {
16     GENERATED_BODY()
17     
18 public:    
19     // Sets default values for this actor's properties
20     ACloud();
21 
22 protected:
23     // Called when the game starts or when spawned
24     virtual void BeginPlay() override;
25 
26     //声明盒体检测组件
27     UPROPERTY(VisibleAnywhere, Category = "Collision")
28     UBoxComponent* BoxComponent;
29 
30     //声明云朵组件
31     UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Show")
32     UStaticMeshComponent* CloudPlane;
33 
34     //声明云朵雨组件
35     UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Show")
36     UStaticMeshComponent* RainPlane;
37 
38     //云朵库
39     UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Show")
40     TArray<UTexture*> CloudTextures;
41 
42     //动态材质实例
43     UPROPERTY(BlueprintReadOnly, Category = "Show")
44     UMaterialInstanceDynamic* MaterialInstanceDynamic;
45     
46     UMaterialInterface* MaterialInterface;
47 
48     //分数文本
49     UPROPERTY(EditAnywhere, Category = "Show")
50     UTextRenderComponent* ScoreText;
51 
52     //检测是否与角色产生碰撞
53     ACake* Cake;
54 
55     //角色接触云朵音乐
56     UPROPERTY(EditAnywhere, Category = "Sound")
57     USoundWave* CloudSound;
58 
59     //云朵雨音乐
60     UPROPERTY(VisibleAnywhere, Category = "Sound")
61     UAudioComponent* RainSound;
62     
63 public:    
64     // Called every frame
65     virtual void Tick(float DeltaTime) override;
66     
67     //随机云朵生成
68     void SetRandomCloudTextures();
69 
70     //显示分数
71     void DisplayScore();
72 
73     //检测是否与角色产生碰撞
74     virtual void NotifyActorBeginOverlap(AActor* OtherActor) override;  //重写碰撞函数
75     
76     //云朵淡出(蓝图实现)
77     UFUNCTION(BlueprintImplementableEvent)
78     void FadeOut();
79 };
复制代码

 

6. Cloud.cpp

复制代码
  1 // Fill out your copyright notice in the Description page of Project Settings.
  2 
  3 #include "Cloud.h"
  4 #include "Kismet/GameplayStatics.h"  //播放音乐
  5 #include "Components/AudioComponent.h"  //云朵雨音乐组件
  6 
  7 // Sets default values
  8 ACloud::ACloud()
  9 {
 10      // Set this actor 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     BoxComponent = CreateDefaultSubobject<UBoxComponent>(TEXT("BoxCollision"));
 15     //设置为默认根组件
 16     RootComponent = BoxComponent;
 17 
 18     //定义云朵
 19     CloudPlane = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("CloudMesh"));
 20     //绑定到根组件(盒体检测)
 21     CloudPlane->SetupAttachment(RootComponent);
 22 
 23     //定义云朵雨
 24     RainPlane = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("RainMesh"));
 25     //绑定到云朵组件
 26     RainPlane->SetupAttachment(CloudPlane);
 27 
 28     //分数文本
 29     ScoreText = CreateDefaultSubobject<UTextRenderComponent>(TEXT("ScoreText"));
 30     //绑定到根组件
 31     ScoreText->SetupAttachment(RootComponent);
 32 
 33     //云朵雨音乐
 34     RainSound = CreateDefaultSubobject<UAudioComponent>(TEXT("RainSound"));
 35     //绑定到云朵组件
 36     RainSound->SetupAttachment(CloudPlane);
 37 }
 38 
 39 // Called when the game starts or when spawned
 40 void ACloud::BeginPlay()
 41 {
 42     Super::BeginPlay();
 43     
 44     SetRandomCloudTextures();  //调用随机云朵生成
 45 
 46     //随机显示云朵雨
 47     if(FMath::RandRange(0,2))
 48     {
 49         RainPlane->SetVisibility(true);
 50 
 51         //播放云朵雨音乐
 52         RainSound->Activate(true);
 53     }
 54 }
 55 
 56 // Called every frame
 57 void ACloud::Tick(float DeltaTime)
 58 {
 59     Super::Tick(DeltaTime);
 60 
 61 }
 62 
 63 void ACloud::SetRandomCloudTextures()
 64 {
 65     //获取 CloudPlane上的材质
 66     MaterialInterface = CloudPlane->GetMaterial(0);
 67     
 68     //通过创建动态材质实例来获取指定材质参数的随机材质
 69     MaterialInstanceDynamic = CloudPlane->CreateDynamicMaterialInstance(0,MaterialInterface);
 70     
 71     //随机数
 72     int index = FMath::RandRange(0,2);
 73     
 74     if(CloudTextures[index])
 75     {
 76         //设置材质参数值(参数节点名Texture,随机云彩库)
 77         MaterialInstanceDynamic->SetTextureParameterValue(FName(TEXT("Texture")), CloudTextures[index]);
 78         //将材质实例赋给模型
 79         CloudPlane->SetMaterial(0, MaterialInstanceDynamic);
 80     }
 81 }
 82 
 83 void ACloud::NotifyActorBeginOverlap(AActor* OtherActor)
 84 {
 85     Super::NotifyActorBeginOverlap(OtherActor);
 86 
 87     //类型转换
 88     Cake = Cast<ACake>(OtherActor);
 89     if(Cake)
 90     {
 91         //按位置播放音乐
 92         UGameplayStatics::PlaySoundAtLocation(this, CloudSound, GetActorLocation());
 93         //检测到角色则调用弹跳
 94         Cake->Jump();
 95         //显示分数
 96         DisplayScore();
 97 
 98         //云朵淡出(蓝图实现)
 99         FadeOut();
100     }
101 }
102 
103 void ACloud::DisplayScore()
104 {
105     Cake->IncreaseScore();
106     
107     //设置文本(类型转换 int - FString - FText)
108     ScoreText->SetText(FText::FromString(FString::FromInt(Cake->GetScore())));
109 }
复制代码

 

7. SpawnCloud.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 "Cloud.h"
 7 #include "GameFramework/Actor.h"
 8 #include "Components/BoxComponent.h"  //盒体检测
 9 #include "SpawnCloud.generated.h"
10 
11 UCLASS()
12 class PROJECT_UPUPCAKE_API ASpawnCloud : public AActor
13 {
14     GENERATED_BODY()
15     
16 public:    
17     // Sets default values for this actor's properties
18     ASpawnCloud();
19 
20 protected:
21     // Called when the game starts or when spawned
22     virtual void BeginPlay() override;
23 
24     //云朵生成区域
25     UPROPERTY(VisibleAnywhere, Category = "Component")
26     UBoxComponent* SpawnArea;
27 
28     //根据角色位置,检测云朵是否可以继续生成
29     UPROPERTY(VisibleAnywhere, Category = "Component")
30     UBoxComponent* TriggerArea;
31 
32     //场景根组件
33     USceneComponent* DefaultRootComponent;
34 
35     //TSubclassOf:限定为 ACloud或其子类
36     UPROPERTY(EditAnywhere, Category = "Cloud")
37     TSubclassOf<ACloud> Cloud;
38 
39     //检测是否与角色产生碰撞
40     ACake* Cake;
41     
42     //云朵初始化
43     UPROPERTY(EditAnywhere, Category = "Cloud")
44     int32 InitialCloud;
45 
46     //云朵生成器每次上升距离
47     UPROPERTY(EditAnywhere, Category = "Cloud")
48     float SpawnSpacing;
49 
50 public:    
51     // Called every frame
52     virtual void Tick(float DeltaTime) override;
53 
54     //随机生成云朵
55     void SpawnCloud();
56 
57     //检测是否与角色产生碰撞
58     virtual void NotifyActorBeginOverlap(AActor* OtherActor) override;  //重写碰撞函数
59     
60     //重开则重新生成云朵
61     UFUNCTION(BlueprintCallable)
62     void ResetCloud();
63 
64 };
复制代码

 

8. SpawnCloud.cpp

复制代码
  1 // Fill out your copyright notice in the Description page of Project Settings.
  2 
  3 #include "SpawnCloud.h"
  4 #include "Kismet/KismetMathLibrary.h"  //随机生成点
  5 #include "Cloud.h"  //生成云朵
  6 #include "Kismet/GameplayStatics.h"  //重开销毁之前的所有云朵
  7 
  8 // Sets default values
  9 ASpawnCloud::ASpawnCloud()
 10 {
 11      // Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
 12     PrimaryActorTick.bCanEverTick = true;
 13 
 14     //场景根组件
 15     DefaultRootComponent = CreateDefaultSubobject<USceneComponent>(TEXT("DefaultRootComponent"));
 16     RootComponent = DefaultRootComponent;
 17     
 18     //云朵生成区域
 19     SpawnArea = CreateDefaultSubobject<UBoxComponent>(TEXT("SpawnArea"));
 20     //绑定到场景根组件
 21     SpawnArea->SetupAttachment(RootComponent);
 22 
 23     //根据角色位置,检测云朵是否可以继续生成
 24     TriggerArea = CreateDefaultSubobject<UBoxComponent>(TEXT("TriggerArea"));
 25     //绑定到场景根组件
 26     TriggerArea->SetupAttachment(RootComponent);
 27 
 28     //云朵初始化
 29     InitialCloud = 6;
 30     //云朵生成器每次上升距离
 31     SpawnSpacing = 300.0f;
 32 }
 33 
 34 // Called when the game starts or when spawned
 35 void ASpawnCloud::BeginPlay()
 36 {
 37     Super::BeginPlay();
 38 
 39     ResetCloud();
 40 }
 41 
 42 // Called every frame
 43 void ASpawnCloud::Tick(float DeltaTime)
 44 {
 45     Super::Tick(DeltaTime);
 46 
 47 }
 48 
 49 void ASpawnCloud::SpawnCloud()
 50 {
 51     FVector SpawnOrigin = SpawnArea->Bounds.Origin;  //生成中心点
 52     FVector SpawnExtent = SpawnArea->Bounds.BoxExtent;  //生成范围
 53 
 54     //生成的位置
 55     //提供圆心和范围,Y轴随机生成点
 56     float YLocation = UKismetMathLibrary::RandomPointInBoundingBox(SpawnOrigin, SpawnExtent).Y;
 57     FVector SpawnLocation = FVector(SpawnArea->GetComponentLocation().X, YLocation, SpawnArea->GetComponentLocation().Z);
 58 
 59     //生成(生成云朵,生成位置,生成旋转)
 60     GetWorld()->SpawnActor<ACloud>(Cloud, SpawnLocation, FRotator::ZeroRotator);
 61 
 62     //云朵生成器上升(0,0,300)
 63     AddActorWorldOffset(FVector(0,0,SpawnSpacing));
 64 }
 65 
 66 void ASpawnCloud::NotifyActorBeginOverlap(AActor* OtherActor)
 67 {
 68     Super::NotifyActorBeginOverlap(OtherActor);
 69 
 70     //类型转换
 71     Cake = Cast<ACake>(OtherActor);
 72     if(Cake)
 73     {
 74         //检测到角色则调用随机生成云朵
 75         SpawnCloud();
 76     }
 77 }
 78 
 79 void ASpawnCloud::ResetCloud()
 80 {
 81     //云朵初始化
 82     InitialCloud = 6;
 83 
 84     //刷新位置为(0,0,0)
 85     SetActorLocation(FVector::ZeroVector);
 86 
 87     //重开销毁之前的所有云朵
 88     TArray<AActor*>ResetClouds;
 89     UGameplayStatics::GetAllActorsOfClass(GetWorld(), ACloud::StaticClass(), ResetClouds);
 90     for(AActor* TActor : ResetClouds)
 91     {
 92         ACloud* FoundClouds = Cast<ACloud>(TActor);  //类型转换
 93         if(FoundClouds!= nullptr)
 94         {
 95             FoundClouds->Destroy();
 96         }
 97     }
 98     
 99     //云朵初始化随机生成
100     while(InitialCloud > 0)
101     {
102         SpawnCloud();
103         InitialCloud--;
104     }
105 }
复制代码

 

 


参考资料:

【SiKi学院Unreal视频教程】UE4/5 虚幻4/5初级课程-向上的小松饼_哔哩哔哩_bilibili

 

 

posted @   哟吼--小文文公主  阅读(196)  评论(2编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
点击右上角即可分享
微信分享提示