Elastyczny system interakcji przedmiotów należących do gracza

0

Tworzę prostą grę logiczną, w której gracz będzie miał różne przedmioty i używając ich musi rozwiązywać różne zagadki logiczne. Mam jednak problem z zaprojektowaniem w miarę elastycznego systemu interakcji przedmiotu, który gracz wybiera z jakimś obiektem na scenie, na przykład: gracz wybiera pochodnię i może: podpalić inną pochodnię rozjaśniając fragment mapy, lub może użyć jej na postaci gracza doprowadzając do przegranej.

Tworzę klasę abstrakcyjną Item dziedziczącą po ScriptableObject:

    public abstract class Item : ScriptableObject
    {
        public GameObject ItemPrefab;
        public Sprite ItemIcon;
        public string ItemName;
     
        public abstract void UseItem();
    }
     

i stworzyłem drugą klasę UsableItem dziedziczącą po klasie Item

    [CreateAssetMenu(fileName = "ScriptableObjects", menuName = "ScriptableObjects/UsableItem", order = 1)]
    public class UsableItem : Item
    {
        public ItemInteractionAction ItemInteractionAction;
       
        public override void UseItem()
        {
            // Switch for all interaction action?
        }
    }
     

i enum ItemInteractionAction:

    public enum ItemInteractionAction
    {
        Fire,
        Water
    }
     

i moim początkowym pomysłem było stworzenie switcha w klasie UsableItem w metodzie UseItem() dla każdego elementu enuma, ale uznałem, że to nie jest zbyt dobry pomysł. Dodatkowo musiałbym stworzyć wiele ifów dla różnych obiektów, które zachowywałyby się inaczej po interakcji z wybranym obiektem.

0

Wygodnie jest jak każdy rodzaj przedmiotu ma swój identyfikator (w postaci stringa, liczby, maski bitowej, whatever) i jeśli masz możliwość łączenia identyfikatorów (poprzez dodawanie stringów, operację bitową OR itp.). Np. w pseudokodzie:

class Torch : UsableItem {
    type = "Torch";
}

class Player : UsableItem {
    type = "Player";
    energy = 100;
}

// tutaj trzymamy różne rodzaje interakcji (nie musi to być luzem, 
// można by to też trzymać bezpośrednio w klasie Player, jeśli jara cię OOP)

hashmap interactions {
    "Player/Torch": function (player, torch) {
        player.energy -= 10;    
    }
}

function act(objectA: UsableItem, objectB: UsableItem) {

   let key1 = objectA.type + "/" + objectB.type; 
   let key2 = objectB.type + "/" + objectA.type;   
   
   let interactionHandler = interactions.get(key1);
   if (interactionHandler) interactionHandler(objectA, objectB);

   // patrzymy czy klucze są w odwrotnej kolejności:
   let interactionHandler = interactions.get(key2);
   if (interactionHandler) interactionHandler(objectB, objectA);   
}

czyli string based programming. Ale można by też np. zrobić maski bitowe (chociaż wtedy masz ograniczenie co do liczby typów przedmiotów, żeby starczyło bitów). Albo użyć jakiegoś pattern matchingu, jeśli twój język programowania na to pozwala. Tylko nie wiem, wydaje mi się, że opcja z pattern matchingiem na poziomie języka by miała te same wady, co switch, czyli byłaby zahardkodowana logika w języku. I trudniej byłoby to rozszerzać / wprowadzać dynamiczne elementy (np. włączać i wyłączać pewne interakcje)

1 użytkowników online, w tym zalogowanych: 0, gości: 1