Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Official 2D Roguelike: Q&A

Discussion in 'Community Learning & Teaching' started by Matthew-Schell, Feb 10, 2015.

Thread Status:
Not open for further replies.
  1. Matthew-Schell

    Matthew-Schell

    Joined:
    Oct 1, 2014
    Posts:
    238
    Please compare your scripts and prefabs to those in the Completed folder of the project to see if you can determine where you went wrong. Double check that the game state is getting to a point where the player is allowed to move. The Enemies have to be able to finish moving before allowing the player to move again, and doingSetup has to be false.
     
  2. David_Munoz

    David_Munoz

    Joined:
    Jul 30, 2015
    Posts:
    2
    Thank you Matthew. Where can i find "the completed folder of the project", is there a link to download it? All i could find was a link to the assets. Also you mentioned "doingSetup", where exactly can i find that property?
     
  3. monsieurtasse

    monsieurtasse

    Joined:
    Feb 2, 2013
    Posts:
    12
    Hi,

    Thanks for the tutorial, and like some others, I tried on expanding the game.
    I wanted the player to be able to interact with more than 1 type of object, instead of just the walls, so I wrote a script without passing a component to "expect", and got rid of the MovingObject class because I'm a beginner and couldn't find another solution quickly.
    Anyway, it works great but (of course), it looks like it messed up the 'turn' mechanic.
    The enemy is now constantly moving to the player as soon as the game starts.
    A debug log seems to indicate that it loops continously through
    Code (CSharp):
    1. for (int i = 0; i < enemies.Count; i++)
    in the GameManager script, ignoring the bools for turn, no matter where I place the "skipMove" check.

    Any ideas?
    Thank you!
     

    Attached Files:

    • Enemy.cs
      File size:
      6.6 KB
      Views:
      1,133
  4. zanyang1103

    zanyang1103

    Joined:
    Aug 20, 2015
    Posts:
    2
    i just start learning Unity and finished this tutorial ,it's a great one ,but i found one place very confusing.
    when you start to add move sound in the player script, you call Move() function to check whether player is able to move. this should be the second time you call Move() function in the same Update() callback,and the first time was in the AttemptMove() function .
    In Move() function , you start a Corountine to actually move the player ,so there are two Corountine trying to move the same object to the same postion.I checked the api of Rigidbody2D.MovePosition:
    So it doesn't matter?
    Am i thinking to much ? I felt a little unconfortable about this.If i missed something ,please tell me.thanks.

    Code (CSharp):
    1. //Call the AttemptMove method of the base class, passing in the component T (in this case Wall) and x and y direction to move.
    2.             base.AttemptMove <T> (xDir, yDir);
    3.            
    4.             //Hit allows us to reference the result of the Linecast done in Move.
    5.             RaycastHit2D hit;
    6.            
    7.             //If Move returns true, meaning Player was able to move into an empty space.
    8.             if (Move (xDir, yDir, out hit))
    9.             {
    10.                 //Call RandomizeSfx of SoundManager to play the move sound, passing in two audio clips to choose from.
    11.                 SoundManager.instance.RandomizeSfx (moveSound1, moveSound2);
    12.             }
     
  5. LichiMan

    LichiMan

    Joined:
    Apr 23, 2013
    Posts:
    6
    Hi!
    I've notice that the Animation Clips we create dragging the sprites to the Player are in 12 FPS.
    Are there a way to change the default FPS when you create new Animation Clips? Or you have to change it in the Animation Window after create them?
    I suppose that we could change the PlayerIdle animation to 6FPS instead of change the speed to 0.5?
    Thanks!
     
  6. Matthew-Schell

    Matthew-Schell

    Joined:
    Oct 1, 2014
    Posts:
    238
    No you're actually correct, that was something I added late in development and ends up calling Move twice. As you say it doesn't matter. I was using it to check IF the player had been able to move using the returned bool but it probably could have been done better.
     
  7. Matthew-Schell

    Matthew-Schell

    Joined:
    Oct 1, 2014
    Posts:
    238
    Please post your code using the code tags (search forum for a guide). As a starting point, make sure this line in your GM is setting playersTurn to true:
    Code (csharp):
    1.  
    2. [HideInInspector] public bool playersTurn = true;     //Boolean to check if it's players turn, hidden in inspector but public.
    3.  
     
  8. monsieurtasse

    monsieurtasse

    Joined:
    Feb 2, 2013
    Posts:
    12
    I attached the Enemy script since my post needed to be moderated when I added the code, and it's still doing it, dont know why. Please see the attached script in my previous post, sorry for the inconvenience!

    The GameManager is the same expect for the name of the fundtion it calls in the Enemy script.

    thank you for your time!

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. namespace Completed
    5. {
    6.     using System.Collections.Generic;        //Allows us to use Lists.
    7.     using UnityEngine.UI;                    //Allows us to use UI.
    8.  
    9.     public class GameManager : MonoBehaviour
    10.     {
    11.  
    12.         public float levelStartDelay = 2f;                        //Time to wait before starting level, in seconds.
    13.         public float turnDelay = 0.1f;                            //Delay between each Player turn.
    14.      
    15.         public int playerMoralePoints = 100;                        //Starting value for Player food points.
    16.         public int playerActionPoints = 20;
    17.         public int playerRhumPoints = 0;
    18.      
    19.         public static GameManager instance = null;                //Static instance of GameManager which allows it to be accessed by any other script.
    20.         [HideInInspector] public bool playersTurn = true;        //Boolean to check if it's players turn, hidden in inspector but public.
    21.         public GameObject Player;
    22.      
    23.         private Text levelText;                                    //Text to display current level number.
    24.         private GameObject levelImage;                            //Image to block out level as levels are being set up, background for levelText.
    25.      
    26.         private BoardManager boardScript;                        //Store a reference to our BoardManager which will set up the level.
    27.         private int level = 5;                                    //Current level number, expressed in game as "Day 1".
    28.      
    29.         private List<Enemy> enemies;                            //List of all Enemy units, used to issue them move commands.
    30.         private bool enemiesMoving = false;                                //Boolean to check if enemies are moving.
    31.      
    32.         private bool doingSetup = true;                            //Boolean to check if we're setting up board, prevent Player from moving during setup.
    33.      
    34.      
    35.      
    36.         //Awake is always called before any Start functions
    37.         void Awake()
    38.         {
    39.             //Check if instance already exists
    40.             if (instance == null)            
    41.                 //if not, set instance to this
    42.                 instance = this;
    43.          
    44.             //If instance already exists and it's not this:
    45.             else if (instance != this)            
    46.                 //Then destroy this. This enforces our singleton pattern, meaning there can only ever be one instance of a GameManager.
    47.                 Destroy(gameObject);
    48.          
    49.             //Sets this to not be destroyed when reloading scene
    50.             DontDestroyOnLoad(gameObject);
    51.          
    52.             //Assign enemies to a new List of Enemy objects.
    53.             enemies = new List<Enemy>();
    54.          
    55.             //Get a component reference to the attached BoardManager script
    56.             boardScript = GetComponent<BoardManager>();
    57.          
    58.             //Call the InitGame function to initialize the first level
    59.             InitGame();
    60.         }
    61.      
    62.         //This is called each time a scene is loaded.
    63.         void OnLevelWasLoaded(int index)
    64.         {
    65.             //Add one to our level number.
    66.             level++;        
    67.             //Call InitGame to initialize our level.
    68.             InitGame();
    69.         }
    70.      
    71.         //Initializes the game for each level.
    72.         void InitGame()
    73.         {
    74.      
    75.             playersTurn = false;
    76.          
    77.             //While doingSetup is true the player can't move, prevent player from moving while title card is up.
    78.             doingSetup = true;
    79.          
    80.             //Get a reference to our image LevelImage by finding it by name.
    81.             levelImage = GameObject.Find("LevelImage");
    82.          
    83.             //Get a reference to our text LevelText's text component by finding it by name and calling GetComponent.
    84.             levelText = GameObject.Find("LevelText").GetComponent<Text>();
    85.          
    86.             //Set the text of levelText to the string "Day" and append the current level number.
    87.             levelText.text = "Day " + level;
    88.          
    89.             //Set levelImage to active blocking player's view of the game board during setup.
    90.             levelImage.SetActive(true);
    91.          
    92.             //Call the HideLevelImage function with a delay in seconds of levelStartDelay.
    93.             Invoke("HideLevelImage", levelStartDelay);
    94.          
    95.             //Clear any Enemy objects in our List to prepare for next level.
    96.             enemies.Clear();
    97.          
    98.             //Call the SetupScene function of the BoardManager script, pass it current level number.
    99.             boardScript.SetupScene(level);
    100.          
    101.         }
    102.      
    103.  
    104.         //Hides black image used between levels
    105.         void HideLevelImage()
    106.         {
    107.             //Disable the levelImage gameObject.
    108.             levelImage.SetActive(false);
    109.          
    110.             //Set doingSetup to false allowing player to move again.
    111.             doingSetup = false;
    112.             playersTurn = true;
    113.          
    114.         }    
    115.  
    116.      
    117.      
    118.         //Update is called every frame.
    119.         void Update()
    120.         {
    121.             //Check that playersTurn or enemiesMoving or doingSetup are not currently true.
    122.             if(playersTurn || enemiesMoving || doingSetup)            
    123.                 //If any of these are true, return and do not start MoveEnemies.
    124.                 return;
    125.          
    126.             //Start moving enemies.
    127.             StartCoroutine (MoveEnemies ());
    128.         }
    129.      
    130.         //Call this to add the passed in Enemy to the List of Enemy objects.
    131.         public void AddEnemyToList(Enemy script)
    132.         {
    133.             //Add Enemy to List enemies.
    134.             enemies.Add(script);
    135.         }
    136.      
    137.      
    138.         //GameOver is called when the player reaches 0 food points
    139.         public void GameOver()
    140.         {
    141.             //Set levelText to display number of levels passed and game over message
    142.             levelText.text = "After " + level + " days, you were alone.";
    143.          
    144.             //Enable black background image gameObject.
    145.             levelImage.SetActive(true);
    146.          
    147.             //Disable this GameManager.
    148.             enabled = false;
    149.         }
    150.      
    151.         //Coroutine to move enemies in sequence.
    152.         IEnumerator MoveEnemies()
    153.         {
    154.             //While enemiesMoving is true player is unable to move.
    155.             enemiesMoving = true;
    156.          
    157.             //Wait for turnDelay seconds, defaults to .1 (100 ms).
    158.             yield return new WaitForSeconds(turnDelay);
    159.          
    160.             //If there are no enemies spawned (IE in first level):
    161.             if (enemies.Count == 0)
    162.             {
    163.                 //Wait for turnDelay seconds between moves, replaces delay caused by enemies moving when there are none.
    164.                 yield return new WaitForSeconds(turnDelay);
    165.             }
    166.          
    167.             //Loop through List of Enemy objects.
    168.             for (int i = 0; i < enemies.Count; i++)
    169.             {
    170.                 //Call the EnemyDirection function of Enemy at index i in the enemies List.
    171.                 enemies[i].EnemyDirection ();
    172.              
    173.                 //Wait for Enemy's moveTime before moving next Enemy,
    174.                 yield return new WaitForSeconds(enemies[i].moveTime);
    175.  
    176.                 Debug.Log("GAMEMANAGER");
    177.             }
    178.          
    179.             //Once Enemies are done moving, set playersTurn to true so player can move.
    180.             playersTurn = true;
    181.          
    182.             //Enemies are done moving, set enemiesMoving to false.
    183.             enemiesMoving = false;
    184.         }
    185.      
    186.      
    187.      
    188.     }
    189. }
    190.  
    191.  
     
  9. Matthew-Schell

    Matthew-Schell

    Joined:
    Oct 1, 2014
    Posts:
    238
    You are setting PlayersTurn to false in InitGame. That may be a problem. Make sure that you are setting it to true to stop the enemies moving in line 122. My guess is that that conditional is continually evaluating to true and calling MovEnemies again and again.
     
  10. monsieurtasse

    monsieurtasse

    Joined:
    Feb 2, 2013
    Posts:
    12
    Thank you for the answer!
    I changed the player bool so the player can't move during the black screen. And it worked before I rewrote the original movement script where I replaced the AttempMove<T> method, so I guess that comes from the new movement script I did.
    I'm still investigating, but I'm not sure whether it comes from the enemiesMoving bool from the GameManager or the placement of the skipMove bool in Enemy script...
    I'm so close to have this project working!
     
  11. Fragmental

    Fragmental

    Joined:
    Jun 30, 2013
    Posts:
    61
    What I didn't realize before is that, in almost every situation I've tried, Player Food Points gets zeroed out on the start of a new level. So, I guess this is my real problem.
     
  12. Matthew-Schell

    Matthew-Schell

    Joined:
    Oct 1, 2014
    Posts:
    238
    @tasse and @Fragmental and generally to other people modding and extending this project: good luck! If you have questions about implementation in the original project I'm happy to answer, but to the extent that you've written stuff you're going to have to solve those problems yourself.

    @tasse the point of doingSetup was to stop the player acting while the level was being spawned and the title was being displayed, you may get better mileage using it that way although I'm not sure what else you've changed.

    @Fragmental in the original project the Player gets foodPoints in Start from the GameManager (at the beginning of the level) and passes the foodPoints total back to the game manager in OnDisable so that that value will persist in the GameManager between levels when the player is destroyed by loading the next scene. It seems likely you've changed something that is breaking this process.
     
  13. Fragmental

    Fragmental

    Joined:
    Jun 30, 2013
    Posts:
    61
    @Matthew Schell That's fair. In the original project, how and when is Player's ondisable invoked?

    Edit: I'm still uncertain of the question above. If you have no time to read or respond to anything below, please respond to that.

    I think I figured out how to fix the problem with missing foodpoints. I moved "food = GameManager.instance.playerFoodPoints;" out of "protected override void start()" and into "void awake()" in the player script. I'm not entirely sure why this works. At first I thought awake was called each time a script was enabled and start was called only once, but now I'm just not sure.

    And in response to
    I tried this, but I had some difficulty. If I add the variable to the GameManager script, it's not attached to an object in the scene, so I can't assign the Player object from the scene. If I try to assign it to the variable via the GameManager script on the prefab, it won't let me assign objects from the scene. Only prefabs, which is not helpful.

    Loader script is attached to a GameObject, so I added a variable to it. However, I had some issues trying to access that variable if I make it a public variable.

    Code (csharp):
    1.  
    2. public class Loader : MonoBehaviour {
    3.  
    4.     public GameObject gameManager;
    5.         //added so enemy can find player object
    6.     public GameObject playerObject;
    7.  
    and then to access it in BoardManager I have to do this...
    Code (csharp):
    1.  
    2.         cameraRef = GameObject.Find("Main Camera");
    3.         loaderRef = cameraRef.GetComponent<Loader>();
    4.         playerObj = loaderRef.playerObject;
    5.  
    I believe this does work, and would allow me to access the player object even if it was disabled before clicking play but this seems like a simpler option
    Code (csharp):
    1.  
    2.         playerObj = GameObject.Find("Player");
    3.         playerObj.SetActive(false);
    4.  
    I also tried making the playerObject variable a public static in the Loader script. I then have to assign it in Loader's Awake() with GameObject.Find("Player"); So I wouldn't be able to use it to disable the Player before pressing play, but I could use it to declare the one static variable and then use it in both BoardManager and the Enemy script. However, when I try using the static variable in BoardManager, with "playerObj = Loader.playerStatic;" I get the error "Object reference not set to an instance of an object". Oddly enough, if I use the static in Enemy script, with "target = Loader.playerStatic.transform;" I don't get that error. I'm not entirely sure it's working correctly in Enemy script, but it seems to be.

    So, by using the static to solve the bug from Enemy script and by moving the foodpoints to awake in Player script, it seems to all be working fine. I'm still feeling mystified about the whole thing, though. I probably need to watch through the tutorials again and read and learn some more and stuff...
     
    Last edited: Aug 22, 2015
  14. tckelly38

    tckelly38

    Joined:
    Aug 22, 2015
    Posts:
    1
    Hey, I'm doing a slightly modified version of this game,

    On video 5 I go to run the game after adding boardmanager and gamemanager and tiles are all evenly space out(see attached) I was wondering how I can fix this? also, how do I zoom the camera in so I'm not so far out? Scipts are exact same, except that I took out the wall and outerwall stuff. Capture.JPG
     
  15. Darokar

    Darokar

    Joined:
    Aug 22, 2015
    Posts:
    5
    Hi i have problem witch tutorial rouge 2d in 2.Level Generation - 1.Writing the Board Manager

    I copy all code and have error :



    Any solution ???
     
  16. brandc

    brandc

    Joined:
    Feb 23, 2015
    Posts:
    16
    Matthew,

    Have you finished your version of he Vlambeer prototype you were working on?
     
  17. Darokar

    Darokar

    Joined:
    Aug 22, 2015
    Posts:
    5
  18. Matthew-Schell

    Matthew-Schell

    Joined:
    Oct 1, 2014
    Posts:
    238
    As you say, as you read and learn more this stuff will become clear. Again, without really close familiarity with your project it's hard to trouble shoot. The reason that Awake is likely working is that Awake is called before Start, so for whatever reason calling it earlier is causing it to work.

    As far as the player in the original project the Player was in the scene originally. The GameManager was being instantiated but you could actually put it in the scene in advance and drag a reference, that should work fine.
     
  19. Matthew-Schell

    Matthew-Schell

    Joined:
    Oct 1, 2014
    Posts:
    238
    Looking at it my guess is that the pixels to units setting is off in your new sprites. Double check that your sprite sheet has Pixels To Units set to 32 in the Import Settings (highlight the sprite sheet in project view and this will appear in inspector). This means 32 pixels will equal 1 unit in game space.
     
  20. Matthew-Schell

    Matthew-Schell

    Joined:
    Oct 1, 2014
    Posts:
    238
    If you are copying the scripts from the website you should just use the ones in the Completed folder. You won't learn as much but they will work. The issue here is that you have two copies of the script with the same name in the same namespace.
     
  21. Matthew-Schell

    Matthew-Schell

    Joined:
    Oct 1, 2014
    Posts:
    238
    I did make a version of it that sort of worked although it could be cleaned up a bit. Basically what I did was create a grid of random wall tiles and then have an object that moved around deleting wall tiles when the level started. It was crude but made some reasonably cool nuclear-throne-ish levels.
     
  22. Master-Uri

    Master-Uri

    Joined:
    Aug 27, 2015
    Posts:
    4
    Hey everyone! Awesome tutorial! ...But I'm stuck on part 5 (Writing the Game Manager), specifically when you get to test the game for the first time. My enemies are not created in the game (and not listed in the hierarchy after running the game). I've seen people with same issues here but all their issues were fixed by setting Sorting Layer to - Units. Except my enemies are already set to Units in sorting layer. Tag - Enemy, Layer - BlockingLayer, Sorting Layer - Units. I thought it was something with animation so I recreated enemies from scratch couple of time. Then I thought that it might be my BoardManager script. But as I'm new to scripting - I've made sure to re-write the code exactly as it says in the tutorial. I also checked it with the code provided under the tutorial video and even tried to run the game with the code copied from the provided from under the tutorial video (modifying it a bit, so I don't get any errors). The only way I can get an enemy on the game is when I drag my prefab to the hierarchy and run the game.

    Here is my BoardManager script.

    Code (CSharp):
    1. using UnityEngine;
    2. using System;
    3. using System.Collections.Generic;
    4. using Random = UnityEngine.Random;
    5.  
    6. public class BoardManager : MonoBehaviour {
    7.    
    8.     [Serializable]
    9.     public class Count
    10.     {
    11.         public int minimum;
    12.         public int maximum;
    13.        
    14.         public Count (int min, int max)
    15.         {
    16.             minimum = min;
    17.             maximum = max;
    18.         }
    19.        
    20.     }
    21.    
    22.     public int columns = 8;
    23.     public int rows = 8;
    24.     public Count wallCount = new Count (5,9);
    25.     public Count foodCount = new Count (1,5);
    26.     public GameObject exit;
    27.     public GameObject [] floorTiles;
    28.     public GameObject [] wallTiles;
    29.     public GameObject [] foodTiles;
    30.     public GameObject [] enemyTiles;
    31.     public GameObject [] outerWallTiles;
    32.    
    33.     private Transform boardHolder;
    34.     private List <Vector3> gridPositions = new List<Vector3>();
    35.    
    36.     void InitialiseList()
    37.     {
    38.         gridPositions.Clear ();
    39.         for (int x = 1; x < columns - 1; x++)
    40.         {
    41.             for (int y = 1; y < rows - 1; y++)
    42.             {
    43.                 gridPositions.Add(new Vector3(x,y,0f));
    44.             }
    45.         }
    46.     }
    47.    
    48.     void BoardSetup()
    49.     {
    50.         boardHolder = new GameObject ("Board").transform;
    51.        
    52.         for (int x = -1; x < columns + 1; x++) {
    53.             for (int y = -1; y < rows + 1; y++) {
    54.                 GameObject toInstantiate = floorTiles [Random.Range (0, floorTiles.Length)];
    55.                 if (x == -1 || x == columns || y == -1 || y == rows)
    56.                     toInstantiate = outerWallTiles [Random.Range (0, outerWallTiles.Length)];
    57.                 GameObject instance = Instantiate (toInstantiate, new Vector3 (x, y, 0f), Quaternion.identity) as GameObject;
    58.                
    59.                 instance.transform.SetParent (boardHolder);
    60.             }
    61.         }
    62.     }
    63.    
    64.    
    65.     Vector3 RandomPosition()
    66.     {
    67.         int randomIndex = Random.Range(0, gridPositions.Count);
    68.         Vector3 randomPosition = gridPositions[randomIndex];
    69.         gridPositions.RemoveAt(randomIndex);
    70.         return randomPosition;
    71.     }
    72.    
    73.     void LayoutObjectAtRandom(GameObject[] tileArray, int minimum, int maximum)
    74.     {
    75.         int objectCount = Random.Range (minimum, maximum + 1);
    76.         for (int i=1; i<objectCount; i++)
    77.         {
    78.             Vector3 randomPosition = RandomPosition();
    79.             GameObject tileChoice = tileArray[Random.Range (0, tileArray.Length)];
    80.             Instantiate (tileChoice, randomPosition, Quaternion.identity);
    81.         }
    82.     }
    83.     public void SetupScene (int level)
    84.     {
    85.         BoardSetup();
    86.         InitialiseList();
    87.         LayoutObjectAtRandom (wallTiles, wallCount.minimum, wallCount.maximum);
    88.         LayoutObjectAtRandom (foodTiles, foodCount.minimum, foodCount.maximum);
    89.         int enemyCount = (int)Mathf.Log(level, 2f);
    90.         LayoutObjectAtRandom (enemyTiles, enemyCount, enemyCount);
    91.         Instantiate (exit, new Vector3 (columns - 1, rows - 1, 0f), Quaternion.identity);
    92.     }
    93.    
    94. }
    95.  
    And these are my Enemy1 settings:



    Any help would be much appreciated. Thank you.
     
  23. Matthew-Schell

    Matthew-Schell

    Joined:
    Oct 1, 2014
    Posts:
    238
    @Master Uri At first glance what you've shown looks OK. I am assuming the problem is not with the enemy prefab if they're not being instantiated at all. I would double check that there are actually enemies assigned to the Enemy Tiles array via the inspector? Do you see an error saying the prefab you're trying to instantiate is null or array index out of range? Compare your GameManager prefab to the one in Completed > Prefabs and make sure it matches up, specifically that there are enemies in EnemyTiles.
     
  24. Master-Uri

    Master-Uri

    Joined:
    Aug 27, 2015
    Posts:
    4
    Thanks for the answer. I've double-checked my GameManager prefabs with the completed prefabs and they are identical. As for the errors - there are no errors whatsoever... The other thing I've noticed (don't know if it is connected to my issue) sometimes when I load the game food Items aren't created also. But, if I get this correctly, at least one food item should be created. Oh and enemies are assigned to Enemy tiles (same as food items). I made sure to triple-check the inspector when I was deleting and creating new enemy prefabs :) Could it be possible that there is an issue in my Unity? Cause I currently live in China and as I was downloading Unity the connection got cut off couple of times so I ended up re-downloading and re-installing it.
    Thank you for your help.
     
  25. Matthew-Schell

    Matthew-Schell

    Joined:
    Oct 1, 2014
    Posts:
    238
    @Master Uri try replacing your BoardManager script with the one from the completed folder temporarily (add it to your GM and disable your original, set up as you did). The problem must be in that script. I really don't think it's a problem with Unity from the download.
     
  26. Campusanis

    Campusanis

    Joined:
    Jul 9, 2013
    Posts:
    5
    I solved this "problem" (not that it's a big deal, but if nothing else, you're doing the LineCast twice, which can't be optimal) by doing the moveSound logic in MovingObject instead of in Player.
    So in my Move function in MovingObject, I include the RandomizeSfx line (and declare the moveSound1 and moveSound2 variables in MovingObject):

    Code (CSharp):
    1.  
    2. if (hit.transform == null) {
    3.    StartCoroutine(SmoothMovement(end));
    4.    SoundManager.instance.RandomizeSfx(moveSound1, moveSound2);
    5.  
    6.    return true;
    7. }
    8. else
    9.    return false;
    I find it makes most sense to play the move sounds in the same place where the relevant move logic is done (or anyway, I can tell myself that to justify this ;) ).
    Now you could even add the move sounds to the enemies, although I didn't do that, which still works.
     
  27. Master-Uri

    Master-Uri

    Joined:
    Aug 27, 2015
    Posts:
    4
    @Matthew Schell Thank you. it looks like it really was something wrong with my Board Manager script. But I don't understand one thing. I have replaced it yesterday and it didn't work. Mystery... Well anyways big THANK YOU Matthew)) Now I can continue with the project))
     
    Matthew-Schell likes this.
  28. Master-Uri

    Master-Uri

    Joined:
    Aug 27, 2015
    Posts:
    4
    Oh. I found where my issue was.

    Code (CSharp):
    1. //Instantiate objects until the randomly chosen limit objectCount is reached
    2.             for(int i = 0; i < objectCount; i++)
    The only difference between my BoardManager script and the one from completed folder was that in the line shown above I have assigned int i = 1... so the problem was in just 1 number. I'm so ashamed now that I couldn't find this error for 4 days. And sorry to bother you with my silly questions.
     
    Matthew-Schell likes this.
  29. Nimue

    Nimue

    Joined:
    Apr 27, 2015
    Posts:
    6
    Hello again everyone :) I ended up restarting the tutorial due to some unavoidable enforced downtime and to make a long story short when I drag the sprites to the Player prefab it does not give me the option to create a new animation. Any suggestions?
     
    Husa_FIN likes this.
  30. Deleted User

    Deleted User

    Guest

    I am having trouble with Part 2.

    I successfully setup all three animations with one small problem.

    The final enemy (with the clothes) has a very fast animation. With the player animation, I took care of this (as instructed) by editing the speed in the animation controller (setting it to .5), but since I am using the animation controller override for the final enemy, I don't have that option. And since the second enemy seems to have the correct animation pace at normal speed (ie speed = 1, not .5), if I change it to .5 to fix the animation of the final via the override, the second one will now be too slow.

    I feel like maybe I am missing something super simple here, but I can't figure out what it is.

    Thanks in advance. I am using Version 5.1.1f1

    P.S. Is the second enemy's animation supposed to look slower than the others by default? Maybe my expectation is just off.
     
  31. halbard100

    halbard100

    Joined:
    Feb 17, 2015
    Posts:
    3
    @Klosterheim My Enemy2 looks faster than my Enemy1 too, but I think that's just the way it's animated.
     
    Deleted User likes this.
  32. halbard100

    halbard100

    Joined:
    Feb 17, 2015
    Posts:
    3
    I'm having an issue with Audio in that none of it plays. My code is all the same and I've got the Audio Sources in their proper place, but just no sound. Not even from the music and I have 'Play on Awake' and 'Loop' checked. Thought it might be the 'Spatial Blend' but changing that does nothing. I'm using Unity 5.1.3f1
     
  33. Deleted User

    Deleted User

    Guest

    Cool, thanks for the response. I will move on!
     
    Matthew-Schell likes this.
  34. MadMathias

    MadMathias

    Joined:
    Oct 1, 2014
    Posts:
    2
    I'm having a problem with Tutorial 5.

    Trying to test the BoardManager script I get no warnings, and I get no tiles instantiated. Followed the tutorial to point, and I'm not sure where I went wrong.
     
  35. ShenHibiki

    ShenHibiki

    Joined:
    Sep 2, 2015
    Posts:
    1
    Hello! I'm new to Unity, has only AS2 experience before, and sooome other things.
    (also, English is not my main language, please don't hate me ;w;)

    So far, the proyect seemed pretty straightforward to me, and had just little hiccups, though I did manage to make some small changes for myself (flipping the sprite when moving to the left, walls leaving some debris, and stuff like that)

    My problem comes when I have to add a UI.
    The game works PERFECTLY before that. But as soon as I add the Canvas, empty, and try to run the game, I get an error:

    NullReferenceException: Object reference not set to an instance of an object
    Player.Update () (at Assets/Scripts/Player.cs:99)​

    And in that line, all I have is the Update function, specifically this line

    if (!GameManager.instance.playersTurn) return;
    Given that the game works ok before that, it has to be some kind of clash when adding the Canvas. I tried deleting it and noticed the problem is ONLY there, when there's an 'EventManager' in the heriarchy, the one that's created along with the Canvas... if I delete the EventManager, but keep the Canvas, the error goes away, but I think the Canvas needs the Manager, right?
     
  36. Mohobie

    Mohobie

    Joined:
    Sep 5, 2015
    Posts:
    13
    1st Thanks for the excellent tutorial! I appreciate the effort it took to make it as well as all the work you appear to be putting in to help others. I have encountered 1 small issue. I have apparently checked everything but the right thing. I have completed the project - the final where you add multiplatform support. I have 1 issue which I can not track down to any specific element so i'm linking a complete project here.

    The Problem: Inner wall tiles do not engage the OnCantMove. I have no compiler errors or errors while running in game. When I attempt to interact with a wall nothing appears to happen. No animation, no "hit". The food still drops which indicates that I'm firing a move attempt. Can anyone please help me track down this final little bugger? I've been stubborn headed and trying to solve it on my own for a few days now. Thanks

    Project Download Here
     
  37. Mohobie

    Mohobie

    Joined:
    Sep 5, 2015
    Posts:
    13
    Worth noting. I attempted to replace my wall peices with the completed versions in an effort to track the problem. I think thats currently the ones in use in the download.
     
  38. pwn_dhami

    pwn_dhami

    Joined:
    Sep 2, 2015
    Posts:
    5
    i try to develop this game . after completing BoardManager and GameManager Scripts , I have a problem in game view , the board is not in its right place i.e. not in center , when i play the borad appear in the right most corner ,i want to fix it in the center . please help to get it out . Thanks.
     
  39. pwn_dhami

    pwn_dhami

    Joined:
    Sep 2, 2015
    Posts:
    5
    hi . I am new in unity . while developing this proj , i have a problem . in the game view board is not appear as whole , it is at the right corner only half of the board is shown in the game view . what can i do.
     
  40. Mohobie

    Mohobie

    Joined:
    Sep 5, 2015
    Posts:
    13
    Sorry for the triple post, but I was able to determine where to code comes to a halt but not why. As far as I can tell the culprit is in MovingObject in the AttemptMove block. T hitComponent = hit.transform.GetComponent <T> (); hitComponent appears to always come back null.


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

    Mohobie

    Joined:
    Sep 5, 2015
    Posts:
    13
    Try repositioning the camera
     
  42. dillonbro

    dillonbro

    Joined:
    Sep 9, 2015
    Posts:
    1
    i am getting 4 errors i copy and pasted your code into unity to see if it was just my error when writing it but when i put your final example code in i get errors as well none of which i know how to fix




    Code (CSharp):
    1. using System.Collections.Generic;       //Allows us to use Lists.
    2. using Random = UnityEngine.Random;      //Tells Random to use the Unity Engine random number generator.
    3.  
    4. namespace Completed
    5.  
    6. {
    7.  
    8.     public class BoardManager : MonoBehaviour
    9.     {
    10.         // Using Serializable allows us to embed a class with sub properties in the inspector.
    11.         [Serializable]
    12.         public class Count
    13.         {
    14.             public int minimum;             //Minimum value for our Count class.
    15.             public int maximum;             //Maximum value for our Count class.
    16.          
    17.          
    18.             //Assignment constructor.
    19.             public Count (int min, int max)
    20.             {
    21.                 minimum = min;
    22.                 maximum = max;
    23.             }
    24.         }
    25.      
    26.      
    27.         public int columns = 8;                                         //Number of columns in our game board.
    28.         public int rows = 8;                                            //Number of rows in our game board.
    29.         public Count wallCount = new Count (5, 9);                      //Lower and upper limit for our random number of walls per level.
    30.         public Count foodCount = new Count (1, 5);                      //Lower and upper limit for our random number of food items per level.
    31.         public GameObject exit;                                         //Prefab to spawn for exit.
    32.         public GameObject[] floorTiles;                                 //Array of floor prefabs.
    33.         public GameObject[] wallTiles;                                  //Array of wall prefabs.
    34.         public GameObject[] foodTiles;                                  //Array of food prefabs.
    35.         public GameObject[] enemyTiles;                                 //Array of enemy prefabs.
    36.         public GameObject[] outerWallTiles;                             //Array of outer tile prefabs.
    37.      
    38.         private Transform boardHolder;                                  //A variable to store a reference to the transform of our Board object.
    39.         private List <Vector3> gridPositions = new List <Vector3> ();   //A list of possible locations to place tiles.
    40.      
    41.      
    42.         //Clears our list gridPositions and prepares it to generate a new board.
    43.         void InitialiseList ()
    44.         {
    45.             //Clear our list gridPositions.
    46.             gridPositions.Clear ();
    47.          
    48.             //Loop through x axis (columns).
    49.             for(int x = 1; x < columns-1; x++)
    50.             {
    51.                 //Within each column, loop through y axis (rows).
    52.                 for(int y = 1; y < rows-1; y++)
    53.                 {
    54.                     //At each index add a new Vector3 to our list with the x and y coordinates of that position.
    55.                     gridPositions.Add (new Vector3(x, y, 0f));
    56.                 }
    57.             }
    58.         }
    59.      
    60.      
    61.         //Sets up the outer walls and floor (background) of the game board.
    62.         void BoardSetup ()
    63.         {
    64.             //Instantiate Board and set boardHolder to its transform.
    65.             boardHolder = new GameObject ("Board").transform;
    66.          
    67.             //Loop along x axis, starting from -1 (to fill corner) with floor or outerwall edge tiles.
    68.             for(int x = -1; x < columns + 1; x++)
    69.             {
    70.                 //Loop along y axis, starting from -1 to place floor or outerwall tiles.
    71.                 for(int y = -1; y < rows + 1; y++)
    72.                 {
    73.                     //Choose a random tile from our array of floor tile prefabs and prepare to instantiate it.
    74.                     GameObject toInstantiate = floorTiles[Random.Range (0,floorTiles.Length)];
    75.                  
    76.                     //Check if we current position is at board edge, if so choose a random outer wall prefab from our array of outer wall tiles.
    77.                     if(x == -1 || x == columns || y == -1 || y == rows)
    78.                         toInstantiate = outerWallTiles [Random.Range (0, outerWallTiles.Length)];
    79.                  
    80.                     //Instantiate the GameObject instance using the prefab chosen for toInstantiate at the Vector3 corresponding to current grid position in loop, cast it to GameObject.
    81.                     GameObject instance =
    82.                         Instantiate (toInstantiate, new Vector3 (x, y, 0f), Quaternion.identity) as GameObject;
    83.                  
    84.                     //Set the parent of our newly instantiated object instance to boardHolder, this is just organizational to avoid cluttering hierarchy.
    85.                     instance.transform.SetParent (boardHolder);
    86.                 }
    87.             }
    88.         }
    89.      
    90.      
    91.         //RandomPosition returns a random position from our list gridPositions.
    92.         Vector3 RandomPosition ()
    93.         {
    94.             //Declare an integer randomIndex, set it's value to a random number between 0 and the count of items in our List gridPositions.
    95.             int randomIndex = Random.Range (0, gridPositions.Count);
    96.          
    97.             //Declare a variable of type Vector3 called randomPosition, set it's value to the entry at randomIndex from our List gridPositions.
    98.             Vector3 randomPosition = gridPositions[randomIndex];
    99.          
    100.             //Remove the entry at randomIndex from the list so that it can't be re-used.
    101.             gridPositions.RemoveAt (randomIndex);
    102.          
    103.             //Return the randomly selected Vector3 position.
    104.             return randomPosition;
    105.         }
    106.      
    107.      
    108.         //LayoutObjectAtRandom accepts an array of game objects to choose from along with a minimum and maximum range for the number of objects to create.
    109.         void LayoutObjectAtRandom (GameObject[] tileArray, int minimum, int maximum)
    110.         {
    111.             //Choose a random number of objects to instantiate within the minimum and maximum limits
    112.             int objectCount = Random.Range (minimum, maximum+1);
    113.          
    114.             //Instantiate objects until the randomly chosen limit objectCount is reached
    115.             for(int i = 0; i < objectCount; i++)
    116.             {
    117.                 //Choose a position for randomPosition by getting a random position from our list of available Vector3s stored in gridPosition
    118.                 Vector3 randomPosition = RandomPosition();
    119.              
    120.                 //Choose a random tile from tileArray and assign it to tileChoice
    121.                 GameObject tileChoice = tileArray[Random.Range (0, tileArray.Length)];
    122.              
    123.                 //Instantiate tileChoice at the position returned by RandomPosition with no change in rotation
    124.                 Instantiate(tileChoice, randomPosition, Quaternion.identity);
    125.             }
    126.         }
    127.      
    128.      
    129.         //SetupScene initializes our level and calls the previous functions to lay out the game board
    130.         public void SetupScene (int level)
    131.         {
    132.             //Creates the outer walls and floor.
    133.             BoardSetup ();
    134.          
    135.             //Reset our list of gridpositions.
    136.             InitialiseList ();
    137.          
    138.             //Instantiate a random number of wall tiles based on minimum and maximum, at randomized positions.
    139.             LayoutObjectAtRandom (wallTiles, wallCount.minimum, wallCount.maximum);
    140.          
    141.             //Instantiate a random number of food tiles based on minimum and maximum, at randomized positions.
    142.             LayoutObjectAtRandom (foodTiles, foodCount.minimum, foodCount.maximum);
    143.          
    144.             //Determine number of enemies based on current level number, based on a logarithmic progression
    145.             int enemyCount = (int)Mathf.Log(level, 2f);
    146.          
    147.             //Instantiate a random number of enemies based on minimum and maximum, at randomized positions.
    148.             LayoutObjectAtRandom (enemyTiles, enemyCount, enemyCount);
    149.          
    150.             //Instantiate the exit tile in the upper right hand corner of our game board
    151.             Instantiate (exit, new Vector3 (columns - 1, rows - 1, 0f), Quaternion.identity);
    152.         }
    153.     }
    154. }
     

    Attached Files:

  43. pwn_dhami

    pwn_dhami

    Joined:
    Sep 2, 2015
    Posts:
    5
    first thanks for concern my problem . Now i have develop whole game again bcz some errors . the game works nicely ,but when i add a canvas (text,image) to it ,when i play the game, game board in the game view is not display only the thing is displayed is Food: 100 (which i set in the text). what can i do please sujjest me .
     
  44. Krowek

    Krowek

    Joined:
    Sep 10, 2015
    Posts:
    1
    Hi, I have a problem with part 5, I don't wona using lvl Generator, and if I design manually lvl and off script BoardManager my character walk in place. How to fix that.?
    PS. It's my first tutorial and i can't programing.
     
  45. Matthew-Schell

    Matthew-Schell

    Joined:
    Oct 1, 2014
    Posts:
    238
    If hitComponent is returning null I'd double check your raycasting. hit.transform in your debug at 57 is returning something? It may be that the thing it's hitting doesn't have the appropriate component (wall) attached? Make sure in Player when you're calling wall you're calling it this way as well:

    Code (CSharp):
    1. AttemptMove<Wall> (horizontal, vertical);
     
  46. Matthew-Schell

    Matthew-Schell

    Joined:
    Oct 1, 2014
    Posts:
    238
    Check your scene setup against the finished scene / prefabs in the Completed folder, make sure you have appropriate scripts attached to the GameManager prefab.
     
  47. Matthew-Schell

    Matthew-Schell

    Joined:
    Oct 1, 2014
    Posts:
    238
    The error you're getting means you are trying to do something with a variable which is still null, has nothing assigned. In this case it seems like your GameManager.instance is null, meaning that the GameManager has not been instantiated in the scene by Loader. If the problem started when you began setting up UI it's also possible that the Food Text variable has not been assigned in the player script. Double check the finished scene Main in the folder Completed to compare the Player inspector to your own.
     
  48. Matthew-Schell

    Matthew-Schell

    Joined:
    Oct 1, 2014
    Posts:
    238

    If you are going to copy and paste the whole scripts you should just use the finished ones in the Completed folder. They have comments you can read to understand what they do. The reason you are getting errors is because you have two scripts with the same name in the same namespace: Completed.
     
  49. Matthew-Schell

    Matthew-Schell

    Joined:
    Oct 1, 2014
    Posts:
    238
    The issue is probably related to the order the objects are in in the hierarchy, make sure that your canvas matches the configuration of the canvas in the Main scene in Completed > Scenes. Or it's possible that the LevelImage is somehow not being deactivated when it should, after the level is setup.
     
  50. Matthew-Schell

    Matthew-Schell

    Joined:
    Oct 1, 2014
    Posts:
    238
    This is not a good tutorial for a first time programmer, it's intermediate level. Please start with Roll A Ball on the learn site to learn the basics, then do Space Shooter or Survival Shooter, then come back. Also I am answering questions related to people trying to complete the project as is. If you want to do something else, that's up to you to figure out.
     
Thread Status:
Not open for further replies.