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:
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.
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.