Search Unity

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. OboShape

    OboShape

    Joined:
    Feb 17, 2014
    Posts:
    836
    hi @yuvalk
    just thought i would drop a note till Matt gets to you :)

    the xDir and yDir are the input movements where the player is needing to get to, on its own these are just input variables and within this context are stored in the end vector2 variable and are not acted upon, until checks are done, then they can be applied with the smoothmovement(end) coroutine.

    so it takes the players current transform, then checks to see if the end position (ie the xDir and yDir based on input) are hitting anything.
    if it hits something it returns null and does nothing, if the proposed input doesnt hit anything, then the player can move and starts the smoothmovement(end) coroutine which actually moves the player.

    just a way of saying, "hey you want to go here, ill just check to see if where you want to go to is valid before i actually move you..."

    thats my understanding anyhoo :)

    for anyone reading here is the implementation
    Code (CSharp):
    1.     protected bool Move(int xDir, int yDir, out RaycastHit2D hit)
    2.     {
    3.         Vector2 start = transform.position;
    4.         Vector2 end = start + new Vector2 (xDir, yDir);
    5.  
    6.         boxCollider.enabled = false;
    7.         hit = Physics2D.Linecast(start, end, blockingLayer);
    8.         boxCollider.enabled = true;
    9.  
    10.         if(hit.transform == null)
    11.         {
    12.             StartCoroutine(SmoothMovement(end));
    13.             return true;
    14.         }
    15.         return false;
    16.     }
     
  2. eL_Jay

    eL_Jay

    Joined:
    Nov 27, 2013
    Posts:
    7
    Fixed
    I solved the problem. it was a really dumb mistake of mine.
    I tried adding the GameManager SCRIPT to the Loader Script instead of the PREFAB!
    Adding the prefab and using a legit script solved the troubles.


    Relating to tutorial 5:
    I keep getting an CS0103 error in the Loader script. Saying the GameManager isn't available, even though I've made it public in the gamemanager script:

    GameManager Script:
    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.  
    8.     public class GameManager : MonoBehaviour
    9.     {
    10.  
    11.         public static GameManager instance = null;              //Static instance of GameManager which allows it to be accessed by any other script.
    12.         private BoardManager boardScript;                       //Store a reference to our BoardManager which will set up the level.
    13.         private int level = 3;                                  //Current level number, expressed in game as "Day 1".
    14.  
    15.         //Awake is always called before any Start functions
    16.         void Awake()
    17.         {
    18.             //Check if instance already exists
    19.             if (instance == null)
    20.              
    21.                 //if not, set instance to this
    22.                 instance = this;
    23.          
    24.             //If instance already exists and it's not this:
    25.             else if (instance != this)
    26.              
    27.                 //Then destroy this. This enforces our singleton pattern, meaning there can only ever be one instance of a GameManager.
    28.                 Destroy(gameObject);
    29.          
    30.             //Sets this to not be destroyed when reloading scene
    31.             DontDestroyOnLoad(gameObject);
    32.          
    33.             //Get a component reference to the attached BoardManager script
    34.             boardScript = GetComponent<BoardManager>();
    35.          
    36.             //Call the InitGame function to initialize the first level
    37.             InitGame();
    38.         }
    39.      
    40.         //Initializes the game for each level.
    41.         void InitGame()
    42.         {
    43.             //Call the SetupScene function of the BoardManager script, pass it current level number.
    44.             boardScript.SetupScene(level);
    45.          
    46.         }
    47.      
    48.      
    49.      
    50.         //Update is called every frame.
    51.         void Update()
    52.         {
    53.          
    54.         }
    55. }
    56. }
    Loader1:
    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. namespace Completed
    5. {
    6.     public class Loader : MonoBehaviour {
    7.  
    8.         public GameObject gameManager;
    9.         // Use this for initialization
    10.         void Awake () {
    11.         if ( GameManager.instance == null)
    12.             Instantiate(gameManager);
    13.         }
    14.     }
    15. }
    Loader 2: (without namespace)
    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4.  
    5.     public class Loader : MonoBehaviour {
    6.  
    7.         public GameObject gameManager;
    8.         // Use this for initialization
    9.         void Awake () {
    10.         if ( GameManager.instance == null)
    11.             Instantiate(gameManager);
    12.         }
    13.      
    14.         // Update is called once per frame
    15.         void Update () {
    16.      
    17.         }
    18.  
    19. }
    Both Loader scripts give errors refering to variabels that aren't available.
     
    Last edited: Apr 13, 2015
  3. OboShape

    OboShape

    Joined:
    Feb 17, 2014
    Posts:
    836
    in your loader script is the GameManager in the IF statement red?
    if it is, when you right click on it does the contextual menu give an option to resolve?
     
  4. Adam-Buckner

    Adam-Buckner

    Joined:
    Jun 27, 2007
    Posts:
    5,664
    Thanks again @OboShape! Matt's had a few very well deserved days off, but I'm sure he'll be here with bells on when he's back.
     
  5. Matthew-Schell

    Matthew-Schell

    Joined:
    Oct 1, 2014
    Posts:
    238
    Check out the docs for Vector3.MoveTowards here:

    http://docs.unity3d.com/ScriptReference/Vector3.MoveTowards.html

    What's happening is that each frame we're moving part of the distance between rb2d.position and end, and we're assigning new position to that intermediate point as the movment happens. We're creating a reciprocal because it's computationally cheaper / more efficient. Hope that helps!
     
  6. Matthew-Schell

    Matthew-Schell

    Joined:
    Oct 1, 2014
    Posts:
    238
    My guess is that you are writing a variable in MonoDevelop but not changing it in the inspector. The value in the inspector for a public variable will always overwrite the default value in the script.
     
  7. Matthew-Schell

    Matthew-Schell

    Joined:
    Oct 1, 2014
    Posts:
    238
    If you're getting that error you're probably trying to instantiate a gameobject you haven't assigned in the editor. Make sure all your prefabs are assigned in the variable slots in the inspector.
     
  8. Matthew-Schell

    Matthew-Schell

    Joined:
    Oct 1, 2014
    Posts:
    238
    No this won't cause the player to move twice because we're just calling Move to get the return type (a bool) which tells us if it's POSSIBLE to move.
     
  9. Matthew-Schell

    Matthew-Schell

    Joined:
    Oct 1, 2014
    Posts:
    238
    @OboShape had a few weeks of travelling and running around, thanks for chiming in on the thread while I was away! Much appreciated.
     
    OboShape likes this.
  10. sfried

    sfried

    Joined:
    Apr 4, 2015
    Posts:
    3
    Do I have to learn C# in order to progress through the tutorial?
     
  11. Matthew-Schell

    Matthew-Schell

    Joined:
    Oct 1, 2014
    Posts:
    238
    Yes, you should know basic C#. This is an intermediate level tutorial. I'd take a look at either Roll A Ball or Survival Shooter projects for a more entry level starting point. And I would point out that your expectation of learning C# in an hour is not very realistic. Even passively watching one of these projects without following any of the steps will take more time than that. If you're passionate about learning to make games you should plan to be learning and researching constantly as you develop your skills over time. It's an absolutely key part of the process that takes time and energy. And it's fun!
     
  12. AndyKerrison

    AndyKerrison

    Joined:
    Apr 17, 2015
    Posts:
    2
    Firstly, awesome tutorial! I've been programming for many years but have done very little with games and none with Unity, so this was the perfect introduction for me.

    But also:
    No, I think he is right. I've checked it in the debugger... in Move() the line that calls StartCoroutine(SmoothMovement) will get called twice, the first time from doing AttemptMove and then again from the actual move. Comment out the conditional that triggers the movement sound in the player script, or the call to attempt move, and either way you still move once.

    From the looks of it the reason it doesn't move you twice is that transform.position is still the same by the time the second call is made, so you just get two calls to go 1 place away from the same point.

    Also you asked if anyone had suggestions to get around the movetime limit and possibility of players/enemies moving into each others squares... I think this could be done by generating all the movement destinations in one step, and then cross referencing them against each other. Then you can generate an alternative move for any 'clashes' before finally triggering all the movements simultaneously. Will add some complexity though.
     
  13. Matthew-Schell

    Matthew-Schell

    Joined:
    Oct 1, 2014
    Posts:
    238
    Glad to hear the tut was helpful! You may be right, I added that line to trigger the sound late in the project. I'll have to have a look back over it. I did originally do something like what you suggested but it was indeed a little complex and was thought somewhat 'un-Unity-like' by the others on the team :) And therefore maybe not the best example for teaching.
     
  14. Yardi93

    Yardi93

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

    awillshire

    Joined:
    Apr 29, 2014
    Posts:
    20
    Hi All,

    I've worked through the complete tutorial (fantastic btw!) and it seems to be working fine. I have noticed however a slight glitch that I must have introduced. After moving the character for an extended period, the character sprite gets progressively out of sync with the background tiles. It seems like it happens a pixel at a time, and I'll be darned if I can't find out where I've made the fubar. Before I go pasting code willy nilly, I thought I'd ask if anybody had seen anything similar, or if they might have a suggestion about where I should focus my efforts to resolve. Thanks in advance!

    Cheers,
    Andrew.
     
  16. Matthew-Schell

    Matthew-Schell

    Joined:
    Oct 1, 2014
    Posts:
    238
    If you're copying and pasting the completed scripts you might as well just use the ones in the completed folder. I doubt you'll learn as much but that's up to you. What happening is by copying and pasting and creating a new script you now have two copies of those classes, because they are already in that project in the completed folder. If you notice in the videos none of the scripts you're supposed to type out contain the code namespace Completed{}

    Either remove that line (and the closing bracket for it at the bottom of the script) or just use the scripts in the completed folder.
     
  17. Matthew-Schell

    Matthew-Schell

    Joined:
    Oct 1, 2014
    Posts:
    238
    Hmmm I haven't seen this error. Can you make sure your character's rigidbody is set to isKinematic? It may be that there's some renegade physics stuff going on.
     
  18. Desoxi

    Desoxi

    Joined:
    Apr 12, 2015
    Posts:
    195
    Hi, i do get these errors when trying two things:

    1. Running against the outer walls

    NullReferenceException: Object reference not set to an instance of an object
    Player.OnCantMove[Wall] (.Wall component) (at Assets/Scripts/Player.cs:63)
    MovingObject.AttemptMove[Wall] (Int32 xDir, Int32 yDir) (at Assets/Scripts/MovingObject.cs:77)
    Player.AttemptMove[Wall] (Int32 xDir, Int32 yDir) (at Assets/Scripts/Player.cs:52)
    Player.Update () (at Assets/Scripts/Player.cs:44)

    2. Enemy runs against the inner walls

    NullReferenceException: Object reference not set to an instance of an object
    Enemy.OnCantMove[Player] (.Player component) (at Assets/Scripts/Enemy.cs:54)
    MovingObject.AttemptMove[Player] (Int32 xDir, Int32 yDir) (at Assets/Scripts/MovingObject.cs:77)
    Enemy.AttemptMove[Player] (Int32 xDir, Int32 yDir) (at Assets/Scripts/Enemy.cs:29)
    Enemy.MoveEnemy () (at Assets/Scripts/Enemy.cs:47)

    When the first error occurs, the game continues, but when the second error occurs, where the enemy is running against an inner wall i cant move the player anymore. But you can see that the animations are still working (idle).

    Im trying to figure out why this is happening but cant find anything else than the "OnCantMove" method is just working on one Object. For example:

    The enemy OnCantMove method says this:
    Code (CSharp):
    1. protected override void OnCantMove<T>(T component)
    2.     {
    3.         anim.SetTrigger("enemyAttack");
    4.         Player hitPlayer = component as Player;
    5.         hitPlayer.LoseFood(playerDamage);
    6.     }
    Why is there a cast to "Player"? What if the obstacle is an inner wall? Then it casts the inner wall to a player object...? The same goes for the player OnCantMove method:

    Code (CSharp):
    1. protected override void OnCantMove<T>(T component)
    2.     {
    3.         Wall hitWall = component as Wall;
    4.         hitWall.DamageWall(wallDamage);
    5.         anim.SetTrigger("playerChop");
    6.     }
    I hope you can help me in solving this^^
    Im using Unity 5 btw.
     
  19. Desoxi

    Desoxi

    Joined:
    Apr 12, 2015
    Posts:
    195
    Okay i solved it! And sorry for the double post!

    In my MovingObject class the AttemptMove method was wrong:

    Code (CSharp):
    1. protected virtual void AttemptMove<T>(int xDir, int yDir)
    2.         where T : Component
    3.     {
    4.         RaycastHit2D hit;
    5.  
    6.         bool canMove = Move(xDir, yDir, out hit);
    7.  
    8.         if (hit.transform == null)
    9.         {
    10.             return;
    11.         }
    12.  
    13.         T hitComponent = hit.transform.GetComponent<T>();
    14.  
    15.         if (!canMove && hit.transform != null)
    16.         {
    17.             OnCantMove(hitComponent);
    18.         }
    19.     }
    Instead of "if (!canMove && hit.transform != null)" it had to be "if (!canMove && hitComponent != null)".
    Well, what i still do not understand is, why that leads to the errors i got? Arent they both true/false at the same time when something is hit? And it both had the line "OnCantMove(hitComponent);" in there... :/


    EDIT:

    Okay solved this too... It is because in the Player class -> Update() we call the method like this:
    AttemptMove<Wall>(horizontal, vertical);
    And because we give the generic param "Wall", T hitComponent = hit.transform.GetComponent<T>(); can only get a Wall Component and otherwise its is null. So, although "hit.transform" is not null, the component "hitComponent" we give on to "OnCantMove(hitComponent) is null... which leads to this annoying error.
     
    Last edited: Apr 24, 2015
  20. awillshire

    awillshire

    Joined:
    Apr 29, 2014
    Posts:
    20
    Hi Matt,
    Thanks very much for the advice! I do have it set to isKinematic, so that's not it. Maybe I'll just work through the tute again from scratch, that always helps bed down the concepts. I always type in everything (instead of cut/paste), so I've obviously glitched something :).
    Cheers,
    Andrew.
     
  21. Kaziarl

    Kaziarl

    Joined:
    Apr 23, 2015
    Posts:
    10
    Howdy.

    On video #5; Writing the Game Manager, the map, items, and exit all spawn in correctly. However, while an enemy does spawn in (as can be seen in the hierarchy) it's not visible. I've double checked the code in this video, compared it to the example code provided on the page, and gone back to the video that talked about making the enemy prefabs, and everything seems to be correct. Any idea on where I can look for the problem?
     
  22. Pequisto

    Pequisto

    Joined:
    Apr 21, 2015
    Posts:
    66
    Excellent tutorial, Matt! (I am also a fan of NQ but that seems like a lifetime away now, doesn't it?)
     
  23. pvqr

    pvqr

    Joined:
    Apr 27, 2015
    Posts:
    38
    Awesome Tutorial!
    I"ve been developing a 3D game using Unity for a while now, but I never tried 2D before. This tutorial is very good for those who already know C# and are comfortable with Unity Engine.

    I'd love to see a 2D procedural dungeon generator tutorial made by you. I've read the comments in this forum post and found very useful links, I'll try to implement my own for now.

    If you ever make a 2D P.D.G. tutorial please let me know!
    Thanks for sharing your knowledge.
     
  24. moosecanoes

    moosecanoes

    Joined:
    Apr 27, 2015
    Posts:
    1
    Doing the project, but when I load "Loader.cs" into my Camera, it hangs and memory leaks until i force quit. The completed scene works fine. I checked all the code... so what am I missing?

    Specifically, my BoardManager.cs has a memory leak.

    I just replaced my methods in BoardManager with the complete one... something was wrong but I have no clue what it was.

    Unity ain't easy kids.
     
    Last edited: Apr 27, 2015
  25. pvqr

    pvqr

    Joined:
    Apr 27, 2015
    Posts:
    38
    Hei man, did you find another way to use a 2D collider on the player without override the current one? I'm having problems implementing some stuff because I need the 2D collider bigger, but I just can't use it, it triggers the food/exit.. etc.
     
  26. Matthew-Schell

    Matthew-Schell

    Joined:
    Oct 1, 2014
    Posts:
    238
    hey @Kaziarl can you check the sprite sorting layer on the enemies against the videos? Also make sure that the animation is set up correctly. Other than that I'm not sure.
     
  27. Matthew-Schell

    Matthew-Schell

    Joined:
    Oct 1, 2014
    Posts:
    238
    Glad you liked the tut and thanks for checking out NQ!

    I just released a NewbQuest episode a few weeks ago with Steve Swink actually. I'm trying to keep the show going but have been super busy so it was on hiatus for a while. There'll be more episodes soon, though probably not as often. For those wondering it's my youtube / podcast show interviewing game devs, both well known and newcomers, over at http://www.newbquest.com/
     
    Pequisto likes this.
  28. Matthew-Schell

    Matthew-Schell

    Joined:
    Oct 1, 2014
    Posts:
    238
    You can add another collider on a child object, maybe set it to a different layer? You can manage what layers collide with what under edit > project settings > 2d physics. I'd try to set it up so it only collides with the things you want it to using layers.

    As far as a procedural dungeon generator this is definitely a topic I'm interested in. I need to figure out if I can boil it down so it's not too long or advanced. I actually got a very simple version going based on the Nuclear Throne approach linked earlier in this thread, I might do a thing on that when I get some time.
     
  29. Kaziarl

    Kaziarl

    Joined:
    Apr 23, 2015
    Posts:
    10
    I managed to figure it out. Looks like something got messed up with the animation controllers, so they weren't displaying the sprites like they should. I rebuilt them from scratch and got it working though, so all is good.
     
  30. pvqr

    pvqr

    Joined:
    Apr 27, 2015
    Posts:
    38
    Thanks for the answer, I figured it out. I'm using the distance to compare if player is on screen or not, but I'll definitely check out the layers. If someone's having problems with the time taking for each turn when having lots of enemies on a big map, you can scan enemies close to you and update only those, it's playable until 6- enemies, then it gets really slow.

    I'm struggling with another problem now that I can't find the solution.. my game has a chance to spawn items after you destroy a wall, but the current mechanics are 'check if can move, if not, hit a wall' when the wall dies the player automatically walks to the destoyed wall place. I want the player to destroy the wall and wait for another turn to walk again, otherwise he will walk into the item respawned without even having the possibility to don't pick it up. Can you help me on that since it's your mechanic you'll probably have a good solution.
     
  31. madamepriss

    madamepriss

    Joined:
    Mar 2, 2015
    Posts:
    6
    I looked through most of these and I couldn't find an answer, I hope this question has not been asked already.

    The tutorial is great! Learned a bunch. Everything worked great until I tried to play it on my phone. It showed up on my phone but I couldn't move.

    I did have one warning:

    Assets/Scripts/Player.cs(22,25): warning CS0414: The private field `Player.touchOrigin' is assigned but its value is never used

    Looked over everything and couldn't see an issue.

    Here is my code from player.cs:

    using UnityEngine;
    using System.Collections;
    using UnityEngine.UI;
    public class Player : MovingObject {
    public int wallDamage = 1;
    public int pointsPerFood = 10;
    public int pointsPerSoda = 20;
    public float restartLevelDelay = 1f;
    public Text foodText;
    public AudioClip moveSound1;
    public AudioClip moveSound2;
    public AudioClip eatSound1;
    public AudioClip eatSound2;
    public AudioClip drinkSound1;
    public AudioClip drinkSound2;
    public AudioClip gameOverSound;
    private Animator animator;
    private int food;
    private Vector2 touchOrigin = -Vector2.one;
    // Use this for initialization
    protected override void Start () {
    animator = GetComponent<Animator>();
    food = GameManager.instance.playerFoodPoints;
    foodText.text = "Food: " + food;
    base.Start ();

    }
    private void OnDisable()
    {
    GameManager.instance.playerFoodPoints = food;
    }

    // Update is called once per frame
    void Update () {
    if (!GameManager.instance.playersTurn)
    return;
    int horizontal = 0;
    int vertical = 0;
    #if UNITY_EDITOR || UNITY_STANDALONE || UNITY_WEBPLAYER
    horizontal = (int)Input.GetAxisRaw ("Horizontal");
    vertical = (int)Input.GetAxisRaw ("Vertical");
    if (horizontal != 0)
    vertical = 0;
    #elif UNITY_IOS || UNITY_ANDROID || UNITY_WP8 || UNITY_IPHONE
    if (Input.touchCount > 0 )
    {
    Touch myTouch = Input.touches[0];
    if (myTouch.phase == TouchPhase.Began)
    {
    touchOrgin = myTouch.position;
    }
    else if (myTouch.phase == TouchPhase.Ended && touchOrgin.x >=0)
    {
    Vector2 touchEnd = myTouch.position;
    float x = touchEnd.x - touchOrgin.x;
    float y = touchEnd.y - touchOrgin.y;
    touchOrgin.x = -1;
    if (Mathf.Abs(x) > Mathf.Abs(y))
    horizontal = x > 0 ? 1 : -1;
    else
    vertical = y > 0 ? 1 : -1;
    }
    }
    #endif

    if (horizontal != 0 || vertical != 0)
    AttemptMove<Wall> (horizontal, vertical);

    }
    protected override void AttemptMove <T>(int xDir, int yDir)
    {
    food--;
    foodText.text = "Food: " + food;
    base.AttemptMove <T> (xDir, yDir);
    RaycastHit2D hit;
    if (Move (xDir, yDir, out hit)) {

    SoundManager.instance.RandomizeSfx(moveSound1, moveSound2);
    }
    CheckIfGameOver ();
    GameManager.instance.playersTurn = false;
    }
    private void OnTriggerEnter2D (Collider2D other)
    {
    if (other.tag == "Exit") {
    Invoke ("Restart", restartLevelDelay);
    enabled = false;
    } else if (other.tag == "Food") {
    food += pointsPerFood;
    foodText.text = "+" + pointsPerFood + " Food: " + food;
    SoundManager.instance.RandomizeSfx(eatSound1, eatSound2);
    other.gameObject.SetActive (false);
    } else if (other.tag == "Soda") {
    food += pointsPerSoda;
    foodText.text = "+" + pointsPerSoda + " Food: " + food;
    SoundManager.instance.RandomizeSfx(drinkSound1, drinkSound2);
    other.gameObject.SetActive(false);
    }
    }

    protected override void OnCantMove <T> (T component)
    {
    Wall hitWall = component as Wall;
    hitWall.DamageWall (wallDamage);
    animator.SetTrigger ("playerChop");
    }
    private void Restart()
    {
    Application.LoadLevel (Application.loadedLevel);
    }
    public void LoseFood (int loss)
    {
    animator.SetTrigger ("playerHit");
    food -= loss;
    foodText.text = "-" + loss + " Food: " + food;
    CheckIfGameOver ();
    }

    private void CheckIfGameOver()
    {
    if (food <= 0)
    {
    SoundManager.instance.PlaySingle(gameOverSound);
    SoundManager.instance.musicSource.Stop ();
    GameManager.instance.GameOver ();
    }
    }
    }
     
  32. Nimue

    Nimue

    Joined:
    Apr 27, 2015
    Posts:
    6
    I'm enjoying this tutorial a lot, it's helping me learn about the Unity interface and my C# all at the same time. Learning by doing works best for me :) I'm having a problem where when I run the game I can move the player once and that's it. I just finished part 11. Is there something in the rest of the tutorial that will fix this or is it a problem I'm missing from earlier? I've already been through my scripts with a fine toothed comb, since I type everything manually. I saw someone else had this issue in an earlier post and fixed it by resetting the transform on the player, but mine's already at 0,0,0. Any suggestions?
     
  33. Desoxi

    Desoxi

    Joined:
    Apr 12, 2015
    Posts:
    195
    Hey, did you check the playersTurn bool variable in GameManager? Maybe it remains "false" which would lead to that issue^^
    Which variables are getting checked in the Update() of your GameManager?
     
  34. Desoxi

    Desoxi

    Joined:
    Apr 12, 2015
    Posts:
    195
    Hey i have an issue too:
    The problem is, that you are still able to move one move after your food value is <=0.
    I checked the order in which the methods are getting executed etc. with Debug.Log and the coroutine in the GameManager seems to set it always to true when it is over, which normally is ok. But not when you get below 0. It happens because you drop below 0 in the middle of the coroutine. The GameisOver check is getting called at the end of the coroutine..
    Is there an elegant way to work around this? I would create a public bool gameIsOver in the GameManager which can be modified trough the LoseFood() Method in the Player Class which sets it to true when you drop below 0.
    But maybe you know a better way?

    Here is the call Order:

    upload_2015-5-2_14-6-4.png

    EDIT:
    Okay sorry, i already found a more or less good solution.
    In the CheckIfGameOver() method is just added the line "enabled = false" which disables the whole Player script i guess..?
    Code (CSharp):
    1. private void CheckIfGameOver()
    2.     {
    3.         if (food <= 0)
    4.         {
    5.             enabled = false;
    6.             GameManager.instance.playersTurn = false;
    7.             GameManager.instance.GameOver();
    8.         }
    9.     }
    And it works, altough the playersTurn variable still gets set to true at the end of the game.
     
    Last edited: May 2, 2015
  35. Maraku Mure

    Maraku Mure

    Joined:
    May 2, 2015
    Posts:
    28
    Hi guys I'm at the 12th part (http://unity3d.com/learn/tutorials/projects/2d-roguelike/ui-levels) about UI and screen fading between two game levels.

    I wrote the code correctly but, dunno why,...when I execute the project I got some problems...

    First I get a lot of notice "The referenced script on this Behaviour is missing!" and then I got two errors: "GameObject (named 'LevelText') references runtime script in scene file. Fixing!"
    GameObject (named 'LevelImage') references runtime script in scene file. Fixing!"

    I don't know what to do...further more I don't even know what is missing! :(
    I tried to googling the problem but I couldn't find any useful answer about this problem...

    Could someone help me?
     
  36. Desoxi

    Desoxi

    Joined:
    Apr 12, 2015
    Posts:
    195
    Hm, did you move the script into another folder after adding it to the game object?
    I would remove the script component which isnt working and add it again^^
     
  37. OboShape

    OboShape

    Joined:
    Feb 17, 2014
    Posts:
    836
    one thing i would double check, that within the gamemanager script, check the InitGame() function.

    when setting the LevelImage and LevelText variables, on the GameObject.Find() make sure that whatever is in quotes, like "LevelImage" or "LevelText" it is the exact same name and case as the name of the objects in your UI Heirarchy.

    if you can double check those see if they match up.

    one other thing would be to pause the game at runtime, if you can, then check all the items in the heirarchy as in the inspector you may see a yellow warning stating that a script is missing.
    this could be something like a script name doesnt match exactly with the name of the class in that script, these both have to be the same.
     
  38. Maraku Mure

    Maraku Mure

    Joined:
    May 2, 2015
    Posts:
    28
    Thank you guys for your replies,
    anyway...no I didn't move anything, further I got these errors only after using the UI stuff...I tried to close and reopen the project and scene and I get an error in the inspector about UI objects like this http://prntscr.com/70pnhd

    P.s.
    I even tried to delete the two objects and to recreate them....

    P.p.s
    Now I deleted the two items and commented all the scripts related to them. I got always the warning but the game can run...and the FoodText item (always an UI item) works perfectly...
     
  39. OboShape

    OboShape

    Joined:
    Feb 17, 2014
    Posts:
    836
    If the errors you are getting are the same as the picture you supplied. this means that there is no script associated with this component its lost its way somewhere along the line. you can do either of the following to resolve;

    remove LevelText game object from the heirarch, then right click your Canvas > UI > Text. this will create a new child text object, which you will have to rename back from 'Text' to 'LevelText'.

    or, in the inspector, when your LevelText gameobject is highlighted. you can click the gear icon on the right (for the one that states the script is missing), and select remove component.
    you can then add a new UI text component back onto this object, by clicking the 'Add Component' > UI > Text.

    doing either of these will mean you have to set all the properties of them again, like font color, text, truncation etc ....

    see how that goes.

    [edit] just read that again sorry..
    so even when you recreate the UI element this script component is missing all the time?

    ObO
     
  40. GrizzlySol

    GrizzlySol

    Joined:
    May 17, 2013
    Posts:
    2
    Hey everyone
    I'm new to unity and I have been working through this tutorial and seem to be stuck on the levels portion.
    Every time a new level is created it seems to be creating more walls and enemies then it should. The first level plays fine but the second level has two enemies and too many food, soda and wall items.
    Then when I reach the 3rd level the level screen says its still day 2 and after trying to move my player dies. The game over screen reads that I died on day 5. Also, my food score at the bottom reads as 0.

    I know other people have had this problem earlier in the thread but their solutions don't seem to be working for me. Any help would be awesome.
    Thanks!
     
  41. Important Business

    Important Business

    Joined:
    Apr 4, 2015
    Posts:
    16
    Hello, just started doing the 2D roguelike, and I am on part 5.

    Question; Why doesnt the loader script work for me? I copy this into the script, but when I drag it into the main camera, it says there are still errors.

    The download for my script is below. Please tell me what I did wrong!
     

    Attached Files:

  42. OboShape

    OboShape

    Joined:
    Feb 17, 2014
    Posts:
    836
    Afternoon :)
    if you dont mind can i make a couple of suggestions. just to make it easier for folk to read your code, if you could post the code using the code tags, just in case people dont like downloading files. another one, if you get errors coming up, it would be great if you could post them too, as this will give a bit of direction as to what is to be looked at.

    ive posted your code here.

    Code (CSharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4.  
    5. public class Loader : MonoBehaviour
    6. {
    7. public GameObject gameManager;
    8.     void Awake ()
    9.     {
    10.       if (gameManager.instance == null)    
    11.              Instantiate (gameManager);
    12. }
    13. }
    line 10 should read the following instead.
    Code (CSharp):
    1. if (GameManager.instance == null)  
    GameManager is a reference to the static class, which we need to look to check for an instance.
    gameManager in this script refers to the gamemanager prefab that you dragged to the inspector slot.

    I've been caught out so many times with my cAsE sensitivity :)

    see how that goes, fingers crossed that gets it resolved for you and you can progress with the tute ;)

    ObO
     
    Last edited: May 8, 2015
  43. OboShape

    OboShape

    Joined:
    Feb 17, 2014
    Posts:
    836
    hi @madamepriss,
    just as a thought not tried it on mobile as yet myself, but just a couple of ideas to check and see.
    are you are getting any input touches registering at all? what Mobile type are you running this on?

    where you have the following code.
    Code (CSharp):
    1. #elif UNITY_IOS || UNITY_ANDROID || UNITY_WP8 || UNITY_IPHONE
    2. if (Input.touchCount > 0 )
    3. {
    if you try to change this to
    Code (CSharp):
    1. #elif UNITY_IOS || UNITY_ANDROID || UNITY_WP8 || UNITY_IPHONE
    2. Debug.Log ("Do i get to here?");
    3. Debug.Log ("Input Touches registering : " + Input.touchCount);
    4. if (Input.touchCount > 0 )
    5. {
    just a thought, that way you can see if you are getting to run the right preprocessor for your platform, and see if you are getting any touches registered.
     
    Last edited: May 4, 2015
  44. Maraku Mure

    Maraku Mure

    Joined:
    May 2, 2015
    Posts:
    28
    Ok I go step by step...

    - If there is only the FoodText the game works but it always gives me this warning (it appears 8 times)

    The referenced script on this Behaviour is missing!

    -
    If I add the LevelImage (the are the properties and the "script" on the item) http://prntscr.com/71cbgz
    The game works but I get always the 8 warning about the referenced script missing.

    - If I add the Text item without uncommenting the script related to the object, I get 15 warnings (the same above) plus an error
    GameObject (named 'LevelText') references runtime script in scene file. Fixing!
    So due to my bad english I repeat, I only added the item in the game scene but the script does not contain any reference to the object...all declarations, all code parts are still commented.

    - If I save the project (and the scene) and reopen it the TextItem lose the properties script. http://prntscr.com/71cd02 as you can see in this image.

    I dunno what to do...
     
  45. Stoove

    Stoove

    Joined:
    Apr 16, 2015
    Posts:
    1
    Solved: Check the MainCamera has Loader.cs attached (I had GameManager.cs and BoardManager.cs attached instead; the gameManager prefab was not being instantiated).

    Hi there, I've been following along with the tutorial and I've arrived at Part 11, where the game begins to come together. When I implement the Enemy script's MoveEnemy() method, I get an interesting error which I can't track the source of:

    MissingReferenceException: The object of type 'Transform' has been destroyed but you are still trying to access it. Your script should either check if it is null or you should not destroy the object. UnityEngine.Transform.get_position () (at C:/buildslave/unity/build/artifacts/generated/common/runtime/UnityEngineTransform.gen.cs:28) Enemy.MoveEnemy () (at Assets/Scripts/Enemy.cs:42) GameManager+<MoveEnemies>c__Iterator3.MoveNext () (at Assets/Scripts/GameManager.cs:82)

    This occurs on the first Enemy movement turn in all levels after the first. The following line is flagged by the Console as the culprit;

    Code (CSharp):
    1. if (Mathf.Abs (target.position.x - transform.position.x) < float.Epsilon) {
    Which is part of the aforementioned method. I did a bit of digging, and it seems like the program is indeed trying to move an Enemy which has been deleted, hence its Transform no longer exists. The game works fine if I include the following code immediately before the offending line;

    Code (CSharp):
    1.         if (target == null || transform == null){
    2.             return;
    3.         }
    (No errors are returned and the game works fine). What baffles me is why there are Enemies registered in the List<Enemy> enemies which don't exist. I can double check this by inserting
    Code (CSharp):
    1. Debug.Log ("enemy moving cout = " + enemies.Count);
    inside the GameManager.MoveEnemies() method, which returns the value 1 on the first level and then 2 on the second level. However, there is only one GameObject of type Enemy in the Heirarchy in the second level! Note that I am ensuring to call enemies.Clear() before each initialization of a new level.

    My theory is that somehow the Enemy script from the previous level survives to re-register itself upon the level load (from Player.Restart(), which is shown below). This is causing the list enemies to contain references to objects which don't actually exist.

    Code (CSharp):
    1.     private void Restart () {
    2.         Application.LoadLevel(Application.loadedLevel);
    3.     }
    I would really appreciate it if anyone can suggest some ways for me to check what is happening [please be gentle - I'm only just starting with Object Oriented programming styles and have about a week's experience with C#]. If anyone has seen this type of error previously, or can indicate a possible reason in my code that the Enemy scripts are not being properly cleaned up, I would appreciate the help.

    Finally, I attach the code I have written for my version of the project. I've done my best to check that it matches the code given in the Completed folder, and I am unable to find any substantial differences. [Please excuse any commented code which doesn't make sense - I've been playing around with my own solutions to this problem which ended up being interesting but useless.]

    GameManager.cs
    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4.  
    5. public class GameManager : MonoBehaviour {
    6.  
    7.     public static GameManager instance = null;
    8.     public BoardManager boardScript; // reference to BoardManager script
    9.     public float turnDelay = 0.1f;
    10.  
    11.  
    12.     public int playerFoodPoints = 100;
    13.     [HideInInspector] public bool playersTurn = true;
    14.  
    15.  
    16.     private int level = 3;
    17.     private List<Enemy> enemies;
    18.     private bool enemiesMoving;
    19.  
    20.     // Use this for initialization
    21.     void Awake () {
    22.  
    23.  
    24.  
    25.         if (instance == null) {
    26.             instance = this;
    27.         } else if (instance != this) {
    28.             Destroy (gameObject);
    29.         }
    30.  
    31.         DontDestroyOnLoad (gameObject);
    32.         enemies = new List<Enemy>();
    33.         boardScript = GetComponent <BoardManager> ();
    34. //        enemies.Clear();
    35.         InitGame ();
    36.     }
    37.  
    38.     void InitGame () {
    39.  
    40. //        Debug.Log ("Removed " + enemies.Count + "enemies from list.");
    41.         enemies.Clear();
    42. //        StopCoroutine(MoveEnemies());
    43. //        Debug.Log("n.o. enemies at Init = " + enemies.Count);
    44.         boardScript.SetupScene (level);
    45. //        Debug.Log("n.o. enemies after Init = " + enemies.Count);
    46. //        enemies = GameObject.FindGameObjectsWithTag("Enemy");
    47.         Debug.Log ("Enemy count registered: " + enemies.Count);
    48.     }
    49.  
    50. //    void OnLevelWasLoaded() {
    51. //        InitGame();
    52. //    }
    53.  
    54.     public void GameOver () {
    55.         enabled = false;
    56.     }
    57.  
    58.     // Update is called once per frame
    59.     void Update () {
    60.         if (playersTurn || enemiesMoving) {
    61.             return;
    62.         }
    63. //        Debug.Log ("enemy moving cout = " + enemies.Count);
    64.         StartCoroutine(MoveEnemies());
    65.  
    66.     }
    67.  
    68.     public void AddEnemyToList(Enemy script) {
    69.         enemies.Add (script);
    70.  
    71.     }
    72.  
    73.     IEnumerator MoveEnemies () {
    74.         enemiesMoving = true;
    75.         yield return new WaitForSeconds(turnDelay);
    76.         if (enemies.Count == 0) {
    77.             yield return new WaitForSeconds(turnDelay);
    78.         }
    79.  
    80.         for (int i=0; i < enemies.Count; i++) {
    81. //            Debug.Log ("enemy moving cout = " + enemies.Count);
    82.             enemies[i].MoveEnemy();
    83.             yield return new WaitForSeconds(enemies[i].moveTime);
    84.  
    85.         }
    86.         playersTurn = true;
    87.         enemiesMoving = false;
    88.  
    89.  
    90.     }
    91.  
    92. }
    93.  
    BoardManager.cs
    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.         public int minimum;
    11.         public int maximum;
    12.  
    13.         public Count ( int min, int max ) {
    14.             minimum = min;
    15.             maximum = max;
    16.         }
    17.  
    18.     }
    19.  
    20.     public int columns = 8;
    21.     public int rows = 8;
    22.     public Count wallCount = new Count(5,9);
    23.     public Count foodCount = new Count(1,5);
    24.     public GameObject exit;
    25.     public GameObject player;
    26.     public GameObject[] floorTiles;
    27.     public GameObject[] wallTiles;
    28.     public GameObject[] foodTiles;
    29.     public GameObject[] enemyTiles;
    30.     public GameObject[] outerWallTiles;
    31.  
    32.     private Transform boardHolder;
    33.     private List <Vector3> gridPositions = new List<Vector3>();
    34.  
    35.     void InitializeList() {
    36.         gridPositions.Clear ();
    37.  
    38.         for (int x = 1; x < columns - 1; x++) {
    39.             for (int y = 1; y < rows - 1; y++) {
    40.                 gridPositions.Add(new Vector3(x, y, 0.0f ) );
    41.             }
    42.         }
    43.     }
    44.  
    45.     void BoardSetup() {
    46.         boardHolder = new GameObject ("Board").transform;
    47.         GameObject toInstantiate;
    48.  
    49.         // Build edge of board
    50.         for (int x = -1; x <= columns ; x++) {
    51.             for (int y = -1; y <= rows; y++) {
    52.                 // check for outer wall first, place those in edge col.s or rows
    53.                 if ( x==-1 || x==columns || y==-1 || y==rows ) {
    54.                     toInstantiate = outerWallTiles[Random.Range(0,outerWallTiles.Length)];
    55.                 }
    56.                 // otherwise it's floor, so instantiate a floor tile
    57.                 else {
    58.                     toInstantiate = floorTiles[Random.Range(0,floorTiles.Length)];
    59.                 }
    60.  
    61.                 GameObject instance = Instantiate(toInstantiate,new Vector3(x,y,0f),Quaternion.identity) as GameObject;
    62.                 instance.transform.SetParent(boardHolder);
    63.             }
    64.         }
    65.  
    66.     }
    67.  
    68.     Vector3 RandomPosition () {
    69.         int randomIndex = Random.Range (0, gridPositions.Count); // Count is a property of a list
    70.         Vector3 randomPosition = gridPositions[randomIndex];
    71.         gridPositions.RemoveAt (randomIndex); // Remove so can't add several
    72.  
    73.         return randomPosition;
    74.     }
    75.  
    76.     void LayoutObjectAtRandom (GameObject[] tileArray, int minimum, int maximum) {
    77.         int objectCount = Random.Range (minimum, maximum + 1);
    78.         for (int i = 0; i<objectCount; i++) {
    79.             Vector3 randomPosition = RandomPosition();
    80.             GameObject tileChoice = tileArray[Random.Range(0,tileArray.Length)];
    81.             Instantiate (tileChoice,randomPosition,Quaternion.identity);
    82.         }
    83.     }
    84.  
    85.     public void SetupScene(int level) {
    86.         BoardSetup ();
    87.         InitializeList ();
    88.         LayoutObjectAtRandom (wallTiles, wallCount.minimum, wallCount.maximum);
    89.         LayoutObjectAtRandom (foodTiles, foodCount.minimum, foodCount.maximum);
    90.         int enemyCount = (int)Mathf.Log (level, 2f);
    91. //        Instantiate (player, new Vector3 (0,0,0f),Quaternion.identity);
    92.         LayoutObjectAtRandom (enemyTiles, enemyCount, enemyCount);
    93.  
    94.         Instantiate (exit, new Vector3 (columns-1, rows-1, 0f), Quaternion.identity);
    95.     }
    96. }
    97.  
    MovingObject.cs
    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.     // Use this for initialization
    14.     protected virtual void Start () {
    15.         // can be overriden by inherited classes
    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; // implicitly discards z axis
    24.         Vector2 end = start + new Vector2 (xDir, yDir);
    25.  
    26.         boxCollider.enabled = false; // prevent the collider of the object from being hit by the linecast
    27.         // Ray2D castRay = Ray2D (start, Vector2 (xDir, yDir)); Don't need this in 2D
    28.         hit = Physics2D.Linecast (start, end, blockingLayer);
    29.         boxCollider.enabled = true;
    30.  
    31.         if (hit.transform == null) {
    32.             StartCoroutine (SmoothMovement (end));
    33.             return true;
    34.         } else {
    35.             return false;
    36.         }
    37.  
    38.     }
    39.  
    40.     protected IEnumerator SmoothMovement (Vector3 endPt) {
    41.         float sqrRemainingDistance = (transform.position - endPt).sqrMagnitude;
    42.         while (sqrRemainingDistance > float.Epsilon) {
    43.             Vector3 newPosition = Vector3.MoveTowards (rb2D.position,endPt,inverseMoveTime * Time.deltaTime); // only works for unitary distance changes
    44.             rb2D.MovePosition(newPosition);
    45.             sqrRemainingDistance = (newPosition-endPt).sqrMagnitude;
    46.             yield return null;
    47.         }
    48.     }
    49.  
    50.     protected virtual void AttemptMove <T> (int xDir, int yDir)
    51.         where T : Component // this is a generic parameter
    52.     {
    53.         RaycastHit2D hit;
    54.         bool canMove = Move (xDir, yDir, out hit);
    55.  
    56.         if (hit.transform == null) {
    57.             return;
    58.         }
    59.  
    60.         T hitComponent = hit.transform.GetComponent<T>();
    61.  
    62.         if (!canMove && hitComponent != null) {
    63.             OnCantMove(hitComponent);
    64.         }
    65.  
    66.  
    67.     }
    68.  
    69.     protected abstract void OnCantMove <T> (T component)
    70.         where T : Component;
    71.  
    72. }
    73.  
    Enemy.cs
    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class Enemy : MovingObject {
    5.  
    6.     public int playerDamage;
    7.  
    8.     private Animator animator;
    9.     private Transform target;
    10.     private bool skipMove;
    11.  
    12.     //private Transform tform;
    13.  
    14.     protected override void Start() {
    15.         //tform = GetComponent<Transform> ();
    16.         GameManager.instance.AddEnemyToList(this);
    17.         Debug.Log("Added enemy to list");
    18.         animator = GetComponent<Animator>();
    19.         target = GameObject.FindGameObjectWithTag("Player").transform;
    20.         base.Start();
    21.     }
    22.  
    23.     protected override void AttemptMove <T> (int xDir, int yDir) {
    24.         if (skipMove){
    25.             skipMove = false;
    26.             return;
    27.         }
    28.  
    29.         base.AttemptMove <T> (xDir, yDir);
    30.  
    31.         skipMove = true;
    32.  
    33.     }
    34.  
    35.     public void MoveEnemy () {
    36.         int xDir = 0;
    37.         int yDir = 0;
    38. //        target = GameObject.FindGameObjectWithTag("Player").transform;
    39. //        if (target == null || transform == null){
    40. //            return;
    41. //        }
    42.         if (Mathf.Abs (target.position.x - transform.position.x) < float.Epsilon) {
    43.             yDir = target.position.y > transform.position.y ? 1 : -1;
    44.         } else
    45.         {
    46.             xDir = target.position.x > transform.position.x ? 1 : -1;
    47.         }
    48.  
    49.         AttemptMove <Player> (xDir, yDir);
    50.  
    51.     }
    52.  
    53.     protected override void OnCantMove <T> (T component) {
    54.         Player hitPlayer = component as Player;
    55.         animator.SetTrigger("enemyAttack");
    56.         hitPlayer.LoseFood(playerDamage);
    57.  
    58.     }
    59.  
    60. }
    61.  
    Player.cs
    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class Player : MovingObject {
    5.  
    6.     public int wallDamage = 1;
    7.     public int pointsPerFood = 10;
    8.     public int pointsPerSoda = 20;
    9.     public float restartLevelDelay = 1f;
    10.  
    11.     private Animator animator;
    12.     private int food;
    13.  
    14.     // Use this for initialization
    15.     protected override void Start () {
    16.         animator = GetComponent<Animator> ();
    17.  
    18.         food = GameManager.instance.playerFoodPoints;
    19.  
    20.         base.Start ();
    21.     }
    22.  
    23.     private void OnDisable() {
    24.         GameManager.instance.playerFoodPoints = food;
    25.     }
    26.  
    27.     // Update is called once per frame
    28.     void Update () {
    29.         if (!GameManager.instance.playersTurn) {
    30.             return;
    31.         }
    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.  
    49.     protected override void AttemptMove <T> (int xDir, int yDir)
    50.     {
    51.         food--;
    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.         } else if (other.tag == "Food") {
    66.             food += pointsPerFood;
    67.             other.gameObject.SetActive(false);
    68.         } else if (other.tag == "Soda") {
    69.             food += pointsPerSoda;
    70.             other.gameObject.SetActive(false);
    71.         }
    72.     }
    73.  
    74.     protected override void OnCantMove<T> (T component)
    75.     {
    76.         Wall hitWall = component as Wall;
    77.         hitWall.DamageWall(wallDamage);
    78.         animator.SetTrigger("playerChop");
    79.     }
    80.  
    81.     private void Restart () {
    82. //        GameManager.instance.StopCoroutine(GameManager.instance.MoveEnemies());
    83.         Application.LoadLevel(Application.loadedLevel);
    84.     }
    85.  
    86.     public void LoseFood (int loss) {
    87.         animator.SetTrigger("playerHit");
    88.         food -= loss;
    89.         CheckIfGameOver();
    90.     }
    91.  
    92.     private void CheckIfGameOver () {
    93.         if (food <= 0) {
    94.             GameManager.instance.GameOver();
    95.         }
    96.     }
    97.  
    98. }
    99.  
     
    Last edited: May 6, 2015
  46. RetroGamer28

    RetroGamer28

    Joined:
    Apr 28, 2015
    Posts:
    7
    Hi Matt I too have the same problem but I typed everything following the Rogue 2D video 4 tutorial. These images is what I did for the boardmanager:

    Image1.jpg

    I have followed everything the tutorial told me to do and I did check several times for any mistakes as they were corrected already. In video 5 of the tutorial the man states that I should add both the board manager and game manager to the game object together. When I do that I get the same error message shown in the third image. I also noticed another error message at the bottom in red is telling me something is wrong. I just want to find out what I did wrong so I could progress further into this tutorial.
     

    Attached Files:

  47. decikins

    decikins

    Joined:
    May 8, 2015
    Posts:
    1
    I had the exact same problem, and after double and triple checking all my code (which was all fine), I realised I'd accidentally left the original instance of the Game Manager in the hierarchy.
    Make sure you delete the original Game Manager game object from the hierarchy, and this should fix it.
     
    PhoenixBound and OboShape like this.
  48. daithi43

    daithi43

    Joined:
    Apr 2, 2015
    Posts:
    3
    Hi guys,
    I completed this tutorial a few days ago and have been adding some simple features to it since then, however I've encountered a problem when trying to add a function to restart the game after the players food runs out. What happens is each time the player dies, regardless of what level it occurred on, the game restarts on level 2. The "RestartGame" coroutine I've added to the GameManager script is given below. This is called from the GameManager "GameOver" function. Any help would be greatly appreciated.

    Code (CSharp):
    1. IEnumerator RestartGame()
    2.     {
    3.         yield return new WaitForSeconds(2);
    4.         Destroy (gameObject);
    5.         Destroy (SoundManager.instance.gameObject);
    6.         Application.LoadLevel (Application.loadedLevel);
    7.     }
     
  49. Nimue

    Nimue

    Joined:
    Apr 27, 2015
    Posts:
    6
    Sorry it took me so long to get back to you, thank you for the suggestions. I looked more closely and it seems that the enemy script is not firing. I'm going to look at it more closely, but any suggestions would be helpful. The enemy never moves at all so I think something in there is the problem. playersTurn returns true so that's not the problem. :)
     
  50. OboShape

    OboShape

    Joined:
    Feb 17, 2014
    Posts:
    836
    Sorry Maraku Mure for my delay in getting back to you, been away at work all week, ill have a look see if theres anything i can come up with or find tomorrow to try and help.
     
Thread Status:
Not open for further replies.