diff --git a/.gitignore b/.gitignore index 06b35ce..bf6c3b3 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ Saved/ *.sln *.suo *.xcodeproj +.vs/ diff --git a/Config/DefaultEngine.ini b/Config/DefaultEngine.ini index 867d235..5c1d6f4 100644 --- a/Config/DefaultEngine.ini +++ b/Config/DefaultEngine.ini @@ -14,38 +14,6 @@ UIScaleCurve=(EditorCurveData=(Keys=((Time=480,Value=0.444),(Time=720,Value=0.666),(Time=1080,Value=1.0),(Time=8640,Value=8.0))),ExternalCurve=None) UIScaleCurve=(EditorCurveData=(Keys=((Time=480.000000,Value=0.444000),(Time=720.000000,Value=0.666000),(Time=1080.000000,Value=1.000000),(Time=8640.000000,Value=8.000000))),ExternalCurve=None) -[/Script/Engine.RendererSettings] -r.MobileHDR=True -r.AllowOcclusionQueries=True -r.MinScreenRadiusForLights=0.030000 -r.MinScreenRadiusForDepthPrepass=0.030000 -r.PrecomputedVisibilityWarning=False -r.TextureStreaming=True -Compat.UseDXT5NormalMaps=False -r.AllowStaticLighting=True -r.NormalMapsForStaticLighting=False -r.GBuffer=True -r.GenerateMeshDistanceFields=False -r.Shadow.DistanceFieldPenumbraSize=0.050000 -r.TessellationAdaptivePixelsPerTriangle=48.000000 -r.SeparateTranslucency=True -r.CustomDepth=1 -r.DefaultFeature.Bloom=True -r.DefaultFeature.AmbientOcclusion=True -r.DefaultFeature.AmbientOcclusionStaticFraction=True -r.DefaultFeature.AutoExposure=True -r.DefaultFeature.MotionBlur=True -r.DefaultFeature.LensFlare=True -r.DefaultFeature.AntiAliasing=2 -r.EarlyZPass=3 -r.EarlyZPassMovable=False -r.DBuffer=False -r.ClearSceneMethod=1 -r.MSAA.CompositingSampleCount=2 -r.WireframeCullThreshold=5.000000 -UIScaleRule=ShortestSide -UIScaleCurve=(EditorCurveData=(Keys=),ExternalCurve=None) - [/Script/HardwareTargeting.HardwareTargetingSettings] TargetedHardwareClass=Desktop AppliedTargetedHardwareClass=Desktop @@ -65,4 +33,47 @@ ServerDefaultMap=/Engine/Maps/Entry GlobalDefaultGameMode=/Game/Blueprints/MyGameMode.MyGameMode_C GlobalDefaultServerGameMode=None +[/Script/Engine.PhysicsSettings] +DefaultGravityZ=-980.000000 +DefaultTerminalVelocity=4000.000000 +DefaultFluidFriction=0.300000 +SimulateScratchMemorySize=262144 +RagdollAggregateThreshold=4 +TriangleMeshTriangleMinAreaThreshold=5.000000 +bEnableShapeSharing=False +bEnablePCM=True +bEnableStabilization=False +bWarnMissingLocks=True +bEnable2DPhysics=False +PhysicErrorCorrection=(PingExtrapolation=0.100000,PingLimit=100.000000,ErrorPerLinearDifference=1.000000,ErrorPerAngularDifference=1.000000,MaxRestoredStateError=1.000000,MaxLinearHardSnapDistance=400.000000,PositionLerp=0.000000,AngleLerp=0.400000,LinearVelocityCoefficient=100.000000,AngularVelocityCoefficient=10.000000,ErrorAccumulationSeconds=0.500000,ErrorAccumulationDistanceSq=15.000000,ErrorAccumulationSimilarity=100.000000) +LockedAxis=Invalid +DefaultDegreesOfFreedom=Full3D +BounceThresholdVelocity=200.000000 +FrictionCombineMode=Average +RestitutionCombineMode=Average +MaxAngularVelocity=3600.000000 +MaxDepenetrationVelocity=0.000000 +ContactOffsetMultiplier=0.020000 +MinContactOffset=2.000000 +MaxContactOffset=8.000000 +bSimulateSkeletalMeshOnDedicatedServer=True +DefaultShapeComplexity=CTF_UseSimpleAndComplex +bDefaultHasComplexCollision=True +bSuppressFaceRemapTable=False +bSupportUVFromHitResults=False +bDisableActiveActors=False +bDisableKinematicStaticPairs=False +bDisableKinematicKinematicPairs=False +bDisableCCD=False +bEnableEnhancedDeterminism=False +MaxPhysicsDeltaTime=0.033333 +bSubstepping=False +bSubsteppingAsync=False +MaxSubstepDeltaTime=0.016667 +MaxSubsteps=6 +SyncSceneSmoothingFactor=0.000000 +InitialAverageFrameRate=0.016667 +PhysXTreeRebuildRate=10 +DefaultBroadphaseSettings=(bUseMBPOnClient=False,bUseMBPOnServer=False,MBPBounds=(Min=(X=0.000000,Y=0.000000,Z=0.000000),Max=(X=0.000000,Y=0.000000,Z=0.000000),IsValid=0),MBPNumSubdivs=2) + diff --git a/Config/DefaultGame.ini b/Config/DefaultGame.ini index 6ce40b5..c2ca3a4 100644 --- a/Config/DefaultGame.ini +++ b/Config/DefaultGame.ini @@ -11,8 +11,7 @@ LicensingTerms= PrivacyPolicy= ProjectID=1D61FE7D544EDE8A25D93CB98BB60D75 ProjectName=FlockAI -ProjectVersion= +ProjectVersion=1.0 SupportContact=parmandorc@gmail.com ProjectDisplayedTitle=FlockAI - diff --git a/Content/Blueprints/AgentBP.uasset b/Content/Blueprints/AgentBP.uasset index 61ceeb8..45c11d5 100644 Binary files a/Content/Blueprints/AgentBP.uasset and b/Content/Blueprints/AgentBP.uasset differ diff --git a/FlockAI.uproject b/FlockAI.uproject index 1e03ed3..c34987d 100644 --- a/FlockAI.uproject +++ b/FlockAI.uproject @@ -1,6 +1,6 @@ { "FileVersion": 3, - "EngineAssociation": "4.7", + "EngineAssociation": "4.22", "Category": "", "Description": "", "Modules": [ diff --git a/Source/FlockAI.Target.cs b/Source/FlockAI.Target.cs index 8230f1e..d80c3a0 100644 --- a/Source/FlockAI.Target.cs +++ b/Source/FlockAI.Target.cs @@ -5,21 +5,9 @@ public class FlockAITarget : TargetRules { - public FlockAITarget(TargetInfo Target) + public FlockAITarget(TargetInfo Target) : base(Target) { Type = TargetType.Game; - } - - // - // TargetRules interface. - // - - public override void SetupBinaries( - TargetInfo Target, - ref List OutBuildBinaryConfigurations, - ref List OutExtraModuleNames - ) - { - OutExtraModuleNames.Add("FlockAI"); + ExtraModuleNames.Add("FlockAI"); } } diff --git a/Source/FlockAI/FlockAI.Build.cs b/Source/FlockAI/FlockAI.Build.cs index 31ad64f..39adcd7 100644 --- a/Source/FlockAI/FlockAI.Build.cs +++ b/Source/FlockAI/FlockAI.Build.cs @@ -4,8 +4,10 @@ public class FlockAI : ModuleRules { - public FlockAI(TargetInfo Target) + public FlockAI(ReadOnlyTargetRules Target) : base(Target) { - PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore" }); + PrivatePCHHeaderFile = "Public/FlockAI.h"; + + PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore" }); } } diff --git a/Source/FlockAI/Private/Agent.cpp b/Source/FlockAI/Private/Agent.cpp index a0f6796..18b5c3f 100644 --- a/Source/FlockAI/Private/Agent.cpp +++ b/Source/FlockAI/Private/Agent.cpp @@ -2,12 +2,14 @@ #include "FlockAI.h" #include "Agent.h" +#include "Stimulus.h" AAgent::AAgent() { PrimaryActorTick.bCanEverTick = true; - + PrimaryActorTick.bStartWithTickEnabled = true; + // Initializing default values BaseMovementSpeed = 200.0f; MaxMovementSpeed = 300.0f; @@ -25,26 +27,124 @@ AAgent::AAgent() VisionSphere = CreateDefaultSubobject(TEXT("VisionSphere")); VisionSphere->AttachTo(RootComponent); VisionSphere->SetSphereRadius(VisionRadius); + + InertiaWeigh = 0.0f; + AgentPhysicalRadius = 45.0f; + SeparationWeight = 0.5f; } void AAgent::BeginPlay() { + Super::BeginPlay(); + // Initialize move vector NewMoveVector = GetActorRotation().Vector().GetSafeNormal(); } +void AAgent::ResetComponents() +{ + AlignmentComponent = FVector::ZeroVector; + CohesionComponent = FVector::ZeroVector; + SeparationComponent = FVector::ZeroVector; + NegativeStimuliComponent = FVector::ZeroVector; + NegativeStimuliMaxFactor = 0.0f; + PositiveStimuliComponent = FVector::ZeroVector; + PositiveStimuliMaxFactor = 0.0f; +} + +void AAgent::DebugComponents() +{ + FVector TempVector; + TempVector = AlignmentComponent * AlignmentWeight; + UE_LOG(LogFlockAI, Log, TEXT("Alignment: %s"), *TempVector.ToString()); + TempVector = CohesionComponent * CohesionWeight; + UE_LOG(LogFlockAI, Log, TEXT("Cohesion: %s"), *TempVector.ToString()); + TempVector = SeparationComponent * SeparationWeight; + UE_LOG(LogFlockAI, Log, TEXT("Separation: %s"), *TempVector.ToString()); + UE_LOG(LogFlockAI, Log, TEXT("NegativeStimuli: %s"), *NegativeStimuliComponent.ToString()); + UE_LOG(LogFlockAI, Log, TEXT("PositiveStimuli: %s"), *PositiveStimuliComponent.ToString()); +} + +void AAgent::CalculateNewMoveVector_Implementation() +{ + ResetComponents(); + + FVector ActorLocation = GetActorLocation(); + + VisionSphere->GetOverlappingActors(Neighbourhood, StaticClass()); + // Compute Alignment Component Vector + for (AActor* Actor : Neighbourhood) + { + AAgent* Agent = (AAgent*)Actor; + AlignmentComponent += Agent->CurrentMoveVector.GetSafeNormal(); + } + AlignmentComponent.Normalize(); + Neighbourhood.Remove(this); + if (Neighbourhood.Num() > 0) + { + // Compute Cohesion Component Vector + for (AActor* Agent : Neighbourhood) + { + CohesionComponent += Agent->GetActorLocation() - ActorLocation; + } + CohesionComponent /= Neighbourhood.Num() * 100.0f; + // Compute Separation Component Vector + for (AActor* Agent : Neighbourhood) + { + FVector SeparationVector = ActorLocation - Agent->GetActorLocation(); + SeparationComponent += SeparationVector.GetSafeNormal() / FMath::Abs(SeparationVector.Size() - AgentPhysicalRadius * 2.0f); + } + SeparationComponent *= (1.0f + Neighbourhood.Num() / 5.0f) * 100.0f; + } + + TArray StimulusActors; + VisionSphere->GetOverlappingActors(StimulusActors, AStimulus::StaticClass()); + for (AActor* Actor : StimulusActors) + { + AStimulus* Stimulus = (AStimulus*)Actor; + FVector StimuliVector = Stimulus->GetActorLocation() - ActorLocation; + if (Stimulus->Value < 0.0f) + { + // Compute Negative Stimuli Component Vector + FVector NegativeStimuliVector = StimuliVector.GetSafeNormal() / FMath::Abs(StimuliVector.Size() - AgentPhysicalRadius) * 100.0f * Stimulus->Value; + NegativeStimuliComponent += NegativeStimuliVector; + NegativeStimuliMaxFactor = FMath::Max(NegativeStimuliMaxFactor, NegativeStimuliVector.Size()); + } + else + { + // Compute Positive Stimuli Component Vector + float PositiveStimuliFactor = Stimulus->Value / StimuliVector.Size(); + if (PositiveStimuliFactor > PositiveStimuliMaxFactor) + { + PositiveStimuliComponent = StimuliVector.GetSafeNormal() * Stimulus->Value; + PositiveStimuliMaxFactor = PositiveStimuliFactor; + } + } + } + // Compute Aggregation of Components + NegativeStimuliComponent = NegativeStimuliComponent.GetSafeNormal() * NegativeStimuliMaxFactor; + NewMoveVector = NegativeStimuliComponent + PositiveStimuliComponent; + NewMoveVector += AlignmentComponent * AlignmentWeight; + NewMoveVector += CohesionComponent * CohesionWeight; + NewMoveVector += SeparationComponent * SeparationWeight; + + //DebugComponents(); +} + void AAgent::Tick(float DeltaSeconds) { + Super::Tick(DeltaSeconds); + CurrentMoveVector = NewMoveVector; - + CalculateNewMoveVector(); - + const FVector NewDirection = (NewMoveVector * BaseMovementSpeed * DeltaSeconds).GetClampedToMaxSize(MaxMovementSpeed * DeltaSeconds); const FRotator NewRotation = NewMoveVector.Rotation(); - + FHitResult Hit(1.f); RootComponent->MoveComponent(NewDirection, NewRotation, true, &Hit); - + if (Hit.IsValidBlockingHit()) { const FVector Normal2D = Hit.Normal.GetSafeNormal2D(); diff --git a/Source/FlockAI/Public/Agent.h b/Source/FlockAI/Public/Agent.h index 76cd07a..cf075fb 100644 --- a/Source/FlockAI/Public/Agent.h +++ b/Source/FlockAI/Public/Agent.h @@ -6,63 +6,84 @@ #include "Agent.generated.h" /** - * + * */ UCLASS() class FLOCKAI_API AAgent : public AActor { - GENERATED_BODY() - + GENERATED_BODY() + /* The mesh component */ UPROPERTY(Category = Mesh, VisibleDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = "true")) class UStaticMeshComponent* MeshComponent; - + /* The collider for the area of vision of the Agent, where it can detect other Agents */ UPROPERTY(Category = AI, VisibleDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = "true")) class USphereComponent* VisionSphere; - + public: AAgent(); - + /* The weight of the Alignment vector component */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = AI) float AlignmentWeight; - /* The weight of the Cohesion vector component */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = AI) float CohesionWeight; - /* The weight of the Separation vector component */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = AI) float SeparationWeight; - /* The base movement speed for the Agents */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = AI) float BaseMovementSpeed; - /* The maximum movement speed the Agents can have */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = AI) float MaxMovementSpeed; - /* The maximum radius at which the Agent can detect other Agents */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = AI) float VisionRadius; - + + UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = AI) + FVector AlignmentComponent; + UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = AI) + FVector CohesionComponent; + UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = AI) + FVector SeparationComponent; + UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = AI) + FVector NegativeStimuliComponent; + UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = AI) + FVector PositiveStimuliComponent; + UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = AI) + float NegativeStimuliMaxFactor; + UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = AI) + float PositiveStimuliMaxFactor; + UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = AI) + TArray Neighbourhood; + UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = AI) + float InertiaWeigh; + UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = AI) + float AgentPhysicalRadius; + /* This event is called every tick, before applying the calculated move vector to move the Agent */ - UFUNCTION(BlueprintImplementableEvent, Category = AI) + UFUNCTION(BlueprintNativeEvent, Category = AI) void CalculateNewMoveVector(); - + void CalculateNewMoveVector_Implementation(); + // Begin Actor Interface virtual void Tick(float DeltaSeconds) override; virtual void BeginPlay() override; // End Actor Interface - + +protected: + void ResetComponents(); + void DebugComponents(); + protected: /* The movement vector (in local) this agent should move this tick. */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = AI) FVector NewMoveVector; - + /* The movement vector (in local) this agent had last tick. */ - UPROPERTY(EditAnywhere , BlueprintReadOnly, Category = AI) + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = AI) FVector CurrentMoveVector; }; diff --git a/Source/FlockAIEditor.Target.cs b/Source/FlockAIEditor.Target.cs index 6314285..625e58c 100644 --- a/Source/FlockAIEditor.Target.cs +++ b/Source/FlockAIEditor.Target.cs @@ -5,21 +5,9 @@ public class FlockAIEditorTarget : TargetRules { - public FlockAIEditorTarget(TargetInfo Target) + public FlockAIEditorTarget(TargetInfo Target) : base(Target) { Type = TargetType.Editor; - } - - // - // TargetRules interface. - // - - public override void SetupBinaries( - TargetInfo Target, - ref List OutBuildBinaryConfigurations, - ref List OutExtraModuleNames - ) - { - OutExtraModuleNames.Add("FlockAI"); + ExtraModuleNames.Add("FlockAI"); } }