[PloobsEngine] Tutorial 10 – Finite State Machine


This tutorial will show how to use  the ploobsengine build in finite state machine. (the complet list of tutorials can be found here) The code for this sample is NOT included in the advanced demos package avaliable for download (but you can easily copy and past from this post).

Finite State Machine (FSM) is a very classic (and simple) AI technique used in almost all kinds of games, for a good explanation visit this site.

In this tutorial, we are assuming that you know what FSM is.

In Ploobs, the only thing you need to do is to extend the IState class. It has some simple methods that will be automatically called by the FSM control object. The important ones are the UpdateState() used to update the state and the NextState() used to make the states transitions .

The following piece of code shows a generic state (made specially for this sample). It will only delegate its responsabilities to other methods using lambda expression:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PloobsEngine.IA;
using PloobsEngine.SceneControl;
using Microsoft.Xna.Framework;

namespace EngineTestes.AI.FSM
{
    class StateSample : IState
    {
        public StateSample(String Name,IObject Object)
        {
            this.Object = Object;
            this.name = Name;
        }

        IObject Object;
        #region IState Members

        public Func NextStateFunc;
        public Action InitFunc;
        public Action FinishFunc;
        public Action UpdateFunc;

        public void Init()
        {
            if (InitFunc != null)
                InitFunc(Object);
        }

        public string NextState()
        {
            if (NextStateFunc != null)
                return NextStateFunc(Object);
            return null;
        }

        public void UpdateState(Microsoft.Xna.Framework.GameTime gameTime)
        {
            if (UpdateFunc != null)
                UpdateFunc(gameTime, Object);
        }

        public void Finish()
        {
            if (FinishFunc != null)
                FinishFunc(Object);
        }

        #endregion

        #region IState Members

        String name;
        public string Name
        {
            get { return name; }
        }

        #endregion
    }
}

We are just overriding some functions functions that are self explanatory.

The special one is the NextState, it is called all frames after the UpdateState and is responsible for return the next state of the FSM, if it returns something different from null, the FSM will change its state according with the state name returned and will call the Finish methof of the current state and the Init of the next state.

The following code shows the PloobsScene that will use the FSM. Look at the state definitions and the FSM initialization code.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PloobsEngine.SceneControl;
using PloobsEngine.Physics;
using PloobsEngine.Modelo;
using PloobsEngine.Material;
using PloobsEngine.Engine;
using PloobsEngine.Physics.Bepu;
using Microsoft.Xna.Framework;
using PloobsEngine.Cameras;
using EngineTestes.AI.FSM;
using PloobsEngine.IA;
using Microsoft.Xna.Framework.Input;

namespace ProjectTemplate
{
    public class FSMScreen : IScene
    {
        StateMachine fsm;
        ///
        /// Sets the world and render technich. ///
        ///The render tech.
        ///The world.
        protected override void SetWorldAndRenderTechnich(out IRenderTechnic renderTech, out IWorld world)
        {
            ///create the IWorld
            world = new IWorld(new BepuPhysicWorld(-0.97f, true, 1), new SimpleCuller());

            ///Create the deferred technich
            ForwardRenderTecnichDescription desc = new ForwardRenderTecnichDescription();
            renderTech = new ForwardRenderTecnich(desc);
        }

        protected override void LoadContent(GraphicInfo GraphicInfo, GraphicFactory factory, IContentManager contentManager)
        {
            base.LoadContent(GraphicInfo, factory, contentManager);

            {
                SimpleModel simpleModel = new SimpleModel(factory, "Model//block");
                simpleModel.SetTexture(factory.CreateTexture2DColor(1, 1, Color.White), TextureType.DIFFUSE);
                ///Physic info (position, rotation and scale are set here)
                BoxObject tmesh = new BoxObject(Vector3.Zero, 1, 1, 1, 10, new Vector3(1000, 1, 1000), Matrix.Identity, MaterialDescription.DefaultBepuMaterial());
                tmesh.isMotionLess = true;
                ///Forward Shader (look at this shader construction for more info)
                ForwardXNABasicShader shader = new ForwardXNABasicShader();
                ///Deferred material
                ForwardMaterial fmaterial = new ForwardMaterial(shader);
                ///The object itself
                IObject obj = new IObject(fmaterial, simpleModel, tmesh);
                ///Add to the world
                this.World.AddObject(obj);

                ///create the FSM
                fsm = new StateMachine();
                ///atach the fsm to the object using the attachment property (there are lots of ways of doing this, like extending the iobject class)
                AttachmentUpdate atachment = new AttachmentUpdate(
                    (a, b) => fsm.UpdateFSM(b)
                        );
                obj.IObjectAttachment.Add(atachment);

                ////Simple State example
                ///Press Space to go to state2 and press enter in state 2 to get back to state1 =P
                {
                    StateSample state1 = new StateSample("state1",obj);
                    state1.NextStateFunc =
                      (a) =>
                      {
                          KeyboardState kstate = Keyboard.GetState();
                          if (kstate.IsKeyDown(Keys.Space))
                          {
                              return "state2";
                          }
                          return null;
                      };
                    fsm.AddState(state1);

                    ///SET THE CURRENT STATE
                    fsm.SetCurrentState(state1.Name);
                }

                ///create state 2 (similar)
                {
                    StateSample state2 = new StateSample("state2",obj);
                    state2.NextStateFunc =
                      (a) =>
                      {
                          KeyboardState kstate = Keyboard.GetState();
                          if (kstate.IsKeyDown(Keys.Enter))
                          {
                              return "state1";
                          }
                          return null;
                      };
                    fsm.AddState(state2);
                }
            }

            ///add a camera
            this.World.CameraManager.AddCamera(new CameraFirstPerson(GraphicInfo.Viewport));
        }

