Announcement

Collapse
No announcement yet.

Victor's Behaviour tree basic zombie(C++/Blueprints) [TUTORIALl]

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

    Victor's Behaviour tree basic zombie(C++/Blueprints) [TUTORIALl]

    In this tutorial, im going to show, step by step, how to create a very simple zombie AI that is idle until it sees a player, and when it sees it it goes to attack it melee.

    The behavior tree is a very interesting feature, still WIP, and really barebones, you will find that the default tasks are really few and more are needed most of the time.
    The system works by selecting a task to run, and execute it. When the task is finished, it searches for the next task to do.

    Tasks
    The Tasks are derived from BTTask_Blackboard if you want to create them in c++, and BTTask_Blueprint if you want to create them in blueprints. For my needs, most of the time ive found that keeping them in blueprints helps a LOT with prototyping, if i need a task that does strange things, i code the difficult part on C++, most of the times in my base AI Controller class or Bot Pawn, and then i call that function from blueprint. If you are worried of performance, you can still make the task purely C++ if you want.

    Services
    A service is some kind of minitask, that is called all the time. Its what i use to check sight, i have my ZombieSearchPlayer Service wich just calls the SearchPlayer() function in my c++ code( as its a bit more complex logic, i made it as c++ function). That service is called on a interval of time, you can set it one time and some random offset. Of course, if you use lower intervals, calling the service many times, you can slow the game, so better have care to what you are calculating. One example is that my SearchPlayer function was not very well optimized, as it searches all the pawns in the map and checks if one is a player, and calling that every 0.1 seconds on 15 zombies isnt good to the performance, so i added a check and only search for a player if you dont have a target already)

    Composites
    A Composite selects wich task to run, by default, you will see a number in the composites and tasks, thats is the order the behavior tree will check each task. The Sequence composite is one of the most useful, it makes tasks run one after another. Selector only runs a task if the one before failed. And Simple Parallel is the one to use if you want several tasks executing at once ( im using it for the melee attack, one task performs the damage and the animation, while other makes the bot run to target)

    Decorators
    You can attach Decorators to both Composites and Tasks. The Decorator is to control the flow, for example a very useful one is the Blackboard Decorator. In that one you can make it so it only makes the task in that branch execute if some blackboard value is set or not. The cool thing about Decorators is that you can make them as some kind of "event". The Blackboard Decorator can override a different task that is runnning, if you set "Observer aborts" property to Both, it overrides its branch and every other branch that has lower priority (its to the right), If you click the Decorator, you will see that some nodes get colored, the ones that can be overriden. In the zombie logic, when the Enemy blackboard variable is set, the decorator is fired and cancels the default "wait" task.

    Blackboard
    The blackboard is VERY important, its a data asset, that you need to create in the editor. It holds the values your behavior tree uses. In the zombie example, it has Enemy variable only, as its the only needed. But in more complex AI i have, i have more than 10 values in the blackboard to drive different Decorators and add variables to tasks.
    Tasks get their data from the Blackboard, yes, you could access the controller or pawn easily and use the values there. But if the data is in the blackboard, you can use it to drive Decorators, and see the variables at runtime easily when debugging.


    Example
    Enough theory, lets go to the actual example. The plan is a very basic zombie/creature/whatever AI that stands still until it sees a player, and if it sees the player it goes to hit him in the face.
    You should do this with ShooterGame example, editing it, or with a project that uses similar code. Becouse the shootergame already provides bot class that can die and take damage, wich is useful for the AI.

    To start, make sure you have Behavior Tree Editor enabled. To enable it, go to Edit->Editor Preferences-> Experimental. Check the Behavior Tree Editor property.

    When the BTEditor is enabled, create 2 new assets in your content browser. One of type Behavior Tree , and other of type Data Asset, use class Blackboard when it asks wich data asset class to use. Name them something logical, like SimpleZombieBT, and SimpleZombieBlackboard


    Now, lets go to the Blackboard Data Asset. You will get a property window. Ignore the "Parent" tab, and in the "Keys" array, add one value, set the KeyType to type Object, and the name to Enemy, also, in the BaseClass under Key Type once you set that as object, i recomend you to set it as Character or your base player class, for safety.

    Once that is set, go to the Behavior tree asset, and open it. You will be welcomed with a blueprint like grid with only one ROOT node.
    Click that node, and set the Blackboard Asset value to the blackboard you just created. After that click in the dark grey bar on the lower part of the ROOT node, drag it( an arrow should appear), and like in blueprints, it prompts a menu. Select a "Sequence", this will be our basic sequence for the character.
    Drag from the lower dark grey bar of the Sequence node, and create another sequence node. In that node, right click it, and select Add Decorator. Add a Blackboard Decorator. Click that decorator(blue), and see the properties.
    Click image for larger version

Name:	Decoratr.PNG
Views:	1
Size:	14.8 KB
ID:	1134193

    That decorator will fire its branch whenever the "Enemy" key in the blackboard is set.
    Now, add some pathfinding logic to the zombie, so it runs to the Enemy
    Add a MoveTo Task node, and connect it to the Attack logic. In the task properties, put Acceptable Radius as 100, its a good value to end the pathfinding, then the hit logic will trigger.
    Makse sure the Blackboard Key of the Move To node is set as Enemy. Becouse we obviously want the AI to move to the Enemy position.
    Add a SimpleParallel composite attached to the sequence that has the blackboard.
    That node makes a base task to run (left bottom grey bar), and while it runs it also runs the tasks attached to the right side. When the main task finishes, the secondary tasks are stopped.
    Add a MoveDirectlyToward task at the right side, set Acceptable Radius to 0, and make sure the blackboard key is Enemy.

    Why 2 different "move" tasks?
    Easy, becouse Move To uses actual pathfinding, while MoveDirectlyTowards doesnt. Thats why we are using Move To if its far, and Movedirectlytowards when its close.
    At this moment, the behavior tree looks like this:
    Click image for larger version

Name:	BT2.PNG
Views:	1
Size:	62.5 KB
ID:	1134194
    If you try to run it, it will do nothing. Yet.




    C++ Code
    The important logic for the Melee attack and the Search Enemy functions are written in my own ACreatureAI and ACreatureBot classes. ACreatureAI inherits from AAIController and ACreatureBot from AShooterCharacter.

    This is the CreatureAI.h
    Code:
    UCLASS()
    class ACreatureAI : public AAIController
    {
    	GENERATED_UCLASS_BODY()
    
    	
    
    	UPROPERTY(transient)
    	TSubobjectPtr<class UBlackboardComponent> BlackboardComp;
    
    	UPROPERTY(transient)
    	TSubobjectPtr<class UBehaviorTreeComponent> BehaviorComp;
    
    	virtual void Possess(class APawn* InPawn) OVERRIDE;
    
    	virtual void BeginInactiveState() OVERRIDE;
    
    	void Respawn();
    
    	
    	UFUNCTION(BlueprintCallable, Category = Behavior)
    	void SetEnemy(class APawn* InPawn);
    	UFUNCTION(BlueprintCallable, Category = Behavior)
    	class AShooterCharacter* GetEnemy() const;
    
    
    	
    
    
    	UFUNCTION(BlueprintCallable, Category = Behaviour)
    	bool PawnCanBeSeen(APawn * target);
    
           /* Checks sight to all pawns in map, sets enemy if it finds a thing */
    
    	UFUNCTION(BlueprintCallable, Category = Behaviour)
    	void SearchEnemyInView();
    
    	
    protected:
    	int32 EnemyKeyID;		
    };
    The Cpp file is like this
    Code:
    
    #include "ShooterGame.h"
    
    
    
    ACreatureAI::ACreatureAI(const class FPostConstructInitializeProperties& PCIP)
    	: Super(PCIP)
    {
    // create blackboard and behaviour components in the constructor
    	BlackboardComp = PCIP.CreateDefaultSubobject<UBlackboardComponent>(this, TEXT("BlackBoardComp"));
    
    	BehaviorComp = PCIP.CreateDefaultSubobject<UBehaviorTreeComponent>(this, TEXT("BehaviorComp"));
    
    	bWantsPlayerState = true;
    }
    
    
    
    void ACreatureAI::Possess(APawn* InPawn)
    {
    	Super::Possess(InPawn);
    
    	ACreatureBot* Bot = Cast<ACreatureBot>(InPawn);
    
    	// start behavior
    	if (Bot && Bot->BotBehavior)
    	{		
    
    		BlackboardComp->InitializeBlackboard(Bot->BotBehavior->BlackboardAsset);
    
                    // Get the enemy blackboard ID, and store it to access that blackboard key later.
    		EnemyKeyID = BlackboardComp->GetKeyID("Enemy");
    		
    
    		BehaviorComp->StartTree(Bot->BotBehavior);
    	}
    }
    
    void ACreatureAI::BeginInactiveState()
    {
    	Super::BeginInactiveState();
    
    	AGameState* GameState = GetWorld()->GameState;
    
    	const float MinRespawnDelay = (GameState && GameState->GameModeClass) ? GetDefault<AGameMode>(GameState->GameModeClass)->MinRespawnDelay : 1.0f;
    
    	GetWorldTimerManager().SetTimer(this, &ACreatureAI::Respawn, MinRespawnDelay);
    }
    
    void ACreatureAI::Respawn()
    {
    //	GetWorld()->GetAuthGameMode()->RestartPlayer(this);
    }
    
    
    
    
    void ACreatureAI::SetEnemy(class APawn* InPawn)
    {
    	if (BlackboardComp)
    	{
    		BlackboardComp->SetValueAsObject(EnemyKeyID, InPawn);
    		SetFocus(InPawn);
    	}
    }
    
    class AShooterCharacter* ACreatureAI::GetEnemy() const
    {
    	if (BlackboardComp)
    	{
    		return Cast<AShooterCharacter>(BlackboardComp->GetValueAsObject(EnemyKeyID));
    	}
    
    	return NULL;
    }
    
    
    void ACreatureAI::UpdateControlRotation(float DeltaTime, bool bUpdatePawn)
    {
    	// Look toward focus
    	FVector FocalPoint = GetFocalPoint();
    	if (!FocalPoint.IsZero() && GetPawn())
    	{
    		FVector Direction = FocalPoint - GetPawn()->GetActorLocation();
    		FRotator NewControlRotation = Direction.Rotation();
    
    		NewControlRotation.Yaw = FRotator::ClampAxis(NewControlRotation.Yaw);
    
    		SetControlRotation(NewControlRotation);
    
    		APawn* const P = GetPawn();
    		if (P && bUpdatePawn)
    		{
    			P->FaceRotation(NewControlRotation, DeltaTime);
    		}
    
    	}
    }
    
    
    bool ACreatureAI::PawnCanBeSeen(APawn * target)
    {
    	if (target == NULL || GetPawn() == NULL)
    	{
    		return false;
    	}
    	FVector difference = target->GetActorLocation() - GetPawn()->GetActorLocation();
    	float angle = FVector::DotProduct(difference, GetPawn()->GetActorRotation().Vector());
    
    	if (LineOfSightTo(target, GetPawn()->GetActorLocation()) && angle >0)
    	{
    		return true;
    	}
    	else
    	{
    		return false;
    	}
    }
    
    
    void ACreatureAI::SearchEnemyInView()
    {
    	APawn* MyBot = GetPawn();
    	if (MyBot == NULL)
    	{
    		return;
    	}
    
    	const FVector MyLoc = MyBot->GetActorLocation();
    	float BestDistSq = MAX_FLT;
    	AShooterCharacter* BestPawn = NULL;
    
    	//foreach all pawns in world
    	for (FConstPawnIterator It = GetWorld()->GetPawnIterator(); It; ++It)
    	{
    		UE_LOG(LogShooterWeapon, Log, TEXT(" ENEMY SEEN %s "), *GetNameSafe(*It));
    		if (PawnCanBeSeen(*It))
    		{
    			AShooterCharacter* TestPawn = Cast<AShooterCharacter>(*It);
    
    			if (TestPawn && TestPawn->IsAlive() && Cast<ACreatureBot>(TestPawn) == NULL)
    			{
    				const float DistSq = (TestPawn->GetActorLocation() - MyLoc).SizeSquared();
     				if (DistSq < BestDistSq)
    				{
    					 BestDistSq = DistSq;
    					BestPawn = TestPawn;
    				 }
     			}
    		}
    	}
    
    	if (BestPawn)
    	{
    		// We saw someone, so set him as target.
    		SetEnemy(BestPawn);
    	
    	}
    	
    }

    The important thing is the Search Enemy in View function, wich checks EVERY pawn in the map, and checks if it can be seen (PawnCanBeSeen function). If the pawn is visible, it casts it to CreatureBot, wich is the AI class, and if it isnt a AI class, then it can be a target, so store it. Get the closest pawn, and target that one. The SetEnemy function writes the enemy pawn to the blackboard, so it fires the decorators in the trees and can be used for the MoveTo and MoveToward classes.


    The CreatureBot class is actually much simpler, as its just a character inheriting from ShooterCharacter, wich has the PerformMelee attack function and its several variables.

    CreatureBot.h
    Code:
    UCLASS()
    class ACreatureBot : public AShooterCharacter
    {
    	GENERATED_UCLASS_BODY()
    
    
    	UPROPERTY(EditDefaultsOnly, Category = Behaviour)
    	float AttackRange;
    	UPROPERTY(EditDefaultsOnly, Category = Behaviour)
    	float AttackDamage;
    	
    	UPROPERTY(EditAnywhere, Category = Behavior)
    	class UBehaviorTree* BotBehavior;
    
    	UFUNCTION(BlueprintCallable, Category = Behavior)
    	void PerformMeleeAttack();
    
    	float AccumulatedFiretime;
    
    	virtual bool IsFirstPerson() const OVERRIDE;
    
    	virtual void FaceRotation(FRotator NewRotation, float DeltaTime = 0.f) OVERRIDE;
    	bool Attacking;
    };

    CreatureBot.cpp
    Code:
    // Copyright 1998-2014 Epic Games, Inc. All Rights Reserved.
    
    #include "ShooterGame.h"
    
    
    ACreatureBot::ACreatureBot(const class FPostConstructInitializeProperties& PCIP)
    	: Super(PCIP)
    {
    	AIControllerClass = ACreatureAI::StaticClass();
    
    	UpdatePawnMeshes();
    
    	AttackRange = 100;
    	AttackDamage = 10;	
    	bUseControllerRotationYaw = true;
    }
    
    
    bool ACreatureBot::IsFirstPerson() const
    {
    	return false;
    }
    void ACreatureBot::FaceRotation(FRotator NewRotation, float DeltaTime)
    {
    	FRotator CurrentRotation = FMath::RInterpTo(GetActorRotation(), NewRotation, DeltaTime, 8.0f);
    
    	Super::FaceRotation(CurrentRotation, DeltaTime);
    }
    
    
    void ACreatureBot::PerformMeleeAttack()
    {
    	const FVector StartTrace = GetActorLocation();
    	const FVector ShootDir = GetActorRotation().Vector();
    	const FVector EndTrace = StartTrace + ShootDir * AttackRange;
    
    
    
           //  We perform a sphere sweep, checking if there is something in the cylinder that trace creates, and if it finds something, damage it.
    	static FName WeaponFireTag = FName(TEXT("WeaponTrace"));
    	FCollisionQueryParams TraceParams(WeaponFireTag, true);
    	TraceParams.AddIgnoredActor(this);
    	TraceParams.bTraceAsyncScene = true;
    	TraceParams.bReturnPhysicalMaterial = true;
    
    	
    	FHitResult Hit(ForceInit);
    	GetWorld()->SweepSingle(Hit, StartTrace, EndTrace, FQuat::Identity, ECollisionChannel::ECC_Pawn, FCollisionShape::MakeSphere(25), TraceParams);
    
    
    	if (Hit.Actor != NULL)
    	{
    		ACharacter *character = Cast<ACharacter>(Hit.GetActor());
    		if (character != NULL)
    		{
    			FPointDamageEvent PointDmg;
    			PointDmg.DamageTypeClass = UDamageType::StaticClass();
    			PointDmg.HitInfo = Hit;
    			PointDmg.ShotDirection = ShootDir;
    			PointDmg.Damage = AttackDamage;
    			character->TakeDamage(AttackDamage, PointDmg, Controller, this);			
    		}
    	}
    }
    The C++ part is now completed, time to actually make the tasks in blueprint, and add them to the behavior tree

    Blueprint tasks
    Now its time to add the actual "damage melee" task, and the "search player" service.

    Create 2 new blueprints, one inheriting from BTTask_blueprintBase, and other from BTService_BlueprintBase.
    Call the Task "Melee Attack", and the Service "Search Enemy".

    Open the Search Enemy blueprint, and make it like this.
    Click image for larger version

