What is the best way to solve two functions doing the same thing but moving different directions?

C# rookie here. Familiar with some coding basics, and it feels like something should exist to help fix this, but I’m not sure what.

I have a function that I use to move a square cursor around a square grid (modelPosition):

        public Vector2 pressAndHoldMoveUp(Vector2 MODELPOSITION)
        {
            Vector2 modelPosition = MODELPOSITION;
            float counterHoldLimit = 0.5f;
            //float keyCooldown = 0f;

            if (IsPressed(Keys.W))
            {

                //KEY Behaviour: move just once, when first pressed
                if (JustPressed(Keys.W))
                {
                    modelPosition = MoveUp(modelPosition);
                    keyCooldown = 0f;
                }
                //KEY Behaviour: If it wasn't first pressed, we need to wait--add the elapsed game time since last update call.
                else
                {
                    //keyCooldown = 0;
                    keyCooldown += Globals.Time;
                }
                //KEY Behaviour: if we've waited long enough (passed the counterHoldLimit), it will move the position once, and then reset keyCooldown to 1/3.5th the counterHoldLimit
                if (keyCooldown > counterHoldLimit)
                {
                    modelPosition = MoveUp(MODELPOSITION);
                    keyCooldown = keyCooldown - (counterHoldLimit / 3.5f);
                }
            }
            return modelPosition;
        }
        public Vector2 pressAndHoldMoveDown(Vector2 MODELPOSITION)
        {
            Vector2 modelPosition = MODELPOSITION;
            float counterHoldLimit = 0.5f;
            //float keyCooldown = 0f;

            if (IsPressed(Keys.S))
            {

                //KEY Behaviour: move just once, when first pressed
                if (JustPressed(Keys.S))
                {
                    modelPosition = MoveDown(modelPosition);
                    keyCooldown = 0f;
                }
                //KEY Behaviour: If it wasn't first pressed, we need to wait--add the elapsed game time since last update call.
                else
                {
                    //keyCooldown = 0;
                    keyCooldown += Globals.Time;
                }
                //KEY Behaviour: if we've waited long enough (passed the counterHoldLimit), it will move the position once, and then reset keyCooldown to 1/3.5th the counterHoldLimit
                if (keyCooldown > counterHoldLimit)
                {
                    modelPosition = MoveDown(MODELPOSITION);
                    keyCooldown = keyCooldown - (counterHoldLimit / 3.5f);
                }
            }
            return modelPosition;
        }

The only difference is that one uses the W key to move up while the other uses the S key to move down. It feels like there should be a way to simplify to use only one function where I pass in the direction (up/down) and the respective key. However, I’m not sure how I could pass in a function and key.

Any ideas? Thanks for help.

Multiple ways exist to archive this. The easiest would be the following.

Public Vector2 pressAndHoldMove(Vector2 position, Action<Vector2> moveAction, Keys key)

Now you have to replace all Keys.W with key and Move up method calls with moveAction.

You call the method like so

pressAndHoldMove(position, MoveUp, Keys.W);
pressAndHoldMove(position, MoveDown, Keys.S);
...

I personally would actually replace the Action with an Interface that provides a move Method.

Alternatively you could create a move method that is called by an event if any of the move keys are pressed/released to separate the input handling from the actual implementation. IMHO key bindings should never be related directly to the action in the game otherwise rebinding the keys will be a pain.

Note: wrote on the smartphone. Therefore, the code provided might not compile and contain typos:)

Thanks Crone.

In your first approach, is the Actual a native thing (method, class? tried to google but didnt find) in monogame? If not it sounds like I can just pass in a function that I create as an arg? (sounds pretty nice)

I personally would actually replace the Action with an Interface that provides a move Actual Method.

I’m assuming “interface” and “actual method” are not official terms in monogame and I’d need to create something to do that.

Action is a native part of c#. Yes it’s used to pass a method as an argument. If the method has a return type other then void you have to use Func instead of Action.

“Actual” was just a typo sorry for the confusion :).

With an interface that provides a move method I meant something like this:

public class Entity : IMoveable
{
    private Vector2 modelPosition;

    public void Move(Vector2 moveDirection)
    {
          //Example move up/down/left/right
          modelPosition=modelPosition+ moveVector;
    }
}

public interface IMoveable
{
     void Move(Vector2 moveDirection);
}

You could use the code like that:

IMovable entity = new Entity();
pressAndHoldMove(entity, Vector2.Up, Keys.W);
pressAndHoldMove(entity, Vector2.Down, Keys.S);

The pressAndHoldMove method would call
entity.Move(directionVector) when the given key was pressed with the direction vector as an argument.

The Move method of the entity would be a generic solution to move in all directions that could be reusable for everything that needs to move in your game.

1 Like

Just got all the bits written out and connected. Works great–thx!

1 Like