        /// This is called when the screen should draw itself. ///
        protected override void Draw(GameTime gameTime, RenderHelper render)
        {
            base.Draw(gameTime, render);

            ///Draw some text on the screen
            render.RenderTextComplete("Demo: FSM sample", new Vector2(GraphicInfo.Viewport.Width - 315, 15), Color.White, Matrix.Identity);
            ////current state info
            render.RenderTextComplete("Current State: " + fsm.GetCurrentState().Name, new Vector2(GraphicInfo.Viewport.Width - 315, 35), Color.White, Matrix.Identity);
        }

    }
}

We just create the FSM object, attached it to an IObject using a AttachmentUpdate (so the update method of the FSM will be called, see the previous tutorials), then create some states (the behavior of them were defined using the lambda expressions).

We always need to tell the FSM the first state. (setCurrentState call)

You can use the FSM anywhere you want (in menus, in objects …) you just need to call its update all the frames.

The class AttachmentUpdate extends the IObjectAttachment. It has its update method called all the frames. It is a ploobs facility to help us binding a custom behavior to an IObject without needing to extend it.

This is all for today, the next tutorial will talk about the PloobsEngine PathFinding utilities.

, , ,

  1. #1 by Kristy on 19 de agosto de 2017 - 5:09 pm

    This is essential in case you discover out that the diamond you have been offered
    is just not what they mentioned that it was.

  2. #2 by live tv on 19 de agosto de 2017 - 5:26 pm

    Very interesting topic, regards for posting.

  3. #3 by free foundation paper piecing patterns on 19 de agosto de 2017 - 5:33 pm

    Magnificent beat ! I would like to apprentice while you amend your web site, how can i subscribe for a blog web site?

    The account aided me a acceptable deal. I had been tiny bit acquainted of this your broadcast
    provided bright clear idea

  4. #4 by http://dagligdagen.dk on 19 de agosto de 2017 - 5:35 pm

    I have been exploring for a little bit for any high-quality articles or blog posts in this sort of area . Exploring in Yahoo I eventually stumbled upon this site. Studying this information So i?¦m glad to convey that I’ve an incredibly good uncanny feeling I found out just what I needed. I so much no doubt will make certain to do not put out of your mind this web site and provides it a glance on a continuing basis.

  5. #5 by watch tv on 19 de agosto de 2017 - 5:37 pm

    I’m not that much of a internet reader to be honest but your blogs really nice, keep it up! I’ll go ahead and bookmark your website to come back in the future. Cheers

  6. #6 by Delmar on 19 de agosto de 2017 - 5:47 pm

    In conclusion, building rapport seems to be a misplaced artwork for
    a lot of gross sales individuals. For this reason most people (your self included)
    hate getting calls from gross sales reps.

  7. #7 by Sergio Rossi outlet on 19 de agosto de 2017 - 5:55 pm

    When will online casino triumph? Can the computerized meat purge near test? The logical grandmother appears. Test conforms across online casino. The overhead fringes online casino.
    Sergio Rossi outlet http://www.sergiorossioutlet.online

  8. #8 by eyelash extensions on 19 de agosto de 2017 - 6:03 pm

    “I recently came across your blog and have been reading along. I thought I would leave my first comment. I don�t know what to say except that I have enjoyed reading.”

  9. #9 by yeezy 350 boost on 19 de agosto de 2017 - 6:30 pm

  10. #10 by line tv on 19 de agosto de 2017 - 6:51 pm

    Great amazing issues here. I am very satisfied to peer your post. Thanks a lot and i am looking forward to contact you. Will you please drop me a e-mail?

  11. #11 by garage door remotes on 19 de agosto de 2017 - 7:29 pm

    please stop by the websites we adhere to, including this one, as it represents our picks from the web

  12. #12 by cheap christian louboutin heels on 19 de agosto de 2017 - 7:51 pm

  13. #13 by barcode scanner on 19 de agosto de 2017 - 8:06 pm

    I am regular reader, how are you everybody?
    This post posted at this website is truly pleasant.

  14. #14 by michael kors bags on 19 de agosto de 2017 - 8:39 pm

  15. #15 by barbour for sale on 19 de agosto de 2017 - 8:40 pm

    That was intriguing . I love your quality that you put into your work. Please do move forward with more like this.
    barbour for sale http://www.barboursale.online

  16. #16 by garage door opener on 19 de agosto de 2017 - 9:11 pm

    Here is an excellent Weblog You may Come across Intriguing that we Encourage You

1 565 566 567
(não será publicado)