Name:	SearchEnemyBP.PNG
Views:	1
Size:	133.1 KB
ID:	1134195

    The Receive Tick function is not like a normal actor tick that its ticked every frame, this tick is ticked by the interval you put in the service properties.


    Now, Open the MeleeAttack blueprint, this one is QUITE a bit more complicated, becouse i made it work with animation, and not attack instantly, instead, it starts the animation and it performs the damage check a bit later, driven by the AttackTime variable.

    First part, the Receive Execute event.
    This event is called when the task is started, only once per task execution. Here, we use it to play the attack animation
    Click image for larger version

Name:	AttabkBT1.PNG
Views:	1
Size:	134.2 KB
ID:	1134196
    The "Attack Delta" variable is a private float variable to control the time, as they "delay" node doesnt really work properly here, so we add the time logic in tick. The AttackAnimation variable is a editable animation montage.

    The second part is the Tick event.
    Click image for larger version

Name:	AttackBT2.jpg
Views:	1
Size:	63.9 KB
ID:	1134197
    In "timer logic"we increase AttackDelta by DeltaSeconds, and when its more thatn Attack Time (editable float variable) we fire the actual attack logic.
    The atack logic just casts the controller to get the pawn, and the pawn to get the PerformAttack function, to call it. then just end the task, calling "Finish Execute" with Success set to true.

    With this, our 2 blueprints are done. yes, they can be 100 c++ perfectly fine, but with this, if i think i want to make the attacker spawn a particle effect when it attacks, or attach a light when the zombie searches, i can prototype it very fast.


    Completing the Behavior Tree

    Now that we have our 2 blueprints to search player and hit him in the face, we can complete the behavior tree at last. Open it.
    Add the MeleeAttack task to the SimpleParallel node, under the left bar, wich should be of a different color
    also right click on the topmost "Sequence" node, the one that doesnt have the decorator, and add a service, "Search Enemy". then set a normal rate for it to Tick, 0.2 seconds is fine

    The final look of our behavior tree is like this
    Click image for larger version

