• Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
0
Question by danielachy · 5 days ago · 2dmovementstate machineclick to move

What is the best way to implement user input and movement when using a State Machine pattern?

Hello. I am trying to implement a state machine for my player. So far I've implemented two states, 'Move' and 'Idle', but I am planning on expanding it later. The movement system is as follows: when the left MB is pressed, the player's transform is moved towards the mouse position, or something like this:

     Vector3 destination;
     float speed = 1.0f;
     RayCastHit2D hit;
     void UpdateMousePosition()
     {
         if (Input.GetMouseButton(0))
         {
             destination = Camera.main.ScreenToWorldPoint(Input.mousePosition);
             destination.z = 0;
             hit = Physics2D.Raycast(transform.position, (destination - transform.position).normalized);
         }
     }

Then whoever handles the movement logic would call:

 UpdateMousePosition();
 transform.position = Vector3.MoveTowards(transform.position, new Vector3(destination.x, destination.y, 0), speed * Time.deltaTime);

My state machine consists of 5 classes: BaseState; MoveState and IdleState that derive from BaseState, a Factory that generates states, and a StateMachine that handles all the state logic and transitions in its Start() and Update() methods.

Also, there are 3 main methods (EnterState(), ExitState(), InsideState()) where InsideState() is responsible for what happens while the respective state is active. The other two should be self-explanatory. Only the StateMachine class is Monobehaviour.


There are several approaches that I can proceed with from here on, but I am not sure which one to use in terms of good code practices and SOLID.


A) I can create a separate script that handles the movement logic with static methods that I can directly call from the MoveState's InsideState() method. For example:

 public class PlayerMovement
 {
     public static Vector3 mousePos;
     public static void MovePlayer()
     { //movement logic
     }
 }
 
 public class MoveState : BaseState // not MonoBehaviour
 {
     public override void InsideState()
     { 
         PlayerMovement.MovePlayer();
     }
 }

My issue with this is that I am not sure where I should track the cursor's position since it would require an Update method. I could do that from within the StateMachine class:

 public class StateMachine : MonoBehaviour
 {
     PlayerBaseState currentState;
     void Update()
     {
         currentState.InsideState();
         if (Input.GetMouseButton(0))
         {
             PlayerMovement.mousePos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
         }
     }  
 }

but then that would ruin the Single Responsibility principle - should the State Machine be responsible for tracking the mouse at all? Shouldn't it be responsible solely for the states themselves? I watched several tutorials on State Machines and they didn't seem to advise against it.

A.1) I could also do that inside the PlayerMovement script by making it MonoBehaviour but I'm hesitant since I don't want to make my MoveState obsolete. I want to be able to fully utilize the State Machine pattern here.

B) I could omit the PlayerMovement script and add all of the movement logic to the MoveState script while having the StateMachine track if the mouse button is pressed and the cursor's position respectively. This way, MoveState's InsideState() method would only move the player towards the cursor's position, so, like this:

 public class MoveState
 {
     public StateMachine context;
     public override void InsideState()
     { 
         MovePlayer(context.MousePos);
     }
 
     public static void MovePlayer(Vector3 dest)
     { //movement logic
     }
 }
 
 public class StateMachine : MonoBehaviour
 {
     PlayerBaseState currentState;
     public Vector3 MousePos { get; }
     void Update()
     {
         currentState.InsideState();
         if (Input.GetMouseButton(0))
         {
             mousePos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
         }
     }  
 }

C) I could make an even higher abstraction and add a general Player script to my player component that tracks the mouse cursor, or even put it in a GameManager class?

I understand that I could do without a State Machine but my goal is to learn how to use this pattern correctly and to also apply it in future projects, while also making my current project open to extension, so I would appreciate any feedback to my question.

Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

1 Reply

· Add your reply
  • Sort: 
avatar image
0

Answer by danielachy · 2 days ago

Update


The question is still valid.

I decided to put the mouse's logic in a separate script. This way we can get the clicked mouse's position from anywhere using a static method. This will also be useful for when I create different mouse actions other than movement (click on enemy, click on chest, etc). I still have the dilemma though. I made a script entirely for assigning the target position where the player needs to go to the cursor position. Everything from the question's movement logic is there except for Vector3.MoveTowards(...). My dilemma is exactly this - does my state machine use the MoveTowards() method for when the state is set to 'Move' or should I instead change a global boolean via the MoveState's method, that enables the Movement script to move the player?

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

347 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Player moves to the middle of the room when the level starts (2d point and click) 2 Answers

2D Directional top down movement,Topdown 2d Directional Movement 0 Answers

2D Topdown movement without sliding 2 Answers

Help setting maxAceleration 0 Answers

Rolling Barrels through Platforms 0 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges