1. We're looking for feedback on Unity Starter Kits! Let us know what you’d like.
    Dismiss Notice
  2. Unity 2017.2 beta is now available for download.
    Dismiss Notice
  3. Unity 2017.1 is now released.
    Dismiss Notice
  4. Introducing the Unity Essentials Packs! Find out more.
    Dismiss Notice
  5. Check out all the fixes for 5.6 on the patch releases page.
    Dismiss Notice
  6. Help us improve the editor usability and artist workflows. Join our discussion to provide your feedback.
    Dismiss Notice

2D Roguelike: Q&A

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

  1. 8_Stackz

    8_Stackz

    Joined:
    Oct 26, 2015
    Posts:
    1
    -----------------------------------------------------------
    Hey there

    I too had this problem, but I solved it using the following :)

    GameManager:
    Code (csharp):
    1.  
    2.     void Awake () {
    3.         if (instance == null) {
    4.             instance = this;
    5.         } else if (instance != this) {
    6.             Destroy (gameObject);
    7.         }
    8.  
    9.          //For persistance between scenes
    10.          DontDestroyOnLoad (gameObject);
    11.  
    12.          enemies = newList <Enemy> ();
    13.          boardScript = GetComponent <BoardManager> ();
    14.          InitGame ();
    15.     }
    16.  
    17.      private void OnLevelFinishedLoading (Scene scene, LoadSceneMode mode) {
    18.          if (level > 1) {
    19.              InitGame ();
    20.          }
    21.          level++;
    22.      }
    23.  
    24.      private void OnEnable () {
    25.          SceneManager.sceneLoaded += OnLevelFinishedLoading;
    26.      }
    27.  
    28.      privatevoidOnDisable(){
    29.          SceneManager.sceneLoaded-=OnLevelFinishedLoading;
    30.      }
    31.  
    Just add to the level count after the initGame call in OnLevelFinishedLoading, and only call initGame after the first time it has been loaded.
    Hope this helps :)
     
    Matthew-Schell likes this.
  2. AnneSchmidt

    AnneSchmidt

    Joined:
    Aug 8, 2016
    Posts:
    516
    I haven't finished this tutorial yet so, no, no idea. You should take a look at other tutorials having this restart button and see how you can adapt their solution to this project.
     
  3. DatGuyPotato

    DatGuyPotato

    Joined:
    Jul 14, 2016
    Posts:
    8
  4. rmiles55

    rmiles55

    Joined:
    Sep 11, 2016
    Posts:
    1
    Does anyone know of a simple explosion animation I can add to the enemies? I have added code for player weapons, and I destroy the enemies, but it is pretty boring just watching them disappear.
     
  5. CamoClayton

    CamoClayton

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

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4.  
    5.    
    6. public abstract class MovingObject : MonoBehaviour
    7. {
    8.     //how fast the objects move
    9.     public float moveTime = 0.1f;
    10.     public LayerMask blockingLayer;
    11.  
    12.     //sets rigidbody and collider also makes calculations run smoother
    13.     private BoxCollider2D boxCollider;
    14.     private Rigidbody2D rb2D;
    15.     private float inverseMoveTime;
    16.  
    17.     // modified start so that they can be overridden by other classes
    18.     protected virtual void Start ()
    19.     {
    20.         boxCollider = GetComponent <BoxCollider2D> ();
    21.         rb2D = GetComponent <Rigidbody2D> ();
    22.         inverseMoveTime = 1f / moveTime; //division is more effecient.
    23.     }
    24.     protected bool Move (int xDir, int yDir, out RaycastHit2D hit)
    25.     {
    26.         Vector2 start = transform.position;             //Store start position to move from
    27.         Vector2 end = start + new Vector2 (xDir, yDir); //calculate end position
    28.  
    29.         boxCollider.enabled = false;                    //disables the boxcollider so that linecast doesnt hit itself
    30.  
    31.         hit = Physics2D.Linecast (start, end, blockingLayer);
    32.  
    33.         boxCollider.enabled = true;                     //turns boxcollider back on
    34.  
    35.         if(hit.transform == null)
    36.         {
    37.                 StartCoroutine (SmoothMovement (end));
    38.                 return true; //move was successful
    39.             }
    40.  
    41.                 return false; //if something was hit, move unsuccessful.
    42.     }
    43.  
    44.     protected IEnumerator SmoothMovement (Vector3 end)
    45.     {
    46.         float sqrRemainingDistance = (transform.position - end).sqrMagnitude;
    47.  
    48.         while (sqrRemainingDistance > float.Epsilon)
    49.         {
    50.             Vector3 newPosition = Vector3.MoveTowards(rb2D.position, end, inverseMoveTime * Time.deltaTime);
    51.             rb2D.MovePosition (newPosition);
    52.             sqrRemainingDistance = (transform.position - end).sqrMagnitude;
    53.             yield return null;
    54.         }
    55.     }
    56.             protected virtual void AttemptMove <T> (int xDir, int yDir)
    57.             where T : Component
    58.             {
    59.                 RaycastHit2D hit;
    60.                 bool canMove = Move (xDir, yDir, out hit);
    61.  
    62.                 if (hit.transform == null)
    63.                     return;
    64.  
    65.             //if something is hit
    66.                 T hitComponent = hit.transform.GetComponent <T> ();
    67.                    
    68.                 if(!canMove && hitComponent != null)
    69.                     OnCantMove(hitComponent);
    70.             }
    71.  
    72.     //protected abstract function that will be overidden by inherent classes.
    73.     protected abstract void OnCantMove <T> (T component)
    74.         where T : Component;
    75.  
    76.         }
    77.  



    Any help would be appreciated and its rather urgent as I chose to do this tutorial for an assignment. Doh!!
     

    Attached Files:

  6. leomuteki

    leomuteki

    Joined:
    Dec 14, 2016
    Posts:
    2
    Hello everybody!

    In the GameManager script, in the singleton algorithm, we use Destroy(gameObject). Can we substitute the gameObject function for "this". It seems to be more descriptive for readability purposes. If so, why is gameObject used instead of this?

    Thank you!!!
     
  7. EthanLac

    EthanLac

    Joined:
    Dec 17, 2016
    Posts:
    1
    Hi everyone, I seem to be having some trouble with my scripts. In the script for destroying walls (Imaginatively called DestroyWall), VisualStudio complains that "instance" is not accepted as a word, despite it working fine in the tutorial. Could someone please help me with this?

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. namespace Completed
    5. {
    6.     using System.Collections.Generic;
    7.  
    8.     public class DestroyWall : MonoBehaviour
    9.     {
    10.         public AudioClip chopSound1;                //1 of 2 audio clips that play when the wall is attacked by the player.
    11.         public AudioClip chopSound2;                //2 of 2 audio clips that play when the wall is attacked by the player.
    12.         public Sprite dmgSprite;                    //Alternate sprite to display after Wall has been attacked by player.
    13.         public int hp = 3;                          //hit points for the wall.
    14.         public GameObject soundManager;
    15.  
    16.  
    17.         private SpriteRenderer spriteRenderer;      //Store a component reference to the attached SpriteRenderer.
    18.  
    19.  
    20.         void Awake()
    21.         {
    22.             //Get a component reference to the SpriteRenderer.
    23.             spriteRenderer = GetComponent<SpriteRenderer>();
    24.         }
    25.  
    26.  
    27.         //DamageWall is called when the player attacks a wall.
    28.         public void DamageWall(int loss)
    29.         {
    30.             //Call the RandomizeSfx function of SoundManager to play one of two chop sounds.
    31.             soundManager.instance.RandomizeSfx(chopSound1, chopSound2);
    32.  
    33.             //Set spriteRenderer to the damaged wall sprite.
    34.             spriteRenderer.sprite = dmgSprite;
    35.  
    36.             //Subtract loss from hit point total.
    37.             hp -= loss;
    38.  
    39.             //If hit points are less than or equal to zero:
    40.             if (hp <= 0)
    41.                 //Disable the gameObject.
    42.                 gameObject.SetActive(false);
    43.         }
    44.     }
    45. }
    Thanks in advance.
     
  8. TheProfessor

    TheProfessor

    Joined:
    Nov 2, 2014
    Posts:
    47
    So in the Enemy and Player scripts I get an error about the GameManager not having certain member variables/functions existing; I don't see where in the Tutorial videos when/where you go and adjust GameManager to match the one in the Completed folder; when does this occur? It's driving me nuts.
     
  9. TheProfessor

    TheProfessor

    Joined:
    Nov 2, 2014
    Posts:
    47
    I found it, so scratch my above post; but now I have a problem: the "Singleton" code doesn't seem to actually work.

    InitGame() is still called in the destroyed instance before it is destroyed, resulting in duplicate assets.

    Additionally ending Day 2 seems to skip to Day 4, and I have zero food.

    Edit: I fixed it by putting enemies = new..., boardScript =... and InitGame() into an else branch so it's skipped if instance != this.


    I also had to put it into "if instance == null)" branch.

    Another problem I had is that when I hit play, even though my GameManager was the only one in my scene and I had not at all loaded the Completed scene, it insisted on attempting to use the Complete.GameManager and I got a null reference exception on loading levels. I figure this is causing my issues.
     
  10. bardan

    bardan

    Joined:
    Sep 12, 2016
    Posts:
    6
    bro, would you mind sharing your codes..
     
  11. TheProfessor

    TheProfessor

    Joined:
    Nov 2, 2014
    Posts:
    47
    Why? I think I was pretty clear I figured it out, it was in Enemy Animator Controller for some strange arbitrary reason.

    The line: "food = GameManager.instance.playerFoodPoints;" doesn't work in the video they originally type it, because GameManager literally doesn't have a public "playerFoodPoints" member variable at the time in the video.
     
  12. doomvad

    doomvad

    Joined:
    Dec 18, 2016
    Posts:
    2
    Hi everyone here!
    I have an issue, I can't hit walls. I was trying to find the reason using debugger and I found out that the problem of my case was an impossibility to get wall component. In MovingObject script we have a clause:

    T hitComponent = hit.transform.GetComponent<T>();

    So if I collide with wall parameter hitComponent is always NULL and then I can’t pass if-clause to invoke OnCantMove function. But with the enemy collisions parameter hitComponent has {Player} value and everything is clear and works correctly. I have no idea what the problem with the walls. What did I made wrong? (my unity version is 5.5 Personal)
     
  13. TheProfessor

    TheProfessor

    Joined:
    Nov 2, 2014
    Posts:
    47
    Do the Walls have a Wall script attached at the root?
     
  14. doomvad

    doomvad

    Joined:
    Dec 18, 2016
    Posts:
    2
    Yes, it does.
     
  15. nekrophile

    nekrophile

    Joined:
    May 12, 2016
    Posts:
    1
    With SoundManager.cs, the pitch randomization seems to be defined globally for all sounds using RandomizeSfx.

    Can you give me some pointers if I wanted to specify a different range of pitch randomization (i.e. 0.75,1.25) for certain sounds (i.e. scavengers_footstep)?

    Similarly, when using RandomizeSfx what would be the best practice for adjusting the volume of an individual audioclip?
     
  16. Skyyofficial7

    Skyyofficial7

    Joined:
    Jun 18, 2014
    Posts:
    1
    Is there a way to remove the short delays between moves? so that its still in turns but when you keep running in one direction you dont stop after every step.
    would be great if someone knows how to do this
     
  17. TheProfessor

    TheProfessor

    Joined:
    Nov 2, 2014
    Posts:
    47
    Did you try setting timeDelay to 0? =/
     
  18. TheProfessor

    TheProfessor

    Joined:
    Nov 2, 2014
    Posts:
    47
    So some thoughts:

    1. Why is it that the completed scripts uploaded online are in the "Completed" namespace? With bad line endings in some cases to boot. This is a minor issue but I think a lot of people who are new to C# aren't going to realize this causes issues to have two scripts sharing a namespace and won't know how to fix it.

    2. Early videos introduce code that isn't implemented until several videos later; essentially rendering the tutorial out of order and in many cases introduces annoying syntax errors regarding undefined functions. If the SoundManager and completed GameManager classes are only going to be shown later; couldn't the early tutorials found a better way to reference them? Again it's going to causes unnecessary issues with people new to C#.

    3. I haven't found any consistent behaviors with dragging selected sprites onto a GameObject to create an animation clip. It seems to create an animation in the same folder as the Sprite Sheet with the Sprite Sheet's name most of the time, and only prompts for save location and file name a minority of the time.

    The most consistent instruction should have been to create an animation controller for the sprite in question; add it to a game object, select the game object, go to the animation window and create a new clip and choose where to save it with a file name.

    4. There is *something* off about the GameManager instance implementation that isn't working correctly in some instances. It appears to result in duplicate tilesets created each time a scene is loaded;

    5. And sometimes it will try to use the GameManager class from the Complete folder instead of the GameManager that is actually on the game object in the scene in question regardless of it's namespace.
     
  19. jannaisop

    jannaisop

    Joined:
    Dec 26, 2016
    Posts:
    7
    Finished the tutorial but a couple of questions

    How might I go about changing the touch screen controls from swiping to tapping in a direction instead?

    And how can I fix the player getting stuck inside an enemy or the enemies getting stuck inside each other?

    Thanks!
     
    Last edited: Dec 26, 2016
  20. LeonardoCoV

    LeonardoCoV

    Joined:
    Dec 28, 2016
    Posts:
    2
    first one of best tutorials

    Hi I have a trouble it's posted but I don't know mine have another thing and I pass the las two day's trying to solve but nothing... it's again I can move my player one time and no more and another stranger thing the player move on diagnal I don't now... my code is equals the compled i show here moving, game manager and player scripts if need some another please say and I'll post thx for all

    [Edited]
    Oh yeah I missing to tell don't have warnings or errors nor VStudio or monodev

    MovingObject.cs

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


    Code (CSharp):
    1. using System;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5. using UnityEngine.SceneManagement;
    6. using UnityEngine.UI;
    7.  
    8. public class Player : MovingObject
    9. {
    10.     public int wallDamage = 1;
    11.     public int pointsPerFood = 10;
    12.     public int pointsPerSoda = 20;
    13.     public float restartLevelDelay = 1.0f;
    14.     public Text foodText;
    15.     public AudioClip moveSound1;
    16.     public AudioClip moveSound2;
    17.     public AudioClip eatSound1;
    18.     public AudioClip eatSound2;
    19.     public AudioClip drinkSound1;
    20.     public AudioClip drinkSound2;
    21.     public AudioClip gameOverSound;
    22.  
    23.  
    24.     private Animator animator;
    25.     private int food;
    26.     private Vector2 touchOrigin = -Vector2.one;
    27.  
    28.     // Use this for initialization
    29.     protected override void Start ()
    30.     {
    31.         animator = GetComponent<Animator>();
    32.         food = GameManager.instance.playerFoodPoints;
    33.         foodText.text = "Food:" + food;
    34.         base.Start();
    35.     }
    36.  
    37.     private void OnDisable()
    38.     {
    39.         GameManager.instance.playerFoodPoints = food;
    40.     }
    41.  
    42.     // Update is called once per frame
    43.     void Update ()
    44.     {
    45.         if (!GameManager.instance.playersTurn) return;
    46.  
    47.         int horizontal = 0;
    48.         int vertical = 0;
    49.  
    50. #if UNITY_EDITOR || UNITY_STANDALONE || UNITY_WEBPLYER
    51.  
    52.         horizontal = (int)(Input.GetAxisRaw("Horizontal"));
    53.         vertical = (int)(Input.GetAxisRaw("Vertical"));
    54.  
    55.         if (horizontal != 0)
    56.             vertical = 0;
    57.  
    58. #else
    59.         if(Input.touchCount > 0)
    60.         {
    61.             Touch myTouch = Input.touches[0];
    62.  
    63.             if(myTouch.phase == TouchPhase.Began)
    64.             {
    65.                 touchOrigin = myTouch.position;
    66.             }
    67.  
    68.             else if(myTouch.phase == TouchPhase.Ended && touchOrigin.x >=0)
    69.             {
    70.                 Vector2 touchEnd = myTouch.position;
    71.                 float x = touchEnd.x - touchOrigin.x;
    72.                 float y = touchEnd.y - touchOrigin.y;
    73.                 touchOrigin.x = -1;
    74.  
    75.                 if (Mathf.Abs(x) > Mathf.Abs(y))
    76.                     horizontal = x > 0 ? 1 : -1;
    77.                 else
    78.                     vertical = y > 0 ? 1 : -1;
    79.             }
    80.         }
    81.  
    82. #endif
    83.  
    84.         if (horizontal != 0 || vertical != 0)
    85.             AttemptMove<Wall>(horizontal, vertical);
    86.     }
    87.  
    88.     protected override void AttemptMove<T>(int xDir, int yDir)
    89.     {
    90.         food--;
    91.         foodText.text = "Food:" + food;
    92.  
    93.         base.AttemptMove<T>(xDir, yDir);
    94.  
    95.         RaycastHit2D hit;
    96.  
    97.         if(Move(xDir, yDir, out hit))
    98.         {
    99.             SoundManager.instance.RandomizeSfx(moveSound1, moveSound2);
    100.         }
    101.  
    102.         CheckIfGameOver();
    103.  
    104.         GameManager.instance.playersTurn = false;
    105.     }
    106.  
    107.     private void OnTriggerEnter2D(Collider2D other)
    108.     {
    109.         if (other.tag == "Exit")
    110.         {
    111.             Invoke("Restat", restartLevelDelay);
    112.             enabled = false;
    113.         }
    114.  
    115.         else if(other.tag == "Food")
    116.         {
    117.             food += pointsPerFood;
    118.             foodText.text = "+ " + pointsPerFood + " Food " + food;
    119.             SoundManager.instance.RandomizeSfx(eatSound1, eatSound2);
    120.             other.gameObject.SetActive(false);
    121.         }
    122.         else if(other.tag == "Soda")
    123.         {
    124.             food += pointsPerSoda;
    125.             foodText.text = "+ " + pointsPerSoda + " Food " + food;
    126.             SoundManager.instance.RandomizeSfx(drinkSound1, drinkSound2);
    127.             other.gameObject.SetActive(false);
    128.         }
    129.     }
    130.  
    131.     protected override void OnCantMove<T>(T component)
    132.     {
    133.         Wall hitWall = component as Wall;
    134.         hitWall.DamageWall(wallDamage);
    135.         animator.SetTrigger("PlayerChop");
    136.     }
    137.  
    138.     private void Restart()
    139.     {
    140.         SceneManager.LoadScene(0);
    141.     }
    142.  
    143.     public void LoseFood(int loss)
    144.     {
    145.         animator.SetTrigger("PlayerHit");
    146.         food -= loss;
    147.         foodText.text = "-" + loss + "Food: " + food;
    148.         CheckIfGameOver();
    149.     }
    150.  
    151.     private void CheckIfGameOver()
    152.     {
    153.         if (food <= 0)
    154.         {
    155.             SoundManager.instance.PlaySingle(gameOverSound);
    156.             SoundManager.instance.musicSource.Stop();
    157.             GameManager.instance.GameOver();
    158.         }
    159.     }
    160. }
    161.  
    GameManager.cs
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.SceneManagement;
    5. using UnityEngine.UI;
    6.  
    7. public class GameManager : MonoBehaviour
    8. {
    9.     public float levelStartDelay = 2.0f;
    10.     public float turnDelay = .1f;
    11.     public static GameManager instance = null;//to can be acessed by others scripts on game
    12.     public BoardManager boardScript;
    13.     public int playerFoodPoints = 100;
    14.     [HideInInspector]
    15.     public bool playersTurn = true;
    16.  
    17.     private Text levelText;
    18.     private GameObject levelImage;
    19.     private int level = 1;
    20.     private List<Enemy> enemies;
    21.     private bool enemiesMoving;
    22.     private bool doingSetup;
    23.  
    24.  
    25.  
    26.     //This is called each time a scene is loaded.
    27.     void OnLevelFinishedLoading(Scene scene, LoadSceneMode mode)
    28.     {
    29.         //add one to our lvl number
    30.         level++;
    31.         //call Initgma to initialize our level.
    32.         InitGame();
    33.     }
    34.  
    35.     /*private void OnEnable()
    36.     {
    37.         SceneManager.sceneLoaded += OnLevelFinishedLoading;
    38.     }
    39.  
    40.     private void OnDisable()
    41.     {
    42.         SceneManager.sceneLoaded -= OnLevelFinishedLoading;
    43.     }*/
    44.  
    45.     void Awake()
    46.     {
    47.         if (instance == null)
    48.             instance = this;//we play here
    49.         else if (instance != this)
    50.             Destroy(gameObject);//destroy the map(or instance) duplicated
    51.  
    52.         DontDestroyOnLoad(gameObject);
    53.         enemies = new List<Enemy>();  
    54.         boardScript = GetComponent<BoardManager>();
    55.         InitGame();
    56.     }
    57.  
    58.     void InitGame()
    59.     {
    60.         doingSetup = true;
    61.         levelImage = GameObject.Find("LevelImage");
    62.         levelText = GameObject.Find("LevelText").GetComponent<Text>();
    63.         levelText.text = "Day" + level;
    64.         levelImage.SetActive(true);
    65.         Invoke("HideLevelImage", levelStartDelay);
    66.         enemies.Clear();//reset enemies to next lvl
    67.         boardScript.SetupLevel(level);
    68.     }
    69.  
    70.     private void HideLevelImage()
    71.     {
    72.         levelImage.SetActive(false);
    73.         doingSetup = false;
    74.     }
    75.  
    76.     public void GameOver()
    77.     {
    78.         levelText.text = "After " + level + " days, you starved";
    79.         levelImage.SetActive(true);
    80.         enabled = false;
    81.     }
    82.  
    83.     // Update is called once per frame
    84.     void Update()
    85.     {
    86.             if (playersTurn || enemiesMoving || doingSetup)
    87.             return;
    88.  
    89.         StartCoroutine(MoveEnemies());
    90.     }
    91.  
    92.     public void AddEnemyToList(Enemy script)
    93.     {
    94.         enemies.Add(script);
    95.     }
    96.  
    97.     IEnumerator MoveEnemies()
    98.     {
    99.         enemiesMoving = true;
    100.         yield return new WaitForSeconds(turnDelay);
    101.  
    102.         if(enemies.Count == 0)
    103.         {
    104.             yield return new WaitForSeconds(turnDelay);
    105.         }
    106.  
    107.         for(int i = 0; i < enemies.Count; i++)
    108.         {
    109.             enemies[i].MoveEnemy();
    110.             yield return new WaitForSeconds(enemies[i].moveTime);
    111.         }
    112.  
    113.         playersTurn = true;
    114.         enemiesMoving = false;
    115.     }
    116. }
    117.  
    plaese help me thx.
     
    Last edited: Dec 29, 2016
  21. LeonardoCoV

    LeonardoCoV

    Joined:
    Dec 28, 2016
    Posts:
    2
    oooo I FOUND! is the rigid body 2d not seted to kinematic y.y and on wrong walk on second line of function move on MovingObjects I pass wrong the reference like this xD
    Code (CSharp):
    1. Vector2 end = start + new Vector2(xDir, xDir);//is solved yet
    and I found (and fixed) anothers two errors, and I see is have some people have this problem too and I hope it's can be helpfull well the problem... when begin the game is like all good except for the first day is 2 and I can walk arround on sickness and eat fruits and drinking bad health things to cure to try survivor, when I reach exit and go next day the day is 3 or 4 and when you do the first move you die instant, it's simple the board is created two time and you can see on Hierarchy painel, if you delete the second your game bug and if you delete the first your game runs ok but the day count 4 6 8 ... or 3 5 7 9 ... to solve this is simple, on GameManager.cs the function InitGame() is called two times it's because the function OnLevelFinishedLoading(Scene, LoadSceneMode) and Awake() is used initialized game duplicate the board on same scene and put the player on the second map "Day 2" what can do is simple have two options
    1 alterntive- take off the call of InitGame() function from awake because is used 1 time when the game begin the game call GameManager script and no more, with this the gama initilize the "Day 1" with OnLevelFinishedLoading() and all take normal again when you pass to next day and all other this same function will be called calling InitGame in the end (I make this to not change the code so much consuming more process and more 1 memory slot with a count)
    2 alterntive- you can make a other function or put it on awake calling the kernel it's the first time we are run game (it's a new game) well we don't need this function running now, but make rigth your function will be needed on all others next time
     
    Last edited: Dec 29, 2016
    JRWidley likes this.
  22. dacoursey

    dacoursey

    Joined:
    Dec 17, 2016
    Posts:
    28
    I'm trying to do part 5 of the tutorial where the last steps are to add the Loader script to the Main Camera, and then add the GameManager prefab to the Loader script.

    Why don't I have the option like in the video to drag anything into the GameManager field? I'm working in 5.5.0f3

    Thanks
     

    Attached Files:

  23. XerxesIhen

    XerxesIhen

    Joined:
    Jan 4, 2017
    Posts:
    1
    Question01.jpg I have done all the Part 4 tutorial about coding Board Manager, but I can't spawn Floor correctly.
    Please help me!



    Code (CSharp):
    1.  
    2. using UnityEngine;
    3. using System;
    4. //可用Serializable的功能在Unity裡面的Inspector面板裡面修改變數
    5. using System.Collections.Generic;
    6. //可用List功能
    7. using Random = UnityEngine.Random;
    8. //class Random的功能呼叫
    9.  
    10. public class BoardManager : MonoBehaviour {
    11.  
    12.     [Serializable]
    13.     //利用Serializable功能來讀取及時變數並可在Inspector面板裡面修改參數
    14.     public class Count
    15.     //此為可修改之參數功能Count
    16.     {
    17.         public int Minimum;
    18.         public int Maximun;
    19.  
    20.         public Count(int min, int max)
    21.         //此為即時傳送以及修改參數的功能
    22.         {
    23.             Minimum = min;
    24.             Maximun = max;
    25.         }
    26.     }
    27.     public int colums = 8;
    28.     public int rows = 8;
    29.     //上兩句程式為決定遊戲版面大小的參數
    30.     public Count wallCount = new Count(5, 9);
    31.     //此為決定牆壁生產值最小為5,最大為9
    32.     public Count foodCount = new Count(1, 5);
    33.     //此為決定Food生產數量
    34.     public GameObject Exit;
    35.     //此為決定Exit物品的拖放處
    36.     public GameObject[] WallTiles;
    37.     //此為決定Wall物品陣列的拖放處
    38.     public GameObject[] FloorTiles;
    39.     //此為決定Floor物陣列品的拖放處
    40.     public GameObject[] FoodTiles;
    41.     //此為決定Food物品陣列的拖放處
    42.     public GameObject[] EnemyTiles;
    43.     //此為決定Enemy物品陣列的拖放處
    44.     public GameObject[] OuterWallTiles;
    45.     //此為決定OuterWallTiles物品陣列的拖放處
    46.  
    47.     private Transform BoardHolder;
    48.     //將所有生產出的Objects全部歸類為BoardHolder
    49.     private List<Vector3> GridPosition = new List<Vector3>();
    50.     //產生一個List來追蹤所有隨機生產的Objects是否有正常生產
    51.  
    52.     void InitialiseList()
    53.     {
    54.         GridPosition.Clear();
    55.         //清除所有GridPosition裡面所紀錄的Objects
    56.           for( int x =1; x< colums-1; x++)
    57.           //生產的Objects不超出Colums的範圍
    58.         {
    59.             for(int y =1; y< rows-1; y++)
    60.             //生產的Objects不超出Rows的範圍
    61.             {
    62.                 GridPosition.Add(new Vector3(x, y, 0f));
    63.                 //用GridPosition來記錄所有的已生產的Objects
    64.             }
    65.         }
    66.     }
    67.  
    68.     void BoardSetup()
    69.     //製造牆壁
    70.     {
    71.         BoardHolder = new GameObject("Board").transform;
    72.         //將所有的牆壁都歸名為Board的Object
    73.         for( int x= -1; x <colums+1; x++)
    74.         {
    75.             for( int y= -1; y <rows+1; y++)
    76.             {
    77.                 GameObject toInstantiate = FloorTiles[Random.Range(0,FloorTiles.Length)];
    78.                 //用FloorTiles來製造Floor,並用Random來隨機取得座標
    79.                 if (x == -1 || x == colums || y == -1 || y == rows)
    80.                 //一但碰到邊界之後
    81.                 {
    82.                     toInstantiate = OuterWallTiles[Random.Range(0, OuterWallTiles.Length)];
    83.                     //用OuterWallTiles來製造邊界,並用Random來隨機取得座標
    84.                     GameObject instance =
    85.                         Instantiate(toInstantiate, new Vector3(x, y, 0f), Quaternion.identity) as GameObject;
    86.                     //創造一個GameObject instance來複製GameObject toInstantiate並且會對準X及Y並不會任意旋轉
    87.                     instance.transform.SetParent(BoardHolder);
    88.                     //GameObject instance將會收在BoardHolder之中,是整理Hirachy的方法
    89.                 }
    90.             }
    91.         }
    92.     }
    93.  
    94.     Vector3 RandomPosition()
    95.     //隨機座標取得
    96.     {
    97.         int randomIndex = Random.Range(0, GridPosition.Count);
    98.         //隨機座標變數為0至已經生成的數量之間
    99.         Vector3 randomPosition = GridPosition[randomIndex];
    100.         //將Vector3的randomPosistion設成 radomIndex
    101.         GridPosition.RemoveAt(randomIndex);
    102.         //之後將其刪除
    103.         return randomPosition;
    104.     }
    105.  
    106.     void LayoutObjectAtRandom(GameObject[] tileArray, int Minimum, int Maximun)
    107.     {
    108.         int ObjectCount = Random.Range(Minimum, Maximun + 1);
    109.         //隨機產生Object數
    110.         for( int i=0; i< ObjectCount; i++)
    111.         {
    112.             Vector3 randomPosition = RandomPosition();
    113.             //取得隨機RandomPosition
    114.             GameObject TileChoice = tileArray[Random.Range(0, tileArray.Length)];
    115.             //隨機產生TileChoice根據TileArray的分布
    116.             Instantiate(TileChoice, randomPosition, Quaternion.identity);
    117.             //所生成的Copies的位置是根據(TileChoice, randomPosition, Quaternion.identity)而定
    118.         }
    119.  
    120.     }
    121.  
    122.     public void SetupScene(int Level)
    123.     {
    124.         BoardSetup();
    125.         InitialiseList();
    126.         LayoutObjectAtRandom(WallTiles, wallCount.Minimum, wallCount.Maximun);
    127.         LayoutObjectAtRandom(FoodTiles, foodCount.Minimum, foodCount.Maximun);
    128.         int enemyCount = (int)Mathf.Log(Level, 2f);
    129.         LayoutObjectAtRandom(EnemyTiles, enemyCount, enemyCount);
    130.         Instantiate(Exit,new Vector3(colums - 1, rows - 1, 0f), Quaternion.identity);
    131.     }
    132.  
    133.  
    134. }
    135.  
     
  24. Disane

    Disane

    Joined:
    Sep 6, 2016
    Posts:
    2
    I just gone through the video tutorials. There's one thing that desperately needs fixing:
    The player spawining logic and code needs some rethinking. In the video the commentator simply places the player prefab in the game hierarchy (yeah, just like that). Which places the player to a default location which is mostly outside the bounds of the board. There are player spawn related issues regarding the player throughout videos 11 up to 14 because of this.

    My solution would be: modifying the BoardManager and adding the player prefab to the list of spawnable objects and modifying the board creation algorithm in a way that allows the player to be spawned in its own "safe" location where no enemies or obsticles can be spawned. Also, foodText needs to be dyniamically looked up in Start() of the Player's C# script to enable everything that has been said above. If I have time I might post my modifications later today.

    In the meantime could anyone explain to me why Vector3, Quaternions are needed to build the game board, when Vector2 was already available? It's unlikely that you need the Z coordinate being explicitly set, when objects are placed on Z=0 by default. Well, according to my experience.
     
    Last edited: Jan 7, 2017
  25. edwardchuajh

    edwardchuajh

    Joined:
    Jan 8, 2017
    Posts:
    2
    Thanks!! This helped!!
     
  26. TheProfessor

    TheProfessor

    Joined:
    Nov 2, 2014
    Posts:
    47

    Vector3 is probably used because of habit. There isn't really a need for Vector2 unless you're trying really hard not to confuse students new to Unity and 3D games development.

    The player is placed at 0,0,0 and the board is spawned from there; the player isn't outside of bounds if it's perfectly 0,0,0. I think the probability of Monsters spawning within this space next to the player is low enough that it isn't a huge priority if your goal is to be instructional.

    Because at that point you're delving more and more into algorithms.

    The bigger issue I wanna see addressed though that breaks the entire thing is when BoardManager/GameManager is appeared to be called twice in Init().
     
  27. TheProfessor

    TheProfessor

    Joined:
    Nov 2, 2014
    Posts:
    47
    Hrm, for some reason the Awake() in GameManager isn't being called on the subsequent levels with this.
     
  28. Prometheus121

    Prometheus121

    Joined:
    Apr 6, 2016
    Posts:
    15
    So. I've been working on the level generation, and for some reason the top row of outer walls never spawns, and if I change the number of rows and columns, weird things start happening like if I change the rows down, a second outer wall spawns halfway through the map and when I change the columns down, the exit and enemies don't spawn. I'm not sure what it is. Here's my code:

    Board Manager:
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using System;
    5. using Random = UnityEngine.Random;
    6.  
    7. public class BoardManager : MonoBehaviour {
    8.  
    9.     [Serializable]
    10.     public class Count {
    11.         public int minimum;
    12.         public int maximum;
    13.  
    14.         public Count (int min, int max) {
    15.  
    16.             minimum = min;
    17.             maximum = max;
    18.         }
    19.     }
    20.  
    21.     public int columns = 8;
    22.     public int rows = 8;
    23.     public Count wallCount = new Count (5, 9);
    24.     public Count foodCount = new Count (5, 9);
    25.     public GameObject exit;
    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, 0f));
    41.             }
    42.         }
    43.     }
    44.  
    45.     void boardSetUp() {
    46.         boardHolder = new GameObject ("Board").transform;
    47.  
    48.         for (int x = -1; x < columns + 1; x++) {
    49.             for (int y = -1; y < rows + 1; y++) {
    50.                 GameObject toInstantiate = floorTiles[Random.Range (0, floorTiles.Length)];
    51.                 if (x == -1 || x == columns || y == -1 || x == rows) {
    52.                     toInstantiate = outerWallTiles [Random.Range (0, outerWallTiles.Length)];
    53.                 }
    54.                 GameObject instance = Instantiate(toInstantiate, new Vector3 (x, y, 0f), Quaternion.identity) as GameObject;
    55.  
    56.                 instance.transform.SetParent(boardHolder);
    57.             }
    58.         }
    59.     }
    60.  
    61.  
    62.     Vector3 RandomPosition() {
    63.         int randomIndex = Random.Range (0, gridPositions.Count);
    64.         Vector3 randomPosition = gridPositions [randomIndex];
    65.         gridPositions.RemoveAt (randomIndex);
    66.         return randomPosition;
    67.     }
    68.  
    69.     void layoutObjectAtRandom(GameObject[] tileArray, int minimum, int maximum) {
    70.         int objectCount = Random.Range (minimum, maximum + 1);
    71.  
    72.         for (int i = 0; i < objectCount; i++) {
    73.             Vector3 randomPosition = RandomPosition ();
    74.             GameObject tileChoice = tileArray[Random.Range (0, tileArray.Length)];
    75.             Instantiate (tileChoice, randomPosition, Quaternion.identity);
    76.         }
    77.     }
    78.  
    79.     public void SetupScene (int level) {
    80.         boardSetUp();
    81.         InitializeList ();
    82.         layoutObjectAtRandom (wallTiles, wallCount.minimum, wallCount.maximum);
    83.         layoutObjectAtRandom (foodTiles, foodCount.minimum, foodCount.maximum);
    84.         int enemyCount = (int)Mathf.Log (level, 2f);
    85.         layoutObjectAtRandom (enemyTiles, enemyCount, enemyCount);
    86.         Instantiate (exit, new Vector3 (columns - 1, rows - 1, 0f), Quaternion.identity);
    87.     }
    88.        
    89. }
    90.  
    and here's my game manager just in case:
    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.     // Use this for initialization
    12.     void Awake () {
    13.         boardScript = GetComponent<BoardManager> ();
    14.         initGame ();
    15.     }
    16.  
    17.     // Update is called once per frame
    18.     void initGame () {
    19.         boardScript.SetupScene (level);
    20.     }
    21. }
    22.  
    Thanks for any help you can give, guys.
     
  29. breadtop

    breadtop

    Joined:
    Jan 12, 2017
    Posts:
    1
    Hi,

    I'm using this tutorial to build a game but I want to add a start screen to it, with buttons for Level 1, Level 2, Level 3 and Level 4. I want the buttons, once pressed on, to go straight to that level and if the player passes it, to continue on with the next randomly generated levels.

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using UnityEngine.SceneManagement; // Allows SceneManager to be used.
    4.  
    5. public class LoadSceneOnClick : MonoBehaviour
    6. {
    7.  
    8.     public void LoadByIndex(int sceneIndex) // Passes in what scene will be loaded.
    9.     {
    10.         SceneManager.LoadScene(sceneIndex); // SceneManager loads scene.
    11.     }
    12. }
    This is my code for my LoadSceneOnClick script that I am using for each of my main menu buttons. I got this from the Creating A Main Menu tutorial. However it is not working because it assumes that each level is a different scene. This game contains all its levels in a single scene so I'm not sure how to make this work. I've tried passing in the variable for level instead of sceneIndex but it did not work, so maybe I was not doing it right.

    Any help would be appreciated!!

    Thanks :)
     
  30. edwardchuajh

    edwardchuajh

    Joined:
    Jan 8, 2017
    Posts:
    2
    Hi,

    Just helping here, it's in Line 51 of your Board Manager.

    You have a x instead of y.

    if(x ==-1|| x == columns || y ==-1|| x == rows){
     
    Matthew-Schell likes this.
  31. Prometheus121

    Prometheus121

    Joined:
    Apr 6, 2016
    Posts:
    15
    Oh... I have a top wall... Thanks a bunch! I actually used the completed script and it still didnt work so... that's weird. Idk. It works now so. Thanks!
     
    Matthew-Schell likes this.
  32. Matthew-Schell

    Matthew-Schell

    Unity Technologies

    Joined:
    Oct 1, 2014
    Posts:
    228
    This issue is caused because you have copied and pasted the scripts directly from the learn website instead of typing them. Previously those scripts were in the Completed namespace (like those in the Completed folder). If you're not familiar with this concept of namespace, see here: https://msdn.microsoft.com/en-us/library/z2kcy19k.aspx

    I have actually edited the Learn pages to remove the wrapping of these scripts in that namespace since so many people were having issues with it. Generally my recommendation is that people should type the scripts since they will learn better than simply copying and pasting but enough people were getting stuck on this that I decided to change it.
     
  33. Matthew-Schell

    Matthew-Schell

    Unity Technologies

    Joined:
    Oct 1, 2014
    Posts:
    228
    It sounds like you might not have a BoxCollider2D component attached? The error is telling you that the script cannot find one, therefore it is 'null'.
     
  34. Matthew-Schell

    Matthew-Schell

    Unity Technologies

    Joined:
    Oct 1, 2014
    Posts:
    228
    Yes you can.
     
  35. Matthew-Schell

    Matthew-Schell

    Unity Technologies

    Joined:
    Oct 1, 2014
    Posts:
    228
    Re 1) I have actually gone and removed the scripts from the Completed namespace on the site as I agree it's confusing. At the time my thinking was 'people should type the scripts in instead of copying' but in retrospect that was a mistake. The tutorial is intended for intermediate students who would hopefully know what a namespace was, but this being the internet there is no way to control for that.

    Re 2) It's been a while since I made this but I believe that in the sequence shown you should not get errors if you follow the tutorial correctly and do things in that order. That said I made this tutorial a while ago now and looking back on it see many ways I would now do it differently. Hopefully at some point I'll get a chance to do a new version or make an update, but making these things takes many, many months and a ton of labor, so it won't be any time soon. In the mean time hopefully folks can learn some intermediate ideas from it in it's current state. Thanks for your feedback.

    Re 3) This is due to changes in the editor since this was made, I made an annotation on the video on YouTube which appears when you watch it at 1:16. This series was recorded when 5.0 first came out.

    Re 4 and 5) This is new to me, I don't see how it would interact across namespaces... I have however in the past noticed strange behavior with scripts called GameManager in Unity (like the component disappearing when added). You could try refactoring the name and seeing if that helps.
     
  36. Matthew-Schell

    Matthew-Schell

    Unity Technologies

    Joined:
    Oct 1, 2014
    Posts:
    228
    I'm guessing you failed to add a public GameManager variable to your script.
     
  37. NPSao

    NPSao

    Joined:
    Jan 14, 2017
    Posts:
    1
    Hello, one of the later videos tells me to look into the PDF file, provided by the package. This file is also listed in the package contents, but when I add the 2D Rogue Like Asset Package to my project, the pdf file is nowhere to be found!
     
  38. Cobalt313

    Cobalt313

    Joined:
    Sep 14, 2016
    Posts:
    2
    I'm on the third-to-last video where you add the UI elements, and suddenly I'm getting a "NullReferenceException: Object reference not set to an instance of an object" error for Gamemanager apparently refusing to acknowledge that the BoardManager script I tell it to use not only exists, but is also affixed to the same prefab object as the GameManager script itself. Has anyone else encountered this problem and/or have a solution?

    For what it's worth I have just updated my Unity to 5.5 before this step of the project so I suspect some work may have been lost in translation so to speak.
     
  39. Cobalt313

    Cobalt313

    Joined:
    Sep 14, 2016
    Posts:
    2
    Ok so I think I resolved the issue in my previous post but now I'm getting an error from DontDestroyOnLoad(gameObject) and the game increments days and enemies wrong. I compared my work to that of the example and all of it matches save for the parts I was told to substitute in the PDF. Anyone else had a similar issue?
     
  40. fregas

    fregas

    Joined:
    Dec 26, 2016
    Posts:
    3
    Hey, just an FYI for people.

    I was getting a NullReferenceException: Object reference not set to an instance of an object

    whenever my level ended by going to the exit. The error referenced the COMPLETED GameManager, not my own code. The issue seems to be that the Completed/GameManger file had the static public void CallBackInitialization to register SceneLoaded which is different from the tutorial because of upgrades in Unity:

    //thisiscalledonlyonce,andtheparamtertellittobecalledonlyafterthescenewas loaded
    //(otherwise,ourSceneLoadcallbackwouldbecalledtheveryfirstload,andwedon'twantthat)
    [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)]
    static public void CallbackInitialization()
    {
    //registerthecallbacktobecalledeverytimethesceneis loaded
    SceneManager.sceneLoaded += OnSceneLoaded;
    }


    Anyway, commenting out the SceneManager.sceneLoaded line fixed the issue. It was registering the completed GameManager's method w/ unity.
     
    JRWidley likes this.
  41. Urenemas

    Urenemas

    Joined:
    Jul 1, 2016
    Posts:
    2
    Hi I am having a scripting error (using MonoDevelop) on part 4 of the tutorial. I get a single error on line 11 "The type or namespace 'MonoBehaivor" could not be found (are you missing a using directive or an assembly reference,

    I'm going to review it tomorrow so they may be some typos but this is the only error in debug log.


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

    JRWidley

    Joined:
    Nov 22, 2016
    Posts:
    17
    To your 2nd bug fix: i had the same issue - with InitGame() is getting called twice, as you say. I went with your "solution 1" option to fix this. To eliminate the game starting at level 2 i just set level=0; in the public class initializer at the top of the class. That way it's incremented to level 1 in OnLevelFinishedLoading() and then InitGame() is called. This seems to work for me.

    I'd like to know why OnLevelFinishedLoading() is loaded off the first level though - isn't the scene already loaded and built at this point in the code? It should run starting at the end of level 1 (when loading level 2) no??
     
  43. TokyoDan

    TokyoDan

    Joined:
    Jun 16, 2012
    Posts:
    997
    @Urenemas Try changing "public class BoardManager : MonoBehaivor" to "public class BoardManager : MonoBehaviour".
     
  44. drunkenoodle

    drunkenoodle

    Joined:
    Nov 11, 2012
    Posts:
    8
    Great tutorial, had a lot of fun putting it together! I've encountered a strange issue though that only happens about 2 out of 10 times in that the player overlaps the enemy, or the enemy overlaps the other enemy.
    Is this something to do with movements not being done in time for the next entity to move, or down to disabling the box collider for that frame? The box colliders seem to be the right size at 0.9, so they're covering the entire sprite.

    Not sure if anyone else has had this problem...
     
  45. JRWidley

    JRWidley

    Joined:
    Nov 22, 2016
    Posts:
    17
    Does anyone know why the player's time between moves gets longer with each enemy added? By level 4 you can really see the difference. I tested the completed example and it does the same thing.

    I also tested this by temporarily replacing:
    int enemyCount = (int)Mathf.Log(level, 2f);

    with
    int enemyCount = 14;

    and there's about a 3-4 second wait between moves.

    Any ideas how to make the player's move speed constant regardless of enemies?
     
  46. JRWidley

    JRWidley

    Joined:
    Nov 22, 2016
    Posts:
    17
    It looks like this occurs in the GameManager.cs script in the MoveEnemies() function. It's mentioned in this video at 3:50
    https://unity3d.com/learn/tutorials...rial/enemy-animator-controller?playlist=17150

    I still don't like it, i'd rather have a consistent move rate regardless of enemy count. You can do this by switching out MoveEnemies code with this:

    Code (CSharp):
    1. IEnumerator MoveEnemies()
    2.     {      
    3.         enemiesMoving = true;
    4.         yield return new WaitForSeconds(turnDelay * 2); // initial wait of .1f
    5.                
    6.         // move each enemy on our list.
    7.         for (int i = 0; i < enemies.Count; i++)
    8.         {
    9.             enemies[i].MoveEnemy();
    10.         }      
    11.  
    12.         playersTurn = true;
    13.         enemiesMoving = false;
    14.     }
    I'm sure this has some adverse effects however. For instance, now if the enemies can move, they'll all move at the same time, and you can't code a delay for each.
     
  47. JRWidley

    JRWidley

    Joined:
    Nov 22, 2016
    Posts:
    17
    This is a great tutorial BTW! :)
     
  48. drunkenoodle

    drunkenoodle

    Joined:
    Nov 11, 2012
    Posts:
    8
    Hey JR, yeah it's a known issue I think. Basically the time for each enemy added increases as you get more, as you get more yields. So the more enemies, the more wait time gets appended before the player can move again. I was having a think last night, perhaps since it's a grid you could just make use of it by saying which coords have been occupied after each movement.
    So if you've got say 2 enemies, if one flags the space at 1,1 as occupied immediately before it actually animates to that location, the enemy that goes straight after it will know it can't go in that direction (so it'd prevent overlap). Then you could just let the enemy sprite animate in to that space so it only 'looks' like it's still moving in to it.

    Meanwhile the players turn will come around straight away, but the enemies will already have placed themselves as far as data-wise is concerned. Animations are quick enough so that by the time the player's taken their turn, the enemies will have settled.

    Not sure if any of that makes sense as I'm not 100% on the idea myself, but I'll post up here if it yields some decent results. Got to try right?
     
  49. JRWidley

    JRWidley

    Joined:
    Nov 22, 2016
    Posts:
    17
    Thanks drunkenoodle. Yes i could see how that might work. You would need to revise some of the move logic in MovingObjects.cs: Currently Move() casts a ray to the center of the position to see if an object is there or not. So you would either need to do away with this approach, and do a strictly grid based approach for collision detection instead.

    Playtesting my code changes above i noticed i have collision issues - if the player and an enemy attempt to move into the same square at the same time they both land on it on top of each other and are stuck. I guess i can see why the tutorial forces a wait for each enemy before allowing any player movement.

    I'm going to try a few things where i can keep the original Move() function intact first. Will let you know how that goes.
     
  50. drunkenoodle

    drunkenoodle

    Joined:
    Nov 11, 2012
    Posts:
    8
    Sounds good JR, be good to see what you come up with! I can see the logic behind making everything wait and check each time, it's a solid method but as we've seen not without a few drawbacks.

    If I can knock together anything useful I'll post up on here too.

    Cheers!