Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
1 capture
12 Jun 22 - 12 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
  • Help Room /
avatar image
0
Question by fantonucci · May 29, 2018 at 03:12 PM · enemytutorialissueroguelike

2D Roguelike Enemy in Walls

I have been working on the 2D Roguelike tutorial with my students. The game is working great, but we all have the same issue. Occasionally, the enemies will spawn on the same block as an interior wall making them "stuck" for the level. It does not seem to happen in the completed game that downloaded with the resources, and as far as I can tell our scripts match the ones in the completed game perfectly. Is anyone else having the same issue? Please advise on how to fix it!

Comment
Add comment · Show 1
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image KittenSnipes · May 29, 2018 at 10:02 PM 0
Share

@fantonucci When asking questions of these sorts it makes it easier on the people answering if you included a script. Possibly the script that spawns the enemies in the first place.

2 Replies

· Add your reply
  • Sort: 
avatar image
0

Answer by fantonucci · May 30, 2018 at 01:36 PM

OK, Here are my BoardManager and GameManager scripts. They're responsible for the scene setup so I have a feeling the issue might be there:

//BoardManager

using System.Collections; using System; using System.Collections.Generic; using UnityEngine; using Random = UnityEngine.Random;

public class BoardManager : MonoBehaviour { //make Inspector have a drop-down [Serializable] public class Count { public int minimum; public int maximum;

     public Count(int min, int max)
     {
         minimum = min;
         maximum = max;
     }
 }

 public int columns = 8;
 public int rows = 8;

 //level will have a min of 5 walls and a max of 9
 public Count wallCount = new Count(5, 9);

 public Count foodCount = new Count(1, 5);

 public GameObject exit;

 public GameObject[] floorTiles;
 public GameObject[] wallTiles;
 public GameObject[] enemyTiles;
 public GameObject[] foodTiles;
 public GameObject[] outerWallTiles;

 private Transform boardHolder;

 private List<Vector3> gridPositions = new List<Vector3>();

 //Create list of possible positions for enemies, food and walls
 void InitializeList()
 {
     gridPositions.Clear();

     //Leaving border empty so level is passable
     for (int x = 1; x < (columns - 1); x++)
     {
         for (int y = 1; y < (rows - 1); y++)
         {
             gridPositions.Add(new Vector3(x, y, 0f));
         }
     }
 }

 //Lay out the Outer Walls and Floor Tiles
 void BoardSetup()
 {
     boardHolder = new GameObject("Board").transform;

     for (int x = -1; x < columns + 1; x++)
     {
         for (int y = -1; y < rows + 1; y++)
         {
             GameObject toInstantiate = floorTiles[Random.Range(0, floorTiles.Length)];

             //If this spot should be an Outer Wall instead
             if ((x == -1) || (x == columns) || (y == -1) || (y == rows))
                 toInstantiate = outerWallTiles[Random.Range(0, outerWallTiles.Length)];

             //Instantiate (object, position, rotation)
             GameObject instance = Instantiate(toInstantiate, new Vector3(x, y, 0f), Quaternion.identity) as GameObject;

             instance.transform.SetParent(boardHolder);
         }
     }
 }
   
 //Generate random position for the object
 Vector3 RandomPosition()
 {
     int randomIndex = Random.Range(0, gridPositions.Count);

     Vector3 randomPosition = gridPositions[randomIndex];

     //We don't want to put more than 1 item in the same spot
     gridPositions.RemoveAt(randomIndex);

     return randomPosition;
 }

 //Put down random objects
 void LayoutObjectAtRandom(GameObject[] tileArray, int minimum, int maximum)
 {
     //How many of a random object we will spawn
     int objectCount = Random.Range(minimum, maximum + 1);
     Debug.Log(objectCount);

     for (int i = 0; i < objectCount; i++)
     {
         Vector3 randomPosition = RandomPosition();

         GameObject tileChoice = tileArray[Random.Range(0, tileArray.Length)];

         Instantiate(tileChoice, randomPosition, Quaternion.identity);
     }
 }

 //must be a public method because called by GameManager script
 public void SetupScene(int level)
 {
     //Put down outer walls and floor
     BoardSetup();

     InitializeList();   //Creates gridPositions list

     LayoutObjectAtRandom(wallTiles, wallCount.minimum, wallCount.maximum);

     LayoutObjectAtRandom(foodTiles, foodCount.minimum, foodCount.maximum);

     //Generate # of enemies based on level # - difficulty
     //1 enemy at level 2, 2 at level 4, 3 at level 8
     int enemyCount = (int)Mathf.Log(level, 2f);

     LayoutObjectAtRandom(enemyTiles, enemyCount, enemyCount);

     Instantiate(exit, new Vector3(columns - 1, rows - 1, 0f), Quaternion.identity);
 }

}

