Trying to implement a prefab with a really complicated design - very confused

Hello

So I am trying to implement a setup method that needs to do a bunch of checks, and based on these checks implement a prefab.

So heres the idea of what i am doing:

Imagine a sky scraper of which has rooms on every floor. Now this sky scraper has a room which is an elevator room type.

So imagine a layout like this:

In this above example the two elevators are considered “connected” because they are one Y position apart and on the same X axis.
Because of this, i can now implement an elevator platform and set its linked rooms to those two elevators - not terribly challenging to do that.

How ever it gets a lot more complicated when i need to link up multiple elevators for example:

So i kinda started to work out a way to connect it all like this:

void SetElevators(){
    List<Room> elevators = new List<Room>();

      for(int i = 0; i < rooms.Count; i++){
        if(rooms[i].roomType == RoomType.Elevator){

        // get neighbours
        elevators.Clear();
        elevators.Add(rooms[i]); // ADD the first elevator

        for(int j = 0; j < rooms.Count; j++){
        // if not same room type or not on same x-axis, or it is the same room = skip it
        if(rooms[j].roomType != rooms[i].roomType || rooms[j].x != rooms[i].x || rooms[i] == rooms[j]){ continue; }
  
         elevators.Add(rooms[j]); //ADD the next elevator
        }

        //instantiate prefab connected to just these elevators
        CreateElevatorPlatform(elevators);
      }
    }
}

The problem here is two things:

  1. Duplication, this design is surely going to just create a lot of duplication for every elevator that exists. For example, from Elevator A i get neighbor Elevator B, then on B i am getting elevator neighbor A, which i already have connected up when i was getting neighbors for elevator A. So i end up with TWO elevator platforms for the same connection this cause a collision in the same elevator shaft.

  2. Say you have two elevators separated by a normal room:

These elevators are not connected obviously, but from my current code logic, it will create a connection because i didn’t check if they are directly neighbors. But i also can’t just check for just y+1 or y-1, because there could be elevators connected through multiple floors. As in first example there is 3 floors of elevators all connected one after another.

So i am completely lost on how to implement this logic.

Hope some one can help shed light on what is the best solution here.

Thanks.

So I’m trying to figure out what sort of connections you want (according to Question 1). Don’t you want the elevators to connect to eachother.
Do you want the elevators in both elevator-variable lists? It kind of sounds that you do want it, but maybe you’re instantiating a prefab when connecting them too?
Do you want just one elevator-platform connected to all elevators in the list?

Do you know the size of the building x/y and can fetch them through a 2d array or something?
If you don’t have access to this, then I’d suggest doing something like this:

// Room.cs

    public List<Elevator> elevators = new List<Elevator>();
   
    private void ConnectToElevator(Room elevator)
    {
        // don't add elevators we're already connected to.
        if (elevators.Contains(elevator))
            return;

        // connect to the newly added elevator.
        elevators.Add(elevator);
        // connect the new elevator to the already connected elevators.
        foreach (Room connectedElevator in elevators)
            elevator.ConnectToElevator(connectedElevator);

    }

And then in the function do this:

for (int i = 0; i < rooms.Count; i++)
        {
            if (rooms[i].roomType == RoomType.Elevator)
            {
                // check if this room has already been connected to other elevators.
                if (rooms[i].elevators.Count > 0)
                    continue;

                rooms[i].ConnectToElevator(rooms[i]); // Connect us to ourselves.

                // get the neighbours
                for (int j = 0; j < rooms.Count; j++)
                {
                    // if not same room type or not on same x-axis, or it is the same room = skip it
                    if (rooms[j].roomType != rooms[i].roomType || rooms[j].x != rooms[i].x || rooms[i] == rooms[j]) { continue; }

                    // check that the room is adjacent up/down from this elevator. Yes, we need this check.
                    if (rooms[j].y > rooms[i] + 1 || rooms[j].y < rooms[i] - 1)
                        continue;

                    rooms[i].ConnectToElevator(rooms[j]);

                    // moved inside ConnectToElevator
                    //elevators.Add(rooms[j]); //ADD the next elevator
                }

                //instantiate prefab connected to just these elevators
                CreateElevatorPlatform(elevators);
            }
        }

I’m suggesting this since it involves instantiating prefabs and probably isn’t run/done more than once. I didn’t move anything in your code so it’s easier to see what I’ve changed, but I’ve commented out some stuff.

This isn’t really a design question, you might do better in the scripting forum.

3 Likes

You’re method isn’t quite the way i planned to do it.

My goal was along these lines:

Say i had my list of connected elevators, for example:

I would then create a prefab elevator platform, doesn’t matter on which floor it starts on from this list. I would then update this newly created platform that it has access to these 3 elevator rooms.

Pseudo code:

CreatePlatform(ListOfConnectedElevators);

void CreatePlatform(ListOfConnectedElevators){
  // instantiate a platform as PlatformGameObject
  PlatformGameObject.getComponent<ElevatorBehaviour>().setConnections(ListOfConnectedElevators);

//the rooms also need to know what elevator to call when some one waits:

for(int i = 0; i < ListOfConnectedElevators; i++){
     ListOfConnectedElevators.GetComponent<RoomData>().elevatorPlatform = PlatformGameObject;
}
}

