Announcement

Collapse
No announcement yet.

Trasnlating State machine from lesson/book into Unreal Engine workflow

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

  • replied
    just a tiny bump just incase this was missed or something. really curious as to how this might be handled with unreal. still working on my own iteration.

    Leave a comment:


  • Trasnlating State machine from lesson/book into Unreal Engine workflow

    Hello my C++ peoples,

    I wanted to ask for some help with putting this lesson I'm reading from an online book called http://gameprogrammingpatterns.com/ into the Unreal engine c++ workflow.

    I'm currently on the section of state machines or states and I'm trying to translate it into c++ for the unreal engine now that I'm done with the chapter.

    http://gameprogrammingpatterns.com/state.html

    I already translated the first fsm they built as an examlpe with state and input.

    Code:
    void Heroine::handleInput(Input input)
    {
      switch (state_)
      {
        case STATE_STANDING:
          if (input == PRESS_B)
          {
            state_ = STATE_JUMPING;
            yVelocity_ = JUMP_VELOCITY;
            setGraphics(IMAGE_JUMP);
          }
          else if (input == PRESS_DOWN)
          {
            state_ = STATE_DUCKING;
            setGraphics(IMAGE_DUCK);
          }
          break;
    
        case STATE_JUMPING:
          if (input == PRESS_DOWN)
          {
            state_ = STATE_DIVING;
            setGraphics(IMAGE_DIVE);
          }
          break;
    
        case STATE_DUCKING:
          if (input == RELEASE_DOWN)
          {
            state_ = STATE_STANDING;
            setGraphics(IMAGE_STAND);
          }
          break;
      }
    }

    Now I'm working on the next section in where the book applies pattern design with a great amount of object oriented practice. Creating an interface class that gets turned into states and those states then called into the main "heroine" class.

    Code:
    class HeroineState
    {
    public:
      virtual ~HeroineState() {}
      virtual void handleInput(Heroine& heroine, Input input) {}
      virtual void update(Heroine& heroine) {}
    };
    Code:
    class DuckingState : public HeroineState
    {
    public:
      DuckingState()
      : chargeTime_(0)
      {}
    
      virtual void handleInput(Heroine& heroine, Input input) {
        if (input == RELEASE_DOWN)
        {
          // Change to standing state...
          heroine.setGraphics(IMAGE_STAND);
        }
      }
    
      virtual void update(Heroine& heroine) {
        chargeTime_++;
        if (chargeTime_ > MAX_CHARGE)
        {
          heroine.superBomb();
        }
      }
    
    private:
      int chargeTime_;
    };
    Code:
    class Heroine
    {
    public:
      virtual void handleInput(Input input)
      {
        state_->handleInput(*this, input);
      }
    
      virtual void update()
      {
        state_->update(*this);
      }
    
      // Other methods...
    private:
      HeroineState* state_;
    };
    I'm sort've confused because in unreal right now for me to do this, I'd have to create circular logic/inheritance where both classes know about each other and I was wondering if there's a better workflow where I can practice the object oriented mindset and keep these classes well separated and encapsulated.

    I'm a fairly poor coder who's trying to improve his understanding of the coding world so any all advice is helpful but please remember to try and explain it to me as though it's the first time I'm hearing about it (is all I ask.)

    What I currently have so far is:

    A controller input atom header file :
    Code:
    /*
    * Mainly for our input handler to switch our state based on what is currently being pressed.
    * We shall see how well the FSM works off tick.
    */
    
    UENUM()
    enum class Input : uint8
    {
    	PRESS_Up,
    	PRESS_Down,
    	PRESS_Left,
    	PRESS_Right,
    	PRESS_LeftButton,
    	PRESS_TopButton,
    	rejectInput
    };
    
    
    /*
    *	For our special attack only, we want to check to see if the button is being held or released in this example, held will create a more powerful jump when released.
    *	Release will jump.
    */
    UENUM()
    enum class ButtonState : uint8
    {
    	Pressed,
    	Held,
    	Released
    };
    
    /*
    * Which directional states are we traveling in
    *
    */
    UENUM()
    enum class DirectionButtonState : uint8
    {
    	Up,
    	Down,
    	Left,
    	Right
    };
    
    class JUMP_API ControllerInputAtoms
    {
    public:
    	//ControllerInputAtoms();
    	//~ControllerInputAtoms();
    };
    A Character state header file which inherits from that input atoms header file:
    Code:
    #include "ControllerInputAtoms.h"
    #include "PaperCharacter.h"
    #include "CharacterStates.generated.h"
    
    /**
     * Base character states that we will dervie into actual states for our jump man.
     */
    UCLASS()
    class JUMP_API UCharacterStates : public UObject
    {
    	GENERATED_BODY()
    
    public:
    	//virtual ~CharacterStates() {}
    	virtual void handleInput(APaperCharacter& characterRef, Input input) {}
    	virtual void update(APaperCharacter& characterRef) {}
    };
    A jumping state derived from that:

    Code:
    #include "CharacterStates.h"
    #include "Jumping.generated.h"
    
    
    class AJumpCharacter;
    /**
     * 
     */
    UCLASS()
    class JUMP_API UJumping : public UCharacterStates
    {
    	GENERATED_BODY()
    	
    
    
    	//UJumping(); //base constructor
    
    	//UJumping(int maxCharge)
    	//: chargeTime_(0), MAX_CHARGE(maxCharge)
    	//{}
    
    public:
    	virtual void handleInput(APaperCharacter& characterRef, Input input)
    	{
    		if (input == Input::PRESS_LeftButton)
    		{
    			characterRef.GetCharacterMovement()->AddForce(FVector(0.0, 0.0, 5000000));
    		}
    	}
    
    	virtual void update(APaperCharacter& characterRef)
    	{
    		AJumpCharacter* player = Cast<AJumpCharacter*>(characterRef);
    		chargeTime_++;
    		if (chargeTime_ > MAX_CHARGE)
    		{
    			player.doSomething();
    		}
    	}
    
    
    
    	
    };
    : note that this code doesn't work since I cannot cast APaperCharacter to AJumpCharacter without providing the header file from AJumpCharacter (where the circular inheritance thing starts.)

    and then my AJumpCharacter which has been emptied out at the moment so it only has a tick and begin play and normal constructor (base boiler plate APaperCharacter made by unreal.)

    Any and all advice is appreciated! thank you for taking the time to read this
Working...
X