0
\$\begingroup\$

I'm new in coding from zero and I have some problems with architecture of classes (project mb?). I have empty room that I need to add “equipment” to it later (change the type of room). enter image description here I already have a class with a room that contains types of rooms, but I’m not sure that this is the right solution, since the methods of different room types can be large and really different. Is it possible to somehow separate the classes of different type of room (inherit from an empty room, for example) and how to further work with them (reinitialize the room after selecting equipment?)

public enum RoomType
{
   None,
   FirstType,
   SecondType,
   ThirdType
}
public class Room : MonoBehaviour
{
   [SerializeField] private RoomType type = RoomType.None;
}
\$\endgroup\$
6
  • \$\begingroup\$ You may want to search for previous Q&A discussing the concept of composition over inheritance. Unity projects tend to benefit from this approach, where a room "has a" room behaviour component or child, rather than it being the case that a room "is a" room of a specific type. Components / has-a relationships are much easier to swap on the fly. Adding more detail about the behaviours these types have can help us tailor answers to your specific use case. \$\endgroup\$
    – DMGregory
    Nov 9, 2023 at 1:09
  • \$\begingroup\$ You might also want to check out the type object and strategy programming patterns, which can be a big help in taking this kind of "type" behaviour and lifting it into the data layer where it's easy to hot swap on the fly. \$\endgroup\$
    – DMGregory
    Nov 9, 2023 at 1:11
  • \$\begingroup\$ Thank you, DMGregory! You gave an excellent direction for my code development :) I used something similar intuitively before, but didn’t know what it was called. \$\endgroup\$ Nov 9, 2023 at 10:20
  • 2
    \$\begingroup\$ What, conceptually speaking, exactly is a "room" in the context of your game? Are you talking about separate scenes? Or are "rooms" objects that exist together in a scene as gameObjects in 3d space? Or are "rooms" a more abstract concept in the data-model of your game? \$\endgroup\$
    – Philipp
    Nov 9, 2023 at 12:58
  • \$\begingroup\$ Is the only difference between rooms the type of equipment that's in the room? \$\endgroup\$
    – Kevin
    Nov 9, 2023 at 22:15

2 Answers 2

1
\$\begingroup\$

It's very difficult to answer questions about how to architect your game when you provide so few details about the game mechanics. You mentioned that your game is similar to Fallout Shelter, so I'll think along those lines.

Is it possible to somehow separate the classes of different type of room (inherit from an empty room, for example)

Yes, of course you can use class inheritance as with any C# application. If you aren't familiar with the concept of inheritance, you should learn about this basic principle of OOP before trying to make a game.

In brief, you could do something like this. Note that some methods are stubs with //... to indicate "Fill in actual code here".

abstract public class Room : MonoBehaviour {
    private List<Character> occupants;
    public IReadOnlyList<Character> Occupants => occupants;
    public void AddCharacter(Character character) { //... }
    public void RemoveCharacter(Character character) { //... }

    abstract public void ApplyEffect();
}

public class Generator : Room {
    [SerializeField] private float powerPerOccupant = 5.0f;
    private float currentPower;

    public float CurrentPower => currentPower;

    public void ConsumePower(float amount) { //... }

    override public void ApplyEffect() {
        currentPower = Occupants.Count * powerPerOccupant;
    }
}

public class Mine : Room {
    [Range(.01f, 1f)]
    [SerializeField] private float chancePerOccupant = .1f;
    private int currentOre;

    public float CurrentOre => currentOre;

    public void ConsumeOre(float amount) { //... }

    override public void ApplyEffect() {
        for (int i = 0; i < Occupants.Count; i++) {
            float v = Random.value;
            if (v < chancePerOccupant) currentOre += 1;
        }
    }
}

Alternatively, you can use composition rather than inheritance. In this case, Room would be a separate component rather than the base class:

public class Room : MonoBehaviour {
    private List<Character> occupants;
    public IReadOnlyList<Character> Occupants => occupants;
    public void AddCharacter(Character character) { //... }
    public void RemoveCharacter(Character character) { //... }
}

[RequireComponent(typeof(Room))]
abstract public class RoomFunction : MonoBehaviour {
    protected Room room;

    virtual protected void Awake() {
        room = GetComponent<Room>();
        Assert.IsNotNull(room);
    }
}

public class Generator : RoomFunction {
    [SerializeField] private float powerPerOccupant = 5.0f;
    private float currentPower;

    public float CurrentPower => currentPower;

    public void ConsumePower(float amount) { //... }

    override public void ApplyEffect() {
        currentPower = room.Occupants.Count * powerPerOccupant;
    }
}

public class Mine : RoomFunction {
    [Range(.01f, 1f)]
    [SerializeField] private float chancePerOccupant = .1f;
    private int currentOre;

    public float CurrentOre => currentOre;

    public void ConsumeOre(float amount) { //... }

    override public void ApplyEffect() {
        for (int i = 0; i < room.Occupants.Count; i++) {
            float v = Random.value;
            if (v < chancePerOccupant) currentOre += 1;
        }
    }
}

how to further work with them (reinitialize the room after selecting equipment?)

Off the top of my head, there are two potential ways to approach this:

  1. Create a prefab for each type of room. When the player converts an empty room into a functional room, destroy the empty room GameObject and instantiate the functional room to replace it. Then of course you will need to update any references to the room.

  2. This approach only works with the composition-based approach. When the player converts an empty room into a functional room, add the functional room component (such as Generator) to the existing empty room, then instantiate any graphics that are part of the room.

Which approach is best? We can't answer that for you; it depends on both personal preference and the specific details of your game.

\$\endgroup\$
0
\$\begingroup\$

I'd just use RoomtypeID as a field in your room class.

You can then write a function to populate the items (equipment) in that room based on that ID.

You could store the equipment or items in the room in a list which is also a field of the room.

Here is an example of a room class from my game: (hexType is the ID and you can see a list to contain items and zombies)

    public class MapTile 
{
    public HexNum Pos =new(0,0);    // Grid Co-ords
    public string SpriteName;       // Name of sprite to show 
    public Vector3 SPos;            // World position
    public string Grid;             // String of Co-ords
    public bool Fog;                // True if tile is currently fogged of warn hidden
    public bool CanBeSearched;      // True if it can be searched
    public int HexType;             // The type of Hex it is ie "police Station"
    public int NPC_ID;              // The ID of an NPC stored here               

    public List<Zombie> Zombies = new List<Zombie>(); // a list of zombies in the Tile
    public List<Item> Items = new List<Item>(); // a list of Items in the Tile

}
\$\endgroup\$
2
  • \$\begingroup\$ Thank you for your answer, but this a bit unsuitable for my situation. I want to divide object methods to doing my code more organized and more flexible for future. For example, if there will be more than 5 id, unlimited ifs or cases will make code messy, in my opinion \$\endgroup\$ Nov 9, 2023 at 10:33
  • 3
    \$\begingroup\$ Be sure to describe that use case and the constraints it imposes in your question, so folks know in advance what kinds of solutions won't be suitable. Without knowing what "reinitializing the room" entails, for instance, it will be hard for users to guess at solutions that handle that gracefully. \$\endgroup\$
    – DMGregory
    Nov 9, 2023 at 11:45

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .