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

    OrfWare

    Joined:
    May 3, 2017
    Posts:
    2
    About the singleton implementation: when we detect a duplicate we destroy the gameObject.
    But then code execution goes on to the DontDestryOnLoad function call, am I right?
    Shouldn't we return from Awake() after destrotimg gameObject?


    Code (CSharp):
    1.     void Awake()
    2.     {
    3.         if (instance == null)
    4.         {
    5.             instance = this;
    6.         }
    7.         else if (instance != this)
    8.         {
    9.             Destroy(gameObject);
    10.                 // shouldn't we issue a "return" command now?
    11.         }
    12.         DontDestroyOnLoad(gameObject);
    13.  
    14.         boardScript = GetComponent<BoardManager>();
    15.  
    16.         InitGame();
    17.     }
     
  2. OrfWare

    OrfWare

    Joined:
    May 3, 2017
    Posts:
    2
    About player movement. In Player.Update() we call Player.AttemptMove(...)

    Code (CSharp):
    1.        
    2. // Player.cs
    3. protected override void AttemptMove <T> (int xDir, int yDir)
    4.         {
    5.             food--;
    6.             foodText.text = "Food: " + food;
    7.             base.AttemptMove <T> (xDir, yDir);
    8.             RaycastHit2D hit;
    9.             if (Move (xDir, yDir, out hit))
    10.                 SoundManager.instance.RandomizeSfx (moveSound1, moveSound2);
    11.             CheckIfGameOver ();
    12.             GameManager.instance.playersTurn = false;
    13.         }
    Player.AttemptMove calls both base.AttemptMove() and base.Move().

    Code (CSharp):
    1.        
    2. //MovingObject.cs
    3.  protected virtual void AttemptMove <T> (int xDir, int yDir)
    4.             where T : Component
    5.         {
    6.             RaycastHit2D hit;
    7.             bool canMove = Move (xDir, yDir, out hit);
    8.             if(hit.transform == null)
    9.                 return;
    10.             T hitComponent = hit.transform.GetComponent <T> ();
    11.             if(!canMove && hitComponent != null)
    12.                 OnCantMove (hitComponent);
    13.         }
    MovingObject.AttemptMove calls Move() too.
    So MovingObject.Move() is called two times? Is that right?
     
  3. jimm84

    jimm84

    Joined:
    Feb 26, 2017
    Posts:
    7
    Hello, having issues I was hoping someone could give some pointers. I have got as far as video 5 in Roguelike and when I come to test my game I get this error in Red .

    Assets/Scripts/GameManger.cs(52,246): error CS1525: Unexpected symbol `end-of-file'

    I have copied the tut so far as close as possible as far as I'm aware.

    Thanks,
     

    Attached Files:

  4. gwnguy

    gwnguy

    Joined:
    Apr 25, 2017
    Posts:
    144
    Confirm that you have the last curly bracket (The "}" ) in your GameManger.cs script.
     
  5. waldekjulez

    waldekjulez

    Joined:
    May 5, 2017
    Posts:
    1
    Hello I am having problem with the tutorial.
    When I am leaving the first level I am getting thrown back to the scene manager and I am getting the following error message:

    holycow.png
    It drives me nuts I have tried so much but don't understand what's going on...
     
  6. BadWolfWagner

    BadWolfWagner

    Joined:
    Apr 1, 2017
    Posts:
    4
    I was just having this very same problem, took some time to realize that the "GameManager" script that was causing the error was not the one I wrote, instead, it was the one that came in the "_Complete-Game\Scripts" directory.
    I opened the Assets folder in explorer and moved the _Complete-Game folder out of the Assets (so you can keep it, but it won't be read by your project) and everything started working fine.
     
  7. Quetzal64

    Quetzal64

    Joined:
    May 7, 2017
    Posts:
    1
    I'm having a similarish problem, says I have compiling errors and says "no MonoBehaviour scripts in file" even when I copy/pasted the code provided in case I'd typed something wrong. It was also saying there was another file called GameManager and BoardManager in the "Completed" folder so I moved it like you've suggest here, but now it just gives the error for GameManager "Assets/Scripts/GameManager.cs(9,10): error CS0246: The type or namespace name `BoardManager' could not be found. Are you missing `Completed' using directive?" which is confusing to me since it doesn't specify anywhere that "Completed" exists that I can see. BoardManager and GameManager are both saved to my Scripts folder.

    I'm very new to Unity. I've looked around online and other people seem to be having a similar problem. Tried to create a new script with a random name and still gets the same error despite me having done nothing to it. Have turned things off and on again, set the default script editor to MonoDevelop, nothing seems to work.
     
  8. RedEyedDeveloper

    RedEyedDeveloper

    Joined:
    Apr 14, 2017
    Posts:
    8
    Hello all,

    I am having some issues with my Rougelike 2D game i want to add a Scoreboard UI to display score information every time my player eats food and soda, while giving the ability to save the score after death to a offline scoreboard/leader board. Also, i am wanting to add a GNU licence to the game to release the game for non-commercial use whilst acknowledging Unity. Any friendly help would be of paramount help and i thank you in advance.

    Sincerely.

    R.E.D.
     
  9. Trawrr

    Trawrr

    Joined:
    May 15, 2017
    Posts:
    2
    Hi guys,
    I'm having a problem with my player not being able to move. It doesn't look like any inputs are registering. I have spent time going over the coding trying to find the error and am getting no where. Could someone please help me find the problem? I am using Unity 5.6.0f3 and am up to the end of the 11th video in the tutorial series. Thanks.


    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class GameManager : MonoBehaviour {
    6.  
    7.     //how long the game will wait between turns
    8.     public float turnDelay = .1f;
    9.     //allows access of other script
    10.     public static GameManager instance = null;
    11.     //stores Boardmanager reference
    12.     public BoardManager boardScript;
    13.     public int playerFoodPoints = 100;
    14.     //Variable won't be displayed in editor
    15.     [HideInInspector] public bool playersTurn = true;
    16.  
    17.  
    18.     private int level = 3;
    19.     //keep track of and order enemies
    20.     private List<Enemy> enemies;
    21.     private bool enemiesMoving;
    22.  
    23.     // awake is used BEFORE the start function
    24.     void Awake ()
    25.     {
    26.         //To only load one GameManager. Will destroy one copy if two are present.
    27.         if (instance == null)
    28.             instance = this;
    29.         else if (instance != this)
    30.             Destroy (gameObject);
    31.  
    32.         //Won't destroy between loads - so we can keep scores through the game.
    33.         DontDestroyOnLoad (gameObject);
    34.         //to clear enemies from Last level
    35.         enemies = new List<Enemy> ();
    36.         boardScript = GetComponent<BoardManager>();
    37.         InitGame();
    38.     }
    39.  
    40.     void InitGame ()
    41.     {
    42.         enemies.Clear ();
    43.         boardScript.SetupScene(level);
    44.     }
    45.  
    46.     public void GameOver()
    47.     {
    48.         enabled = false;
    49.     }
    50.  
    51.     // Update is called once per frame
    52.     void Update ()
    53.     {
    54.         //if it is either the players turn, or the enemies are moving
    55.         if (playersTurn || enemiesMoving)
    56.             //return and not execute this code
    57.             return;
    58.  
    59.         //calls for function MoveEnemies to be completed
    60.         StartCoroutine(MoveEnemies ());
    61.     }
    62.  
    63.     public void AddEnemyToList(Enemy script)
    64.     {
    65.         enemies.Add (script);
    66.     }
    67.  
    68.     //setting enemies to move one by one
    69.     IEnumerator MoveEnemies()
    70.     {
    71.         enemiesMoving = true;
    72.         //wait for enemy turn to finish/ turn delay
    73.         yield return new WaitForSeconds (turnDelay);
    74.         //check to see if enemies have been spawned
    75.         if (enemies.Count == 0)
    76.         {
    77.             //if no enemies, still wait for turn delay
    78.             yield return new WaitForSeconds(turnDelay);
    79.         }
    80.  
    81.         //loop through enemy list and issue commands
    82.         for (int i = 0; i < enemies.Count; i++)
    83.         {
    84.             //call moveEnemy function
    85.             enemies [i].MoveEnemy ();
    86.             //wait for 1 enemy to finish movement before allowing another to move
    87.             yield return new WaitForSeconds(enemies[i].moveTime);
    88.         }
    89.                 //Player can move again after enemy turn has ended
    90.                 playersTurn = true;
    91.                 //enemies are done moving for this turn
    92.                 enemiesMoving = false;
    93.     }
    94. }
    95.  

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. //Player and enemy will use this for movement
    6.  
    7. //Abstract modifier states that the thing being modified is incomplete.
    8. public abstract class MovingObject : MonoBehaviour {
    9.  
    10.     // Time it will take the object to move in seconds
    11.     public float moveTime = 0.1f;
    12.     //Check for collision
    13.     public LayerMask blockingLayer;
    14.  
    15.     private BoxCollider2D boxCollider;
    16.     private Rigidbody2D rb2D;
    17.     //efficent movment
    18.     private float inverseMoveTime;
    19.  
    20.     // This start method can be overridden by inheriting class. This is used so the inhereting class can start differently if need be.
    21.     protected virtual void Start ()
    22.     {
    23.         boxCollider = GetComponent<BoxCollider2D> ();
    24.         rb2D = GetComponent<Rigidbody2D> ();
    25.         //by adding reciprical of moveTime, we can multiply instaed of divide which is better for computation.
    26.         inverseMoveTime = 1f / moveTime;
    27.     }
    28.  
    29.     //this checks to see if units hit any impassable objects using a raycast. If unit hits, movement will cease in that direction.
    30.     //move is true if can move and false if not
    31.     //movement set for x & y axis with Rayhit to check for collisions. converting to discard Z axis data.
    32.     protected bool Move (int xDir, int yDir, out RaycastHit2D hit)
    33.     {
    34.         //position to move from - current position
    35.         Vector2 start = transform.position;
    36.         //Calculate end position
    37.         Vector2 end = start + new Vector2 (xDir, yDir);
    38.  
    39.         //Disable the objects own collider so raycast doesnt hit it
    40.         boxCollider.enabled = false;
    41.         //Cast a line from start point to end point to check for collisions on BlockingLayer.
    42.         hit = Physics2D.Linecast (start, end, blockingLayer);
    43.         //Place boxcollider back after raycast.
    44.         boxCollider.enabled = true;
    45.  
    46.         //check to see if anything was hit
    47.         if (hit.transform == null)
    48.         {
    49.             // if equal to null, the space was available for entry and unit will be allowed to move onto space
    50.             StartCoroutine (SmoothMovement (end));
    51.             return true;
    52.         }
    53.  
    54.         //if raycast hit something, movemonet will be false
    55.         return false;
    56.  
    57.     }
    58.  
    59.     //This will show how units move from one space to another. End = where to move to.
    60.     protected IEnumerator SmoothMovement (Vector3 end)
    61.     {
    62.         //sqrMagnitude of difference between where we are and where we want to go. sqrMagnitude is cheaper than Magnitude.
    63.         float sqrRemaningDistance = (transform.position - end).sqrMagnitude;
    64.  
    65.         //While loop - finds position thats closer to the end.
    66.         while (sqrRemaningDistance > float.Epsilon)
    67.         {
    68.             //Vector3.MoveTowards moves an object to another point in a straight line
    69.             Vector3 newPosition = Vector3.MoveTowards (rb2D.position, end, inverseMoveTime * Time.deltaTime);
    70.             //Move to new position found
    71.             rb2D.MovePosition (newPosition);
    72.             //Recalculate remainging distance
    73.             sqrRemaningDistance = (transform.position - end).sqrMagnitude;
    74.             //reevaluate perframe before cycling loop
    75.             yield return null;
    76.         }
    77.     }
    78.  
    79.     //How units react to interactable blockers - Enemies =player, player = walls.
    80.     protected virtual void AttemptMove <T> (int xDir, int yDir)
    81.         where T: Component
    82.     {
    83.         RaycastHit2D hit;
    84.         //Will set to canMove to true or false when moving onto new spaces
    85.         bool canMove = Move (xDir, yDir, out hit);
    86.  
    87.         //Check to see if RayCast hit anything
    88.         if (hit.transform == null)
    89.         //if no, don't run the rest of this section of code
    90.             return;
    91.  
    92.         //see what was hit
    93.         T hitComponent = hit.transform.GetComponent <T> ();
    94.  
    95.         //if can move = flase and hitcomponent = null item is interactable
    96.         if(!canMove && hitComponent != null)
    97.             //OnCantMovement is called
    98.             OnCantMove (hitComponent);
    99.     }
    100.  
    101.     //abstract fucntion with no implementation
    102.     // T is substituted in other scripts - as there are different scripts accessing this, T is a placholder.
    103.     protected abstract void OnCantMove <T> (T component)
    104.         where T: Component;
    105. }
    106.  

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.UI;
    5. using UnityEngine.SceneManagement;
    6.  
    7. public class Player : MovingObject
    8. {
    9.     //player dmg to wall per hit
    10.     public int wallDamage = 1;
    11.     //points accrued per food&drink
    12.     public int pointsPerFood = 10;
    13.     public int pointsPerSoda = 20;
    14.     public float restartLevelDelay = 1f;
    15.  
    16.     private Animator animator;
    17.     //stores players points per level before transfering info back to the GameManager to store at the end of the level.
    18.     private int food;
    19.  
    20.     // This is used as the movement for player is slightly different to what is stored under MovingObject.
    21.     protected override void Start ()
    22.     {
    23.         animator = GetComponent<Animator> ();
    24.  
    25.         //Player script will recall the food score a stored in the GameManager and send it back after the level ends.
    26.         food = GameManager.instance.playerFoodPoints;
    27.  
    28.         //call the base movement to work with
    29.         base.Start ();
    30.     }
    31.  
    32.     private void OnDisable()
    33.     {
    34.         //telling the player script to send the foodscore to GameManager
    35.         GameManager.instance.playerFoodPoints = food;
    36.     }
    37.  
    38.  
    39.     // Update is called once per frame
    40.     void Update ()
    41.     {
    42.         //if the players turn has ended, script will return and the code under this will not be followed
    43.         if (GameManager.instance.playersTurn) return;
    44.  
    45.  
    46.         //this stores where the character is moving on the horizontal or vertical axis (as a 1/-1)
    47.         int horizontal = 0;
    48.         int vertical = 0;
    49.  
    50.         //these give the values for horizontal/vertical positions
    51.         horizontal = (int)Input.GetAxisRaw ("Horizontal");
    52.         vertical = (int)Input.GetAxisRaw ("Vertical");
    53.  
    54.         //check to see if moving hoizontally - cant move veritcally
    55.         if (horizontal != 0)
    56.         {
    57.             vertical = 0;
    58.         }
    59.  
    60.         //check to see if there is a non0 value - player wants to move. check to see if space moving into is interactable.
    61.         if (horizontal != 0 || vertical != 0)
    62.         {
    63.             AttemptMove<Walls> (horizontal, vertical);
    64.         }
    65.     }
    66.  
    67.  
    68.     //expected attempt moves player can make - xDirection, yDirection
    69.     //this overrides the base function in MovingObject
    70.     protected override void AttemptMove <T> (int xDir, int yDir)
    71.     {
    72.         //when player moves, 1 food point is spent.
    73.         food--;
    74.  
    75.         //calls attemptmove from base class, considering walls, which is represented as T
    76.         base.AttemptMove <T> (xDir, yDir);
    77.  
    78.         //see what the result of Linecast done in Move
    79.         RaycastHit2D hit;
    80.  
    81.         CheckIfGameOver();
    82.  
    83.         //ends players turn
    84.         GameManager.instance.playersTurn = false;
    85.     }
    86.  
    87.  
    88.     //this will allow player to interact with food, soda and exit
    89.     //tags are found and changed in the editor
    90.     private void OnTriggerEnger2D (Collider2D other)
    91.     {
    92.         //if the tag of object is exit - restart function will be called
    93.         if (other.tag == "Exit")
    94.         {
    95.             Invoke ("Restart", restartLevelDelay);
    96.             enabled = false;
    97.         }
    98.         //check to see if tag is set to food - adds food points
    99.         else if (other.tag == "Food")
    100.         {
    101.             food += pointsPerFood;
    102.             other.gameObject.SetActive (false);
    103.         }
    104.         //check to see if tag is set to soda - adds food points
    105.         else if (other.tag == "Soda")
    106.         {
    107.             food += pointsPerSoda;
    108.             other.gameObject.SetActive (false);
    109.         }
    110.     }
    111.  
    112.  
    113.     //defining what OnCantMove does for player (this is found on MovingObject script, with no implementation)
    114.     protected override void OnCantMove <T> (T component)
    115.     {
    116.         //calls from walls script
    117.         Walls hitWall = component as Walls;
    118.         //applies dmg function to wall - how much dmg player does to wall
    119.         hitWall.DamageWall (wallDamage);
    120.         //calls animation of player attack
    121.         animator.SetTrigger("playerChop");
    122.     }
    123.  
    124.     // next level load when player touches exit tile
    125.     private void Restart()
    126.     {
    127.         //will load last scene
    128.         SceneManager.LoadScene ("Main");
    129.     }
    130.  
    131.     //how many food points will be lost if enemy attacks player - LoseFood = function called whn player is attacked, loss is points lost.
    132.     public void LoseFood (int loss)
    133.     {
    134.         //player being hit animation
    135.         animator.SetTrigger("playerHit");
    136.         //total of points lost subtracted from total
    137.         food -= loss;
    138.         CheckIfGameOver ();
    139.     }
    140.  
    141.  
    142.     //If food = 0, game over function is called from GameManager
    143.     private void CheckIfGameOver()
    144.     {
    145.         if (food <= 0)
    146.             GameManager.instance.GameOver ();
    147.     }
    148. }
    149.  
     
    Last edited: May 15, 2017
  10. Trawrr

    Trawrr

    Joined:
    May 15, 2017
    Posts:
    2

    Anyone else who has this problem, I just found out what I did wrong. Make sure you put the exclamation mark before GameManager in the void Update part of the Player Script.
    eg.

    Code (CSharp):
    1. void Update ()
    2.     {
    3.          if (!GameManager.instance.playersTurn) return;
    4.  
    5.         int horizontal = 0;
    6.         int vertical = 0;
    7.  
    8.         horizontal = (int) Input.GetAxisRaw ("Horizontal");
    9.         vertical = (int) Input.GetAxisRaw ("Vertical");
    10.  
    11.         if (horizontal != 0)
    12.         {
    13.             vertical = 0;
    14.         }
    15.  
    16.          if (horizontal != 0 || vertical != 0)
    17.         {
    18.             AttemptMove<Walls> (horizontal, vertical);
    19.         }
    20.     }
     
  11. MivaSunrise

    MivaSunrise

    Joined:
    May 15, 2017
    Posts:
    1
    I had this issue too, I removed the "namespace Completed" part from the boardmanager (and the {} that went with it) and it seemed to work. I originally had that part in there from copy/pasting from the code below the video, which he doesn't mention in the video.
     
  12. rvauter13

    rvauter13

    Joined:
    May 22, 2017
    Posts:
    1
    I'm Sorry I am not sure where to place this but I wanted to put this somewhere so if some on had the same problem I had they could get a fix. I was on Tutorial 12 Adding UI & Level Transitions and ran into a major problem. When I added the code from the update to run my game I encountered that my GameManger was making 2 instances of the board and this was causing a wide range of problems: it caused the exit to randomly disappear, cause the day to start on Day 2 and increment the level by 2. On Day 4 I would have no health and the game would immediately end as there was no food points. This bothered me for some time till I realized the function OnLevelFinishedLoading was causing the the game to run InitGame function twice. In order to fix this I set doingSetup to false in initialization then I added an if statement to OnLevelFinishedLoading as shown below:
    void OnLevelFinishedLoading (Scene scene, LoadSceneMode mode)
    {
    if(!doingSetup)
    {
    //increment Level
    level++;

    //Call InitGame to Initalize Level
    InitGame();
    }
    }

    This solved all the problems that I was having and i hope it helps other how run into this.
     
  13. Rezyaev

    Rezyaev

    Joined:
    May 23, 2017
    Posts:
    4
    if (instance == null)
    instance = this;
    else if (instance != this)
    Destroy (gameObject);

    DontDestroyOnLoad (gameObject);


    Sorry, but I just can't understand how does this code work. Can somebody explain me?
    (I am from Kazakhstan, so maybe I can't understand because of my English :c)
     
  14. JRWidley

    JRWidley

    Joined:
    Nov 22, 2016
    Posts:
    18
    This is because the GameManager class that uses this is meant to be a static class - meaning there will only be one instance of it.

    If 'instance' does not have a value (i.e. it is null), this code will set the instance variable in this class (GameObject) to reference it's self (GameObject). If a 2nd instance of GameObject is created somewhere else in your program, this code will ensure it is destroyed and keep only the one instance.

    DontDestroyOnLoad() does exactly what it says: doesn't destroy gameObject (the object this script is attached to) when we load a new scene.
     
  15. Rezyaev

    Rezyaev

    Joined:
    May 23, 2017
    Posts:
    4
    Big thank you :)
     
  16. scud24

    scud24

    Joined:
    Apr 19, 2017
    Posts:
    1
    Is there a video or step missing from the tutorials? I have been following the videos and everything was working until the part 9 player script video, which starts referencing things in the GameManager script like
    GameManager.instance.playerFoodPoints that dont seem to have been added to the GameManager script yet in the tutorials. I looked ahead in the tutorials to see if I could figure out what was going on, and the code referenced seems to have magically appeared in the GameManager script in the part 11 enemy animator controller video so I assume it was supposed to have been covered earlier in the series.
     
  17. a5680737

    a5680737

    Joined:
    Mar 30, 2015
    Posts:
    1
    Here's a question that in the doingSetup period,when the screen shows "Day XX" player can move one step because that we set the playersTurn to true in GameManger.
    So,I change this line to
    Code (CSharp):
    1. [HideInInspector]
    2.     public bool playersTurn = false;
    However things didn't change,I set an Log function to log the playersTurn value in Awake function in GameManager,it says "True".
    Then I added a line to set playersTurn to false,now it works.
    Code (CSharp):
    1. //Awake in GameManager
    2.     void Awake () {
    3.         if (instance == null)
    4.         {
    5.             instance = this;
    6.         }
    7.         else if (instance != this)
    8.         {
    9.             Destroy(gameObject);
    10.         }
    11.  
    12.         DontDestroyOnLoad(gameObject);
    13.  
    14.         enemies = new List<Enemy>();
    15.         Debug.logger.Log(playersTurn); //says True
    16.         playersTurn = false; //I added to make sure player can't move during the Init period.
    17.         InitGame();
    18.     }
    I still want to know why this gonna happen,I thought the assignment in declaration line is run in class ctor,which is after Awake and InitGame,so the playersTurn is still the default value.
    But it was wrong! the default value of bool is false instead in .Net,so I have no idea of this,plz help me to figure out.thx!
    sry for my poor english if it brings inconvenience.
     
  18. estevan2

    estevan2

    Joined:
    May 31, 2017
    Posts:
    2
    Hello and first of all: Thx for the great tutorial.
    I am following the tutorial until the beginning of Part 5, where the BoardManager is tested the first time. When i click on Play there are no error messages, but nothing is displayed? Because i tryed to create the project a second time, i just imported the before exported prefabs. The Layers of the prefabs i entered by myself. I' am getting crazy about this issue. I hope some body could help me.

    I am using Unity 5.6.1

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class GameManager : MonoBehaviour {
    6.  
    7.     public BoardManager boardScript;
    8.  
    9.     private int level =3;
    10.  
    11.     void awake()
    12.     {
    13.         boardScript = GetComponent<BoardManager> ();
    14.         InitGame ();
    15.  
    16.     }
    17.  
    18.     void InitGame()
    19.     {
    20.         boardScript.SetupScene (level);
    21.  
    22.     }
    23.  
    24.     // Update is called once per frame
    25.     void Update ()
    26.     {
    27.         //Debug.Log("Hallo Welt");
    28.     }
    29.  
    30. }

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

    RedEyedDeveloper

    Joined:
    Apr 14, 2017
    Posts:
    8
    PLEASE HELP URGENTLY! I have posted two discussion board postings' and i have sent an E-mail and i really need some help please, i have included my original message.

    Hello any and all,

    I am attempting to expand the Rougelike 2D game from the Unity tutorial. What i want to do is simple (in theory) I would like to add a basic menu with a Play, Leader board and Exit buttons', When Play has been clocked the game runs and upon death, another option pops up to return to the min menu or exit the game after the player entered their the initials for their score to be added to the scoreboard. When the returns to the Main menu they can play again by pressing play, the only way they can exit the game is by pressing the exit button on the main menu or upon death pressing exit.


    Now, i have found a tutorial for a main menu but it is not working (Tutorial URL http://pixelnest.io/tutorials/2d-game-unity/menus/ ) The part to at the MenuScript.StartGame() to then add the StartGame() function does not work in the way it was shown in the tutorial in my version of Unity version 5.6.0f3 Personal 64 But Windows edition.

    I have also found a leaderboard tutoral at (URL https://docs.gamesparks.net/tutorials/unity-tutorial-creating-leaderboard-prefabs-posting-scores ) I have not started this one yet for, i am still creating the menu.

    So, after all of that this is the issue(s) The menu button is not working and due to the fact this is for different projects i know it will interfere with the games tutorial built loops'.

    I just want to make a working menu, arcade-style leader-board and options after death.

    Thank you to any and all help

    P.S. Please be kind i am still new to game development.

    Sincerely,

    R.E.D.
     
  20. gwnguy

    gwnguy

    Joined:
    Apr 25, 2017
    Posts:
    144
    GameManager: at line 11, capitalize the word awake:
    void Awake()
     
  21. Goodrum_

    Goodrum_

    Joined:
    Oct 8, 2016
    Posts:
    4
    I encountered an issue when it came to the end of the second video, and generating the board. At the bottom of the post is my script for BoardManager. I tried to use the example script given to fix my issue, but still couldn't get it working.

    When I click play, the south and west walls are not generated, along with the floor. Enemies, inner walls, food and the north and east walls are all generated. I just wondered where I was going wrong?

    Code (csharp):
    1.  
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5. using Random = UnityEngine.Random;
    6.  
    7. public class BoardManager : MonoBehaviour {
    8.  
    9.     [SerializeField]
    10.     public class Count
    11.     {
    12.         public int minimum;
    13.         public int maximum;
    14.  
    15.         public Count (int min, int Max)
    16.         {
    17.             minimum = min;
    18.             maximum = Max;
    19.         }
    20.     }
    21.  
    22.     //sets a default size for the game board
    23.     public int columns = 8;
    24.     public int rows = 8;
    25.     //sets random range of walls between 5 and 9
    26.     public Count wallcount = new Count (5, 9);
    27.     //same as wall count but for food
    28.     public Count foodcount = new Count (1, 5);
    29.     public GameObject exit;
    30.     //create arrays full of items for the game to choose from
    31.     public GameObject[] floorTiles;
    32.     public GameObject[] foodTiles;
    33.     public GameObject[] wallTiles;
    34.     public GameObject[] enemyTiles;
    35.     public GameObject[] outerWallTiles;
    36.  
    37.     //used to keep the hierarchy clean
    38.     private Transform boardHolder;
    39.     //list to keep track of what positions are free and in use
    40.     private List <Vector3> gridPosition = new List<Vector3>();
    41.  
    42.     void InitialiseList()
    43.     {
    44.         gridPosition.Clear ();
    45.  
    46.         for (int x = 1; x < columns - 1; x++) {
    47.             for (int y = 1; y < rows - 1; y++) {
    48.                 //adds a new vector 3 of x and y values to a list of positions to place walls, enemies or pickups
    49.                 gridPosition.Add (new Vector3 (x, y, 0f));
    50.             }
    51.         }
    52.                
    53.     }
    54.  
    55.     //sets up the out wall and floor
    56.     void BoardSetup()
    57.     {
    58.         boardHolder = new GameObject ("Board").transform;
    59.  
    60.         //builds an edge aound the game board
    61.         for (int x = 1; x < columns + 1; x++) {
    62.             for (int y = 1; y < rows + 1; y++) {
    63.                 //declare a variable which is floor tile at random
    64.                 GameObject toInstantiate = floorTiles [Random.Range (0, floorTiles.Length)];
    65.                 if(x==-1 || x== columns || y == -1 || y == rows)
    66.                 {
    67.                     //sets the floor tile to an outer wall
    68.                     toInstantiate = outerWallTiles[Random.Range(0, outerWallTiles.Length)];
    69.  
    70.                     //assigns instance the variable being instantiated to x,y co-ordinates in loop
    71.                     //quaternion.identity means it's instantiated without being rotated
    72.                     GameObject instance = Instantiate(toInstantiate, new Vector3(x,y,0f), Quaternion.identity) as GameObject;
    73.  
    74.                     //set parent of new object to boardHolder
    75.                     instance.transform.SetParent(boardHolder);
    76.                 }
    77.             }
    78.         }
    79.     }
    80.  
    81.     Vector3 RandomPosition()
    82.     {
    83.         //genereates a random number within the range of 0 and the number of positions stored in gridPositions
    84.         int randomIndex = Random.Range (0, gridPosition.Count);
    85.  
    86.         //picks a random position from gridPosition
    87.         Vector3 randomPosition = gridPosition [randomIndex];
    88.         //to prevent spawning two objects in one square, it is removed from the list
    89.         gridPosition.RemoveAt(randomIndex);
    90.  
    91.         return randomPosition;
    92.     }
    93.  
    94.     //spawns tiles at randomPosition
    95.     void LayoutObjectAtRandom(GameObject[] tileArray, int minimum, int maximum)
    96.     {
    97.         //controls how many of an objeect we will spawn
    98.         int objectCount = Random.Range (minimum, maximum + 1);
    99.  
    100.         //allows us to spawn the number of object specified above
    101.         for (int i = 0; i < objectCount; i++) {
    102.             //chose a random position
    103.             Vector3 randomPosition = RandomPosition ();
    104.             //chose a random tile to spawn
    105.             GameObject tileChoice = tileArray [Random.Range (0, tileArray.Length)];
    106.             Instantiate(tileChoice, randomPosition, Quaternion.identity);
    107.         }
    108.     }
    109.        
    110.     //called when it is time to set up the board
    111.     public void SetupScene(int level)
    112.     {
    113.         BoardSetup ();
    114.         InitialiseList ();
    115.         //lays out walls at random
    116.         LayoutObjectAtRandom (wallTiles, wallcount.minimum, wallcount.maximum);
    117.         //lays out food at random
    118.         LayoutObjectAtRandom (foodTiles, foodcount.minimum, foodcount.maximum);
    119.         //this calcuates how many enemies per level, slowly getting harder
    120.         int enemyCount = (int)Mathf.Log(level,2f);
    121.         LayoutObjectAtRandom (enemyTiles, enemyCount, enemyCount);
    122.         //always spawns the exit in the same place
    123.         Instantiate(exit, new Vector3(columns - 1, rows - 1, 0f), Quaternion.identity);
    124.     }
    125. }
    126.  
    127.  
     
  22. gwnguy

    gwnguy

    Joined:
    Apr 25, 2017
    Posts:
    144
    Try changing lines 61 and 62 from

    for (int x = 1; x < columns + 1; x++) {
    for (int y = 1; y < rows + 1; y++) {

    to
    for (int x = -1; x < columns + 1; x++) {
    for (int y = -1; y < rows + 1; y++) {

    (note it starts at -1, not 1)
     
  23. Toothbrush4

    Toothbrush4

    Joined:
    Jun 1, 2017
    Posts:
    1
    I'm unsure if this has been asked on this thread before but it is so big that I cannot search all the way through. What application was used to create the sprites and animations? I am interested in making my own sprites similar to the ones used in the tutorial. Any nudge in the right direction would be greatly appreciated. Thanks!
     
  24. JRWidley

    JRWidley

    Joined:
    Nov 22, 2016
    Posts:
    18
    I'm not sure what tool the sprites in this tutorial were made with, but probably a good starting point for pixel art sprites would be with Aseprite. I've used it - it's inexpensive and easy to use.
     
  25. estevan2

    estevan2

    Joined:
    May 31, 2017
    Posts:
    2
    Super, sometimes I am getting crazy by finding such faults :) thanx a lot
     
  26. majorwitty

    majorwitty

    Joined:
    Jun 14, 2015
    Posts:
    2
    Hi,
    First, thanks for the video tutorials. I really enjoy them & so do my children.

    Did author make a mistake when assigning DmgSprite variable to Scavengers_SpriteSheet_52 reference in both prefab Wall5 and Wall6?

    In video 7 of 14 at 2m 47s it shows author made that assignment. Then Wall7 and Wall8 got _53 and _54.

    From author's audio at 2m 32s assignment should have been Wall6 DmgSprite Scavengers_SpriteSheet_53, Wall7 _54, and Wall8 _55.

    If this is correct could you please add some text to your video noting this.
    Thanks again for videos.
     
  27. ICE_DragonM

    ICE_DragonM

    Joined:
    Feb 14, 2017
    Posts:
    7
    Can someone please explain to me why the code in the video is differs from the code on the website?
    and do I need to refer to the code in the video or the code in Unity website?


    I'm asking that I use Unity 5.6 and I'm understand that there are some changes in the c# code
     
    Last edited: Jun 5, 2017
  28. night_day

    night_day

    Joined:
    Jun 5, 2017
    Posts:
    3
    Not sure what issue you are having specifically, but the code below each video should be good. If you want you can look through the upgrade guide PDF to see specific instances where the video is out of date.

    https://oc.unity3d.com/index.php/s/5rj6Lp4U13kB4h1
     
  29. night_day

    night_day

    Joined:
    Jun 5, 2017
    Posts:
    3
    So I'm having an issue on getting the walls to break. In the AttemptMove method hitComponent is always null, even when I hit a wall, so I can't call the OnCantMove to try to break the wall or play the chop animation since it's always null. I have no idea why this is happening, thanks.

    Code (csharp):
    1.  
    2. protected virtual void AttemptMove <T> (int xDir, int yDir) where T : Component
    3.     {
    4.         RaycastHit2D hit;
    5.         bool canMove = Move(xDir, yDir, out hit);
    6.  
    7.         if (hit.transform == null)
    8.             return;
    9.  
    10.         Debug.Log(hit.transform.GetType().Name);
    11.  
    12.         T hitComponent = hit.transform.GetComponent<T>();
    13.  
    14.         if (!canMove && hitComponent != null)
    15.             OnCantMove(hitComponent);
    16.     }
     
  30. ICE_DragonM

    ICE_DragonM

    Joined:
    Feb 14, 2017
    Posts:
    7
    I do not know which script to refer to, the player's script for example gives me a warning
    "Assets/Scripts/Player.cs(54,16): warning CS0168: The variable `hit' is declared but never used"
    So I do not know if it's because Unity version or I was wrong in the script
     
  31. night_day

    night_day

    Joined:
    Jun 5, 2017
    Posts:
    3
    That's only a warning, it doesn't stop you from running the script. The variable is used later on when sound is added.
     
  32. ICE_DragonM

    ICE_DragonM

    Joined:
    Feb 14, 2017
    Posts:
    7
    Hii Matthew,
    I'm a bit confused by the scripts, I realized that the video scripts are version 4.6 or 5.0,and there are the scripts on the site,
    at first I tried to work by the update file, but when I try the game it started from Day 2, and when I looked at the scripts of the finished project, I saw that the scripts were different from the S*** and did not include an update,
    can you explain about these changes? What changes should be made to make the game work properly? especially the SceneMangers function

    I work if Unity version 5.6
     
    Last edited: Jun 11, 2017
  33. kvu39564

    kvu39564

    Joined:
    May 15, 2017
    Posts:
    9
    I'm having this problem currently where the player moves two spaces. If I comment out the if(Move(xDir, yDir, out hit)) then the player will move as intended. Any solutions?

    Edit: Just to get it working quick (otherwise I'd be up all night), I modified the 'MoveObject' parent class and added protected bool 'canMove'. I then set it in the 'Move' function right before you'd return true or false. Then in the 'Player' class just check 'canMove' instead of calling the 'Move' function in the player's 'AttemptMove'. If there are better solutions, I'm open to learn what they are.
     
    Last edited: Jun 12, 2017
    cyber_shawn likes this.
  34. cyber_shawn

    cyber_shawn

    Joined:
    Jun 13, 2017
    Posts:
    7
    Hello kvu39.. I was wondering the exact same thing for days now. How come my Roguelike guy is moving twice, and how can I change that? However, you lost me on the remedy, Can you show your solution? thks.
     
  35. kvu39564

    kvu39564

    Joined:
    May 15, 2017
    Posts:
    9
    The following is in the MovingObject script.

    Code (CSharp):
    1.  
    2. protected bool canMove; // created a protected bool that the Player script could access
    3.  
    4. protected bool Move(int xDir, int yDir, out RaycastHit2D hit)
    5.     {
    6.         Vector2 start = transform.position;
    7.  
    8.         Vector2 end = start + new Vector2(xDir, yDir);
    9.  
    10.         boxCollider.enabled = false;
    11.  
    12.         hit = Physics2D.Linecast(start, end, blockingLayer);
    13.  
    14.         boxCollider.enabled = true;
    15.  
    16.         if (hit.transform == null)
    17.         {
    18.  
    19.             StartCoroutine(SmoothMovement(end));
    20.  
    21.             //Return true to say that Move was successful
    22.             canMove = true; //  set the value here
    23.             return true;
    24.         }
    25.  
    26.         //If something was hit, return false, Move was unsuccesful.
    27.         canMove = false; //  set the value here
    28.         return false;
    29.     }
    Then in the Player AttemptMove script

    Code (CSharp):
    1.  
    2.         //If Move returns true, meaning Player was able to move into an empty space.
    3.         //f (Move(xDir, yDir, out hit))
    4.         if(canMove) //call the bool hear to check instead of using the Move function
    5.         {
    6.             SoundManager.instance.RandomizeSfx(moveSound1, moveSound2);
    7.         }
    Hope that helps.
     
    Last edited: Jun 13, 2017
  36. cyber_shawn

    cyber_shawn

    Joined:
    Jun 13, 2017
    Posts:
    7
    Hmm, I tried the new code, it ran without errors, but my roguelike character still moves twice, no difference?
     
  37. kvu39564

    kvu39564

    Joined:
    May 15, 2017
    Posts:
    9
    That's strange. With the change, the 'Move' function should only get called once. Did you comment out the old condition check "if (Move (xDir, yDir, out hit)"? If so, could I see your code?
     
  38. cyber_shawn

    cyber_shawn

    Joined:
    Jun 13, 2017
    Posts:
    7
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.SceneManagement; //Allows us to use SceneManager
    using UnityEngine.UI;
    //inherits from MovingObject class not MonoBehaviour
    public class Player : MovingObject {

    public int wallDamage = 1;
    public int pointsPerFood = 10;
    public int pointsPerSoda = 20;
    public Text foodText;
    public float restartLevelDelay = 1;

    public AudioClip drinkSound1;
    public AudioClip drinksound2;
    public AudioClip eatsound1;
    public AudioClip eatSound2;
    public AudioClip moveSound1;
    public AudioClip moveSound2;
    public AudioClip gameOverSound;

    private Animator animator; //Used to store a reference to the Player's animator component.

    private int food; //game currency

    //Start overrides the Start function of MovingObject
    protected override void Start ()
    {
    //Get a component reference to the Player's animator component
    animator = GetComponent<Animator>();

    //Get the current food point total stored in GameManager.instance between levels.
    food = GameManager.instance.playerFoodPoints;

    foodText.text = "food: " + food;
    //Call the Start function of the MovingObject base class.
    base.Start ();
    }

    //AttemptMove overrides the AttemptMove function in the base class MovingObject
    //AttemptMove takes a generic parameter T which for Player will be of the type Wall, it also takes integers for x and y direction to move in.
    protected override void AttemptMove <T> (int xDir, int yDir)
    {
    food--; //Every time player moves, subtract from food points total.
    foodText.text = "food: " + food;
    base.AttemptMove <T> (xDir, yDir); //Call the AttemptMove method of the base class, passing in the component T (in this case Wall) and x and y direction to move.

    RaycastHit2D hit; //Hit allows us to reference the result of the Linecast done in Move.
    //If Move returns true, meaning Player was able to move into an empty space.
    //if (Move (xDir, yDir, out hit))
    if(canMove)
    {
    //Call RandomizeSfx of SoundManager to play the move sound, passing in two audio clips to choose from.
    SoundManager.instance.RandomizeSfx(moveSound1,moveSound2);

    Debug.Log ("player at: " + transform.position);
    }
    CheckIfGameOver (); //Since the player has moved and lost food points, check if the game has ended.

    GameManager.instance.playersTurn = false; //Set the playersTurn boolean of GameManager to false now that players turn is over.
    }

    //OnCantMove overrides the abstract function OnCantMove in MovingObject.
    //It takes a generic parameter T which in the case of Player is a Wall which the player can attack and destroy.
    protected override void OnCantMove <T> (T component)
    {
    //Set hitWall to equal the component passed in as a parameter.
    Wall hitWall = component as Wall;

    //Call the DamageWall function of the Wall we are hitting.
    hitWall.DamageWall (wallDamage);

    //Set the attack trigger of the player's animation controller in order to play the player's attack animation.
    animator.SetTrigger ("playerChop");
    }

    //CheckIfGameOver checks if the player is out of food points and if so, ends the game.
    private void CheckIfGameOver(){

    if (food <= 0) {
    SoundManager.instance.PlaySingle (gameOverSound);
    SoundManager.instance.musicSource.Stop ();
    GameManager.instance.GameOver(); //Call the GameOver function of GameManager.
    }
    }

    //LoseFood is called when an enemy attacks the player.
    //It takes a parameter loss which specifies how many points to lose.
    public void LoseFood (int loss)
    {
    //Set the trigger for the player animator to transition to the playerHit animation.
    animator.SetTrigger ("playerHit");

    //Subtract lost food points from the players total.
    food -= loss;
    foodText.text = "- " + loss + " food: " + food;
    //Check to see if game has ended.
    CheckIfGameOver ();
    }

    private void OnDisable(){ //This function is called when the behaviour becomes disabled or inactive.

    GameManager.instance.playerFoodPoints = food; //When Player object is disabled, store the current local food total in the GameManager so it can be re-loaded in next level.

    }

    //OnTriggerEnter2D is sent when another object enters a trigger collider attached to this object (2D physics only).
    private void OnTriggerEnter2D (Collider2D other)
    {
    //Check if the tag of the trigger collided with is Exit.
    if(other.tag == "Exit")
    {
    //Invoke the Restart function to start the next level with a delay of restartLevelDelay (default 1 second).
    Invoke ("Restart", restartLevelDelay);

    //Disable the player object since level is over.
    enabled = false;
    }

    //Check if the tag of the trigger collided with is Food.
    else if(other.tag == "Food")
    {
    //Add pointsPerFood to the players current food total.
    food += pointsPerFood;

    foodText.text = "+ " + pointsPerFood + " food: " + food;

    SoundManager.instance.RandomizeSfx(eatsound1,eatSound2);
    //Disable the food object the player collided with.
    other.gameObject.SetActive (false);
    }

    //Check if the tag of the trigger collided with is Soda.
    else if(other.tag == "Soda")
    {
    //Add pointsPerSoda to players food points total
    food += pointsPerSoda;

    foodText.text = "+ " + pointsPerSoda + " food: " + food;
    SoundManager.instance.RandomizeSfx(drinkSound1, drinksound2);
    //Disable the soda object the player collided with.
    other.gameObject.SetActive (false);
    }
    }

    //Restart reloads the scene when called.
    public void Restart ()
    {
    //Load the last scene loaded, in this case Main, the only scene in the game.
    SceneManager.LoadScene(0);
    //Application.LoadLevel(Application.loadedLevel);//depreciated?
    }

    // Update is called once per frame
    void Update () {

    if(!GameManager.instance.playersTurn) return; //If it's not the player's turn, exit the function.

    int horizontal = 0; //Used to store the horizontal move direction.
    int vertical = 0; //Used to store the vertical move direction.

    //Check if we are running either in the Unity editor or in a standalone build.
    #if UNITY_EDITOR || UNITY_STANDALONE || UNITY_WEBPLAYER

    //Get input from the input manager, round it to an integer and store in horizontal to set x axis move direction
    horizontal = (int) (Input.GetAxisRaw ("Horizontal"));

    //Get input from the input manager, round it to an integer and store in vertical to set y axis move direction
    vertical = (int) (Input.GetAxisRaw ("Vertical"));

    //Check if moving horizontally, if so set vertical to zero.
    if(horizontal != 0)
    {
    vertical = 0;
    }

    //Check if we have a non-zero value for horizontal or vertical
    if(horizontal != 0 || vertical != 0)
    {
    //Call AttemptMove passing in the generic parameter Wall, since that is what Player may interact with if they encounter one (by attacking it)
    //Pass in horizontal and vertical as parameters to specify the direction to move Player in.
    AttemptMove<Wall> (horizontal, vertical);
    }
    }
    }

    //This is the code that I've got from the tutorials,it works ,no errors, But.I've been trying to understand the movement engine,
    Player still moves twice compared to once for enemy.?
     
  39. cyber_shawn

    cyber_shawn

    Joined:
    Jun 13, 2017
    Posts:
    7
    and the movingObject script...

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    //The abstract keyword enables you to create classes and class members that are incomplete
    //- and must be implemented in a derived class.
    //player and enemy will borrow this
    public abstract class MovingObject : MonoBehaviour {

    public float moveTime = 0.1f; //Time it will take object to move, in seconds.
    public LayerMask blockingLayer; //Layer on which collision will be checked.


    private BoxCollider2D boxCollider; //The BoxCollider2D component attached to this object.
    private Rigidbody2D rb2D; //The Rigidbody2D component attached to this object.
    private float inverseMoveTime; //Used to make movement more efficient.

    protected bool canMove;

    //Protected, virtual functions can be overridden by inheriting classes.
    protected virtual void Start () {
    //Get a component reference to this object's BoxCollider2D
    boxCollider = GetComponent <BoxCollider2D> ();

    //Get a component reference to this object's Rigidbody2D
    rb2D = GetComponent <Rigidbody2D> ();

    //By storing the reciprocal of the move time we can use it by multiplying instead of dividing, this is more efficient!?
    inverseMoveTime = 1f / moveTime;
    }
    //The virtual keyword means AttemptMove can be overridden by inheriting classes using the override keyword.
    //AttemptMove takes a generic parameter T to specify the type of component we expect our unit to interact with if blocked (Player for Enemies, Wall for Player).
    protected virtual void AttemptMove <T> (int xDir, int yDir)
    where T : Component
    {
    //Hit will store whatever our linecast hits when Move is called.
    RaycastHit2D hit;

    //Set canMove to true if Move was successful, false if failed.
    bool canMove = Move (xDir, yDir, out hit);

    //Check if nothing was hit by linecast
    if(hit.transform == null)
    //If nothing was hit, return and don't execute further code.
    return;

    //Get a component reference to the component of type T attached to the object that was hit
    T hitComponent = hit.transform.GetComponent <T> ();

    //If canMove is false and hitComponent is not equal to null, meaning MovingObject is blocked and has hit something it can interact with.
    if(!canMove && hitComponent != null)

    //Call the OnCantMove function and pass it hitComponent as a parameter.
    OnCantMove (hitComponent);
    }
    //Move returns true if it is able to move and false if not.
    //Move takes parameters for x direction, y direction and a RaycastHit2D to check collision.
    protected bool Move (int xDir, int yDir, out RaycastHit2D hit)
    {
    //Store start position to move from, based on objects current transform position.
    Vector2 start = transform.position;

    // Calculate end position based on the direction parameters passed in when calling Move.
    Vector2 end = start + new Vector2 (xDir, yDir);

    //Disable the boxCollider so that linecast doesn't hit this object's own collider.?!wow,goodtoKNow
    boxCollider.enabled = false;

    //Cast a line from start point to end point checking collision on blockingLayer.
    hit = Physics2D.Linecast (start, end, blockingLayer);

    //Re-enable boxCollider after linecast-!use in unison with false statment above
    boxCollider.enabled = true;

    //Check if anything was hit
    if(hit.transform == null)
    {
    //If nothing was hit, start SmoothMovement co-routine passing in the Vector2 end as destination
    StartCoroutine (SmoothMovement (end));
    canMove = true;
    //Return true to say that Move was successful
    return true;
    }

    //If something was hit, return false, Move was unsuccesful.
    canMove = false;
    return false;
    }

    //Co-routine for moving units from one space to next, takes a parameter end to specify where to move to.
    protected IEnumerator SmoothMovement (Vector3 end)
    {
    //Calculate the remaining distance to move based on the square magnitude of the difference between current position and end parameter.
    //Square magnitude is used instead of magnitude because it's computationally cheaper.
    float sqrRemainingDistance = (transform.position - end).sqrMagnitude;

    //While that distance is greater than a very small amount (Epsilon, almost zero):
    while(sqrRemainingDistance > float.Epsilon)
    {
    //Find a new position proportionally closer to the end, based on the moveTime
    Vector3 newPostion = Vector3.MoveTowards(rb2D.position, end, inverseMoveTime * Time.deltaTime);

    //Call MovePosition on attached Rigidbody2D and move it to the calculated position.
    rb2D.MovePosition (newPostion);

    //Recalculate the remaining distance after moving.
    sqrRemainingDistance = (transform.position - end).sqrMagnitude;

    //Return and loop until sqrRemainingDistance is close enough to zero to end the function
    yield return null;
    }
    }
    //The abstract modifier indicates that the thing being modified has a missing or incomplete implementation.
    //OnCantMove will be overriden by functions in the inheriting classes.
    protected abstract void OnCantMove <T> (T component)
    where T : Component;
    }
     
  40. kvu39564

    kvu39564

    Joined:
    May 15, 2017
    Posts:
    9
    Could you add your MovingObject.cs code? I think I have an idea of what's going on.

    P.S. It's a lot easier on the eyes if you could paste your code in with code tags. There's an insert button, then just hit code, and paste your code in there.
     
  41. cyber_shawn

    cyber_shawn

    Joined:
    Jun 13, 2017
    Posts:
    7
    Ok, Maybe this attachment is easier to read, MovingObject class, its not much different from the tutorial's version.
     

    Attached Files:

  42. cyber_shawn

    cyber_shawn

    Joined:
    Jun 13, 2017
    Posts:
    7
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. //The abstract keyword enables you to create classes and class members that are incomplete
    6. //- and must be implemented in a derived class.
    7. //player and enemy will borrow this
    8. public abstract class MovingObject : MonoBehaviour {
    9.  
    10.     public float moveTime = 0.1f;           //Time it will take object to move, in seconds.
    11.     public LayerMask blockingLayer;         //Layer on which collision will be checked.
    12.  
    13.  
    14.     private BoxCollider2D boxCollider;      //The BoxCollider2D component attached to this object.
    15.     private Rigidbody2D rb2D;               //The Rigidbody2D component attached to this object.
    16.     private float inverseMoveTime;          //Used to make movement more efficient.
    17.  
    18.     protected bool canMove;
    19.  
    20.     //Protected, virtual functions can be overridden by inheriting classes.
    21.     protected virtual void Start () {
    22.         //Get a component reference to this object's BoxCollider2D
    23.         boxCollider = GetComponent <BoxCollider2D> ();
    24.  
    25.         //Get a component reference to this object's Rigidbody2D
    26.         rb2D = GetComponent <Rigidbody2D> ();
    27.  
    28.         //By storing the reciprocal of the move time we can use it by multiplying instead of dividing, this is more efficient!?
    29.         inverseMoveTime = 1f / moveTime;
    30.     }
    31.     //The virtual keyword means AttemptMove can be overridden by inheriting classes using the override keyword.
    32.     //AttemptMove takes a generic parameter T to specify the type of component we expect our unit to interact with if blocked (Player for Enemies, Wall for Player).
    33.     protected virtual void AttemptMove <T> (int xDir, int yDir)
    34.         where T : Component
    35.     {
    36.         //Hit will store whatever our linecast hits when Move is called.
    37.         RaycastHit2D hit;
    38.  
    39.         //Set canMove to true if Move was successful, false if failed.
    40.         bool canMove = Move (xDir, yDir, out hit);
    41.  
    42.         //Check if nothing was hit by linecast
    43.         if(hit.transform == null)
    44.             //If nothing was hit, return and don't execute further code.
    45.             return;
    46.  
    47.         //Get a component reference to the component of type T attached to the object that was hit
    48.         T hitComponent = hit.transform.GetComponent <T> ();
    49.  
    50.         //If canMove is false and hitComponent is not equal to null, meaning MovingObject is blocked and has hit something it can interact with.
    51.         if(!canMove && hitComponent != null)
    52.  
    53.             //Call the OnCantMove function and pass it hitComponent as a parameter.
    54.             OnCantMove (hitComponent);
    55.     }
    56.     //Move returns true if it is able to move and false if not.
    57.     //Move takes parameters for x direction, y direction and a RaycastHit2D to check collision.
    58.     protected bool Move (int xDir, int yDir, out RaycastHit2D hit)
    59.     {
    60.         //Store start position to move from, based on objects current transform position.
    61.         Vector2 start = transform.position;
    62.  
    63.         // Calculate end position based on the direction parameters passed in when calling Move.
    64.         Vector2 end = start + new Vector2 (xDir, yDir);
    65.  
    66.         //Disable the boxCollider so that linecast doesn't hit this object's own collider.?!wow,goodtoKNow
    67.         boxCollider.enabled = false;
    68.  
    69.         //Cast a line from start point to end point checking collision on blockingLayer.
    70.         hit = Physics2D.Linecast (start, end, blockingLayer);
    71.  
    72.         //Re-enable boxCollider after linecast-!use in unison with false statment above
    73.         boxCollider.enabled = true;
    74.  
    75.         //Check if anything was hit
    76.         if(hit.transform == null)
    77.         {
    78.             //If nothing was hit, start SmoothMovement co-routine passing in the Vector2 end as destination
    79.             StartCoroutine (SmoothMovement (end));
    80.             canMove = true;
    81.             //Return true to say that Move was successful
    82.             return true;
    83.         }
    84.  
    85.         //If something was hit, return false, Move was unsuccesful.
    86.         canMove = false;
    87.         return false;
    88.     }
    89.  
    90.     //Co-routine for moving units from one space to next, takes a parameter end to specify where to move to.
    91.     protected IEnumerator SmoothMovement (Vector3 end)
    92.     {
    93.         //Calculate the remaining distance to move based on the square magnitude of the difference between current position and end parameter.
    94.         //Square magnitude is used instead of magnitude because it's computationally cheaper.
    95.         float sqrRemainingDistance = (transform.position - end).sqrMagnitude;
    96.  
    97.         //While that distance is greater than a very small amount (Epsilon, almost zero):
    98.         while(sqrRemainingDistance > float.Epsilon)
    99.         {
    100.             //Find a new position proportionally closer to the end, based on the moveTime
    101.             Vector3 newPostion = Vector3.MoveTowards(rb2D.position, end, inverseMoveTime * Time.deltaTime);
    102.  
    103.             //Call MovePosition on attached Rigidbody2D and move it to the calculated position.
    104.             rb2D.MovePosition (newPostion);
    105.  
    106.             //Recalculate the remaining distance after moving.
    107.             sqrRemainingDistance = (transform.position - end).sqrMagnitude;
    108.  
    109.             //Return and loop until sqrRemainingDistance is close enough to zero to end the function
    110.             yield return null;
    111.         }
    112.     }
    113.     //The abstract modifier indicates that the thing being modified has a missing or incomplete implementation.
    114.     //OnCantMove will be overriden by functions in the inheriting classes.
    115.     protected abstract void OnCantMove <T> (T component)
    116.         where T : Component;
    117. }
     
  43. kvu39564

    kvu39564

    Joined:
    May 15, 2017
    Posts:
    9
    Just noticed that the boolean in AttemptMove and the protected bool was the same (oversight on my part). It might be causing issues (although I don't think it should).

    I also noticed in my Move function, I actually returned the 'canMove' value instead of a 'true' or 'false'.

    So, try one could be the following:

    Code (CSharp):
    1.     protected bool Move (int xDir, int yDir, out RaycastHit2D hit)
    2.     {
    3.  
    4.         Vector2 start = transform.position;
    5.         Vector2 end = start + new Vector2 (xDir, yDir);
    6.  
    7.         boxCollider.enabled = false;
    8.  
    9.         hit = Physics2D.Linecast (start, end, blockingLayer);
    10.  
    11.         boxCollider.enabled = true;
    12.  
    13.         if(hit.transform == null)
    14.         {
    15.             StartCoroutine (SmoothMovement (end));
    16.  
    17.             canMove = true; //Update
    18.             return canMove; //Update
    19.         }
    20.  
    21.         canMove = false;  //Update
    22.         return canMove; //Update
    23.     }
    24.  
    [/code]

    Or this:

    Code (CSharp):
    1.  
    2.    protected bool canMove2;  //Update
    3.  
    4.    protected virtual void AttemptMove <T> (int xDir, int yDir)
    5.         where T : Component
    6.     {
    7.         RaycastHit2D hit;
    8.  
    9.         //This might be the issue since it's the same name as the protected bool.
    10.         //You can rename the protected bool to something (ex. canMove2)
    11.         bool canMove = Move (xDir, yDir, out hit);
    12.  
    13.         if(hit.transform == null)
    14.             return;
    15.  
    16.         T hitComponent = hit.transform.GetComponent <T> ();
    17.  
    18.         if(!canMove && hitComponent != null)
    19.             OnCantMove (hitComponent);
    20.     }
    21.  
    22.     protected bool Move (int xDir, int yDir, out RaycastHit2D hit)
    23.     {
    24.  
    25.         Vector2 start = transform.position;
    26.         Vector2 end = start + new Vector2 (xDir, yDir);
    27.  
    28.         boxCollider.enabled = false;
    29.  
    30.         hit = Physics2D.Linecast (start, end, blockingLayer);
    31.  
    32.         boxCollider.enabled = true;
    33.  
    34.         if(hit.transform == null)
    35.         {
    36.             StartCoroutine (SmoothMovement (end));
    37.  
    38.             canMove2 = true; //Update
    39.             return canMove2; //Update
    40.         }
    41.  
    42.         canMove2 = false;  //Update
    43.         return canMove2; //Update
    44.     }
    45.  
    The in your "Player" script reference canMove2.

    Let me know how it goes.
     
    Last edited: Jun 14, 2017
  44. kvu39564

    kvu39564

    Joined:
    May 15, 2017
    Posts:
    9
    Could you attach all of your code files? I'd like to take a look. I feel like there might be another issue and want to help.
     
  45. cyber_shawn

    cyber_shawn

    Joined:
    Jun 13, 2017
    Posts:
    7
    Nope still nothing. I thought you were on to something earlier with the canMove variable,but nothing worked. I've been running trace checks, and the more I look under the hood, the more confused I am. My enemy move function gets called twice per round whether it moves or not? Weird. I suspect problems lie somewhere within the inheritance method calls. The game movement mechanic works well enough for this game, However scaling it up with larger maps causes problems. The character positioning is not quite accurate, causing random map offsets. I'm not convinced this code method is efficient or useful for my needs anymore. Plus, I've heard about an efficient way of creating tile games without any collision at all using a 2D array of sorts It enables you to store game information in the array, which this does not.
     
  46. kvu39564

    kvu39564

    Joined:
    May 15, 2017
    Posts:
    9
    When you run the game, are there two instances of the game running? When you go to the exit, does the level jump by two? There was an issue I had with that when I was doing the tutorial. Removing the InitGame(); line from the Awake() method of GameManager fixed that issues for me. It was mentioned in this thread as well.

    I've read there were better methods to do this game as well, but I'm assuming they chose this route for simplicity to help learn.
     
  47. soundofimpact

    soundofimpact

    Joined:
    Jun 16, 2017
    Posts:
    1
    I'm in part 4 of the tutorial where you have to run the GameManager object in the Scene dialog, after adding completed GameManager and BoardManager scripts to it. This causes Unity to freeze (which freezes my entire PC). I've carefully checked over the code and can't spot any infinite loops, etc. Is there a way to step through what GameManager does in a controlled manner, like in a graphical debugger? Thanks.
     
  48. jimm84

    jimm84

    Joined:
    Feb 26, 2017
    Posts:
    7
    Hello I was hoping someone could help. I have just got to the end of the Roguelike tut video 5 and I ran into this issue. after writing the Loader script and adding the Loader Script to the camera. Although it is saying that issue is in the code of the GameManager.

    NullReferenceException: Object reference not set to an instance of an object
    GameManager.InitGame () (at Assets/Scripts/GameManager.cs:42)
    GameManager.Awake () (at Assets/Scripts/GameManager.cs:35)

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class Loader : MonoBehaviour {
    5.  
    6.     public GameObject gameManager;
    7.  
    8.     void Awake()
    9.     {
    10.         if (GameManager.instance == null)
    11.             Instantiate (gameManager);
    12.     }
    13. }
    GameManager


    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. using System.Collections.Generic;       //Allows us to use Lists.
    5.  
    6. public class GameManager : MonoBehaviour
    7. {
    8.  
    9.     public static GameManager instance = null;              //Static instance of GameManager which allows it to be accessed by any other script.
    10.     private BoardManager boardScript;                    //Store a reference to our BoardManager which will set up the level.
    11.     private int level = 3;                                  //Current level number, expressed in game as "Day 1".
    12.  
    13.     //Awake is always called before any Start functions
    14.     void Awake()
    15.     {
    16.         //Check if instance already exists
    17.         if (instance == null)
    18.  
    19.             //if not, set instance to this
    20.             instance = this;
    21.  
    22.         //If instance already exists and it's not this:
    23.         else if (instance != this)
    24.  
    25.             //Then destroy this. This enforces our singleton pattern, meaning there can only ever be one instance of a GameManager.
    26.             Destroy(gameObject);  
    27.  
    28.         //Sets this to not be destroyed when reloading scene
    29.         DontDestroyOnLoad(gameObject);
    30.  
    31.         //Get a component reference to the attached BoardManager script
    32.         boardScript = GetComponent<BoardManager>();
    33.  
    34.         //Call the InitGame function to initialize the first level
    35.         InitGame();
    36.     }
    37.  
    38.     //Initializes the game for each level.
    39.     void InitGame()
    40.     {
    41.         //Call the SetupScene function of the BoardManager script, pass it current level number.
    42.         boardScript.SetupScene(level);
    43.  
    44.     }
    45.  
    46.  
    47.  
    48.     //Update is called every frame.
    49.     void Update()
    50.     {
    51.  
    52.     }
    53. }
    Thanks for your help, any pointers would be appreciated
     
  49. Tempest74

    Tempest74

    Joined:
    May 17, 2017
    Posts:
    133
    hey, I have a little problem. when I use the code from Adding UI & Level Transitions my game work fine but when i replace
    void OnLevelWasLoaded(int index)
    {
    //Add one to our level number.
    level++;
    //Call InitGame to initialize our level.
    InitGame();
    }
    with this code from https://oc.unity3d.com/index.php/s/...26.789555580.1497628523-1161539556.1494945999:
    void OnLevelFinishedLoading(Scene scene, LoadSceneMode mode)
    {
    level++;
    InitGame();
    }
    void OnEnable()
    {//Tell our ‘OnLevelFinishedLoading’ function to start listening for a scene change event as soon as this script is enabled.
    SceneManager.sceneLoaded += OnLevelFinishedLoading;
    }
    void OnDisable(){
    //Tell our ‘OnLevelFinishedLoading’ function to stop listening for a scene change event as soon as this script is disabled.
    //Remember to always have an unsubscription for every delegate you subscribe to!
    SceneManager.sceneLoaded -= OnLevelFinishedLoading;
    }

    my game start counting the day double like instead of 1 I have 2 and instead of 2 i have 4. why?
    And sometime I die with no reason
     
  50. gwnguy

    gwnguy

    Joined:
    Apr 25, 2017
    Posts:
    144
    First, you are sure you added the GameManager prefab object to your Loader script
    Then, you are sure that both scripts in the GameManager prefab are set up correctly
    Make sure any entries you've made for the scripts, and the scripts themselves, aren't from the "completed" project area.

    Your scripts look correct, so I'd suspect the wiring in Unity.
     
Thread Status:
Not open for further replies.