Name:	LastBT.PNG
Views:	1
Size:	77.7 KB
ID:	1134198


    Thats it, its done. To use it, create a new blueprint for CreatureBot, and set the Blackboard property to SimpleZombieBT. The engine should do the rest for you. Cool factor is even better if you have the behavior tree opened when the game is running, as you will see wich tasks are being executed and more data.

    Yes, this is insanely overkill by a simple AI such as this zombie/creature . But this system shines when you create a complex thing, as it simplifies quite a bit it, giving editor support for everything without having to add a shitload of properties to the controller, and lots of c++ code to deal with the behavior yourself.

    As allways, if you have any doubt, problem, or similar, feel free to comment it here, and ill answer it.
    Attached Files
    Last edited by vblanco; 04-23-2014, 04:20 PM. Reason: typos
    UDK and UE4 programmer and Unreal engine 4 betatester. Currently working on commercial VR games for PSVR.
    Deep knowlegde of C++ and blueprints. Open to freelance work.
    Games released, Deathwave(Steam), VRMultigames(Steam), DWVR(Steam,Oculus,PSVR):
    http://store.steampowered.com/app/463870
    http://store.steampowered.com/app/500360
    http://store.steampowered.com/app/520750

    #2
    awesome tutorial. I will be giving this a go this weekend. thanks!

    Comment


      #3
      not sure if this works now im 4.1, im updating it just in case.
      UDK and UE4 programmer and Unreal engine 4 betatester. Currently working on commercial VR games for PSVR.
      Deep knowlegde of C++ and blueprints. Open to freelance work.
      Games released, Deathwave(Steam), VRMultigames(Steam), DWVR(Steam,Oculus,PSVR):
      http://store.steampowered.com/app/463870
      http://store.steampowered.com/app/500360
      http://store.steampowered.com/app/520750

      Comment


        #4
        This is awesome, thanks for the tutorial.

        For people new to Behavior Trees. This looks like an overwhelming amount of setup just to get that basic behavior working with all these different parts. But, once it is setup adding additional behaviors becomes quite simple, and moving things around and changing the design is also quite easy.

        Comment


          #5
          Originally posted by mikepurvis View Post
          This is awesome, thanks for the tutorial.

          For people new to Behavior Trees. This looks like an overwhelming amount of setup just to get that basic behavior working with all these different parts. But, once it is setup adding additional behaviors becomes quite simple, and moving things around and changing the design is also quite easy.
          For individual behaviours, its indeed a overhead. This zombie can be done without BT just fine and work a be simpler. BT Shine when its complex AI with lots of things to do, and also for reusable tasks beetween different AIs (i use the see player service in all the monsters im creating). In those cases, it allows for a flexibility wich cant be matched by using blueprint alone or your own AI coded into c++.
          UDK and UE4 programmer and Unreal engine 4 betatester. Currently working on commercial VR games for PSVR.
          Deep knowlegde of C++ and blueprints. Open to freelance work.
          Games released, Deathwave(Steam), VRMultigames(Steam), DWVR(Steam,Oculus,PSVR):
          http://store.steampowered.com/app/463870
          http://store.steampowered.com/app/500360
          http://store.steampowered.com/app/520750

          Comment


            #6
            Cool stuff vBlanco, I am a huge fan of the Behavior Tree myself. It would be a great addition to our Wiki's tutorials if you ever felt like adding it. Also, would you be willing to make a version of this with only Blueprints?
            Twitch /unrealalexander| Twitter @UnrealAlexander
            How to report a bug? | Installation & Setup issues?
            Call me to a thread by posting this: [MENTION]Alexander Paschall[/MENTION]

            Comment


              #7
              alexander, ill add them to the wiki, no problems about that. And yes, ill also explain how to do a blueprint only version.
              UDK and UE4 programmer and Unreal engine 4 betatester. Currently working on commercial VR games for PSVR.
              Deep knowlegde of C++ and blueprints. Open to freelance work.
              Games released, Deathwave(Steam), VRMultigames(Steam), DWVR(Steam,Oculus,PSVR):
              http://store.steampowered.com/app/463870
              http://store.steampowered.com/app/500360
              http://store.steampowered.com/app/520750

              Comment


                #8
                Hello! Thank you for sharing!

                I tried to do this tutorial in 4.1. I had two problems:

                1) UpdateControlRotation: I can't seem to find anything about this function. It isn't declared in the header file.

                2) I can't seem to get the event tick function to fire off inside melee attack. It skips right over the task as if there was nothing in it. It does not hit any of the breakpoints. If I add a different event it detects it and goes through the code as I would expect.

                Click image for larger version

