Home > Net >  Player's movement in turn based system is bugged in unity, how can I fixe it?
Player's movement in turn based system is bugged in unity, how can I fixe it?

Time:12-22

I am doing a roguelike game with turn based system in unity, the movement is more like chess, that you move from one place in the grid to another. Is more like moving between vectors then the grid itself.

I did the player's movement and enemy's movement and they are working just fine if i separatedly click the w, a, s, d keys. But when I try to hold it, the player still moves fine, but the enemy move more spaces then the player and it also dont move from grid to grid, but also stays most of the times between grids, more like if you are playing chess and you put the queen half of it in one space and half of it in another.

I know the problem is that it has something to do with the Update() function, that happens only if i hold one of the movement keys, the PlayerScript and EnemyScript codes are all correct. The 3 following codes are from the GameManager, PlayerScript and EnemyScript, the first take care of the turns, the second takes care of the player movement and the third the enemy movement. Thanks in advance for the help :)

`

public class GameManager : MonoBehaviour
{
    public static BoardManager boardScript;
    private int PLAYER_TURN = 1;
    private int ENEMY_TURN = 2;
    private int game_state;
    public GameObject player;
    public GameObject enemy;
    public List<GameObject> enemies;
    
    void Awake()
    {
        int[,] map = new int[0,0];
        boardScript = GetComponent<BoardManager>();
        boardScript.makeMap(map, ref player, ref enemies, enemy);
        game_state = PLAYER_TURN;
    }

    public void Update()
    {
        if(Input.anyKey)
        {
            Debug.Log("oi");
            char c = Input.inputString[0];
            player.GetComponent<PlayerScript>().movement(c);
            game_state = ENEMY_TURN;
        }

        if(game_state == ENEMY_TURN)
        {
            for (int i = 0; i < enemies.Count; i  )
            {
                enemies[i].GetComponent<EnemyScript>().movement();
            }
            game_state = PLAYER_TURN;
        }
    }
}

`

`

public class PlayerScript : MonoBehaviour
{
    private bool isMoving;
    private Vector3 origPos, targetPos;
    private float timeToMove = 0.2f;

    public void movement(char c)
    {
        if (c == 'w' && !isMoving)
            StartCoroutine(movePlayer(Vector3.up));

        if (c == 'a' && !isMoving)
            StartCoroutine(movePlayer(Vector3.left));

        if (c == 's' && !isMoving)
            StartCoroutine(movePlayer(Vector3.down));

        if (c == 'd' && !isMoving)
            StartCoroutine(movePlayer(Vector3.right));

        if (c == 'q' && !isMoving)
            StartCoroutine(movePlayer(new Vector3(-1, 1, 0)));

        if (c == 'e' && !isMoving)
            StartCoroutine(movePlayer(new Vector3(1, 1, 0)));

        if (Input.GetKey(KeyCode.C) && !isMoving)
            StartCoroutine(movePlayer(new Vector3(1, -1, 0)));

        if (Input.GetKey(KeyCode.Z) && !isMoving)
            StartCoroutine(movePlayer(new Vector3(-1, -1, 0)));
    }

    private IEnumerator movePlayer(Vector3 direction)
    {
        isMoving = true;
        float elapsedTime = 0;
        origPos = transform.position;
        targetPos = origPos   direction;

        while(elapsedTime < timeToMove)
        {
            transform.position = Vector3.MoveTowards(origPos, targetPos, (elapsedTime / timeToMove));
            elapsedTime  = Time.deltaTime;
            yield return null;
        }
        transform.position = targetPos;
        isMoving = false;
    }
}

`

public class EnemyScript : MonoBehaviour
{

private bool isMoving;
private Vector3 origPos, targetPos;
private float timeToMove = 0.2f;

public void movement()
{
    int rand = Random.Range(0, 4);
    if (rand == 1)
    {
        StartCoroutine(moveEnemy(Vector3.left));
    }

    if (rand == 2)
    {
        StartCoroutine(moveEnemy(Vector3.right));
    }

    if (rand == 3)
    {
        StartCoroutine(moveEnemy(Vector3.down));
    }

    if (rand == 0)
    {
        StartCoroutine(moveEnemy(Vector3.up));
    }
}

private IEnumerator moveEnemy(Vector3 direction)
{
    isMoving = true;
    float elapsedTime = 0;
    origPos = transform.position;
    targetPos = origPos   direction;

    while(elapsedTime < timeToMove)
    {
        transform.position = Vector3.MoveTowards(origPos, targetPos, (elapsedTime / timeToMove));
        elapsedTime  = Time.deltaTime;
        yield return null;
    }
    transform.position = targetPos;
    isMoving = false;
}
}

`

CodePudding user response:

But when I try to hold it, the player still moves fine, but the enemy move more spaces then the player

I suspect this is because your let the enemies move as soon as the player begins moving, even if the player hasn't reached his target position yet. And because you aren't using isMoving to prevent your enemies from have multiple coroutines running at once (like you are with your player) then when you hold a key down, your player starts moving but your enemy gets several moves all at once while your player's coroutine is still running.

but also stays most of the times between grids, more like if you are playing chess and you put the queen half of it in one space and half of it in another.

Again, I suspect this is because you have multiple moveEnemy coroutines running at once. So when the second instance of the coroutine starts, the enemy is a little bit between grid spaces because the first instance of the coroutine hasn't finished yet. So even though the second instance of the coroutine is only moving him 1 space, he starts out between spaces so he'll end up between spaces. And then that problem compounds depending on how many instances of the coroutine run.

There are a bunch of ways to fix it, but the way that I'd recommend is to change the value of game_state to ENEMY_TURN only once your player has finished moving and set it to PLAYER_TURN only once all your enemies have finished moving. Then add a third state called BETWEEN_TURNS or something like, and set game_state to BETWEEN_TURNS immediately after the player or enemy begins moving. Then do not accept any input during BETWEEN_TURNS. That way you can make sure a complete turn has finished before you start the next turn and you don't have things moving simultaneously (unless that's what you want, in which case you'd need a different solution).

  • Related