//GameManager

using System.Collections; using System.Collections.Generic; //Lets you use Lists using UnityEngine; using UnityEngine.UI; using UnityEngine.SceneManagement;

public class GameManager : MonoBehaviour { //So we can call SetupScene private BoardManager boardScript;

 private int level = 1;

 public static GameManager instance = null;

 public int playerFoodPoints = 100;

 [HideInInspector] public bool playersTurn = true;

 public float turnDelay = .1f;

 private float levelDelay = 2f;

 private Text levelText;

 private GameObject levelImage;

 private List<Enemy> enemies;

 private bool enemiesMoving;

 private bool firstRun = true;

 //Prevents Player from moving during setup
 private bool doingSetup = true;

 // Use this for initialization
 void Awake()
 {
     if (instance == null)
         instance = this;
     else if (instance != this)
         Destroy(gameObject);    //destroys duplicate GameManager

     //When we load a new scene, don't want to destroy score
     DontDestroyOnLoad(gameObject);

     enemies = new List<Enemy>();

     boardScript = GetComponent<BoardManager>();

     InitGame();
 }

 void InitGame()
 {
     doingSetup = true;

     levelImage = GameObject.Find("LevelImage");

     levelText = GameObject.Find("LevelText").GetComponent<Text>();

     levelText.text = "Day " + level;

     levelImage.SetActive(true);

     Invoke("HideLevelImage", levelDelay);

     //Clear out enemies between levels
     //GameManager never exits
     enemies.Clear();

     boardScript.SetupScene(level);
 }

 private void HideLevelImage()
 {
     levelImage.SetActive(false);
     doingSetup = false;
 }

 //This is called each time a scene is loaded
 void OnLevelFinishedLoading(Scene scene, LoadSceneMode mode)
 {
     if (firstRun)
     {
         firstRun = false;
         return;
     }

     level++;

     InitGame();
 }

 void OnEnable()
 {
     //Tell our 'OnLevelFinishedLoading' function to
     //start listening for a scene change as soon
     //as the script is enabled
     SceneManager.sceneLoaded += OnLevelFinishedLoading;
 }

 void OnDisable()
 {
     //Tell OnLevelFinishedLoading to stop listening
     //for a scene change as soon as the script
     //is disabled

     SceneManager.sceneLoaded -= OnLevelFinishedLoading;
 }

 //Coroutine to move our enemies in sequence
 IEnumerator MoveEnemies()
 {
     enemiesMoving = true;

     yield return new WaitForSeconds(turnDelay);

     //Pause if there's no enemies
     if (enemies.Count == 0)
         yield return new WaitForSeconds(turnDelay);

     //Loop through enemies list and move them
     for (int i = 0; i < enemies.Count; i++)
     {
         enemies[i].MoveEnemy();
         yield return new WaitForSeconds(enemies[i].moveTime);
     }

     playersTurn = true;

     enemiesMoving = false;
 }

 public void GameOver()
 {
     levelText.text = "After " + level + " days, you starved.";

     levelImage.SetActive(true);

     enabled = false;
 }

 // Update is called once per frame
 void Update()
 {
     if (playersTurn || enemiesMoving || doingSetup)
         return;

     StartCoroutine(MoveEnemies());
 }

 //Have enemies register with GameManager so they 
 //follow orders to move
 public void AddEnemyToList(Enemy script)
 {
     enemies.Add(script);
 }

}

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image
0