Name:	ZombieBT.png
Views:	1
Size:	137.3 KB
ID:	1050494

                Click image for larger version

Name:	MeleeAttack.jpg
Views:	1
Size:	129.6 KB
ID:	1050495
                Last edited by Voident; 05-06-2014, 04:05 PM.

                Comment


                  #9
                  Originally posted by Voident View Post
                  Hello! Thank you for sharing!

                  I tried to do this tutorial in 4.1. I had two problems:

                  1) UpdateControlRotation: I can't seem to find anything about this function. It isn't declared in the header file.

                  2) I can't seem to get the event tick function to fire off inside melee attack. It skips right over the task as if there was nothing in it. It does not hit any of the breakpoints. If I add a different event it detects it and goes through the code as I would expect.

                  [ATTACH=CONFIG]1874[/ATTACH]

                  [ATTACH=CONFIG]1876[/ATTACH]
                  add also the other part of the event graph, maiby thats the reason.
                  Update control rotation is on 4.1 as now ive checked, anyway, see if its Update Controller Rotation or something like that.
                  UDK and UE4 programmer and Unreal engine 4 betatester. Currently working on commercial VR games for PSVR.
                  Deep knowlegde of C++ and blueprints. Open to freelance work.
                  Games released, Deathwave(Steam), VRMultigames(Steam), DWVR(Steam,Oculus,PSVR):
                  http://store.steampowered.com/app/463870
                  http://store.steampowered.com/app/500360
                  http://store.steampowered.com/app/520750

                  Comment


                    #10
                    I got this to work. Thank you very much! I'm using a reload animation because I don't have a melee one right now.

                    Comment


                      #11
                      any chance a blueprint only version was ever released ? thanks greatly for this at least this is a starting point for us.

                      Comment


                        #12
                        Originally posted by leucus View Post
                        any chance a blueprint only version was ever released ? thanks greatly for this at least this is a starting point for us.
                        To launch the Behavior tree, you can just do it on the pawn blueprint. And here i show mixed tasks, that are declared in blueprint, but then call a c++ function. You can just do your whole blueprint logic inside those Task blueprints.
                        UDK and UE4 programmer and Unreal engine 4 betatester. Currently working on commercial VR games for PSVR.
                        Deep knowlegde of C++ and blueprints. Open to freelance work.
                        Games released, Deathwave(Steam), VRMultigames(Steam), DWVR(Steam,Oculus,PSVR):
                        http://store.steampowered.com/app/463870
                        http://store.steampowered.com/app/500360
                        http://store.steampowered.com/app/520750

                        Comment


                          #13
                          I've tried this and all I get on compile are errors about "Expected an include at the top of the header '#include "CreatureBot.generated.h"'

                          if I add this it complains that it has to be the last include... blah blah...

                          Any thoughts?

                          Comment


                            #14
                            Thank you for the tutorial
                            Godz for UT '99 / UT 2003

                            Comment


                              #15
                              Originally posted by DarkLichNY View Post
                              I've tried this and all I get on compile are errors about "Expected an include at the top of the header '#include "CreatureBot.generated.h"'

                              if I add this it complains that it has to be the last include... blah blah...

                              Any thoughts?
                              can you post the code maybe you just have a typo?

                              Comment

                              Working...
                              X