Announcement

Collapse

The Infinity Blade Forums Have Moved

We've launched brand new Infinity Blade forums with improved features and revamped layout. We've also included a complete archive of the previous posts. Come check out the new Infinity Blade forums.
See more
See less

B.R.A.I.N.S: Behavior Tree AI Plugin powered by Kismet

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

  • B.R.A.I.N.S: Behavior Tree AI Plugin powered by Kismet

    Behavioral Rules Artificial Intelligence Node System (B.R.A.I.N.S).
    A Behavioral Tree-driven, Kismet powered, UnrealScript Plug-in

    B.R.A.I.N.S is a controlled open-source Behavior Tree AI ideal for use in Action, Tactical, Stealth and many other games. It combines several state-of-the-art AI techniques , leveraging existing UDK AI & Navigation, Unrealscript JSON import/export for Behavior Tree Hierarchies, and Kismet as a Visual Editor. Its currently being developed with priority to the requirements for SanctityLost, with intention to expand features for other AI application. Design Documentation and Source Code will be made available for public download. The project is currently under Source Control via Perforce:
    Server: electric-lizard.servegame.com:1666
    Client/Workspace: UDK

    I'll promptly add interested parties to the P4 Access List with a PM, Title containing desired username/password (8 character minimum).
    Example: Give Me BRAINS P4 Access techlord/t3CHl0rd#1
    [SHOT]https://arcadekomodo.com/home/wp-content/uploads/2014/03/brainsbehaviortreeinkismet1.png[/SHOT] [SHOT]https://arcadekomodo.com/home/wp-content/uploads/2014/03/brainsbehaviortreeinkismet41.png[/SHOT]
    Code:
    Root:
    {
        Sequence:
        {
            Parallel:
            {
                Condition: SensoryScanForPlayer,
                Action:Animate,
                Action: Move To Actor
             },    
            Decorator:
            {
                Selector:
                {
                    Condition: SensoryScanForEnemy,
                    Action:Abort Move,
                    Action: Start Firing At,
                }
            }        
    
        }
    }


  • #2
    This is looking sweeter and sweter

    Comment


    • #3
      I don't understand the point of this thread? The title implied there would be an AI framework to discuss and feedback into, then the second post talks about a scripted mood music generator?

      Comment


      • #4
        In my game there will be segments where AI allies will be cooperating with the player. I was planning on giving them several float values to represent emotional states and having certain events modify these. I was also planning on each AI having an array of "goals" which would be ranked by priority. However, which goal to act on would also take into account the emotional state. For example, high anger may cause "Do damage to enemy" to take priority over "Do not allow health to reach 0." You would also be able to give different AI different emotional predispositions to make them have more "personality." This also brings up possibilities of taunting enemy AI to cause them to behave recklessly.

        Those are really great references you listed. Lots of food for thought...

        What are your thoughts on navigation? My problem with path nodes is that they are static and if you have carrier vehicles like Halo 3's Elephant, you need another way of providing navigation info to an AI that is onboard.

        Comment


        • #5
          Originally posted by skwisdemon666 View Post
          In my game there will be segments where AI allies will be cooperating with the player. I was planning on giving them several float values to represent emotional states and having certain events modify these. I was also planning on each AI having an array of "goals" which would be ranked by priority. However, which goal to act on would also take into account the emotional state. For example, high anger may cause "Do damage to enemy" to take priority over "Do not allow health to reach 0." You would also be able to give different AI different emotional predispositions to make them have more "personality." This also brings up possibilities of taunting enemy AI to cause them to behave recklessly.

          Those are really great references you listed. Lots of food for thought...

          What are your thoughts on navigation? My problem with path nodes is that they are static and if you have carrier vehicles like Halo 3's Elephant, you need another way of providing navigation info to an AI that is onboard.
          Hi skwisdemon666,

          Thanks for your inquiry. Are you using Finite State, Hierarchical FSM or a Behavioral Tree? Have you considered a Planner implementation? Navigation on a large moving platform such as Halo 3 Elephant, would require a custom path node system. I would use Skeletal Joints or Sockets to create the nodes.

          Comment


          • #6
            I haven't gotten into actually coding the A.I. just yet, I'm still trying to write out all my pseudo-code to keep things from getting messy when I start. Planners and animation driven behavior definately interest me. I want to keep the number of states very small.

            Comment


            • #7
              Originally posted by skwisdemon666 View Post
              I haven't gotten into actually coding the A.I. just yet, I'm still trying to write out all my pseudo-code to keep things from getting messy when I start. Planners and animation driven behavior definately interest me. I want to keep the number of states very small.
              Three State, Animation-driven AI is exactly how FEAR AI was designed. I'm a fan of FSM and till now the only form of AI I've implemented. This implementation will be a significant departure.

              I'm a big advocate of design docs. Drawing up your plan and psuedo-code is a good idea. I personally use Powerpoint or equivalent. For myself, I've started with a short list of plugin requirements: 1) Modularity, 2) utilize UDK's AI and Navigation as much as possible - no external dependencies, 3) Ease of integration.

              Modularity. I've divided the AI into 3 primary Subsystems: Motor, Sensor, and Planner. The Motor (actions) handle path-finding and animation. The Sensor (conditions) handles collision detection, internal and exterior state/status checks. The Planner (tasks) generates a Plan based on Goals and Sensor Input to drive Motor output. These subsystems will be broken down into further components if necessary.

              Motor Navigation is a hot topic. Dynamic Navigation is a concern because it requires a custom solution. I suspect your writing psuedo-code for dynamic navigation. The situation you posed with Halo3 Elephant also brings up some good questions. I mentioned using joints or sockets as path nodes, however. the representation of a path node can be a 3D vector, a scalar value, a key. Its the cost (heuristic, priority, weight) that's required by search algo.

              I would prefer a generic Search Algo that could be used in multiple situations such as the Planner itself. The cost may be pre-assigned (priority) or calculated on-the-demand (heuristic). Just need to settle on a data structure to map nodes to cost and feed the Search Algo. I'm a lazy programmer, so, I'm searching for a pre-written A* that can be converted to UnrealScript.

              Comment


              • #8
                B.R.A.I.N.S: A Tactical AI UnrealScript Plugin

                Idea:

                Some pawns will be placed on the mAp. But most will use a spawn point.

                Pawn class;
                The pawn class holds certain decision components by weight between 1 and 10. These are
                Flankingweight, coverweight and chargingweight.

                So a pawn with:
                Code:
                Flankingweight=10
                Coverweight= 0
                Chargingweight= 0
                In its default properties will always flank the player as soon as it sees him.

                Ai class:
                When the pawn sees the player, it makes a random decision based on the decision component if the pawn class.

                {Weighted state take cover }
                If it chooses to take cover, it runs to a random cover node ( it had to be a cover node) between itself and the player and starts firing. If it takes a certain amount of damGe, it retreats to a covernode away from the player.


                {Weighted state flankplayer }
                If the bot chooses to flank it goes into this state. It pretty much moves in a wide arc around the player, trying to get behind him, while shooting. It might be wise to use path ode-like actors so the bot knows what paths are areas for flanking instead of just running around the player in the open. So they might use those nodes to move around the player. If they take too much damage, they go to the retreat state, if they do make it bejind the player, they go to the charging state...or stand and shoot.

                {Weighted state charge }
                Bots with heavy charge weight in their pawn class will be used for enemies with low combat skill.
                These bots will immediately charge straight at the player, ignoring cover and firing at him. If they take too much damage though, they go to the retreat state.


                {state retreat}
                After taking damage, the bot falls back to a covernode away from the player. And starts shooting again until he gets killed.

                {state stand and shoot}.
                The bot stands in place and shoots at the player. Retreats when damage gets high.

                Comment


                • #9
                  [SHOT]https://arcadekomodo.com/home/wp-content/uploads/2014/02/UDK-2014-02-27-07-11-52-95.png[/SHOT]

                  Comment


                  • #10
                    Originally posted by TechLord
                    The B.R.A.I.N.S Modular Behavior Tree. Use Kismet as Visual Tree Editor. Use JSON for import/export data format and serialization.
                    I would also like to use Kismet as an editor for my custom object structure and import/export it to JSON. Could you tell me how did you achieve that?

                    Comment


                    • #11
                      Originally posted by Demestotenes View Post
                      I would also like to use Kismet as an editor for my custom object structure and import/export it to JSON. Could you tell me how did you achieve that?
                      Hello Demestotenesm,

                      Disclaimer: Work in Progress, subject to change without notice, has not been tested at this time.

                      The Goal: Utilize Kismet as Visual Editor to build Behavior Tree Nodes Hierarchies. The Approach: Extend classes from Unrealscript Kismet SequenceObject Classes {SequenceCondition, SequenceAction, SequenceVariable}. Kismet Sequences has many similar semantics found in Behavior Trees Task: Actions & Conditions. I'm extending from the Kismet Sequence Class the provides the closest match by functionality to a BT Task.

                      Kismet Sequence B.R.A.I.N.S Subsystem B.R.A.I.N.S Task Description
                      Event Planner Root Tree Search Initialization
                      Condition Planner Composite Task: Parallel, Sequence, Selector, Decorator Comparative Node Selection
                      Action Planner Decorator Component Manipulate Output
                      Condition Sensor Leaf Task Condition
                      Action Motor Leaf Task Action
                      Below are some useful links w/ example: JSONObject, Kismet Custom Nodes, Kismet Gems. A majority of the whats visible in UnrealEd Kismet is assigned in the default properties. My next step is to change the shape/fillcolor or add sprite Icons for BRAINS Kismet nodes, modifiable to label Behaviors/Task to add some visual distinction for BRAIN Kismet Nodes.

                      BrainsPlannerSeqCond_CompositeNode.uc:
                      Code:
                      /**
                       * Plugin: b.r.a.i.n.s - behavioral rules artificial intelligence nodes system
                       * Version: 1.0
                       * Name: BrainsPlannerSeqCond_CompositeNode
                       * Authors: F.L.Taylor (techlord) 2014
                       * References: http://unrealdb.com/the-hidden-powers-of-kismet-pt-2-custom-nodes/
                       * Purpose: Kismet Composite Node
                      */
                      
                      /*
                      Kismet Design Notes
                      InputLinks = ParentNode
                      OutputLinks = ChildNode
                      
                      States manage  Latency and Concurrency
                      */
                      
                      class BrainsPlannerSeqCond_CompositeNode extends SequenceAction
                      	abstract;
                      
                      /** Holds IndexValue of NodeSelectionBehaviors[], CheckNodeBehaviors[] */		
                      var int NodeType;
                      
                      /** Holds CurrentOutputLink; used in Node Selection and Processing */
                      
                      var array<int> ValidOutputLinksIdx;
                      var SeqOpOutputLink CurrentOutputLink;
                      var int CurrentValidOutputLinkIdx;
                      var BrainsPlannerSeqCond_CompositeNode CurrentChildNode;
                      var int OutputLinkIterator;
                      var bool bAllChildNodesActivated;
                      	
                      /** Holds Reference to Composite Node State Task */
                      var BrainsPlannerNodeTask Task;
                      
                      /** Holds Success/Fail Result */
                      var int Result;
                      
                      /* Bail */
                      var bool bBailout;
                      
                      /** Indicates whether or not this latent action has been aborted */
                      var bool bAborted;
                      
                      /** Keep track of Activation Time in Latent Actions so that we don't activate them twice in the same frame */
                      var float LatentActivationTime;
                      
                      /** NodeSelectionBehaviors[] Points to Delegate Functions  */
                      var Array< delegate<OnNodeSelect> > NodeSelectionBehaviors;
                      
                      /** NodeSelectionBehaviors[] Points to Delegate Functions  */
                      var Array< delegate<OnNodeCheck> > NodeCheckBehaviors;
                      
                      /** 
                      NodeSelectionBehaviors[] Delegate Functions  
                      Parallel, Sequence, Selector {Random, Weighted, Priority}, Gate {And,Or,Xor,Not}
                      */
                      
                      delegate OnNodeSelect(int stub);
                      
                      /** OnNodeCheck Delegate Functions  */
                      delegate OnNodeCheck(int stub);
                      
                      /** Kismet Node Activation */
                      event Activated()
                      {
                      	
                      	local SeqOpOutputLink EachOutputLink;
                      	local int EachOutputLinkIdx;	
                      	
                      	`log("Activating"@Name);
                      
                      	//add to Parent Activated Node
                      /*	
                      	if(InputLinks[0].LinkedOp != None)//IsA('BrainsPlannerSeqCond_CompositeNode'
                      	{
                      		`log("Adding to Activate ParentNode:"@InputLinks[0].LinkedOp.Name);
                      		//BrainsPlannerSeqCond_CompositeNode(InputLinks.LinkedOp).ActivatedOutputLinks.AddItem(Self);
                      	}
                      */
                      
                      	//validate Child Node OutputLinks
                      	foreach OutputLinks(EachOutputLink,EachOutputLinkIdx)
                      	{
                      		if(EachOutputLink.Links.Length > 0)
                      		{
                      			`log("Adding to Valid ChildNode["$EachOutputLinkIdx$"]:"@EachOutputLink.Links[0].LinkedOp.Name);
                      			ValidOutputLinksIdx.AddItem(EachOutputLinkIdx);
                      		}
                      	}
                      		
                      	//Activate Node Task
                      	Task = GetWorldInfo().Spawn(class'BrainsPlannerNodeTask');
                      	Task.CompositeNode = Self;
                      	
                      	//debug
                      	if(bOutputObjCommentToScreen)
                      	{	
                      		GetWorldInfo().Game.Broadcast(Task, ObjComment, 'Say');
                      	}
                      	
                      	//Note2Self: Move InitNodeSelectionBehaviors, NodeSelectDelagation to static (global cscope) class or var, RootNode?
                      	InitNodeSelectionBehaviors();
                      	InitNodeCallBehaviors();
                      
                      	`log("Activated"@Name);
                      }
                      
                      /** Child Node Finish Processing */
                      function CheckNodeProcessing()
                      {
                      	
                      }	
                      
                      /** Initialize NodeSelectionBehaviors Delegate Array */	
                      function InitNodeSelectionBehaviors()
                      {
                      	NodeSelectionBehaviors.AddItem(NodeSelectionBehaviorNone);
                      	NodeSelectionBehaviors.AddItem(NodeSelectionBehaviorSequence);
                      	NodeSelectionBehaviors.AddItem(NodeSelectionBehaviorSelector);
                      	NodeSelectionBehaviors.AddItem(NodeSelectionBehaviorParallel);	
                      	NodeSelectionBehaviors.AddItem(NodeSelectionBehaviorDecorator);	
                      }
                      
                      
                      /** Initialize NodeCallBehaviors Delegate Array */	
                      function InitNodeCallBehaviors()
                      {
                      	NodeCheckBehaviors.AddItem(NodeCheckBehaviorNone);
                      	NodeCheckBehaviors.AddItem(NodeCheckBehaviorSequence);
                      	NodeCheckBehaviors.AddItem(NodeCheckBehaviorSelector);
                      	NodeCheckBehaviors.AddItem(NodeCheckBehaviorParallel);	
                      	NodeCheckBehaviors.AddItem(NodeCheckBehaviorDecorator);
                      }
                      
                      /** Call NodeSelectionBehaviors Delegate by Index */	
                      function  SelectNode(optional int idx = -1)
                      {
                      	local delegate<OnNodeSelect> NodeSelectionBehavior;
                      	
                      //`trace();
                      		
                      	//assign delegate from array. see InitNodeSelectionBehaviors
                      	NodeSelectionBehavior = NodeSelectionBehaviors[idx != -1 ? idx : NodeType];
                      	
                      	//call delegate
                      	NodeSelectionBehavior(0); 
                      } 
                      
                      /** Call NodeSelectionBehaviors Delegate by Index */	
                      function  CheckNode(optional int idx = -1)
                      {
                      	local delegate<OnNodeCheck> NodeCheckBehavior;
                      	
                      //`trace();
                      
                      	//assign delegate from array. see InitNodeSelectionBehaviors
                      	NodeCheckBehavior = NodeCheckBehaviors[idx != -1 ? idx : NodeType];
                      	
                      	//call delegate
                      	NodeCheckBehavior(0); 
                      } 
                      	
                      /** NodeSelectionBehaviors Delegate Functions */
                      function NodeSelectionBehaviorNone(int stub)
                      {
                      `trace();
                      }	
                      
                      /** 
                      This NodeSelectionBehavior activates Nodes one at time 
                      (non-blocking), in numerical order.
                      */
                      function NodeSelectionBehaviorSequence(int stub)
                      {
                      `trace();
                       	
                      	`log(Self.Name@"CurrentValidOutputLinkIdx="$CurrentValidOutputLinkIdx@"OutputLinkIterator="$OutputLinkIterator@"bAllChildNodesActivated="$bAllChildNodesActivated);
                      	
                      	//Active Next Child Node
                      	if(!bAllChildNodesActivated)
                      	{
                      		
                      		//set CurrentValidOutputLinkIdx
                      		CurrentValidOutputLinkIdx = ValidOutputLinksIdx[OutputLinkIterator];
                      		
                      		//Set CurrentValidOutputLink
                      		CurrentOutputLink = OutputLinks[CurrentValidOutputLinkIdx];
                      
                      		//validate OutputLink; if OutputLink connects to child node, activate Child 
                      		`log("Activate ChildNode["$CurrentValidOutputLinkIdx$"]:"@CurrentOutputLink.Links[0].LinkedOp.Name);
                      		ForceActivateOutput(CurrentValidOutputLinkIdx);
                      		
                      		//For_Next: sequential increment
                      		OutputLinkIterator++;	
                      		
                      		//For_Condition
                      		if(OutputLinkIterator == ValidOutputLinksIdx.Length)
                      		{	
                      			bAllChildNodesActivated = TRUE;
                      			`log(Self.Name@"CurrentValidOutputLinkIdx="$CurrentValidOutputLinkIdx@"OutputLinkIterator="$OutputLinkIterator@"bAllChildNodesActivated="$bAllChildNodesActivated);
                      		}
                      	
                      	}
                      	
                      }
                      
                      /** 
                      This NodeSelectionBehavior activates Nodes one at time 
                      (non-blocking), dependent on weight/priority/random.
                      */
                      function NodeSelectionBehaviorSelector(int stub)
                      {	
                      `trace();
                       
                      	`log(Self.Name@"CurrentValidOutputLinkIdx="$CurrentValidOutputLinkIdx@"OutputLinkIterator="$OutputLinkIterator@"bAllChildNodesActivated="$bAllChildNodesActivated);
                      	
                      	//Activate A Child Node
                      	if(!bAllChildNodesActivated)
                      	{
                      		
                      		//set CurrentValidOutputLinkIdx
                      		CurrentValidOutputLinkIdx = ValidOutputLinksIdx[OutputLinkIterator];
                      		
                      		//Set CurrentValidOutputLink
                      		CurrentOutputLink = OutputLinks[CurrentValidOutputLinkIdx];
                      
                      		//validate OutputLink; if OutputLink connects to child node, activate Child 
                      		`log("Activate ChildNode["$CurrentValidOutputLinkIdx$"]:"@CurrentOutputLink.Links[0].LinkedOp.Name);
                      		ForceActivateOutput(CurrentValidOutputLinkIdx);
                      		
                      		//For_Next: sequential increment
                      		OutputLinkIterator++;	
                      		
                      		//For_Condition
                      		if(OutputLinkIterator == ValidOutputLinksIdx.Length)
                      		{	
                      			bAllChildNodesActivated = TRUE;
                      			`log(Self.Name@"CurrentValidOutputLinkIdx="$CurrentValidOutputLinkIdx@"OutputLinkIterator="$OutputLinkIterator@"bAllChildNodesActivated="$bAllChildNodesActivated);
                      
                      		}
                      	
                      	}
                       
                      }
                      
                      /**
                      This NodeSelectionBehavior activates all Nodes simulutaneously
                      */
                      function NodeSelectionBehaviorParallel(int stub)
                      {
                      `trace();
                      	
                      	//Activate All ChildNodes
                      	foreach ValidOutputLinksIdx(CurrentValidOutputLinkIdx)
                      	{
                      		CurrentOutputLink = OutputLinks[CurrentValidOutputLinkIdx];
                      
                      		//validate OutputLink; if OutputLink connects to child node, activate Child 
                      		`log("Activate ChildNode["$CurrentValidOutputLinkIdx$"]:"@CurrentOutputLink.Links[0].LinkedOp.Name);
                      		ForceActivateOutput(CurrentValidOutputLinkIdx);
                      	}
                      	
                      	bAllChildNodesActivated = TRUE;
                      	`log(Self.Name@"CurrentValidOutputLinkIdx="$CurrentValidOutputLinkIdx@"OutputLinkIterator="$OutputLinkIterator@"bAllChildNodesActivated="$bAllChildNodesActivated);
                      	
                      
                      }
                      
                      /** 
                      This NodeSelectionBehavior activates First Node 
                      */
                      function NodeSelectionBehaviorDecorator(int stub)
                      {
                      `trace();
                      
                      	if(!bAllChildNodesActivated)
                      	{
                      		//set CurrentValidOutputLinkIdx
                      		CurrentValidOutputLinkIdx = ValidOutputLinksIdx[0];
                      		
                      		//Set CurrentValidOutputLink
                      		CurrentOutputLink = OutputLinks[CurrentValidOutputLinkIdx];
                      
                      		//validate OutputLink; if OutputLink connects to child node, activate Child 
                      		`log("Activate ChildNode["$CurrentValidOutputLinkIdx$"]:"@CurrentOutputLink.Links[0].LinkedOp.Name);
                      		ForceActivateOutput(CurrentValidOutputLinkIdx);
                      
                      		bAllChildNodesActivated = TRUE;
                      		`log(Self.Name@"CurrentValidOutputLinkIdx="$CurrentValidOutputLinkIdx@"OutputLinkIterator=0 OutputLinkIterator="$OutputLinkIterator@"bAllChildNodesActivated="$bAllChildNodesActivated);
                      	}
                      }	
                      
                      
                      /** NodeCheckBehaviors Delegate Functions */
                      function NodeCheckBehaviorNone(int stub)
                      {
                      `trace();
                      	`log("Bail = SUCCESS");
                      	Result = 1;
                      }	
                      
                      /** 
                      This NodeCheckBehavior checks Current Child Node Task Result
                      (non-blocking), If result = 1 Pass, continue to select next; else Result 0 
                      bails on Failure;
                      */
                      function NodeCheckBehaviorSequence(int stub)
                      {
                      
                      `trace();
                      
                      	`log("Checking ChildNode["$CurrentValidOutputLinkIdx$"]:"@CurrentOutputLink.Links[0].LinkedOp.Name);
                      
                      	if(BrainsPlannerSeqCond_CompositeNode(CurrentOutputLink.Links[0].LinkedOp).Task.Status == Finish)
                      	{
                      		`log("ChildNode["$CurrentValidOutputLinkIdx$"] Finished!");
                      		
                      		if( BrainsPlannerSeqCond_CompositeNode(CurrentOutputLink.Links[0].LinkedOp).Result == 1)
                      		{
                      			if(!bAllChildNodesActivated)
                      			{
                      				`log("ChildNode["$CurrentValidOutputLinkIdx$"] Result = SUCCESS, Proceed to Next ChildNode.");
                      				SelectNode();
                      			}
                      			else
                      			{
                      				`log("Bail = SUCCESS");
                      				Result = 1;
                      			}	
                      		}
                      		else
                      		{
                      			`log("Bail = FAILURE");
                      			Result = 0;
                      		}
                      	}	
                      	
                      }	
                      
                      /** 
                      This NodeCheckBehavior checks Current Child Node Task Result
                      (non-blocking), If result = 0 Fails, continue to select next; else Result 0 
                      bails on Success;
                      */
                      function NodeCheckBehaviorSelector(int stub)
                      {
                      `trace();
                      
                      	`log("Checking ChildNode["$CurrentValidOutputLinkIdx$"]:"@CurrentOutputLink.Links[0].LinkedOp.Name);
                      
                      	if(BrainsPlannerSeqCond_CompositeNode(CurrentOutputLink.Links[0].LinkedOp).Task.Status == Finish)
                      	{
                      		`log("ChildNode["$CurrentValidOutputLinkIdx$"] Finished!");
                      
                      		if( BrainsPlannerSeqCond_CompositeNode(CurrentOutputLink.Links[0].LinkedOp).Result == 0)
                      		{
                      			if(!bAllChildNodesActivated)
                      			{
                      				`log("ChildNode["$CurrentValidOutputLinkIdx$"] Result = FAILURE, Proceed to Next ChildNode.");
                      				SelectNode();
                      			}
                      			else
                      			{
                      				`log("Bail = SUCCESS");	
                      				Result = 1;
                      			}
                      		}
                      		else
                      		{
                      			`log("Bail = FAILURE");	
                      			Result = 0;
                      		}
                      	}	
                      	
                      }	
                      
                      
                      function NodeCheckBehaviorParallel(int stub)
                      {
                      	local int TempResult;
                      	
                      	TempResult = 1;
                      
                      `trace();
                      
                      	foreach ValidOutputLinksIdx(CurrentValidOutputLinkIdx)
                      	{
                      		CurrentOutputLink = OutputLinks[CurrentValidOutputLinkIdx];
                      		
                      		`log("Checking ChildNode["$CurrentValidOutputLinkIdx$"]:"@CurrentOutputLink.Links[0].LinkedOp.Name);
                      
                      		if(BrainsPlannerSeqCond_CompositeNode(CurrentOutputLink.Links[0].LinkedOp).Task.Status == Finish)
                      		{
                      			`log("ChildNode["$CurrentValidOutputLinkIdx$"] Finished");
                      			
                      			/* 1*1=1, (1*0|0*1|0*0)=0, Bitwise And?*/
                      			TempResult *= BrainsPlannerSeqCond_CompositeNode(CurrentOutputLink.Links[0].LinkedOp).Result; 
                      		}	
                      		else
                      		/* if not all Finished, exit function*/
                      		{
                      			`log("All ChildNodes are NOT is Finished. Exiting...");
                      			return;
                      		}	
                      		
                      	}
                      	
                      	`log("All ChildNodes Finished!");
                      	`log("Bail = "$TempResult);	
                      	Result = TempResult;
                      	
                      }	
                      
                      
                      function NodeCheckBehaviorDecorator(int stub)
                      {
                      `trace();
                      	`log("Checking ChildNode["$CurrentValidOutputLinkIdx$"]:"@CurrentOutputLink.Links[0].LinkedOp.Name);
                      
                      	if(BrainsPlannerSeqCond_CompositeNode(CurrentOutputLink.Links[0].LinkedOp).Task.Status == Finish)
                      	{
                      		if( BrainsPlannerSeqCond_CompositeNode(CurrentOutputLink.Links[0].LinkedOp).Result == 1)
                      		{
                      			//if decorator functionality complete then Result = 1
                      			`log("Bail = SUCCESS");
                      			Result = 1;
                      		}
                      		else
                      		{
                      			`log("Bail = FAILURE");
                      			Result = 0;
                      		}
                      	}		 
                      }	
                      
                      
                      defaultproperties
                      {
                      	ObjCategory="B.R.A.I.N.S"
                      	ObjName="B.R.A.I.N.S Composite Node"
                      	ObjColor=(R=255,G=255,B=255,A=255)
                      	NodeType=0
                      	
                      	bLatentExecution=TRUE
                      	bAutoActivateOutputLinks=FALSE
                      	
                      	OutputLinkIterator=0
                      	bAllChildNodesActivated=FALSE
                      	
                      	InputLinks(0)=(LinkDesc="In")
                      	OutputLinks(0)=(LinkDesc="Out0")
                      	VariableLinks(0)=(ExpectedType=class'SeqVar_Object',LinkDesc="Com0",PropertyName=Component0,MinVars=1,MaxVars=1)
                      
                      	Result=-1
                      }
                      BrainsPlannerNodeTask.uc
                      Code:
                      /**
                       * Plugin: b.r.a.i.n.s - behavioral rules artificial intelligence nodes system
                       * Version: 1.0
                       * Name: BrainsPlannerNodeTask
                       * Authors: F.L.Taylor (techlord) 2014
                       * References: http://unrealdb.com/the-hidden-powers-of-kismet-pt-2-custom-nodes/
                       * Purpose: Composite Node State Task and Latent Function Management
                      */
                      
                      class BrainsPlannerNodeTask extends Actor;
                      
                      /** Composite Node XReference */
                      var BrainsPlannerSeqCond_CompositeNode CompositeNode;
                      
                      var bool bErrorTriggered;
                      var int ErrorCode;
                      var string ErrorDescription;
                      
                      /**latency testing*/
                      var int randomsleep;
                      var int fakelatentfunction;
                      
                      var enum ProcessStates
                      {
                      	Inactive,
                      	Start,
                      	Running,
                      	Halt,
                      	Finish,
                      	Deactivate
                      } Status;
                      
                      /** Inactive */	
                      auto state Inactive
                      {
                      Begin:
                      	`log(CompositeNode.Name@"Inactive State");
                      	Status = Inactive;
                      	GotoState( 'Start' );
                      }
                      
                      /** Start Processing*/	
                      state Start
                      {
                      Begin:
                      	`log(CompositeNode.Name@"Start State");
                      	Status = Start;
                      	CompositeNode.SelectNode();
                      	GotoState( 'Running' );
                      }
                      
                      /** Selecting or Waiting For Children to complete process*/	
                      state Running
                      {
                      	
                      	function Tick( float Delta )
                      	{
                      		
                      	//`trace();
                      		`log(CompositeNode.Name@"Checking");	
                      		
                      		super.Tick(Delta);
                      		
                      		CompositeNode.CheckNode();
                      		
                      		if(CompositeNode.Result != -1)
                      		{	
                      			`log(CompositeNode.Name@"Results are in. Change to Finish.");
                      			GotoState( 'Finish' );
                      		}		
                      	}
                      	
                      Begin:
                      	`log(CompositeNode.Name@"Running State");
                      	Status = Running;
                      }
                      
                      /** Pause or Suspend Due To Error*/
                      state Halt
                      {
                      Begin:
                      	`log(CompositeNode.Name@"Halt State "$randomsleep$" seconds");
                      	Status = Halt;
                      	//randomsleep = rand(0); /**test random latency call (sleep)*/
                      	//Sleep(randomsleep);
                      	
                      	if(bErrorTriggered)
                      	{	
                      		//error encountered
                      		GotoState('Finish');
                      	}
                      	else
                      	{	//suspended; return to previous.
                      		PopState();
                      	}	
                      }
                      
                      /** Processing Completed, Calculate Children ReturnStatus Generate TRUE(Success)|FALSE(Fail)*/
                      state Finish
                      {
                      Begin:
                      	`log(CompositeNode.Name@"Finish State");
                      	Status = Finish;
                      	
                      }
                      
                      state Deactivate
                      {
                      Begin:
                      	`log(CompositeNode.Name@"Deactivate State");
                      	Status = Deactivate;
                      
                      }
                      
                      defaultproperties
                      {
                      }
                      Progress: Until now, my exposure to working with Kismet has been little to none, I now find myself breaking down the Kismet Classes to get a firm understanding of its inner workings. What I discovered is that much of the low level engine is exposed to unrealscript via Kismet Sequences, so in many cases a Kismet Function is called even if one is not using the visual editor. So Kismet isn't just a wrapper as previously believed. To get a grasp on inner working, I homed in on the linkage communication between the Sequence Objects. Below is the hierarchy for the four types of Sequence Objects:

                      Object -> SequenceObject -> SequenceOp -> SequencEvent, SequenceAction, SequenceCondition
                      Object -> SequenceObject -> SequenceVariable

                      I narrow my focus on the InputLinks/OutputLinks/VariableLinks member declared in the SequenceOp Class. In the context of Tree Hierarchy: InputLinks are ParentNodes,
                      OutputLinks are ChildNodes.

                      to be continued....

                      PS: I'm open to suggestions on using custom shapes and sprites for Kismet Nodes (circles, squares, diamond, etc).

                      Comment


                      • #12
                        looks very interesting, i will keep on eye on this thread !

                        Comment


                        • #13
                          Thank your for your explanation.

                          I wanted to use Kismet classes in my project, however it turned out that activating them from unrealscript crashed the game.

                          Comment


                          • #14
                            Originally posted by Demestotenes View Post
                            Thank your for your explanation.

                            I wanted to use Kismet classes in my project, however it turned out that activating them from unrealscript crashed the game.
                            Please elaborate on how you're trying to use them and why your trying to activate them from unrealscript. The only issue I have with them is not being able to use state as they are derived from a non-actor classes.

                            Comment


                            • #15

                              [SHOT]https://arcadekomodo.com/home/wp-content/uploads/2014/03/brainsbehaviortreeinkismet1.png[/SHOT]

                              [SHOT]https://arcadekomodo.com/home/wp-content/uploads/2014/03/brainsbehaviortreeinkismet2.png[/SHOT]

                              [SHOT]https://arcadekomodo.com/home/wp-content/uploads/2014/03/brainsbehaviortreeinkismet3.png[/SHOT]

                              [SHOT]https://arcadekomodo.com/home/wp-content/uploads/2014/03/brainsbehaviortreeinkismet41.png[/SHOT]

                              Comment

                              Working...
                              X