Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

2D Roguelike tutorial - player only moves once

Discussion in 'Scripting' started by dean-o, Feb 15, 2015.

  1. dean-o

    dean-o

    Joined:
    Oct 13, 2014
    Posts:
    7
    Good day,

    I've been working through said tutorial and have hit a wall. The game runs but the player moves only once visually. Everything else to continues to run just fine but with each press of a direction key the player remains still.

    I'm not sure exactly which script/s this relates to but here is my player script:

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using UnityEngine.UI;
    4.  
    5. public class Player : MovingObject {
    6.  
    7.     public int wallDamage = 1;
    8.     public int pointsPerFood = 10;
    9.     public int pointsPerSoda = 20;
    10.     public float restartLevelDelay = 1f;
    11.     public Text foodText;
    12.  
    13.     private Animator animator;
    14.     private int food;
    15.  
    16.     protected override void Start () {
    17.         animator = GetComponent<Animator> ();
    18.  
    19.         food = GameManager.instance.playerFoodPoints;
    20.  
    21.         foodText.text = "Food: " + food;
    22.  
    23.         base.Start ();
    24.     }
    25.  
    26.     private void Ondisable(){
    27.         GameManager.instance.playerFoodPoints = food;
    28.     }
    29.  
    30.     void Update () {
    31.         if(!GameManager.instance.playersTurn)return;
    32.  
    33.         int horizontal = 0;
    34.         int vertical = 0;
    35.  
    36.         horizontal = (int)(Input.GetAxisRaw ("Horizontal"));
    37.         vertical = (int)(Input.GetAxisRaw ("Vertical"));
    38.  
    39.         if(horizontal !=0){
    40.             vertical = 0;
    41.         }
    42.  
    43.         if(horizontal !=0 || vertical !=0){
    44.             AttemptMove<Wall>(horizontal,vertical);
    45.         }
    46.     }
    47.  
    48.     protected override void AttemptMove<T>(int xDir, int yDir){
    49.         food --;
    50.         foodText.text = "Food: " + food;
    51.  
    52.         base.AttemptMove<T> (xDir, yDir);
    53.  
    54.         RaycastHit2D hit;
    55.  
    56.         CheckIfGameOver ();
    57.  
    58.         GameManager.instance.playersTurn = false;
    59.     }
    60.  
    61.     private void OnTriggerEnter2D(Collider2D other){
    62.         if(other.tag == "Exit"){
    63.             Invoke("Restart", restartLevelDelay);
    64.             enabled = false;
    65.         }
    66.         else if(other.tag == "Food"){
    67.             food += pointsPerFood;
    68.             foodText.text = "+" + pointsPerFood + "Food: " + food;
    69.             other.gameObject.SetActive(false);
    70.         }
    71.         else if(other.tag == "Soda"){
    72.             food += pointsPerSoda;
    73.             foodText.text = "+" + pointsPerSoda + "Food: " + food;
    74.             other.gameObject.SetActive(false);
    75.         }
    76.     }
    77.  
    78.     protected override void OnCantMove<T>(T component){
    79.         Wall hitWall = component as Wall;
    80.         hitWall.DamageWall (wallDamage);
    81.         animator.SetTrigger ("playerChop");
    82.     }
    83.  
    84.     public void Restart(){
    85.         Application.LoadLevel (Application.loadedLevel);
    86.     }
    87.  
    88.     public void LoseFood(int loss){
    89.         animator.SetTrigger ("playerHit");
    90.         food -= loss;
    91.         foodText.text = "-" + loss + "Food: " + food;
    92.         CheckIfGameOver ();
    93.     }
    94.  
    95.     private void CheckIfGameOver(){
    96.         if(food <= 0)
    97.             GameManager.instance.GameOver ();
    98.     }
    99. }
    100.  
    Thank you,
    Dean.
     
  2. lordconstant

    lordconstant

    Joined:
    Jul 4, 2013
    Posts:
    389
    Can you show us the base.AttemptMove<T>(xDir, yDir); function, i think this is where your character movement is actually happening.
     
  3. dean-o

    dean-o

    Joined:
    Oct 13, 2014
    Posts:
    7
    Here is my enemy script Matt MirrorFish;

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class Enemy : MovingObject {
    5.  
    6.     public int playerDamage;
    7.     public AudioClip enemyAttack1;
    8.     public AudioClip enemyAttack2;
    9.  
    10.     private Animator animator;
    11.     private Transform target;
    12.     private bool skipMove;
    13.  
    14.     protected override void Start () {
    15.         GameManager.instance.AddEnemyToList (this);
    16.         animator = GetComponent<Animator> ();
    17.         target = GameObject.FindGameObjectWithTag ("Player").transform;
    18.         base.Start ();
    19.     }
    20.    
    21.     // Update is called once per frame
    22.     void Update () {
    23.    
    24.     }
    25.  
    26.     protected override void AttemptMove<T>(int xDir, int yDir){
    27.         if(skipMove){
    28.             skipMove = false;
    29.             return;
    30.         }
    31.  
    32.         base.AttemptMove<T> (xDir, yDir);
    33.  
    34.         skipMove = true;
    35.     }
    36.  
    37.     public void MoveEnemy(){
    38.         int xDir = 0;
    39.         int yDir = 0;
    40.  
    41.         if(Mathf.Abs(target.position.x - transform.position.x) < float.Epsilon)
    42.             yDir = target.position.y > transform.position.y ? 1 : -1;
    43.         else
    44.             xDir = target.position.x > transform.position.x ? 1 : -1;
    45.  
    46.         AttemptMove <Player> (xDir,yDir);
    47.     }
    48.  
    49.     protected override void OnCantMove<T>(T component){
    50.         Player hitPlayer = component as Player;
    51.  
    52.         hitPlayer.LoseFood (playerDamage);
    53.        
    54.         animator.SetTrigger ("enemyAttack");
    55.  
    56.         SoundManager.instance.RandomizeSfx (enemyAttack1, enemyAttack2);
    57.     }
    58. }
    59.  
     
  4. lordconstant

    lordconstant

    Joined:
    Jul 4, 2013
    Posts:
    389
    Need to see your moving object script to actually see the movement
     
  5. dean-o

    dean-o

    Joined:
    Oct 13, 2014
    Posts:
    7
    Here is my MovingObject script;

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public abstract class MovingObject : MonoBehaviour {
    5.  
    6.     public float moveTime = 0.1f;
    7.     public LayerMask blockingLayer;
    8.  
    9.     private BoxCollider2D boxCollider;
    10.     private Rigidbody2D rb2D;
    11.     private float inverseMoveTime;
    12.  
    13.     protected virtual void Start () {
    14.         boxCollider = GetComponent<BoxCollider2D> ();
    15.         rb2D = GetComponent <Rigidbody2D> ();
    16.         inverseMoveTime = 1f / moveTime;
    17.     }
    18.  
    19.     protected bool Move (int xDir, int yDir, out RaycastHit2D hit){
    20.         Vector2 start = transform.position;
    21.         Vector2 end = start + new Vector2 (xDir, yDir);
    22.  
    23.         boxCollider.enabled = false;
    24.         hit = Physics2D.Linecast (start, end, blockingLayer);
    25.         boxCollider.enabled = true;
    26.  
    27.         if(hit.transform == null){
    28.             StartCoroutine(SmoothMovement (end));
    29.             return true;
    30.         }
    31.  
    32.         return false;
    33.     }
    34.  
    35.     protected IEnumerator SmoothMovement(Vector3 end){
    36.         float sqrRemainingDistance = (transform.position - end).sqrMagnitude;
    37.  
    38.         while(sqrRemainingDistance > float.Epsilon){
    39.             Vector3 newPosition = Vector3.MoveTowards(rb2D.position, end, inverseMoveTime * Time.deltaTime);
    40.             rb2D.MovePosition (newPosition);
    41.             sqrRemainingDistance = (transform.position - end).sqrMagnitude;
    42.             yield return null;
    43.         }
    44.     }
    45.  
    46.     protected virtual void AttemptMove <T> (int xDir, int yDir)
    47.     where T : Component{
    48.         RaycastHit2D hit;
    49.         bool canMove = Move(xDir, yDir, out hit);
    50.  
    51.         if(hit.transform == null)
    52.             return;
    53.  
    54.         T hitComponent = hit.transform.GetComponent<T>();
    55.  
    56.         if(!canMove && hitComponent != null)
    57.             OnCantMove(hitComponent);
    58.     }
    59.  
    60.     protected abstract void OnCantMove <T> (T component)
    61.         where T : Component;
    62. }
    63.  
     
  6. Battlecraftr

    Battlecraftr

    Joined:
    Feb 26, 2015
    Posts:
    1
    I,m having the same problem here did you ever figure it out?
     
  7. Rene-Damm

    Rene-Damm

    Unity Technologies

    Joined:
    Sep 15, 2012
    Posts:
    1,779
    My guess would be that the culprit is in GameManager. It needs to set playersTurn to true after the enemies have moved or the Player update won't do anything after the first player turn.
     
  8. RapidNutcracker

    RapidNutcracker

    Joined:
    May 21, 2015
    Posts:
    1
    Kind of a necropost here, but for anyone like me who just started the tutorial and is having this problem, there was a very simple fix for me.

    My Player prefab was accidentally created with an initial Transform Position (something like -0.15, 0.2245, -5.998).

    The exact values were not important, what was important was that Z-index of ~-6. This caused the recalculation of sqrRemainingDistance (in the while loop of MovingObject's SmoothMovement function) to always be around 36 in my case. Thus, entering into an infinite loop as the distance would never be < float.Epsilon.

    tl;dr: check your Player's Tranform Position in the Unity Editor. Make sure all values are 0.
     

    Attached Files:

  9. Skarrg

    Skarrg

    Joined:
    Dec 11, 2015
    Posts:
    1
    I encountered this too, and thought I would update this thread since it blocked me until I understood.

    Rene was correct. I encountered the problem directly after the "Writing the Player Script" section. Could only move one square, and then no movement at all.

    In line 58 of dean-o's Player script (His first post and if you followed the tutorial, Player.cs) it sets "GameManager.instance.playersTurn=false;". You can see this for yourself by commenting the line out if you're at this point (Which creates other problems so mostly do this for learning.)

    Later in the tutorial series you'll fix that so that the enemies do take turns and everything moves nicely, so if you're also stuck just keep going.

    (Also apologies for dead thread rez, I got excited when I finally figured it out)
     
  10. greatness

    greatness

    Joined:
    Feb 20, 2016
    Posts:
    199
    Well I know that if you didn't write the enemy script, the player can only move once. This is because the game is turn-based. The player moves first, then the enemy moves second. That is all I know.
     
  11. sorenpras

    sorenpras

    Joined:
    Nov 4, 2016
    Posts:
    1
    I am still having problems with this. I have set the transform on the player to 0,0,0 but it doesn't work. I having been trying everything, but nothing seems to be working. I am on part 111 of the tutorial btw.
     
  12. CamoClayton

    CamoClayton

    Joined:
    Nov 29, 2016
    Posts:
    5
    I am having the same issue. My character just sits at the starting point shaking and I cannot move him at all. I have checked the transform which is 0,0,0 and I have also commented out the "GameManager.instance.playersTurn=false;" but still no joy.
    I keep getting a "NullReferenceException Object reference not set to an instance of an object" Message highlighting "boxCollider.enabled = false; ".

    Any help would be appreciated and its rather urgent as I chose to do this tutorial for an assignment. Doh!!
     
    Last edited: Dec 14, 2016
  13. hmezzacappa360

    hmezzacappa360

    Joined:
    Jun 6, 2016
    Posts:
    1
    Hi! I am a complete newbie but after MUCH troubleshooting did get my own version of the 2D Rogue to work. I had the same problem with the player only moving once. After scrutinizing every inch of every script then going back into the Unity editor, I noticed in Main Camera, under Loader (Script), that the Game Manager Prefab was not linked (Sound Manager was). That seemed to fix it! Hope that is helpful.
     
  14. felipedelta0

    felipedelta0

    Joined:
    Mar 7, 2015
    Posts:
    11
    Well, i was trying to fix it too, unsuccessfully, but, if you change your food integer on the player script from private to public and run the game, you'll see the variable starts at 0, so when you move for the first time, it subtract 1 from food. So, food value as -1 trigger the GameOver function. Now, why the food variable starts at 0? I didn't found out yet.
     
  15. TaleOf4Gamers

    TaleOf4Gamers

    Joined:
    Nov 15, 2013
    Posts:
    825
    Uhhh, an int or float by default starts at 0...
    Unless you specify a value it is 0 hence why when changing it to public it says 0 in the inspector. Note that the inspector also overrides any value in script so if the inspector says 0 but your code says 10 it is indeed 0.
     
  16. felipedelta0

    felipedelta0

    Joined:
    Mar 7, 2015
    Posts:
    11
    I know, i just changed to public to see the value, but the problem persists in private. Also, the food variable need to be 100. On the Player's Start() function has the line "food = GameManager.instance.playerFoodPoints;", this variable on the GameManager function has a default value 0.
     
  17. White-studio

    White-studio

    Joined:
    May 1, 2013
    Posts:
    7
    I literally checked everything other than that, I think was the only thing I didn't check, really disappointed with my self, really wanted to figure it out on my own, but anyways mine was also spawning anywhere from 3-4 players on the grid, even though the board manager script implicitly doesn't handle the player, somehow two extra players where being spawned as childs to two of the wall tiles, but any ways, know it works, I am know going to create my own version of it by getting rid of the procedural level design and move over to a semi procedural level design and semi artistic setup, as well as a main menu and in game menu for levelling up the character, wish me luck main menu first I think..
     
  18. Hyrulemaster77

    Hyrulemaster77

    Joined:
    Jul 26, 2019
    Posts:
    1
    Ok, I know this thread is old, but I found something that I think may help! In GameManager near the bottom (after the Player and Enemy code videos) there is a line:

    //Update is called every frame.
    void Update()
    {
    if(playersTurn || enemiesMoving || doingSetup)
    return;
    StartCoroutine (MoveEnemies ());
    }
    public void AddEnemyToList(Enemy script)
    {
    enemies.Add(script);
    }


    -----------------------------

    For me, the issue was with 'doingSetup'. I don't think I had the code for that or perhaps it was added later. When I commented it out that part it works great! Here's what it looks like at the moment:
    ------------------------------

    //Update is called every frame.
    void Update()
    {
    if(playersTurn || enemiesMoving)
    //|| doingSetup)
    return;
    StartCoroutine (MoveEnemies ());
    }
    public void AddEnemyToList(Enemy script)
    {
    enemies.Add(script);
    }

     
  19. kashishs

    kashishs

    Joined:
    Apr 28, 2020
    Posts:
    5
    Hey, I think I have the same issue. However, I'm unable to find a fix for it. Did you find a solution?