Answer by KittenSnipes · Jun 29, 2018 at 12:25 AM

@fantonucci

I have come back to this question and your GameManager script does have some slight changes but I am pretty sure that it should not effect how it runs although I have never used the methods you used. OnEnable is called when the object becomes enabled and active. Plus the original script never does anything when the object becomes disabled and inactive yet yours does. Maybe it is the fact you do something on disable or maybe it is because the OnEnable method is slower than the original method the tutorial uses. Plus you never use the current instances level to increment and to run the function InitGame(). So after all that here is the updated version of your GameManager Script:

         private BoardManager boardScript;
 
         private int level = 1;
         public static GameManager instance = null;
         public int playerFoodPoints = 100;
         [HideInInspector] public bool playersTurn = true;
         public float turnDelay = .1f;
         private float levelDelay = 2f;
         private Text levelText;
         private GameObject levelImage;
         private List<Enemy> enemies;
         private bool enemiesMoving;
         //Prevents Player from moving during setup
         private bool doingSetup = true;
 
         // Use this for initialization
         void Awake()
         {
             if (instance == null)
                 instance = this;
             else if (instance != this)
                 Destroy(gameObject);    //destroys duplicate GameManager
                                         //When we load a new scene, don't want to destroy score
             DontDestroyOnLoad(gameObject);
             enemies = new List<Enemy>();
             boardScript = GetComponent<BoardManager>();
             InitGame();
         }
 
         void InitGame()
         {
             doingSetup = true;
             levelImage = GameObject.Find("LevelImage");
             levelText = GameObject.Find("LevelText").GetComponent<Text>();
             levelText.text = "Day " + level;
             levelImage.SetActive(true);
             Invoke("HideLevelImage", levelDelay);
             //Clear out enemies between levels
             //GameManager never exits
             enemies.Clear();
             boardScript.SetupScene(level);
         }
 
         private void HideLevelImage()
         {
             levelImage.SetActive(false);
             doingSetup = false;
         }
 
 
 
 
 
         //The 2 functions I added. These were different than the ones you had in your script.
 
         //this is called only once, and the paramter tells it to be called only after the scene was loaded
         //(otherwise, our Scene Load callback would be called the very first load, and we don't want that)
         [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)]
         static public void CallbackInitialization()
         {
             //register the callback to be called everytime the scene is loaded
             SceneManager.sceneLoaded += OnSceneLoaded;
         }
 
         //This is called each time a scene is loaded.
         static private void OnSceneLoaded(Scene arg0, LoadSceneMode arg1)
         {
             instance.level++;
             instance.InitGame();
         }
 
         //Hopefully these make it work because this was the only difference.
 
 
 
 
 
         //Coroutine to move our enemies in sequence
         IEnumerator MoveEnemies()
         {
             enemiesMoving = true;
             yield return new WaitForSeconds(turnDelay);
             //Pause if there's no enemies
             if (enemies.Count == 0)
                 yield return new WaitForSeconds(turnDelay);
             //Loop through enemies list and move them
             for (int i = 0; i < enemies.Count; i++)
             {
                 enemies[i].MoveEnemy();
                 yield return new WaitForSeconds(enemies[i].moveTime);
             }
             playersTurn = true;
             enemiesMoving = false;
         }
 
         public void GameOver()
         {
             levelText.text = "After " + level + " days, you starved.";
             levelImage.SetActive(true);
             enabled = false;
         }
 
         // Update is called once per frame
         void Update()
         {
             if (playersTurn || enemiesMoving || doingSetup)
                 return;
             StartCoroutine(MoveEnemies());
         }
 
         //Have enemies register with GameManager so they 
         //follow orders to move
         public void AddEnemyToList(Enemy script)
         {
             enemies.Add(script);
         }

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

145 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

2d roguelike tutorial board manager issues 2 Answers

OverslapSphere dont detect enemyhealth 0 Answers

Something wrong with enemy tilting in space shooter extending tutorial? 0 Answers

Problems with enemies 1 Answer

RogueLike 2D Tutorial Help 0 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges