07UEC++吃豆人[导航网格和ai控制器]

新建一个AIController的类

 现在将导航网格拖入场景中

将位置归为0,0,0

调整画刷,让其包裹整个场景

 然后把导航勾上

在世界大纲中,我们就发现了这个组件

我们设置单元格大小和高度为5

当出现绿色就说明参数是合格的,绿色区域就是可以导航的区域 

 然后我们取消掉这个勾

========================

编写AI控制器的头文件

UCLASS()
class PACMAN_API AEnermyController : public AAIController
{
	GENERATED_BODY()
public:
	//覆盖父类的函数
	//控制函数
    void OnPossess(class APawn* PawnToPossess) override;

	//移动完成函数
	virtual void OnMoveCompleted(FAIRequestID RequestID,const FPathFollowingResult& Result) override;

	//找到新的目的地
	void GoToNewDestination();
private:

    //被控制的角色
	class APacdotEnermy* ControlleredEnermy;
	
};

 编写源文件

#include "EnermyController.h"
#include "PacdotEnermy.h"
#include "NavigationSystem.h"

void AEnermyController::OnPossess( APawn* PawnToPossess)
{
	//建议覆盖的函数,要调用一下父类的函数
	Super::OnPossess(PawnToPossess);

	//转化被控制的对象为APacdotEnermy类型
	ControlleredEnermy = Cast<APacdotEnermy>(PawnToPossess);
}

void AEnermyController::OnMoveCompleted(FAIRequestID RequestID, const FPathFollowingResult& Result)
{
	Super::OnMoveCompleted(RequestID, Result);

	//移动完成时,直接开启下一次的移动
	GoToNewDestination();
}

void AEnermyController::GoToNewDestination()
{
	//得到场景中导航网格的指针
	UNavigationSystemV1* NavMesh = UNavigationSystemV1::GetCurrent(this);
	if (NavMesh)
	{
		//保存目的地的结构体
		FNavLocation RondamLocation;
		//在可到达半径范围内,得到一个随机点
		//参数一:被控制角色的位置
		//参数二:搜索半径
		//参数三:保存新目的地
		//返回值:是否找到新目的地
		const bool bNewDestinationFound = NavMesh->GetRandomReachablePointInRadius(ControlleredEnermy->GetActorLocation(),10000, RondamLocation);
		if (bNewDestinationFound)
		{
			//参数二:在目的地附近多远就可以视为移动完成
			MoveToLocation(RondamLocation.Location, 50.0f);
		}
	}
}

 加一个这个,在这个文件

进入敌人蓝图,选择ai控制器

现在还没有逻辑来驱动东西开始 

 打开游戏模式c++类

创建枚举,存储游戏状态

UENUM(BlueprintType)
enum class EGameState : uint8
{
	EMenu,
	EPlay,
	EPause,
	EWin,
	EGameOver
};

 编写游戏模式类的头文件

#include "CoreMinimal.h"
#include "GameFramework/GameModeBase.h"
#include "PacmanGameModeBase.generated.h"

/**
 * 
 */
//设置一个枚举
UENUM(BlueprintType)
enum class EGameState : uint8
{
	EMenu,
	EPlay,
	EPause,
	EWin,
	EGameOver
};
UCLASS()
class PACMAN_API APacmanGameModeBase : public AGameModeBase
{
	GENERATED_BODY()
public:
	//构造函数
	APacmanGameModeBase();

	//当前的游戏状态
	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	EGameState CurrentState;

	//场景中食物的总数
	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	int PacdotNum;

	//设置和查询食物的总数
	int GetPacdotNum() const;
	void SetPacdotNum(int value);

	//设置和查询游戏状态
	EGameState GetCurrentState() const;
	void SetCurrentState(EGameState value);

