其他分享
首页 > 其他分享> > 探究如何实现AI集群

探究如何实现AI集群

作者:互联网

第一种,自行实现

参考了一下一个unity项目的阵列实现。

https://github.com/Matthew-J-Spencer/Formations

第二种用商城提供的现成的工具

接下来是自己造轮子的时间了。

具体的并没有按这来写,实际的核心代码如下

TArray<FVector> FormationFactory::GetPoints(FVector orignPostion)
{
	switch (FormationType)
	{
	case EFormationType::Circle:return  GetCirclePoint(orignPostion);
		break;
	case EFormationType::Box:return GetBoxPoint(orignPostion);
		break;
	default:return TArray<FVector>();
		break;
	}
}

TArray<FVector> FormationFactory::GetBoxPoint(FVector orignPostion)
{
	TArray<FVector> pointArray(new FVector(),Box.Count);
	FVector fristVector;
	int32 width;
	int32 high;

	//get the first point , then use the point can get other points by calculation
	width = Box.width;
	high = FMath::CeilToInt(Box.Count/width) ;
	fristVector = FVector(orignPostion.X-(width/2)*Distance,orignPostion.Y+(high/2)*Distance,orignPostion.Z);
	for (int i=0;i<pointArray.Num();i++)
	{
		pointArray[i].X = fristVector.X + ((i)%width)*Distance;
		pointArray[i].Y = fristVector.Y - ((i)/width)*Distance;
		pointArray[i].Z = fristVector.Z;
	}
	return pointArray;
}

TArray<FVector> FormationFactory::GetCirclePoint(FVector orignPostion)
{
	TArray<FVector> pointArray(new FVector(),Circle.Count);
	FVector fristVector = orignPostion;
	int32 trunsNum = 0;
	int32 currntIndex = 0;
	int32 currntMaxIndex = 1;
	for (int i=0;i<pointArray.Num();i++)
	{
		/*//first
		pointArray[i] = fristVector;
		//second
		pointArray[i] = fristVector + FVector(0,100,0);
		//third
		pointArray[i] = fristVector + FVector(0,100,0).RotateAngleAxis(60*PI/180,FVector::UpVector);*/
		//normal
		currntIndex++;
		if(currntIndex>currntMaxIndex)
		{
			currntIndex = 1;
			currntMaxIndex += Circle.Raise;
			trunsNum++;
		}
		
		pointArray[i] = fristVector + FVector(0,1,0).RotateAngleAxis((float)(currntIndex-1)/currntMaxIndex*360,FVector::UpVector)*Distance*trunsNum;
		// UE_LOG(LogTemp,Log,TEXT("当前圈数:%d ,当前圈数中下标:%d,当前圈数最大下标:%d"),trunsNum,currntIndex,currntMaxIndex);
	}
	return pointArray;
}

IMPLEMENT_SIMPLE_AUTOMATION_TEST(FFormationFactoryTest,"Test.Formation Test",EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter)