From what i understand your method updates each room to inform them what other rooms they are connected to which would create data like this:

This to me seems a lot of duplicated data which i was trying to avoid in the design. To me it would seem more efficient to give the elevator platform a list of rooms it can go to, and those rooms have a reference to the elevator platform to tell it to come to said floor (seeing as they can only have one elevator platform connected to each elevator room).

What are you thoughts on that?

Seems like you’re missing one piece that would help to tie things together.

If you added Floors it seems like it would make for a better data structure. I don’t really know what exactly you are doing so this may be way off base. But anyway…

Elevators
Floors
Rooms (not really needed they kind of are just there on the floors)

Floors contain Rooms
Elevators go to Floors (I don’t really follow why you are linking elevators to rooms directly)

You can then end up with something like this:

Elevator 1
=====Floor 1 (certain Rooms maybe Room A, B, C and D are here)
=====Floor 2 (certain other rooms maybe E, F and G are here)

Elevator 2
=====Floor 2 (rooms maybe E, F and G are here)
=====Floor 3 (other rooms)
=====Floor 4 (other rooms)

etc.

You wouldn’t need any links between elevators and rooms because the rooms would only be on certain floors anyway so that is kind of abstracted away.

But again I am not sure exactly what it is you are doing.

And this is not a Game Design question but a technical implementation question which should be in the Scripting forum.

Elevators are simply a type of room. But you got the right idea above where by having the elevator platform (not the room) keeps a list of the rooms (of type=Elevator) it can go to on each floor:

Platform goes to:
=====Elevator Room 1 (this room also holds a reference to Platform)
=====Elevator Room 2 (same for this room as above ^)

There for if i am at Elevator Room 1 i get the reference to Platform and say “come here i need to go to Elevator Room X”

From that i can check the platform to see if i can even go to Elevator Room X.

But my attempts were kinda stuck as i was trying to create the data and link it all up. Although am wondering maybe i should ask in scripting forum for code guidance at this point. =/

The difficult become apparent when i was trying to chain multiple elevators together to one platform it was hard to work out how to check for it.

1 Like

Yes, there’s some duplicate data with my suggestion. But if that’s the problem, just move the list/function from Room.cs into the elevator script. Also, no, the lists wouldn’t be populated as this:

Room A:
B
Room B:
A
C
Room C:
B

but rather

Room A:
A
B
C
Room B:
A
B
C
Room C:
A
B
C
but not necessarily in that order. Note that in ConnectToElevators, we walk through the list of all connected elevators and attach to all of them to make this happen. You could just move the stuff from Room into your elevatorscript instead, and basically do the same steps though. If any elevator room is connected to this elevator room, check if that elevator room has an elevator (need a variable in Room.cs), add this room to that elevator. If none of the possible connections has an elevator attached, this is a new elevator room. Instantiate an elevatorplatform and attach the room to the platform, and setting the variable in Room obviously. This all assumes of course that the rooms doesn’t come in a random floor-order though, say 2,1,3 in y but rather 1,2,3 or 3,2,1 in order for this to work.

So it’s a bit of a mess, but given the structure as is now, that would be my suggestion. Actually, thinking about it again, since this function won’t execute regularly, you could just make a helper function to fetch your rooms. That’s simple and clean, and so on. It’ll have to iterate through the rooms a lot more though, but you could consider using it.

private void SetElevators()
    {
        List<Room> elevators;
        for(int i = 0; i < rooms.Count; i++)
        {
            if (rooms[i].roomType == RoomType.Elevator)
            {
                // check if this room has already been connected to other elevators.
                if (rooms[i].elevator != null)
                    continue;

                // create a new chain of elevators.
                elevators = new List<Room>();
                elevators.Add(rooms[i]);

                int length = 1;

                // check for all elevators above this one.
                Room r = FindRoom(rooms[i].x, rooms[i].y + length);
                while (r != null && r.roomType == RoomType.Elevator)
                {
                    // found an elevator above us.
                    elevators.Add(r);
                    // keep checking for more elevators.
                    length++;
                    r = FindRoom(rooms[i].x, rooms[i].y + length);
                }

                // check for all elevators below this one.
                length = 1;
                r = FindRoom(rooms[i].x, rooms[i].y - length);
                while (r != null && r.roomType == RoomType.Elevator)
                {
                    // found an elevator below us.
                    elevators.Add(r);
                    // keep checking for more elevators.
                    length++;
                    r = FindRoom(rooms[i].x, rooms[i].y - length);
                }

                //instantiate prefab connected to just these elevators
                // TODO: When creating the elevator platform, iterate through the list and
                // set the variable "elevator" for each room to the elevatorscript/gameobject/whatever.
                CreateElevatorPlatform(elevators);
            }
        }
    }

    private Room FindRoom(int x, int y)
    {
        for (int i = 0; i < rooms.Count; i++)
        {
            if (rooms[i].x == x && rooms[i].y == y)
                return rooms[i];
        }
        return null;
    }