Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Best way to make a tileable isometric conveyor placement system?

Discussion in 'Scripting' started by thevvulf, Sep 25, 2021.

  1. thevvulf

    thevvulf

    Joined:
    Oct 31, 2020
    Posts:
    36
    I've wanted to make a good conveyor system for a while now, but I can't think of how I wanted to make the placement system. Any good conveyor system can tell which direction each one should face, using the conveyors next to it. So far I know and have just hardcoded these values, but its incredibly difficult and unreliable. I was wondering if there's a better way of doing it? So far I just use a for loop and check the position and i + 1 and i - 1, then changing the current sprite accordingly. If anyone doesn't know what I mean, I'm looking for something similar to Lumbermills, if that helps.
     
  2. orionsyndrome

    orionsyndrome

    Joined:
    May 4, 2014
    Posts:
    3,043
    maybe check out Code Monkey's tutorial on conveyors? he made the full system as far as I can remember. and there are even better tutorials out there, I'm also 100% positive there was a recent upload to asset store, this thing is super popular.

    I Made a Factory Game in 20 HOURS!
     
  3. orionsyndrome

    orionsyndrome

    Joined:
    May 4, 2014
    Posts:
    3,043
    In general you can set up the following

    Make a cardinal orientation enum
    Code (csharp):
    1. public enum Orientation {
    2.   East,
    3.   North,
    4.   West,
    5.   South
    6. }
    Then make extensions to make semantical correlations
    Code (csharp):
    1. public static class OrientationExtensions {
    2.  
    3.   public static Vector2 ToVector2(this Orientation value) {
    4.     switch(value) {
    5.       case Orientation.East: return Vector2.right;
    6.       case Orientation.North: return Vector2.up;
    7.       case Orientation.West: return Vector2.left;
    8.       case Orientation.South: return Vector2.down;
    9.       default: throw new NotSupportedException();
    10.     }
    11.   }
    12.  
    13. }
    Super reliable, easy to read.

    Aand just now I have realized you mean that you want to graphically orient the conveyor belts?
    But now I'm not sure what's the problem.

    a)
    If you know the orientation of each sprite, you just choose the sprite that reflects the orientation.

    b)
    If you want to auto-detect the nearby orientation when placing, there is no other way but to, well, detect the nearby orientation and adjust accordingly. Can you be more precise in what exactly you're trying to achieve, what you have already information-wise, and why is that insufficient at this point in time?
     
  4. thevvulf

    thevvulf

    Joined:
    Oct 31, 2020
    Posts:
    36
    I have a functioning system, the problem is that it takes up far more than I feel it should. I have at least 50 lines of just switch and if statements to determine positions, when I feel that this could be cut down to a much smaller number and be far more efficient. What I have now are a million tests like if(cs[i + 1].transform.position == transform.position + northVec2) where northVec2 is just a predefined vector 2, which is currently representing 8, 3.75 since thats the difference in position where the tile goes up-right. Then, if thats the case, I change the sprite to the one I made that fits the up-right orientation. I then do this for every possible straight angle, turn, starting point, etc., which grows very fast.
     
  5. orionsyndrome

    orionsyndrome

    Joined:
    May 4, 2014
    Posts:
    3,043
    Sometimes this is unavoidable, but what you can do is to move this logic somewhere else, and build a proper utility that you can use on a high-level.

    When you want to track a discrete state, it helps to translate it to an integer.
    For example,
    mystate = 5;
    and this has some meaning to the rest of the system. This is similar to that enum I described before. When there is a logical correlation between the state components, you can also get away with more dimensions, for example SouthWest would mean South + West even though SouthWest is a constant with a value 5 for example.

    If you really want to generalize, think of it this way, let's say you really want to build a compound state from South and West and then check whether something is both South and West. That's called composing, and you work with flags.

    South is just an information on the North-South axis that has 3 possible states: positive, negative, and zero.
    Likewise, West lives on the East-West axis. Notice that each axis can have only one state, because they're mutually exclusive. And so you can quickly figure out that you need 2 bits of entropy to encode this information, because 2^2 = 4.
    Code (csharp):
    1. 00 = zero
    2. 01 = positive
    3. 10 = negative
    4. 11 = unused
    Now it's easy to compose two or more axes into a single state, i.e. 10 00 01 would mean positive X, zero Y, negative Z, but would in itself have a value of 33 (which is 100001 in binary).
    But to really stay in control over this new mode of thinking, you need to be able to also decompose it.

    To work with this, you need to understand bitwise operators. Try with this guide I wrote earlier.

    You can thus compose states like this
    Code (csharp):
    1. mystate = Orientation.South | Orientation.West; // composition is encoded
    and you can query it like this
    Code (csharp):
    1. southward = ((int)mystate & (int)Orientation.South) > 0; // returns true or false
    Of course, this all comes to fruition when you make a dedicated class or a utility that will help you transcend this into tools that are much more readable, for example

    Code (csharp):
    1. if(something.orientation.HasOrientation(Orientation.West | Orientation.South)) {}
    2. // or more conveniently
    3. if(something.orientation.HasOrientation(Orientation.SouthWest)) {}
    4. // which does the same thing
    5.  
    or
    Code (csharp):
    1. something.orientation = somethingElse.orientation.GetOpposite();
    There are ways and ways to set this up.
     
    Last edited: Sep 25, 2021
  6. orionsyndrome

    orionsyndrome

    Joined:
    May 4, 2014
    Posts:
    3,043
    Also don't forget that you really want to abstract away rotational and reflection symmetries. If you're comparing two things and care only about their relative differences in orientation, why repeat yourself for every single axis alignment.

    There is no need to repeat the same checks all over the place, if you could've done it once somewhere and then reused the whole thing. And I see people do this all the time, so it seems that setting this up really depends on your experience and confidence with such systems.

    If it's too hard for you to come up with an abstraction, maybe it is the most accessible and the most readable to simply state a wall of 'ifs' and get it done.