bool FFormationFactoryTest::RunTest(const FString& Parameters)
{
	FormationFactory formationFactory;
	formationFactory.Box = FBoxType(10,5);
	formationFactory.Circle = FCircleType(10,3);
	formationFactory.Distance = 100;
	formationFactory.FormationType = EFormationType::Box;

void AFormationCreate_Base::CreateBoxFormation(FBoxType Box)
{
	
	Factory.Box = Box;
	Factory.Distance = Distance;
	Factory.FormationType = EFormationType::Box;
	CreateAIs(Box.Count,Factory.GetPoints(GetTargetLocation()));
	
}

void AFormationCreate_Base::CreateCircleFormation(FCircleType Circle)
{
	Factory.Circle = Circle;
	Factory.Distance = Distance;
	Factory.FormationType = EFormationType::Circle;
	CreateAIs(Circle.Count,Factory.GetPoints(GetActorLocation()));
}

void AFormationCreate_Base::updataBox(FBoxType Box)
{
	if(AIs.Num() == 0)
	{
		CreateBoxFormation(Box);
		return;;
	}
	updataAICount(Box.Count);
	Factory.Box = Box;
	Factory.Distance = Distance;
	Factory.FormationType = EFormationType::Box;
	updataAis(Factory.GetPoints(GetActorLocation()));
}

void AFormationCreate_Base::updataCircle(FCircleType Circle)
{
	if(AIs.Num() == 0)
	{
		CreateCircleFormation(Circle);
		return;;
	}
	updataAICount(Circle.Count);
	Factory.Circle = Circle;
	Factory.Distance = Distance;
	Factory.FormationType = EFormationType::Circle;
	updataAis(Factory.GetPoints(GetActorLocation()));
}

void AFormationCreate_Base::updataAICount(uint32 Count)
{
	int32 tempCount = Count;
	if((this->AICount) == tempCount)
		return;
	if((this->AICount) > tempCount)
	{
		//make the other character be unactive
		for(int i = tempCount-1;i<AIs.Num();i++)
		{
			AIs[i]->SetHidden(true);
			AIs[i]->SetActorHiddenInGame(true);
		}
	}
	if((this->AICount) <tempCount)
	{
		//active some unactive character,and create some character if this characters is less
		int newAIs =  tempCount-AIs.Num();
		for(int i = 0;i<newAIs;i++)
		{
			CreateAI(FVector::ZeroVector);
		}
	}
	this->AICount = tempCount;
}

void AFormationCreate_Base::CreateAI(FVector item)
{
	DrawDebugBox(GetWorld(),item,FVector(5),FColor::Red,false,10,0,0);
	item += FVector(0,0,100);
	FRotator rotator = GetActorRotation();
	ACharacter* AICharacter = (ACharacter*)(GetWorld()->SpawnActor(AI,&item,&rotator)) ;
	if (IsValid(AICharacter))
	{
		AIs.Add(AICharacter);
		AICharacter->SetActorLocation(item);
		
		// AICharacter->PossessedBy(GetWorld()->SpawnActor<AAIController>(AI.GetDefaultObject()->AIControllerClass));
		UE_LOG(LogTemp,Log,TEXT("已生成"));
	}
	
}

void AFormationCreate_Base::CreateAIs(uint32 Count, const TArray<FVector>& list)
{
	
	for(FVector item:list)
	{
		CreateAI(item);
	}
	AICount = Count;
}

void AFormationCreate_Base::updataAis(const TArray<FVector>& list)
{
	UE_LOG(LogTemp,Log,TEXT("更新坐标"));
	for(int i = 0;i<AICount;i++)
	{
		//if it postion is defaluet,set new postion,if not then move to new postion
		if(AIs[i]->GetActorLocation() == FVector::ZeroVector)
		{
			AIs[i]->SetActorLocation(list[i]);
		}else
		{
			// AAIController* AIController = Cast<AAIController> (AIs[i]->GetController());
			// AIController->MoveTo(list[i]);
			AAIController* AICtl = AIs[i]->GetController<AAIController>();
			if(IsValid(AICtl))
			{
				FVector point = FVector(list[i]);
				AICtl->MoveToLocation(point,10,false);
			}
		}
	}
}
	UFUNCTION(BlueprintCallable,Category="Formation")
	void CreateBoxFormation(FBoxType Box);
	UFUNCTION(BlueprintCallable,Category="Formation")
	void CreateCircleFormation(FCircleType Circle);
	UFUNCTION(BlueprintCallable,Category="Formation")
	void updataBox(FBoxType Box);
	UFUNCTION(BlueprintCallable,Category="Formation")
	void updataCircle(FCircleType Circle);

上面是暴露给蓝图的函数,因为具体的阵列效果需要在蓝图里去检查。因此做了基本的暴露

大致思路是先算出来具体的坐标,再再对应坐标上生成AI,当更新阵列时,通过AI的位移方法移动到指定点上。

不足的地方

阵列变化不够自然:解决方法通过一定计算,给每个点匹配最佳的位移坐标

位移之后AI方向不受控制:在AI移动的方法添加方向的计算,以便于在最后的时间内,能够自然的转换到指定方向。

总而言之。需要提升的地方有很多,这里花了两天时间,学习到最后将效果展示出来。

标签:Box,Distance,FVector,AI,void,Factory,探究,集群,Circle
来源: https://www.cnblogs.com/ldnanchao/p/16133329.html