0
\$\begingroup\$

I am doing a school assignment based off of the Unity3D tutorial 2D RogueLike (all code available here)

In my version though, the movement is not turnbased and I am having some trouble figuring it out.

If I I make the player lose its turn after movement, the character will stay perfectly aligned with the grid. But if I let the player keep his turn, the character moves in increments not in alignment with anything(ór how long the computer think I held down the movebutton for).

I tried to fix it with this:

    GameManager.instance.playersTurn = false;

    Thread.Sleep(500);

    GameManager.instance.playersTurn = true;

and it sort of 'fixes' it. It now only moves 1 unit, provided I don't hold down the movebutton for longer than the 500ms, hereafter it seems to 'lose sync' with the board again... Also, it now takes 500ms from i press move, till the character actually moves.

Here is an example of how it looks if i just quickly tap the button to move(so its in sync) enter image description here

and here is one when i held down the button for more than the 500ms ( out of sync) enter image description here

So the specific question.

How do I make sure that the character only moves 1 tile/unit with a single button press?

I would greatly appreciate a solution to this

\$\endgroup\$
1
\$\begingroup\$

Disclaimer: Coded in 3D, converted to 2D

You could use IEnumerator. Like this:

public const float stepDuration = 0.5f;
private Coroutine playerMovement;

private void Update()
{
    if (playerMovement == null)
    {
        if (Input.GetKey(KeyCode.W))        //In general not a good idea to use Input.GetKey; use Input.GetButton instead
            playerMovement = StartCoroutine(Move(Vector2.up));
        else if (Input.GetKey(KeyCode.S))
            playerMovement = StartCoroutine(Move(Vector2.down));
        else if (Input.GetKey(KeyCode.D))
            playerMovement = StartCoroutine(Move(Vector2.right));
        else if (Input.GetKey(KeyCode.A))
            playerMovement = StartCoroutine(Move(Vector2.left));
    }
}

private IEnumerator Move(Vector2 direction)
{
    Vector2 startPosition = transform.position;
    Vector2 destinationPosition = transform.position + direction;
    float t = 0.0f;

    while (t < 1.0f)
    {
        transform.position = Vector2.Lerp(startPosition, destinationPosition, t);
        t += Time.deltaTime / stepDuration;
        yield return new WaitForEndOfFrame();
    }

    transform.position = destinationPosition;

    playerMovement = null;
}

If you have boundaries you should fire a Linecast before moving. Something similar to this:

private IEnumerator Move(Vector2 direction)
{
    Vector2 startPosition = transform.position;
    Vector2 destinationPosition = transform.position + direction;
    float t = 0.0f;

    if (!Physics2D.Linecast(startPosition, destinationPosition))
    {
        while (t < 1.0f)
        {
            transform.position = Vector2.Lerp(startPosition, destinationPosition, t);
            t += Time.deltaTime / stepDuration;
            yield return new WaitForEndOfFrame();
        }

        transform.position = destinationPosition;
    }

    playerMovement = null;
}

If you don't want the player to float in the air (e.g. if there isn't a sprite on that position) simply fire a Linecast / Raycast to the ground. (in 3D)

private IEnumerator Move(Vector3 direction)
{
    Vector3 startPosition = transform.position;
    Vector3 destinationPosition = transform.position + direction;
    float t = 0.0f;

    if (!Physics.Linecast(startPosition, destinationPosition) && Physics.Linecast(destinationPosition, destinationPosition + Vector3.down * 3.0f))
    {
        while (t < 1.0f)
        {
            transform.position = Vector3.Lerp(startPosition, destinationPosition, t);
            t += Time.deltaTime / stepDuration;
            yield return new WaitForEndOfFrame();
        }

        transform.position = destinationPosition;
    }

    playerMovement = null;
}
\$\endgroup\$
  • 1
    \$\begingroup\$ totally forgot about this question and and fixed it on my own days later. I am sorry, I appreciate your effort and accept your answer. Good day to you sir \$\endgroup\$ – Matt Baech Apr 15 '16 at 6:49
0
\$\begingroup\$

I found a similar question on the unity forum a while ago, this may be useful since you are not limiting how many times your character can move(it is not turn based therefore the controller you are using will no longer be waiting for an opponent to move it will behave oddly because when moving it will be called again and again without waiting and will cause this offset) so instead try the script on this site and set the increment according to your project. http://answers.unity3d.com/questions/819654/problem-achieving-grid-based-movement-with-c.html

\$\endgroup\$
  • \$\begingroup\$ I suggest you convert the meat of the answer you link to be an answer here (instead of just linking). \$\endgroup\$ – MichaelHouse Dec 15 '15 at 23:39
  • \$\begingroup\$ Yeah, I would have inserted code, however when I wrote this comment I was a bit pressed for time if I remember correctly. But yes, you are absolutely right... it is much better to convert the code to answer the question directly. \$\endgroup\$ – Joseph Cooper Dec 17 '15 at 16:07
0
\$\begingroup\$

one good way of doing it, is creating a new gameObject where you want the anchor to be, and every frame checking if the player is farther than 1 unit from the anchor. When you want the anchor to stop it's effect, just create a script constantly moving the anchor to the player.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.