	//游戏开始函数
	void StartGame();
	//游戏暂停函数
	void PauseGame();
	//重新开始函数
	void ReStartGame();


protected:
	//开始函数
	virtual void BeginPlay() override;
private:
	//场景中的所有敌人
	TArray<class APacdotEnermy *> Enermis;

	
};
//定义成内敛函数
FORCEINLINE int APacmanGameModeBase::GetPacdotNum() const
{
	return PacdotNum;
}

FORCEINLINE EGameState APacmanGameModeBase::GetCurrentState() const
{
	return CurrentState;
}

编写源代码

#include "PacmanGameModeBase.h"
#include "Pacdot.h"
#include "PacdotEnermy.h"
#include "EngineUtils.h"
#include "EnermyController.h"

APacmanGameModeBase::APacmanGameModeBase()
{
	//初始化游戏状态为菜单模式
	CurrentState = EGameState::EMenu;

}
void APacmanGameModeBase::BeginPlay()
{
	//利用迭代,查找场景中有多少食物
	for (TActorIterator<APacdot> PacItr(GetWorld()); PacItr; ++PacItr)
	{
		PacdotNum++;
	}
	//利用迭代,找到所有敌人
	for (TActorIterator<APacdotEnermy> EneItr(GetWorld()); EneItr; ++EneItr)
	{
		Enermis.Add(Cast<APacdotEnermy>(*EneItr));
	}

}



void APacmanGameModeBase::SetCurrentState(EGameState value)
{
	CurrentState = value;
	switch (CurrentState)
	{
	case EGameState::EMenu:
		break;
	case EGameState::EPlay:
		break;
	case EGameState::EPause:
		break;
	case EGameState::EWin:
		break;
	case EGameState::EGameOver:
		break;
	default:
		break;
	}
}



void APacmanGameModeBase::SetPacdotNum(int value)
{
	PacdotNum = value;
	//如果没有食物了,就获胜了
	if (PacdotNum == 0)
	{
		SetCurrentState(EGameState::EWin);
	}
}

void APacmanGameModeBase::StartGame()
{
	//如果游戏在菜单状态,该函数才有效
	if (CurrentState == EGameState::EMenu)
	{
		SetCurrentState(EGameState::EPlay);
		//启动游戏之后,让每个敌人开始移动
		for (auto Iter(Enermis.CreateIterator()); Iter; ++Iter)
		{
			Cast<AEnermyController>((*Iter)->GetController())->GoToNewDestination();
		}
	}
}

void APacmanGameModeBase::PauseGame()
{
}

void APacmanGameModeBase::ReStartGame()
{
}

然后打开主角类,首先定义一个游戏模式类的指针成员变量

class APacmanGameModeBase * ModeBaseRef;

在源文件中导入头文件

#include "Kismet/GameplayStatics.h"

 然后我们在游戏开始函数里,得到当前游戏模式

	//得到当前游戏模式
	ModeBaseRef = Cast< APacmanGameModeBase>(UGameplayStatics::GetGameMode(this));

添加三个函数

	//游戏开始函数
	void StartGame();
	//游戏暂停函数
	void PauseGame();
	//重新开始函数
	void ReStartGame();

在源文件中进行定义

void APacdotPlayer::StartGame()
{
	ModeBaseRef->StartGame();
}

void APacdotPlayer::PauseGame()
{
	ModeBaseRef->PauseGame();
}

void APacdotPlayer::ReStartGame()
{
	ModeBaseRef->ReStartGame();
}

然后进行按键绑定

PlayerInputComponent->BindAction("StartGame", IE_Pressed, this, &APacdotPlayer::StartGame);
PlayerInputComponent->BindAction("PauseGame", IE_Pressed, this, &APacdotPlayer::PauseGame);
PlayerInputComponent->BindAction("ReStartGame", IE_Pressed, this,&APacdotPlayer::ReStartGame);

编译,运行游戏,敌人可以动了

现在实现避免敌人互相碰撞

我们添加一个碰撞通道

然后添加碰撞预设

给敌人蓝图的胶囊体设置碰撞预设 

 

 这两个碰撞预设都设为nocollision

 

 

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

无情的阅读机器

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值