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. Matthew-Schell

    Matthew-Schell

    Joined:
    Oct 1, 2014
    Posts:
    238
    This is the official thread for discussion, issues and Q&A for the 2D Roguelike project.

    Please use this thread if you have any questions, issues or feedback on this project.

    2D Roguelike is a learning project on our Learn Site:
    http://unity3d.com/learn/tutorials/projects/2d-roguelike

    Learn how to make a 2D Roguelike game with this project. Over the course of the project will create procedural tile based levels, implement turn based movement, add a hunger system, audio and mobile touch controls. This video series was filmed in Unity 5, but is compatible with Unity 4.6 as well.

    Post your questions and the team and we will try to help you out!

    IMPORTANT:
    If you want to post a script you are having trouble with, please post the whole script that is throwing an error using proper code formatting detailed in the thread below, a screenshot of the public variables in the inspector and copy and paste the error message from the console if there is one.

    http://forum.unity3d.com/threads/using-code-tags-properly.143875/

    Known Issues:
    • Please turn "annotations" on, as we try to annotate these videos if any issues are found. Many people turn annotations off, and miss these comments.
    • Due to changes in the Unity API related to loading scenes since Unity 5.3, we've modified the scripts in the Completed folder to reflect the new API, and added an upgrade guide PDF to the asset package detailing the modified steps for the tutorial.
    • Download the upgrade PDF directly from here.
     
    Last edited: Sep 14, 2016
  2. BusyRobot

    BusyRobot

    Joined:
    Feb 22, 2013
    Posts:
    148
    I'm up to part 5. I'm not following the tutorial exactly as I'm building a different type of game, but I'm using it to give me an understanding of how to set things up.

    I've set things up as you have, except when I run my code, I'm getting the error "Object reference not set to an instance of an object" on the line where I try to instantiate the board manager (which in my code is called SetupGame) in the GameManager script.

    I think this is because the boardScript variable is not set, and at this point in the tutorial the board manager script has not been attached to any game object to be set as a variable in the Game Manager prefab.

    Do I have to attach the boardScript script to a GO and then set it in the Game Manager prefab?

    I'm new to Unity and C# so maybe I'm missing something.
     
  3. Matthew-Schell

    Matthew-Schell

    Joined:
    Oct 1, 2014
    Posts:
    238
    Both the GameManager and BoardManager scripts should be attached to the GameManager prefab and have those same script names, since they're referred to by those names within the scripts. Since you're doing your own thing it's a bit hard to tell what else may be wrong but make sure that you have BoardManager attached to an object and that the GM can somehow get a reference to it. If necessary make the boardScript variable in GM public and drag a reference.
     
  4. Shadeless

    Shadeless

    Joined:
    Jul 22, 2013
    Posts:
    136
    Hi Matt,

    First of all, thanks for this tutorial. I found it really informative and it's really cool to see an intermediate tutorial coming out from UT. And I'd love to see more.

    But there appears to be a seam between the tiles, ( http://prntscr.com/63isrw) and I think this ties in with Unit's pixel perfect camera problem that I was talking about some time ago, if you remember. In fact, I'm sure that if you do move the camera with the character, there will be some pixel issues.

    Has any solution for these issues popped out yet?

    Cheers
     
  5. Matthew-Schell

    Matthew-Schell

    Joined:
    Oct 1, 2014
    Posts:
    238
    hey Shadeless,

    I could be wrong but in my experience that seam / line is only visible in the editor. It doesn't appear in builds of the game (or at least builds I've made).

    I don't have a new update re pixel issues BUT we do have a whole new team of developers working exclusively on 2D recently (quite a few more than were on it before) so I think we can expect some good progress in that area in coming months! Glad you're enjoying the tutorial!
     
  6. _Carl

    _Carl

    Joined:
    Jan 12, 2014
    Posts:
    5
    Hi Matt,

    Thanks a lot for this it's exactly what I have been looking for. Just a quick question, how hard would it be to modify this to include the generation of multiple rooms per level? With doors and such and are there any examples of this?
     
  7. Matthew-Schell

    Matthew-Schell

    Joined:
    Oct 1, 2014
    Posts:
    238
    You're welcome! There are many examples of procedural dungeon generation online, here is one:

    http://www.roguebasin.com/index.php?title=Dungeon-Building_Algorithm

    The implementation in BoardManager is mostly random and therefore pretty simple. It's definitely possible to extend it in a more dungeon-y direction but it'll take some doing. If you make progress follow back up and let us know what you did!
     
  8. zbegra

    zbegra

    Joined:
    Dec 14, 2010
    Posts:
    10
    Hi Matthew, the video for number 8 is set to private :)
     
  9. Matthew-Schell

    Matthew-Schell

    Joined:
    Oct 1, 2014
    Posts:
    238
  10. Aiursrage2k

    Aiursrage2k

    Joined:
    Nov 1, 2009
    Posts:
    4,835
  11. RamonBoza

    RamonBoza

    Joined:
    Feb 12, 2015
    Posts:
    1
    there,

    I'm having some troubles with the second tutorial.

    I have created the three first animations for Player


    and moved the controller to AnimatorController


    then if I look inside the player controller, all the animations appear there


    but not like in the tutorial with an "initial state", but the Idle one is like selected by default.

    but when I click on play button only a blue background is displayed.

    Do you know what could be happening?

    System: Mac OS X 10.9.5
     
  12. _Carl

    _Carl

    Joined:
    Jan 12, 2014
    Posts:
    5
    The "initial state" is a Unity 5 feature if I'm not mistaken? The blue background, Is it a bar under the name of the animation? When you attach transitions that bar should move to the animation that is playing. Everything you've done seems correct so far!
     
  13. Matthew-Schell

    Matthew-Schell

    Joined:
    Oct 1, 2014
    Posts:
    238
    I'll take a look at it. I LOVE Nuclear Throne and actually was just playing last night (still terrible though, only got past the snow area w/ the robots once lol). I do want to do some more stuff on level generation and the approach in Scavengers is still fairly simple, I may do something in one of the live training sessions. Thanks for the link!
     
    BlueBlane likes this.
  14. Matthew-Schell

    Matthew-Schell

    Joined:
    Oct 1, 2014
    Posts:
    238
    @RamonBoza yes, the tutorial is filmed in Unity 5 so it will look a bit different than what you have if you're in 4.6. That said what you have is correct and the orange, default state for PlayerIdle should be playing when you play the scene. Make sure that the Player game object is in the scene and in view of the camera with a sprite renderer, animator attached.
     
  15. TwiiK

    TwiiK

    Joined:
    Oct 23, 2007
    Posts:
    1,729
    I feel a bit like this tutorial is intermediate just because it can be. I've made more advanced games than this, but I've not touched many of the concepts covered in this tutorial. I've been making games for years, but I'm self thought and I haven't got a programming background. I feel the tutorial glosses over why it feels it's necessary to make things so complex, at least in my opinion, for such a simple game.

    Here's some of the things I'm curious about:

    1. Why have the loader class which instantiates the two managers instead of just adding the two managers to the scene manually?

    2. What are the benefits to singletons? I usually just have my managers as gameobjects and then I use GameObject.Find in the Awake() function of my scripts to find them. That way I don't have to access them with manager.instance.whatever each time. I can just do manager.whatever. This benefit in itself I find is big enough to never want to use singletons. Otherwise I just use a static class if I can.

    3. Why use DontDestroyOnLoad() on the managers and then reload the scene each time you complete a level instead of just have a function that resets the board? Everything happens in the same scene anyway. Doing it this way just seems so unnecessary?

    4. I'm still unsure as to what virtual, abstract, override and protected does. What are the benefits of all this over just using Unity's component system? Why not have MovingObject as a normal component that you add to both the player and the enemies?

    5. Is that optimized move code really necessary? I find it very hard to read. Is it something that will make a difference in a game like this or will it only be noticeable if we were to have thousands of enemies moving at once or something? I'm thinking about the square magnitude and multiplying instead of dividing parts. Basically part 6 of the tutorial. I find it very easy to relate to the magnitude of a vector as a distance on my screen, but square magnitude becomes just an abstract concept so I stay away from it. Also why do you have to compare it to float.Epsilon instead of just 0? I've never seen float.Epsilon before. I didn't even know it was a thing. :p

    Basically, are there performance benefits to doing it this way? With all this inheritance stuff I mean. Will it scale better than components? It's the Enemy, Player and MovingObject scripts I'm having the most issues with. The rest of the tutorial/project seem very straight forwards, but these scripts just feel much more complex than they could have been.

    From my point of view it just ends up being very hard to read with little benefit. Like using Thesaurus on a piece of text. For instance I find it very hard to see just what functions actually come into play for the player and the enemy. Both the player and the enemy seem to override the AttemptMove() function, but inside it they call the AttemptMove() function of the base class. Trying to follow that code line for line I find to be very hard. :p

    I'm obviously not demanding an explanation, I feel it's a nice tutorial and there's surely a lot for me to take from it. I'm just saying I would really appreciate some more information about the more complex parts. :) I've looked in the completed folder to check out the code comments for the completed scripts, but I didn't get much from them.

    I think I will attempt to write the code the way I would have done it myself to see what changes I will have to make to make it work like in the tutorial. Perhaps that will shed some light on this for me. Maybe I'll realize why you would choose inheritance for certain things. :)

    Lastly, who did the music for the game? It's really good.
     
    MochiTo and Wacky-Moose like this.
  16. orb

    orb

    Joined:
    Nov 24, 2010
    Posts:
    3,037
    I do similar things in a very similar project - they make more sense when you have slightly different scenes that share managers.

    I've got a game manager that loads if necessary, otherwise it inherits the existing instance. It doesn't just hold the current state and score, but also tells the loader where to return after special scenes (mini-games, for example). Different tile sets and map generators are used in each scene, while input, player and game managers stick around between scenes. The game manager just grabs the map settings object from the named object and builds the appropriate map.

    I wouldn't mind seeing some additional videos where these sort of concepts are explored.
     
    pkjmerli likes this.
  17. Matthew-Schell

    Matthew-Schell

    Joined:
    Oct 1, 2014
    Posts:
    238
    hey Twiik,

    Last things first, I did the music and sound myself (I've produced electronic music for many years). I'm glad to hear you liked it :)

    I'll try to go step by step through your questions, but holistically I understand your complaint. Everyone has to find a workflow that balances readability, efficiency and makes sense for them and their projects. In this project I actually wrote the game first and then collaborated with Mike Geig and James Bouckley (gameplay programmer on the content team) to write the final scripts.

    One of the goals of an intermediate as opposed to a beginner tutorial is to help our users to stretch and learn new concepts. In this case some of the concepts that I think are a little bit of a stretch for some but are definitely quite important and valuable are some you mentioned: singletons and inheritance, and generics which you didn't mention. So your point that it's "intermediate for the sake of being intermediate" is partially true. This felt like a good opportunity to show those concepts and so we decided to include them. We could have cut those parts or worked around them to make it simple but we felt it was a good teachable moment that would help people.


    Now to your specific questions:

    1. Why have the loader class which instantiates the two managers instead of just adding the two managers to the scene manually?

    This prevents cases where you might inadvertently cause two managers to be added to a scene, especially with both set to DontDestroyOnLoad. If the GameMeaner is set to not destroy, and then you reload the scene with it in there, you'll end up with two.

    2. What are the benefits to singletons? I usually just have my managers as gameobjects and then I use GameObject.Find in the Awake() function of my scripts to find them. That way I don't have to access them with manager.instance.whatever each time. I can just do manager.whatever. This benefit in itself I find is big enough to never want to use singletons. Otherwise I just use a static class if I can.

    The risk of GameObject.find is that you'll have a case where the object isn't there, throw a null reference exception and crash. It's also expensive performance wise, especially if you're instantiating lots of enemies for example in a complex scene, each which has to find the manager at runtime during it's Awake().

    3. Why use DontDestroyOnLoad() on the managers and then reload the scene each time you complete a level instead of just have a function that resets the board? Everything happens in the same scene anyway. Doing it this way just seems so unnecessary?

    In this case reloading the scene is just easier and cleaner in my mind. I don't see exactly what about it is un-necessary or particularly undesirable? I actually wrote one version with resetting the board and re-initializing everything and it was just way more work and less reliable.

    4. I'm still unsure as to what virtual, abstract, override and protected does. What are the benefits of all this over just using Unity's component system? Why not have MovingObject as a normal component that you add to both the player and the enemies?

    In this case part of the motivation here was to get people to start thinking about inheritance. I actually did try writing a motor component and doing it the way that you said and in the end ending up duplicating my movement code into the enemy and player scripts, which James then suggested I do using inheritance. I can't remember what the issue I had was originally unfortunately but this would be a good case for you to try both and see what you like.

    That said I think you should be able to imagine situations where using inheritance in a larger project and having lets say a base class Weapon which MachineGun inherits from would be sensible and useful so this was partly an opportunity to start people thinking about the potential there.

    5. Is that optimized move code really necessary? I find it very hard to read. Is it something that will make a difference in a game like this or will it only be noticeable if we were to have thousands of enemies moving at once or something? I'm thinking about the square magnitude and multiplying instead of dividing parts. Basically part 6 of the tutorial. I find it very easy to relate to the magnitude of a vector as a distance on my screen, but square magnitude becomes just an abstract concept so I stay away from it. Also why do you have to compare it to float.Epsilon instead of just 0? I've never seen float.Epsilon before. I didn't even know it was a thing. :p

    Yes. Generally speaking we try to show best practices that people can learn from in terms of architecture and performance. Because this game is small and simple we certainly could have cut corners and gotten away with things performance wise, but then we would have taught people those behaviors were OK and they might have taken them into larger projects.

    Basically, are there performance benefits to doing it this way? With all this inheritance stuff I mean. Will it scale better than components? It's the Enemy, Player and MovingObject scripts I'm having the most issues with. The rest of the tutorial/project seem very straight forwards, but these scripts just feel much more complex than they could have been.

    Short answer, there are not (to my knowledge) performance benefits in terms of speed, but this will allow you to keep your project organized and avoid spaghetti code. For example lets say I had the move code copied in both player and enemy, then realized I needed to change it, I'd have to change two scripts (and potentially forget to change one) etc. Inheritance is pretty standard practice in object oriented programming, check out Mike's lesson inheritance (as well as some other intermediate scripting concepts) here:

    http://unity3d.com/learn/tutorials/modules/intermediate/scripting/inheritance

    Hope that helps! And as always, find an approach that works for your skill level and your projects. There are many, many ways to skin a cat.
     
    BioBrain, heromedel and MochiTo like this.
  18. TwiiK

    TwiiK

    Joined:
    Oct 23, 2007
    Posts:
    1,729
    Thanks for the reply. It cleared things up a lot for me. There have been intermediate Unity tutorials in the past, but the intermediate part has been the scale of the project, not the complexity of the code. That may be the reason I was a bit surprised here because this is a very small project.

    I have Handmade Hero (https://handmadehero.org) running in the background while I code and his approach is similar to this tutorial I guess. He makes things much much more complex than they have to be to teach people how it would be if the game (engine) they're making actually was more complex.

    I like extending Unity tutorials with extra features so I guess I will try it both ways and see if I end up switching back to my old ways or if I actually learn something from this and stick with inheritance. :p

    As for pt. 3 I guess I had this preconceived notion that reloading the level was the most expensive and cumbersome way to remake the map for the next level. Guess I will try this both ways as well.

    By generics I'm guessing you mean the <T> part? I was going to mention that, but I forgot. I've always used things like SendMessage when I don't know what component I'm dealing with.

    All in all, I guess I'm a prime candidate for such a tutorial. :p

    PS: Thanks for the link to the scripting tutorials. I haven't seen those before.
     
    Last edited: Feb 12, 2015
    MochiTo likes this.
  19. TwiiK

    TwiiK

    Joined:
    Oct 23, 2007
    Posts:
    1,729
    Heh, the first 2 minutes of that video explained what the protected keyword does. I'm not sure if you mentioned it and I missed it, but small things like that would have helped me understand why the code is the way it is. Or perhaps just put a disclaimer in the beginning that the viewer should have at least skimmed through the intermediate scripting tutorials before taking on this tutorial. You may have said something along those lines and I may have missed that as well.

    There was one more thing I forgot to mention that was bugging me. One thing I haven't seen mentioned anywhere before. This line:
    Code (csharp):
    1. using Random = UnityEngine.Random;
    If you create a new C# script in Unity you get these by default:
    Code (csharp):
    1. using UnityEngine;
    2. using System.Collections;
    And you can use Random as much as you want. Why do you need that line? I can see in my project that Random stops working if I remove it in this particular script file, but I've never had it before and I've used Random in all my projects.

    And one more question that's been bothering me for a long time. :p

    Why do you have to type this to use lists?
    Code (csharp):
    1. using System.Collections.Generic;
    Instead of just:
    Code (csharp):
    1. using System;
    Both Collections and Generic are inside System. Shouldn't "using System;" include everything in it? I would think that was the whole point. That you could specify just the parts you needed or instead just include the whole shebang.

    Edit: I answered the question about Random myself. I see that I've always written [System.Serializable] instead of [Serializable] so I haven't had to write "using System;" and thus I've never gotten the Random name collision. The things you learn. :p
     
    Last edited: Feb 13, 2015
    urmas likes this.
  20. orb

    orb

    Joined:
    Nov 24, 2010
    Posts:
    3,037
    "Intermediate knowledge level" to me implies "already knows C#", so it's perfectly understandable to skip basic concepts ;)

    Besides, there are plenty of C# tutorials out there, and I think many people hate retreading old ground. If they're going to teach Unity, they shouldn't spend 5 episodes of a tutorial series on generics, public vs. private variables and details of .NET collections. Microsoft have some good tutorials and references on MSDN.

    The "using" directive only gives you a shortcut to the specified part of a namespace hierarchy. Again something a tutorial on MSDN will explain :)

    Tangentially related, possibly off-topic:
    What they SHOULD do is include a series of intermediate tutorials (probably text, as pure code isn't fit for video) that summarises the differences in Unity's .NET vs. MS/Mono .NET. Specifically the bits that are missing. I know certain functionality either isn't there or requires manual addition of assemblies (third-party or copying Mono stuff around), like zlib compression. So a guide for .NET programmers to get up to speed.
     
    MochiTo, NewPath and Socrates like this.
  21. TwiiK

    TwiiK

    Joined:
    Oct 23, 2007
    Posts:
    1,729
    Perhaps you're right, but like I said there have been Unity tutorials tagged as intermediate before and the code complexity in those has been the usual Unity level, ie. just components, no inheritance, generics etc. The intermediate part just dealt with the scope of the tutorial and the number of concepts taught.

    I understand what you're saying, but like I said it caught me by surprise. I think I understand everything in the tutorial now and why it's done the way it is, but it took me some time and I have probably 15 years of programming experience. To my knowledge this is the first tutorial project Unity has done which has been at this level of code complexity. Perhaps I was expecting a gentler introduction. I've read all about the the different parts of C# before, but without any real incentive to use any of them it didn't stick.

    Something like a short text description of the project and what it builds upon or expects from the viewer could be something to consider. "This tutorial uses inheritance, generics, etc. etc. and if you're not comfortable with these concepts then perhaps consider checking out these links first" or something.

    And those last questions I just threw in here because Matthew seemed like he knew his stuff and I expected there were more rookie Unity'ers with some of the same questions. :)

    Jasper Flick creates awesome, advanced text based Unity tutorials: http://catlikecoding.com/unity/tutorials/maze/

    It would be really neat if Unity adopted a Q&A system similar to his. Such that beneath each video in a tutorial series there could be a list of any special concepts covered in that video with links to an explanation about those concepts. And then I'm thinking human readable explanations, not the MSDN kind. :p

    That way you wouldn't have to write the explanation yourself each time if it already exists. You just link to it. Sort of like a tagging system. Except it would be a searchable database. One point of entry could for instance be that a user wondering what "protected" means. He goes to the tutorials section and types in "protected" in the search box and the site gives him the written explanation of the keywords along with the different tutorials implementing this concept. The other would be the Jasper Flick way of listing the keyword with a link to the explanation beneath the video for those following along with the tutorial.

    I'm thinking out loud here and I'm not critiquing this particular tutorial, I'm listing ways that I feel Unity could improve its tutorials. I've been writing tutorials and end-user guides for my clients for nearly 10 years and I don't take any knowledge for granted anymore. Every time I do I'm punished with a phone call or worse. :p And honestly it doesn't take me that much longer to do. Looking at the Unity comments it's easy to tell i'm not the only one taken by surprise by this particular tutorial. I think a lot of these questions could have been tackled straight on with a more elaborate learning "hub". It's all about democratizing game development, am I right? :)
     
    TheGrimDerp likes this.
  22. OboShape

    OboShape

    Joined:
    Feb 17, 2014
    Posts:
    836
    Just finished it tonight. Well Done Guys :)

    enjoyed working through it, yea the coding takes a big direction change for me, but, this has forced me to go away and learn more. purely as i wanted to learn and improve my understanding why something was written that way.

    so, had a good read up on Generics over the last couple of day. (head hurts a bit)
    dug more into inheritance and namespaces.

    good times, learned loads! well done again!

    DaZ
     
  23. thefreehunter

    thefreehunter

    Joined:
    Feb 7, 2015
    Posts:
    2
    I got to part 11 before I realized the player should have been moving a few sections prior. Looking at the comments on the YouTube video, it seems some others have had problems with this too. I even copied the completed code and made some changes to get it working without errors. Everything looks great, but when I press the arrow key, nothing happens.

    Anyone else run into this? I'm using Unity 4.6.

    Here is the error whenever I am playing the game and press a movement key:

    NullReferenceException: Object reference not set to an instance of an object
    MovingObject.Move (Int32 xDir, Int32 yDir, UnityEngine.RaycastHit2D& hit) (at Assets/Scripts/MovingObject.cs:34)
    MovingObject.AttemptMove[Walls] (Int32 xDir, Int32 yDir) (at Assets/Scripts/MovingObject.cs:99)
    Player.AttemptMove[Walls] (Int32 xDir, Int32 yDir) (at Assets/Scripts/Player.cs:77)
    Player.Update () (at Assets/Scripts/Player.cs:65)
     
    Last edited: Feb 19, 2015
  24. OboShape

    OboShape

    Joined:
    Feb 17, 2014
    Posts:
    836
    Morning FreeHunter, thought id try and help until Matt gets back to you,

    just out of curiosity, have you been following the series in the correct sequence? just that you were saying that you were on the enemy animator before going back.

    have a double check of the code in MovingObject.cs script, looks like its trying to use something that hasnt been assigned.

    check the base virtual Start function in MovingObject.cs, are you assigning the boxCollider?
    (as line 3 below)

    Code (CSharp):
    1.     protected virtual void Start()
    2.     {
    3.         boxCollider = GetComponent<BoxCollider2D>();
    4.         rb2D = GetComponent<Rigidbody2D>();
    5.         inverseMoveTime = 1f /moveTime;
    6.     }
    are you getting any yellow warnings coming up at all when you start, saying that something has not been assigned or used?

    DaZ
     
  25. thefreehunter

    thefreehunter

    Joined:
    Feb 7, 2015
    Posts:
    2
    Yes, I've been following in order. I see that the movement code went in during part 9, but it wasn't tested until part 11. I went back to see if I had missed anything, but I've been going in order.

    Here is my Start function in MovingObject:

    Code (CSharp):
    1. protected virtual void Start ()
    2. {
    3.             boxCollider = GetComponent <BoxCollider2D> ();
    4.             rb2D = GetComponent <Rigidbody2D> ();
    5.             inverseMoveTime = 1f / moveTime;
    6. }
    I don't have any yellow warnings, but when I start I do have several red warnings:

    NullReferenceException: Object reference not set to an instance of an object
    Enemy.Start () (at Assets/Scripts/Enemy.cs:15) (line 15 is GameManager.instance.AddEnemyToList(this);)

    NullReferenceException: Object reference not set to an instance of an object
    Player.Start () (at Assets/Scripts/Player.cs:24) (line 24 is food = GameManager.instance.playerFoodPoints;)

    And when I try to move, I get the same error I previously posted, happening maybe 5 times every time I push a movement key.
     
  26. OboShape

    OboShape

    Joined:
    Feb 17, 2014
    Posts:
    836
    ill have another work the tute tomorrow.

    cant be too much wrong, must be a minor problem, but a niggly one :)
    im guessing something in the gamemanager or tags , or a base class , but ill have a dig.
     
  27. seldom

    seldom

    Joined:
    Dec 4, 2013
    Posts:
    118
    I wanted the level progression to have a rhythm of low and high suspense stages, instead of constantly increasing the difficulty. I implemented that by moving the board settings (walls, food, enemies) to config files. For anyone interested, here is the process in tutorial form.

    First, add a ScriptableObject class for the config files. It stores all board config data as well as transition data for deciding which config to use in the next level. That way we can let the random number generator decide whether to use the current config again or to move to a successor config.
    Code (csharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using System.Linq;
    5.  
    6. namespace Completed
    7. {
    8.    public class BoardConfig : ScriptableObject
    9.    {
    10.      public BoardManager.Count wallCount;   // Range for our random number of walls per level.
    11.      public BoardManager.Count foodCount;   // Range for our random number of food items per level.
    12.      public BoardManager.Count enemyCount;   // Range for our random number of enemy units per level.
    13.  
    14.      public List<BoardConfigTransition> transitions;   // all possible successor configs
    15.  
    16.      // returns a BoardConfig randomly selected from the transitions list
    17.      public BoardConfig GetNext()
    18.      {
    19.        float totalWeights = transitions.Sum( tr => tr.weight );
    20.        float rnd = Random.Range(0, totalWeights);
    21.        float sumSoFar = 0;
    22.    
    23.        foreach(var transition in transitions)
    24.        {
    25.          sumSoFar += transition.weight;
    26.          if (sumSoFar >= rnd)
    27.            return transition.target;
    28.        }
    29.  
    30.        return transitions.Last().target;
    31.      }
    32.    }
    33.  
    34.    [System.Serializable]
    35.    public class BoardConfigTransition
    36.    {
    37.      public BoardConfig target;
    38.      public float weight;
    39.  
    40.      public BoardConfigTransition(BoardConfig target, float weight)
    41.      {
    42.        this.target = target;
    43.        this.weight = weight;
    44.      }
    45.    }
    46. }

    Now you can remove the wallCount and foodCount variables from BoardManager, and make the SetupScene method take its object counts from a config.
    Code (csharp):
    1.      //SetupScene initializes our level and calls the previous functions to lay out the game board
    2.      public void SetupScene (int level, BoardConfig boardConfig)
    3.      {
    4.        //Creates the outer walls and floor.
    5.        BoardSetup ();
    6.    
    7.        //Reset our list of gridpositions.
    8.        InitialiseList ();
    9.    
    10.        //Instantiate a random number of wall tiles based on minimum and maximum, at randomized positions.
    11.        LayoutObjectAtRandom(wallTiles, boardConfig.wallCount.minimum, boardConfig.wallCount.maximum);
    12.    
    13.        //Instantiate a random number of food tiles based on minimum and maximum, at randomized positions.
    14.        LayoutObjectAtRandom(foodTiles, boardConfig.foodCount.minimum, boardConfig.foodCount.maximum);
    15.    
    16.        //Instantiate a random number of enemies based on minimum and maximum, at randomized positions.
    17.        LayoutObjectAtRandom(enemyTiles, boardConfig.enemyCount.minimum, boardConfig.enemyCount.maximum);
    18.    
    19.        //Instantiate the exit tile in the upper right hand corner of our game board
    20.        Instantiate (exit, new Vector3 (columns - 1, rows - 1, 0f), Quaternion.identity);
    21.      }

    GameManager is responsible for storing the config. Add a variable:
    Code (csharp):
    1.      public BoardConfig boardConfig;               //Configuration settings for the game board
    Add it as an argument to the boardScript.SetupScene call, and update it when a new level is about to be created:
    Code (csharp):
    1.      //This is called each time a scene is loaded.
    2.      void OnLevelWasLoaded(int index)
    3.      {
    4.        //Add one to our level number.
    5.        level++;
    6.        //Select the next board config
    7.        boardConfig = boardConfig.GetNext();
    8.        //Call InitGame to initialize our level.
    9.        InitGame();
    10.      }

    You're almost done with code, just one more tool for creating our config files:
    Code (csharp):
    1. using UnityEngine;
    2. using UnityEditor;
    3.  
    4. public class CreateBoardConfig
    5. {
    6.    [MenuItem("Assets/Create/BoardConfig")]
    7.    static void DoCreateBoardConfig()
    8.    {
    9.      var config = ScriptableObject.CreateInstance<Completed.BoardConfig>();
    10.      AssetDatabase.CreateAsset(config, "Assets/EntryBoard.asset");
    11.      AssetDatabase.SaveAssets();
    12.    }
    13. }

    Now you need to set up the data files.
    First, use the menu Assets > Create > BoardConfig to generate the config file Assets/EntryBoard. Make three copies of it (CRTL+D) and name them EasyBoard, RegularBoard and ChallengeBoard. The EntryBoard config is for the first level, the other ones will cycle throughout the remaining levels.

    Use the inspector to populate them, I picked these values:
    Code (csharp):
    1. EntryBoard:
    2.    wallCount 10-12
    3.    foodCount 1-1
    4.    enemyCount 0-0
    5.    transitions:
    6.      EasyBoard 1
    7.  
    8. EasyBoard:
    9.    wallCount 5-10
    10.    foodCount 2-3
    11.    enemyCount 1-1
    12.    transitions:
    13.      EasyBoard 1
    14.      RegularBoard 1
    15.  
    16. RegularBoard:
    17.    wallCount 5-10
    18.    foodCount 1-2
    19.    enemyCount 2-2
    20.    transitions:
    21.      RegularBoard 1
    22.      ChallengingBoard 1
    23.  
    24. ChallengingBoard:
    25.    wallCount 4-8
    26.    foodCount 1-1
    27.    enemyCount 3-5
    28.    transition:
    29.      EasyBoard 1


    Lastly, find the GameManager prefab and assign the EntryBoard asset to its boardConfig variable. Now you're ready for testing. If you're not sure what config is active at any point, inspect the GameManager instance in the scene.

    You can see an alternative way to edit the config transitions graph here:


    In the video I'm using the relations inspector with the following script:
    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4. using System.Collections.Generic;
    5. using RelationsInspector;
    6. using RelationsInspector.Backend;
    7. using System.Linq;
    8.  
    9. namespace Completed
    10. {
    11.    public class BoardConfigBackend : ScriptableObjectBackend<BoardConfig,float>
    12.    {
    13.      public override IEnumerable<Tuple<BoardConfig, float>> GetRelations(BoardConfig config)
    14.      {
    15.        if (config.transitions == null)
    16.          yield break;
    17.  
    18.        foreach (var transition in config.transitions)
    19.          yield return new Tuple<BoardConfig, float>(transition.target, transition.weight);
    20.      }
    21.  
    22.      public override void CreateRelation(BoardConfig source, BoardConfig target, float tag)
    23.      {
    24.        if (source.transitions == null)
    25.          source.transitions = new List<BoardConfigTransition>();
    26.  
    27.        source.transitions.Add( new BoardConfigTransition(target, tag) );
    28.        api.AddRelation(source, target, tag);
    29.      }
    30.  
    31.      public override void DeleteRelation(BoardConfig source, BoardConfig target, float tag)
    32.      {
    33.        var targetEntries = source.transitions.Where( t => target == t.target);
    34.  
    35.        if (!targetEntries.Any())
    36.        {
    37.          Debug.LogError("RemoveRelation: source is not related to target");
    38.          return;
    39.        }
    40.  
    41.        source.transitions.Remove(targetEntries.First());
    42.        api.RemoveRelation(source, target, tag);
    43.      }
    44.    }
    45. }
    46.  
     
    Last edited: Jan 29, 2016
    kleinrock and Kropti67 like this.
  28. Steerpike

    Steerpike

    Joined:
    Mar 4, 2014
    Posts:
    4
    Thank you for the tutorial, it was very helpful.

    [SOLVED - left this here in case anyone else runs into the same issue]
    I have *one* bug in my version - the player can walk through the enemies.
    The player and enemies all have their collision set up, all are set to the BlockingLayer Layer, and all have blockingLayer public variable correctly pointed to the BlockingLayer.
    Looking through the code, the only line (as far as I can work out) that is supposed to detect the player moving through enemies is this:
    hit = Physics2D.Linecast (start, end, blockingLayer);

    Any suggestions as to why this might not be working for me (I typed all the code in by hand rather than copy-pasting as I find that that makes me attend to the reason for each line - on the other hand it *does* mean that the bug is likely to be a typo somewhere...)

    EDIT: Ha! As is often the way with these things, as soon as you ask for help with a bug, you spot it yourself....
    I couldn't see anything wrong with the code so I tried flicking back and forth between my enemy prefabs and the ones in the Completed/Prefab folder to see if I could spot any difference. Somehow the Box Collider 2D Size X & Y had been changed to 0.0001 on both my enemies! I have no idea how this happened...
     
    Last edited: Feb 21, 2015
  29. hodge_podge

    hodge_podge

    Joined:
    Feb 22, 2015
    Posts:
    30
    Thanks so much for the tutorial Matt, I didn't have any issues following your instructions.

    I do hope you (or anyone reading this ;)) will consider extending this project just by a little bit by doing small things like adding the ability to start combat with a zombie determined (for starters, you could just reuse the wall destroy code and add a Bool isDead and then put the zombie on a different layer to get this sort of thing in a very basic way.) by simple RNG rolls and perhaps a player found melee object or implementing a more advance level generator to the project.

    I'm sure a lot of people would appreciate it if this project could be improved in those ways.
     
    Doenertier likes this.
  30. godwintineractive

    godwintineractive

    Joined:
    Feb 23, 2015
    Posts:
    1
    Hey man, first thing thanks for this great tutorial! I'm just a beginner though.

    second I'm already into part 5 and so far everything seems good but when I tried to play it (already put all the prefrabs in their respective places) it's like they're overlapping, I used 254x254 sprites though..
     

    Attached Files:

    Last edited: Feb 23, 2015
  31. brandc

    brandc

    Joined:
    Feb 23, 2015
    Posts:
    16
    Hi all,

    I've changed a lot of the code but used this as a base to work from. I've also used code from the Amaranth open source project available on BitBucket. The tiles are from the open source project Pixel Dungeon over on github.

    So far room and dungeon generation is pretty much complete and working well. I'll be releasing this pretty soon so others can have a look.

    I've tried to add as many options to the inspector so creating a different feel to the dungeon is pretty simple.



    Thanks for the Roguelike tutorial it was a great read :)
     
    Sire404 likes this.
  32. Matthew-Schell

    Matthew-Schell

    Joined:
    Oct 1, 2014
    Posts:
    238
    @thefreehunter Is it possible that your GameManager object is not being loaded? Is the GM in the hierarchy when you get these errors?

    @seldom Cool! Thanks for extending this and sharing what you did, will have to check this out when I get a second.

    @hodge_podge Thanks for the feedback, as you can see some others have been taking a stab at extending parts of the project, if you'd like to give it a shot and post what you get here, even if it's incomplete I'm sure people would be interested to discuss and chime in. As you can see in the thread some of our community members already are.

    @godwintineractive check your pixels to units setting in the import settings for the sprite. If yours are 254 then you should set all of them to 254 in there.

    @MythicalDog Neat! Really interested to see what you came up with, I've actually got a little prototype where I implemented some of these ideas: http://www.vlambeer.com/2013/04/02/random-level-generation-in-wasteland-kings/ (as suggested by @Aiursrage2k ) that I'll probably share on an upcoming live stream (once I get the kinks figured out) but I'd be very interested to see what you came up with for yours, it looks quite a bit fancier than what I've done (including doors! cool!) And glad to hear you enjoyed the project, I had a ton of fun making it :)
     
  33. donderper

    donderper

    Joined:
    Apr 7, 2014
    Posts:
    5
    Wow, I just wanted to say how great this is. I've been making small roguelike-ish things for the last year iteratively improving upon code I originally found here. There's so many different things I wanted to implement or have already done, but kind of half-assed, that you fully cleared up and made look super easy. Even stuff like setting Random = UnityEngine.Range or simplifying generating random amounts between two values by using a serialized class I wouldn't have thought of or gone out of my way to find out about. Thanks so much.
     
    Last edited: Feb 24, 2015
  34. Matthew-Schell

    Matthew-Schell

    Joined:
    Oct 1, 2014
    Posts:
    238
    Thanks man! Very happy to help. Hopefully as this thread goes on we can gather further resources for people interested in the same ideas here.
     
  35. donderper

    donderper

    Joined:
    Apr 7, 2014
    Posts:
    5
    One thing I never got around to fully figuring out was how to make large maps without every tile being a unity object. There was some vague information online about writing sprites onto a plane and doing it in NxN sized chunks.

    Another aspect to it was using instances of a serialised tile script to track each imaginary tile location and whether it was passable or not plus other information, with all the scripts stored in a board manager script. Your method of keeping every sprite one unity length and using raycasting is probably more straightforward though. Besides the fact that in terms of efficiency there's probably going to be a lot less "stuff" unity objects than tile unity objects. So once you've taken out all the tile objects, that's the largest performance boost.

    Edit: I totally forgot to mention (cause I never use it anymore) but the reason you want a tile script for each tile is because each acts as a node in eric lippert's implementation of the A* pathfinding algorithm.
     
    Last edited: Feb 26, 2015
  36. ag_858

    ag_858

    Joined:
    Mar 28, 2014
    Posts:
    4
    I agree with what others have said about some of the complexity feeling unnecessary. The singleton pattern serves a purpose but the inheritance code really seems like the kind of thing that you would do when going after perfection afterwards.

    Like, in a game jam I would just chuck an open-ended MovingObject.cs component on all movable objects and have another separate component call its functions depending on if it were a player or enemy, I feel it would be more agile and Unity-ish that way.
     
  37. BusyRobot

    BusyRobot

    Joined:
    Feb 22, 2013
    Posts:
    148
    I'm getting the error "An object reference is required to access non-static member `GameManager.boardScript'"

    When I try to access a variable in boardscript from another script, like this

    Code (CSharp):
    1. GameManager.instance.boardScript.CreateEdgeTiles(5, 5, (int)mapPos.x, (int)mapPos.y);
    (CreateEdgeTiles is my own function I've created and made public).
     
  38. hodge_podge

    hodge_podge

    Joined:
    Feb 22, 2015
    Posts:
    30
    I appreciate that you took the time to respond. I took my own shot at expanding a few parts of the project. Currently, I added a shroud/fog of war system to the game where the player character can only reveal tiles 2 units from his position and the ability to remove zombies from the board if they are attacked 4 times (just like walls).

    All you have to do really for those features is just slightly modify the wall code to work within the enemy script for the ability to disable objects and add a bool to check if they are disabled for their attack code for the zombies.

    For the fog of war/shroud, all you have to do is create a pitch black tile and layer it above all other prefabs. Then you prefab said tile and instantiate it on the BoardSetup method. You then create detector object with a unique tag, rb, follow script and its own 2d Collider. You then size its 2D Collider to the how far you want your player to see. All you have to do at that point is write a simple script that checks for the tag you put on the detector object and have it disable the shroud/fog of war instance on collision.

    After that you should be good after make sure the follow script on the detector follows the player object (iirc if you try child the detector to the player its Collider will override the player's)I'm sure their are better ways to handle this, so if anyone has a better solution, feel free to share it.
     
    Last edited: Feb 27, 2015
  39. CDMcGwire

    CDMcGwire

    Joined:
    Aug 30, 2014
    Posts:
    133
    Just started watching this series of videos. Currently at board manager, the first part to get in depth on the scripting involved in this project.

    I have a suggestion about how Scripting is demonstrated in future tutorials. It seems that most tutorials simply dive head first into the script and explain as they go. While it works, it is a bit confusing, even with a significant amount of coding experience, and leaves me rewinding and fast forwarding constantly to keep up.

    My suggestion then, is that a brief, high-level overview of the code be given before the demonstrator begins to write, that way the viewer knows what to expect and can see where the specific implementation is going as it is written.

    Sorry if this is expounded upon enough, crunched for time at the moment!
     
    TizzyTool likes this.
  40. Fernando-Mondo

    Fernando-Mondo

    Joined:
    Aug 14, 2013
    Posts:
    4
    Hi, I finished the tutorial series and it's amazing, but how English is my second language, I guess I missed something.

    When the player die, how do you restart the game? Because you stop the music and disable the GameManager.
     
    tomtaichii likes this.
  41. kapaww

    kapaww

    Joined:
    Mar 8, 2015
    Posts:
    1
    Hi, I'm new to Unity, I've followed the 2D Roguelike video tutorial and import the package

    However, the import process is never complete, under project setting, NavMeshLayers.asset is not importing and somehow stuck.

    Is it possible for me to continue the tutorial without the NavMeshLayers.asset not imported?

    asdfadf.png been running like this all day

    English is my 3rd language, sorry for the grammar
     
  42. CDMcGwire

    CDMcGwire

    Joined:
    Aug 30, 2014
    Posts:
    133
    Well, I wish I could write Russian as well as you write English, so stop apologizing. :p
     
    Milos7 and SicraS like this.
  43. Papiertig0r

    Papiertig0r

    Joined:
    Jun 27, 2014
    Posts:
    4
    I love the unity tutorials, they give a great understanding of how unity works and how you can approach different assignments.

    However, I am at lection 11 and I can destroy walls but I can't be attacked by enemies nor pick up food, I double checked every script and prefab, I seem to be missing something obvious here, could someone help me?
     
    Rexor4321 and justsoelmo like this.
  44. swatdogg

    swatdogg

    Joined:
    Feb 4, 2015
    Posts:
    2
    I have been enjoying myself up until now. I'm sure it is something simple I am missing as I have been trying to find a solution for a little over 2 hours, but I just can't seem to find it. My player will move one space and then after that no matter what direction I press, he will not move. The enemy continues to move and I can even hit an inner wall but the player will not move any spaces past the first space. Any thoughts as to what might be causing this would be greatly helpful.
     
  45. swatdogg

    swatdogg

    Joined:
    Feb 4, 2015
    Posts:
    2

    I appear to have solved this problem myself as I changed the transform on my player from 0,0,13 (which it must have defaulted to when I established him) to 0,0,0. He now is able to move as designed. I knew it was going to be simple, just surprised at the cause.
     
  46. Pablo_Fawkes

    Pablo_Fawkes

    Joined:
    Mar 9, 2015
    Posts:
    2
    First of all, thanks for this amazing tutorial.
    I managed to do something wrong that I cannot fix, I can't trace it, if only I could go deeper while debugging (I guess I would need to have the pro version ;P)!
    When I destroy a wall or take a soda/fruit, an outer wall tile also dissapears. Starting from the bottom left, and then going up, unpredictably. It's like everytime I call secActive(false), an outer wall tile might dissapear (the floor tile is still in, and I can't go through the dissapeared tile whatsoever).

    Does any of you have any idea of what might be causing it?

    Thanks in advance!

    (Edit: btw, the rest of the code works fine so far)
     
  47. dkpjester

    dkpjester

    Joined:
    Mar 4, 2015
    Posts:
    2
    I've got a lot of dev experience in C# but this is my first honest stab at Unity and it's 1am so if this is a dumb question please bear with me. I got this project done with the exception of the touch controls and I've had a consistent problem I can't seem to suss out. When I transition levels the game flips out a bit and the best I can tell from some debugging is the game is creating multiple versions of the board (tiles overlap and zombies/food appear on top of walls from what i assume are other boards). As a result of the multiple loads the level counter gets incremented a bunch I think. Typically the scenario goes like this: Level 1: works as expected. Level 2: Loads with proper text. I see three boards in the hierarchy, two zombies appear which shouldn't be the case for level 2, things are stacked but the game is still playable. When i go to load level 3, it reads as Day 5, there is crap everywhere food level is at 0 when you try to move you die and death text reads Day 5. I only have one copy of game manager in the hierarchy but boards are getting loaded all over the place. I'm sure this just a noob setup issue, but does anyone have any insight into this behavior? Any help would be greatly appreciated.
     
  48. Fernando-Mondo

    Fernando-Mondo

    Joined:
    Aug 14, 2013
    Posts:
    4
    Well, while I wait help from someone, I will try help us too.

    kapaww, check your current version of unity, and download the package again, here work fine.

    Papiertig0r, check the layer of enemies and tiles prefabs, I have a similar problem when I created them.

    Pablo_Fawkes, the best way to debug is calling the "print" method : print(object message) , I really think that you put yours tiles prefabs on the wrong layer, please check it.

    dkpjester, check the "loader" object, I think that you didn't put the singleton instance check method.

    kapaww, my English is not so good too. :p
     
  49. Pablo_Fawkes

    Pablo_Fawkes

    Joined:
    Mar 9, 2015
    Posts:
    2
    Thank you :)
     
  50. dkpjester

    dkpjester

    Joined:
    Mar 4, 2015
    Posts:
    2
    Your advice made me go back and check my loader and while the code was right, I'd somehow attached the loader from the completed directory to my camera and not my own. I'm still not 100% sure why it did that as a result as the code was the same (my guess is namespace weirdness with my prefabs), but once I got my loader attached to the camera it worked fine. Thank you for the response!
     
    Last edited: Mar 12, 2015
Thread Status:
Not open for further replies.