Ejemplo n.º 1
0
        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            base.LoadContent();

            _state = new ExampleState(GameModel);
            _state.LoadContent();
        }
Ejemplo n.º 2
0
    public void Start()
    {
        // You need to pass the "netstandard" assembly reference when in Unity.
        // This is not necessary on a standalone .NET Core 2.2 console program.
        // You can also pass more references and namespace usings for the C# snippets if needed.
        var netstandard = AppDomain.CurrentDomain.GetAssemblies().First(n => n.GetName().Name == "netstandard").Location;
        var config      = new YggParserConfig();

        config.ReferenceAssemblyPaths.Add(netstandard);

        // You choose which currently loaded assemblies are searched for types deriving from the Node class.
        config.NodeTypeAssemblies.Add(typeof(Node).Assembly.GetName().Name);
        config.NodeTypeAssemblies.Add(typeof(ExampleCustomAction).Assembly.GetName().Name);

        // Create the compiler and parser. They can be reused for multiple parsings.
        // The only state maintained by a parser instance is the initial config passed on its constructor.
        var compiler = new YggCompiler();
        var parser   = new YggParser(config, compiler);

        // The parser gives back a behaviour tree definition, which can be used to instantiate the tree multiple times (or any node within by its GUID).
        // The definition also keeps track of errors that might have happened during parsing, and other debug information.
        // Node GUIDs can be assigned manually on the script files themselves. If they don't have one, the parser assigns a random one. They must be unique
        // withing the context of all the files parsed. The same goes for 'TypeDefs'. You can reference TypeDefs between files.
        var scriptFilePath = Path.Combine(Application.streamingAssetsPath, "exampleScript.ygg");
        var definition     = parser.BuildFromFiles <ExampleState>(scriptFilePath);

        // The errors often have useful information to debug them. In this example there should be none.
        if (definition.Errors.Count > 0)
        {
            throw new Exception("Errors while parsing script files.");
        }

        // You can instantiate any node defined on the parsed scripts by passing their GUID.
        // This creates an instance of that node and all its descendants.
        // This also calls Initialize() on the instantiated nodes (in a depth-first traversal, if that matters to you).
        // The script files themselves have no explicit root, so you must instantiate the tree using the desired root node's GUID.
        var root = definition.Instantiate("root");

        // The behaviour tree object serves as a manager that handles the node's execution and async continuations.
        // The behaviour tree is what keeps the "continuation state" of the tree. This means you can reuse a single "root" node instance
        // on multiple behaviour trees that get updated separately without issues. This is only valid for the node types that Yggdrasil comes
        // with by default. If you create new node types inheriting from the Node class, you must make sure they don't keep any state themselves.
        _tree = new BehaviourTree(root);

        // Some example state object passed to the tree's nodes. Kept as a field here to allocate it only once.
        _state = new ExampleState();

        // You can pre-pool some coroutines. Otherwise, the first run of the tree will allocate as necessary.
        // They get recycled automatically. The amount of coroutines needed depends on how deep an async Coroutine method stack call can get during execution.
        // Unless the nodes use multiple nested async Coroutine methods, this means only one Coroutine<Result> per node on the deepest possible branch of the tree.
        // Parallel and Interrupt nodes can complicate the math, since they create multiple simultaneously active branches.
        // Pre-pooling yourself like this is optional. It'll create as necessary during execution.
        Yggdrasil.Coroutines.Coroutine.Pool.PrePool(20);
        Yggdrasil.Coroutines.Coroutine <Result> .Pool.PrePool(20);
    }
Ejemplo n.º 3
0
            protected override void OnRecover(object message)
            {
                switch (message)
                {
                case Evt evt:
                    UpdateState(evt);
                    break;

                case SnapshotOffer snapshot when snapshot.Snapshot is ExampleState:
                    _state = (ExampleState)snapshot.Snapshot;
                    break;
                }
            }
Ejemplo n.º 4
0
 private void UpdateState(Evt evt)
 {
     _state = _state.Updated(evt);
 }
    //##############################################################################################
    // If we ever encounter the player, shoot at them. Otherwise, patrol from A to B, wait, then
    // patrol back.
    //##############################################################################################
    public override void EnemyUpdate()
    {
        base.EnemyUpdate();

        float playerDistance = (transform.position - FirstPersonPlayerComponent.player.transform.position).magnitude;

        // any detection of the player during the patrol stops and shoot
        if (exampleState != ExampleState.Shooting && playerDistance < SHOOT_RADIUS)
        {
            exampleState = ExampleState.Shooting;
            StopMoving();
            rotation.SetAnimationIndex(SHOOT_ANIMATION_INDEX);
        }

        // Pretty simple finite state machine
        if (exampleState == ExampleState.Idle)
        {
            if (patrolIdleTimer.Finished())
            {
                exampleState = ExampleState.Patrolling;
                MoveToPosition(patrollingAToB ? patrolPointB.position : patrolPointA.position);
                rotation.SetAnimationIndex(WALK_ANIMATION_INDEX);
                patrollingAToB = !patrollingAToB;
            }
        }
        else if (exampleState == ExampleState.Patrolling)
        {
            if (AtGoal())
            {
                patrolIdleTimer.Start();
                exampleState = ExampleState.Idle;
                rotation.SetAnimationIndex(IDLE_ANIMATION_INDEX);
            }
        }
        else if (exampleState == ExampleState.Shooting)
        {
            if (playerDistance > SHOOT_RADIUS)
            {
                exampleState = ExampleState.Idle;
                patrolIdleTimer.Start();
            }

            bool hasShootToken = AttackTokenComponent.RequestToken(gameObject);

            if (shootTimer.Finished() && hasShootToken)
            {
                Vector3 toPlayer = FirstPersonPlayerComponent.player.transform.position - transform.position;
                toPlayer.y         = 0.0f;
                transform.rotation = Quaternion.LookRotation(toPlayer);

                gun.Shoot();
                shootTimer.Start();
                rotation.SetAnimationIndex(IDLE_ANIMATION_INDEX);
            }
        }

        // Make sure to re-register for next frames update if we're still near enough!
        if (playerDistance < UDPATE_RADIUS)
        {
            EnemyManagerComponent.RegisterUpdate(this);
        }
    }
Ejemplo n.º 6
0
 // Start is called before the first frame update
 void Start()
 {
     exampleState  = new ExampleState(this);
     exampleState2 = new ExampleState2(this);
     Initialize(exampleState);
 }
Ejemplo n.º 7
0
 public void SetState(ExampleState state)
 {
     State = state;
 }