虚幻Unreal - A计划(一年有效期) 扫二维码继续学习 二维码时效为半小时

(37评价)
价格: 1664.00元
Unreal中级案例-课时92
嘚啊噗昂嘻嗷吱发起了问答2020-11-18
5
回复
1013
浏览
// Fill out your copyright notice in the Description page of Project Settings.


#include "Enemy/NormalEnemyController.h"
#include "Enemy/NormalEnemy.h"
#include "NavigationSystem.h"
#include "TimerManager.h"
#include <GameFramework/CharacterMovementComponent.h>
#include "Kismet/KismetMathLibrary.h"
#include "Components/SkeletalMeshComponent.h"
#include "Animation/AnimInstance.h"
#include "Animation/AnimMontage.h"

ANormalEnemyController::ANormalEnemyController()
{
	//实例化导航系统组件
	NavSys = FNavigationSystem::GetCurrent<UNavigationSystemV1>(this);////此处的this报空指针
}

void ANormalEnemyController::OnPossess(APawn* InPawn)
{
	Super::OnPossess(InPawn);
	//类型转换
	EnemyPawn = Cast<ANormalEnemy>(InPawn);
	//获得动画实例
	AnimInstance = EnemyPawn->GetMesh()->GetAnimInstance();
	//调整巡逻速度
	EnemyPawn->GetCharacterMovement()->MaxWalkSpeed = PatrolWalkSpeed;
}

int ANormalEnemyController::GetNextAnimationIndex()
{
	//随机动画索引
	CurrentAttackIndex= FMath::RandRange(0, 2);
	return CurrentAttackIndex;
}

bool ANormalEnemyController::bInAttackRange()
{
	//判断TargetActor有效性
	if (TargetActor)
	{
		//判断距离有效性
		return(EnemyPawn->GetDistanceTo(TargetActor) <= AttackRange);
	}
	else
	{
		return false;
	}
}


void ANormalEnemyController::OnMoveCompleted(FAIRequestID RequestID, const FPathFollowingResult& Result)
{
	Super::OnMoveCompleted(RequestID, Result);
	//判断返回状态
	if (bIsRuningBack)
	{
		//调整返回状态
		bIsRuningBack = false;
		//重置巡逻状态
		bIsPatrolling = true;
		//调整巡逻速度
		EnemyPawn->GetCharacterMovement()->MaxWalkSpeed = PatrolWalkSpeed;
	}
	//判断是否在攻击范围
	if (bInAttackRange())
	{
		//调用攻击函数
		PerformAttack();
		return;
	}
	//判断巡逻状态
	if (bIsPatrolling)
	{
		//设置Idle时间
		float IdleTime = FMath::RandRange(1, 10);
		//设置定时器
		GetWorldTimerManager().SetTimer(TimerHandle_Patrol, this, &ANormalEnemyController::DetectedPatrol, IdleTime, false);
	}
}

void ANormalEnemyController::DetectedPatrol()
{
	//判断巡逻状态
	if (bIsPatrolling)
	{
		Patrol();
	}

}

void ANormalEnemyController::PerformAttack()
{
	//判断敌人状态
	if (!EnemyPawn->GetbDead() && !bIsRuningBack && bWasAggroed)
	{
		//停止巡逻
		bIsPatrolling = false;
		//停止移动
		EnemyPawn->GetCharacterMovement()->StopMovementImmediately();
		//判断目标有效性
		if (TargetActor)
		{
			//获取朝向目标的角度(1、敌人位置,2、目标位置)
			FRotator Rotation= UKismetMathLibrary::FindLookAtRotation(EnemyPawn->GetActorLocation(), TargetActor->GetActorLocation());
			//设置敌人角度
			EnemyPawn->SetActorRotation(Rotation);
		}
		//设置当前动画
		CurrentAttackMontage = EnemyPawn->AttackAnimations[CurrentAttackIndex];
		//播放攻击动画
		AnimInstance->Montage_Play(CurrentAttackMontage);
		//调用定时器
		GetWorldTimerManager().SetTimer(TimerHandle_AnimPlayOver,this,&ANormalEnemyController::OnAnimPlayOver,CurrentAttackMontage->SequenceLength,false);
	}
}

void ANormalEnemyController::OnAnimPlayOver()
{
	//停止之前播放动画
	CurrentAttackMontage = nullptr;
	//放下一次需要播放的动画
	CurrentAttackIndex = GetNextAnimationIndex();
	//判断目标是否在攻击范围内
	if (bInAttackRange())
	{
		//继续攻击
		PerformAttack();
	}
	else
	{
		//移向目标
		MoveToActor(TargetActor);
	}
}

void ANormalEnemyController::OnAggoredPulled(AActor* Target)
{
	//判断狂暴状态
	if (!bWasAggroed&&bIsRuningBack)
	{
		//调整狂暴状态
		bWasAggroed = true;
		//设置当前目标
		TargetActor = Target;
		//调整巡逻状态
		bIsPatrolling = false;
		//设置追逐速度
		EnemyPawn->GetCharacterMovement()->MaxWalkSpeed = AggroedWalkSpeed;
		//利用定时器持续检测敌人与目标距离
		GetWorldTimerManager().SetTimer(TimerHandle_CalDis, this, &ANormalEnemyController::CacualteTargetDistance, 1.0f, true);
		//判断追逐时的攻击范围
		if (bInAttackRange())
		{
			//调用攻击函数
			PerformAttack();
		}
		else
		{
			//移向目标
			MoveToActor(TargetActor);
		}
	}
}

void ANormalEnemyController::CacualteTargetDistance()
{
	//判断数据有效性
	if (FVector::Dist(EnemyPawn->GetActorLocation(),TargetActor->GetActorLocation())>MaxDistanceToFollowTarget)
	{
		//重置敌人状态
		OnReset();
	}
}

void ANormalEnemyController::OnReset()
{
	//停止播放攻击动画
	AnimInstance->Montage_Stop(0.0f);
	//调整返回状态
	bIsRuningBack = true;
	//清除定时器
	GetWorldTimerManager().ClearTimer(TimerHandle_Patrol);
	GetWorldTimerManager().ClearTimer(TimerHandle_AnimPlayOver);
	GetWorldTimerManager().ClearTimer(TimerHandle_CalDis);
	//目标置为空
	TargetActor = nullptr;
	//调整狂暴状态
	bWasAggroed = false;
	//回到初始位置
	MoveToLocation(EnemyPawn->StartLocation);
}

void ANormalEnemyController::Patrol()
{
	//定义巡逻半径
	const float SearchRadius = 1000.0f;
	//判断NavSys有效性
	if (NavSys)
	{
		//定义随机巡逻点
		FNavLocation RandomPt;
		//调用获得半径内随机可达点函数
		bool bFound = NavSys->GetRandomReachablePointInRadius(EnemyPawn->GetActorLocation(), SearchRadius, RandomPt);
		//判断能否找到
		if (bFound)
		{
			//移向找到的随机位置
			MoveToLocation(RandomPt.Location);
		}
	}
}

在构造函数中,传入的this报空指针

所有回复
发表回复
你还没有登录,请先 登录或 注册!