Announcement

Collapse
No announcement yet.

NavLink and making AI jump?

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

    NavLink and making AI jump?

    I was curious if there was a way for the AI to be able to know to jump from one place to another with a NavLink? If not, how would I tell my AI to be able to jump from one platform to another???\

    Click image for larger version

Name:	navmeshstufff.jpg
Views:	1
Size:	35.7 KB
ID:	1134209
    Portfolio/Tutorials: http://chadreddick.com

    #2
    It's currently not supported out of the box and would require some C++ coding. You can however implement a kind of jumping behavior with navlinks and triggers. Navigation links tells AI "you can traverse this segment", so if you place a link between two platforms AI will find a path as expected. You just need to take care of the jumping part, and you can "fake" it by placing a trigger on the link start that will make AI move to the other end.

    Making "AI move" could be done in couple of ways: you can simply teleport your AI, matinee-animate him, or set his physics to Flying and just let him continue (should work, but I haven't tried it ). If using the flying option don't forget to turn Walking back on once "jump" is done

    If you're interested in proper way of solving this in C++ just let me know.
    Senior AI Programmer @ Epic Games by day, AI programmer at night!
    My slow-blog on random AI thing (including UE4 AI).
    My no longer active UE4 AI blog.

    Comment


      #3
      @MieszkoZ: Thanks for your insight! ! I am interested in the proper way of doing this in C++ actually ^_^. Cause then It would be easier to set level blueprints by calling the AI's function.

      Issue I'm having is how would I go about changing the AI's Physics to be set to Flying ?
      Portfolio/Tutorials: http://chadreddick.com

      Comment


        #4
        A proper C++ solution would involve following steps:

        * Implement a new Navigation Area class - you do that by deriving from UNavArea. Let's call it UNavArea_Jump
        * Define a "jump flag" - the implementation details don't really matter, but a enum would work best here.
        - Set the "jump flag" in UNavArea_Jump::AreaFlags
        * Now you'll be able to assign UNavArea_Jump as a navigation area of navigation links.
        * Next step is to implement your own path following component. Derive from UPathFollowingComponent. Let's call it UMyPathFollowingComponent.
        * Have UMyPathFollowingComponent override UPathFollowingComponent::SetMoveSegment(uint32 SegmentStartIndex) function. This function gets called whenever AI is starting to follow new path segment
        - if FNavMeshNodeFlags(Path->PathPoints[SegmentStartIndex].Flags).AreaFlags has your defined "jump flag" set it means it's "jumpable"
        - the simplest solution would be to enable flying in such a case. You do that by calling SetMovementMode(MOVE_Flying) on your movement component. From within path following component you can get this by casting UPathFollowingComponent::MovementComp to UCharacterMovementComponent.
        - don't forget to set movement mode back to MOVE_Flying once AI finished following "jump segment"

        That should pretty much do it Sorry for any potential misspelling of class or function names
        Senior AI Programmer @ Epic Games by day, AI programmer at night!
        My slow-blog on random AI thing (including UE4 AI).
        My no longer active UE4 AI blog.

        Comment


          #5
          Originally posted by MieszkoZ View Post
          A proper C++ solution would involve following steps:

          * Implement a new Navigation Area class - you do that by deriving from UNavArea. Let's call it UNavArea_Jump
          * Define a "jump flag" - the implementation details don't really matter, but a enum would work best here.
          - Set the "jump flag" in UNavArea_Jump::AreaFlags
          * Now you'll be able to assign UNavArea_Jump as a navigation area of navigation links.
          * Next step is to implement your own path following component. Derive from UPathFollowingComponent. Let's call it UMyPathFollowingComponent.
          * Have UMyPathFollowingComponent override UPathFollowingComponent::SetMoveSegment(uint32 SegmentStartIndex) function. This function gets called whenever AI is starting to follow new path segment
          - if FNavMeshNodeFlags(Path->PathPoints[SegmentStartIndex].Flags).AreaFlags has your defined "jump flag" set it means it's "jumpable"
          - the simplest solution would be to enable flying in such a case. You do that by calling SetMovementMode(MOVE_Flying) on your movement component. From within path following component you can get this by casting UPathFollowingComponent::MovementComp to UCharacterMovementComponent.
          - don't forget to set movement mode back to MOVE_Flying once AI finished following "jump segment"

          That should pretty much do it Sorry for any potential misspelling of class or function names
          MieszkoZ, Thank you for this!!!! Must say a clever way to get things working!! If I have troubles I will reply through this thread ^_^!!!
          Portfolio/Tutorials: http://chadreddick.com

          Comment


            #6
            Originally posted by CHADALAK1 View Post
            Must say a clever way to get things working!!
            "Clever" is what we aim for with our AI code Thanks!
            Senior AI Programmer @ Epic Games by day, AI programmer at night!
            My slow-blog on random AI thing (including UE4 AI).
            My no longer active UE4 AI blog.

            Comment


              #7
              Originally posted by MieszkoZ View Post
              A proper C++ solution would involve following steps:

              * Implement a new Navigation Area class - you do that by deriving from UNavArea. Let's call it UNavArea_Jump
              * Define a "jump flag" - the implementation details don't really matter, but a enum would work best here.
              - Set the "jump flag" in UNavArea_Jump::AreaFlags
              * Now you'll be able to assign UNavArea_Jump as a navigation area of navigation links.
              * Next step is to implement your own path following component. Derive from UPathFollowingComponent. Let's call it UMyPathFollowingComponent.
              * Have UMyPathFollowingComponent override UPathFollowingComponent::SetMoveSegment(uint32 SegmentStartIndex) function. This function gets called whenever AI is starting to follow new path segment
              - if FNavMeshNodeFlags(Path->PathPoints[SegmentStartIndex].Flags).AreaFlags has your defined "jump flag" set it means it's "jumpable"
              - the simplest solution would be to enable flying in such a case. You do that by calling SetMovementMode(MOVE_Flying) on your movement component. From within path following component you can get this by casting UPathFollowingComponent::MovementComp to UCharacterMovementComponent.
              - don't forget to set movement mode back to MOVE_Flying once AI finished following "jump segment"

              That should pretty much do it Sorry for any potential misspelling of class or function names
              Ok, so far, I got everything set up. However, what do i do with the UMyPathFollowingComponent to have the AI follow that particular component? or does it do it by default if the UNavArea is set to my custom UNavArea? I'm trying to do a debug message to see if it appears when it attempts to go to the NavLink, but nothing happens.

              UNavArea_Jump.h

              Code:
              
              #pragma once
              
              #include "AI/Navigation/NavAreas/NavArea.h"
              #include "UNavArea_Jump.generated.h"
              
              /**
               * 
               */
              UCLASS()
              class UUNavArea_Jump : public UNavArea
              {
              	GENERATED_UCLASS_BODY()
              
              	enum AI_Path_Choice
              	{
              		Jump
              	};
              
              	
              	
              };
              .cpp

              Code:
              
              #include "SideScrollerConcept.h"
              #include "UNavArea_Jump.h"
              
              
              UUNavArea_Jump::UUNavArea_Jump(const class FPostConstructInitializeProperties& PCIP)
              	: Super(PCIP)
              {
              	AI_Path_Choice AI_Choice = Jump;
              }
              UMyPathFollowingComponent.h

              Code:
              
              #pragma once
              
              #include "AI/Navigation/PathFollowingComponent.h"
              #include "MyPathFollowingComponent.generated.h"
              
              /**
               * 
               */
              UCLASS()
              class UMyPathFollowingComponent : public UPathFollowingComponent
              {
              	GENERATED_UCLASS_BODY()
              
              	virtual void SetMoveSegment(uint32 SegmentStartIndex) OVERRIDE;
              	
              };
              .cpp

              Code:
              
              #include "SideScrollerConcept.h"
              #include "MyPathFollowingComponent.h"
              #include "UNavArea_Jump.h"
              
              
              UMyPathFollowingComponent::UMyPathFollowingComponent(const class FPostConstructInitializeProperties& PCIP)
              	: Super(PCIP)
              {
              
              }
              
              void UMyPathFollowingComponent::SetMoveSegment(uint32 SegmentStartIndex)
              {
              	if (FNavMeshNodeFlags(Path->PathPoints[SegmentStartIndex].Flags).AreaFlags == UUNavArea_Jump::Jump)
              	{
              		GEngine->AddOnScreenDebugMessage(-1, 2.f, FColor::Blue, TEXT("I AM JUMPING!"));
              	}
              }
              Click image for larger version

Name:	navLink.jpg
Views:	1
Size:	44.6 KB
ID:	1050254

              I also noticed the AreaFlags is a uint6
              Portfolio/Tutorials: http://chadreddick.com

              Comment


                #8
                Currently the only way to have your AI use your custom pathfollowing component is to implement your own AIController and specify the override in its controller, like so:

                Code:
                AMyAIController::AMyAIController(const class FPostConstructInitializeProperties& PCIP)
                	: Super(PCIP.SetDefaultSubobjectClass<UMyPathFollowingComponent>(TEXT("PathFollowingComponent")))
                {
                }
                Originally posted by CHADALAK1 View Post
                I also noticed the AreaFlags is a uint6
                Area flags are limited to 16 bits due to compatibility with Recast library that's running our navmesh generation. One important thing to note about AreaFlags is that it's a collection of flags not a single integer value, so in your code you should not be checking whether FNavMeshNodeFlags(Path->PathPoints[SegmentStartIndex].Flags).AreaFlags is equal to any specific value. Instead check if flags you're interested in are set by doing a binary AND with your flag. In your case it would be something like this:

                Code:
                const uint16 AreaFlags = FNavMeshNodeFlags(Path->PathPoints[SegmentStartIndex].Flags).AreaFlags;
                const uint16 JumpFlag = uint16(1 << UUNavArea_Jump::Jump);
                if ((AreaFlags & JumpFlag) != 0)
                {
                    ...
                }
                One last thing, the image you attached indicates you're setting up a smart link rather then a regular navigation link. Use a regular link, that's guaranteed to work
                Last edited by MieszkoZ; 04-27-2014, 07:22 AM. Reason: added a note not to use smart link
                Senior AI Programmer @ Epic Games by day, AI programmer at night!
                My slow-blog on random AI thing (including UE4 AI).
                My no longer active UE4 AI blog.

                Comment


                  #9
                  Originally posted by MieszkoZ View Post
                  Currently the only way to have your AI use your custom pathfollowing component is to implement your own AIController and specify the override in its controller, like so:

                  Code:
                  AMyAIController::AMyAIController(const class FPostConstructInitializeProperties& PCIP)
                  	: Super(PCIP.SetDefaultSubobjectClass<UMyPathFollowingComponent>(TEXT("PathFollowingComponent")))
                  {
                  }


                  Area flags are limited to 16 bits due to compatibility with Recast library that's running our navmesh generation. One important thing to note about AreaFlags is that it's a collection of flags not a single integer value, so in your code you should not be checking whether FNavMeshNodeFlags(Path->PathPoints[SegmentStartIndex].Flags).AreaFlags is equal to any specific value. Instead check if flags you're interested in are set by doing a binary AND with your flag. In your case it would be something like this:

                  Code:
                  const uint16 AreaFlags = FNavMeshNodeFlags(Path->PathPoints[SegmentStartIndex].Flags).AreaFlags;
                  const uint16 JumpFlag = uint16(1 << UUNavArea_Jump::Jump);
                  if ((AreaFlags & JumpFlag) != 0)
                  {
                      ...
                  }
                  One last thing, the image you attached indicates you're setting up a smart link rather then a regular navigation link. Use a regular link, that's guaranteed to work
                  Alright! I got everything to work! HOWEVER, the AI keeps jumping all the time... how could I tell the AI to jump when it gets to that link? cause it will keep jumping even far away from the link .


                  MyPathFollowingComponent.cpp
                  Code:
                  #include "SideScrollerConcept.h"
                  #include "MyPathFollowingComponent.h"
                  #include "UNavArea_Jump.h"
                  #include "CorruptBot.h"
                  
                  
                  UMyPathFollowingComponent::UMyPathFollowingComponent(const class FPostConstructInitializeProperties& PCIP)
                  	: Super(PCIP)
                  {
                  	
                  }
                  
                  void UMyPathFollowingComponent::SetMoveSegment(uint32 SegmentStartIndex)
                  {
                  	const uint16 AreaFlags = FNavMeshNodeFlags(Path->PathPoints[SegmentStartIndex].Flags).AreaFlags;
                  	const uint16 JumpFlag = uint16(1 << UUNavArea_Jump::Jump);
                  
                  	if (AreaFlags && JumpFlag != 0)
                  	{
                  
                  		GEngine->AddOnScreenDebugMessage(-1, 2.f, FColor::Blue, TEXT("I AM JUMPING"));
                  		if (AreaFlags == JumpFlag)
                  		{
                  			for (FConstPawnIterator It = GetWorld()->GetPawnIterator(); It; ++It)
                  			{
                  				ACorruptBot* AIPawn = Cast<ACorruptBot>(*It);
                  				if (AIPawn)
                  				{
                  					AIPawn->LaunchCharacter(FVector(0, 0, 1000), false, false);
                  				}
                  			}
                  			GEngine->AddOnScreenDebugMessage(-1, 2.f, FColor::Blue, TEXT("FOR REAL"));
                  		}
                  	}
                  }
                  Portfolio/Tutorials: http://chadreddick.com

                  Comment


                    #10
                    One important thing to remember, which I should have mentioned, is that by default AreaFlags == 1, which means your UUNavArea_Jump::Jump has to be > 1.

                    One additional bug you have in your code is that while checking if a flag is set you need to use binary AND, and you used a logic one. Should be: if ((AreaFlags & JumpFlag) != 0)

                    Similarly, somparison (AreaFlags == JumpFlag) will always fail.
                    Senior AI Programmer @ Epic Games by day, AI programmer at night!
                    My slow-blog on random AI thing (including UE4 AI).
                    My no longer active UE4 AI blog.

                    Comment


                      #11
                      Originally posted by MieszkoZ View Post
                      One important thing to remember, which I should have mentioned, is that by default AreaFlags == 1, which means your UUNavArea_Jump::Jump has to be > 1.

                      One additional bug you have in your code is that while checking if a flag is set you need to use binary AND, and you used a logic one. Should be: if ((AreaFlags & JumpFlag) != 0)

                      Similarly, somparison (AreaFlags == JumpFlag) will always fail.
                      OOOHHH the binary does make a difference.. I'm used to using the && logic operator by default sometimes :/. Now the problem is that the check if the AreaFlag equals the JumpFlag. . And I also made the jumpflag = 2.

                      Code:
                      
                      #include "SideScrollerConcept.h"
                      #include "MyPathFollowingComponent.h"
                      #include "UNavArea_Jump.h"
                      #include "CorruptBot.h"
                      
                      
                      UMyPathFollowingComponent::UMyPathFollowingComponent(const class FPostConstructInitializeProperties& PCIP)
                      	: Super(PCIP)
                      {
                      	
                      }
                      
                      void UMyPathFollowingComponent::SetMoveSegment(uint32 SegmentStartIndex)
                      {
                      	const uint16 AreaFlags = FNavMeshNodeFlags(Path->PathPoints[SegmentStartIndex].Flags).AreaFlags;
                      	const uint16 JumpFlag = uint16(2 << UUNavArea_Jump::Jump);
                      
                      	if ((AreaFlags & JumpFlag) != 0)
                      	{
                      
                      		GEngine->AddOnScreenDebugMessage(-1, 2.f, FColor::Blue, TEXT("I AM JUMPING"));
                      		if (AreaFlags >> 2)  //////////////////////////////////////////////////// THIS IS WHERE THE PROBLEM IS
                      		{
                      			for (FConstPawnIterator It = GetWorld()->GetPawnIterator(); It; ++It)
                      			{
                      				ACorruptBot* AIPawn = Cast<ACorruptBot>(*It);
                      				if (AIPawn)
                      				{
                      					AIPawn->LaunchCharacter(FVector(0, 0, 1000), false, false);
                      				}
                      			}
                      			GEngine->AddOnScreenDebugMessage(-1, 2.f, FColor::Blue, TEXT("FOR REAL"));
                      		}
                      	}
                      }
                      Last edited by CHADALAK1; 04-28-2014, 05:28 PM.
                      Portfolio/Tutorials: http://chadreddick.com

                      Comment


                        #12
                        You're doing it wrong

                        Instead of const uint16 JumpFlag = uint16(2 << UUNavArea_Jump::Jump); you should have:

                        Code:
                        enum AI_Path_Choice
                        {
                        	Jump = 1
                        };
                        which will result in (1 << UUNavArea_Jump::Jump) == 2.

                        The reason if (AreaFlags >> 2) fails in your code is that in your case (2 << UUNavArea_Jump::Jump) == 2 since UUNavArea_Jump::Jump == 0 and shifting this kind of value results in 0

                        That should fix it

                        In general when debugging path point flags I'd suggest running the debugger and simply see what is the AreaFlags value on each path point. You'll notice when any one of them has different flags then others
                        Senior AI Programmer @ Epic Games by day, AI programmer at night!
                        My slow-blog on random AI thing (including UE4 AI).
                        My no longer active UE4 AI blog.

                        Comment


                          #13
                          And please read up on bit flags, it will save you a whole lot of grief if you understand what you're actually doing:
                          http://www.cplusplus.com/forum/general/1590/
                          http://www.codeproject.com/Articles/...ing-Enum-Flags
                          Contact: enlight in #unrealengine IRC channel on Freenode, or @macagonator on Twitter

                          Comment


                            #14
                            Originally posted by MieszkoZ View Post
                            You're doing it wrong

                            Instead of const uint16 JumpFlag = uint16(2 << UUNavArea_Jump::Jump); you should have:

                            Code:
                            enum AI_Path_Choice
                            {
                            	Jump = 1
                            };
                            which will result in (1 << UUNavArea_Jump::Jump) == 2.

                            The reason if (AreaFlags >> 2) fails in your code is that in your case (2 << UUNavArea_Jump::Jump) == 2 since UUNavArea_Jump::Jump == 0 and shifting this kind of value results in 0

                            That should fix it

                            In general when debugging path point flags I'd suggest running the debugger and simply see what is the AreaFlags value on each path point. You'll notice when any one of them has different flags then others
                            Thanks for this !!! I apologize for the lack of knowledge with binary and enum flags Dx... Just am a bit new to binary and enum flags :/. I also did a check after those corrections... when i make the AI go to the jump NavLink, the number check goes to 0 :/ ...



                            Code:
                            
                            #include "SideScrollerConcept.h"
                            #include "MyPathFollowingComponent.h"
                            #include "UNavArea_Jump.h"
                            #include "CorruptBot.h"
                            
                            
                            UMyPathFollowingComponent::UMyPathFollowingComponent(const class FPostConstructInitializeProperties& PCIP)
                            	: Super(PCIP)
                            {
                            	
                            }
                            
                            void UMyPathFollowingComponent::SetMoveSegment(uint32 SegmentStartIndex)
                            {
                            	const uint16 AreaFlags = FNavMeshNodeFlags(Path->PathPoints[SegmentStartIndex].Flags).AreaFlags;
                            	const uint16 JumpFlag = uint16(1 << UUNavArea_Jump::Jump);
                            
                            	FString Check = FString::FromInt(AreaFlags);
                            
                            	GEngine->AddOnScreenDebugMessage(-1, 2.f, FColor::Red, Check);
                            
                            	if ((AreaFlags & JumpFlag) != 0)
                            	{
                            		GEngine->AddOnScreenDebugMessage(-1, 2.f, FColor::Blue, TEXT("I AM JUMPING"));
                            		if (AreaFlags >> 2)
                            		{
                            			for (FConstPawnIterator It = GetWorld()->GetPawnIterator(); It; ++It)
                            			{
                            				ACorruptBot* AIPawn = Cast<ACorruptBot>(*It);
                            				if (AIPawn)
                            				{
                            					AIPawn->LaunchCharacter(FVector(0, 0, 1000), false, false);
                            				}
                            			}
                            			GEngine->AddOnScreenDebugMessage(-1, 2.f, FColor::Blue, TEXT("FOR REAL"));
                            		}
                            		
                            	}
                            }
                            i also did the correction to my enum declaration and made Jump = 1. I don't mean to have you guys hold my hand through this... just I want to learn this as much as I can . Since UE3, I always went to the forums for help on unanswered questions and learned from them . Baby steps are helping me learn.


                            @enlight_2014: Thanks for the links!!! makes a little more sense with the enum flags
                            Last edited by CHADALAK1; 04-29-2014, 02:06 AM.
                            Portfolio/Tutorials: http://chadreddick.com

                            Comment


                              #15
                              I did a check on both JumpFlag and AreaFlags. my results were JumpFlag produced 2. So the JumpFlag works fine . ONLY Problem is AreaFlags ALWAYS goes to 0 when making the AI go to the NavLink ...

                              MieszkoZ, I'm sorry to be barking up your tree , but what is preventing the AreaFlags from being 2?
                              Portfolio/Tutorials: http://chadreddick.com

                              Comment

                              Working...
                              X