0

I'm trying to find the best way to create a dictionary that can hold 6 different sub-types of the abstract Reward type, while also remember the individual item's original sub-type when pulled out again. Several approaches have worked, but I feel like they were all sub-par and that there must be better solutions.

Solutions that works, but I think could be improved on:

  • A list for each reward sub-type. (Will not scale well as I add large amounts of sub-types)

  • A list of lists. (This is both ugly and seems inefficient)

  • Multidimensional array. (Same issues as a list of lists)

Here are the relevant class snippets for my scenario:


 public class RewardAssetContainer : MonoBehaviour
{
// Sounds
private static AudioClip losenedBowels = new AudioClip();
public static AudioClip LosenedBowels { get { return losenedBowels; } }
}

public abstract class Reward 
{
protected EffectTypes effectType;
protected Rareity rareity;
protected Sprite itemIcon;
protected string itemName;
protected GameObject specialEffect;
}

interface iSoundEffect
{
void SetVolume(float _newVol);
void PlaySound();
void StopSound();
}

class DeathSoundEffect: Reward, iSoundEffect
{
    private AudioSource sound;

public DeathSoundEffect(string _itemName, AudioClip _sound, float _vol, EffectTypes _effectType, Rareity _rareity, Sprite _itemIcon)
{
    sound = new AudioSource();

    itemName = _itemName;
    sound.volume = _vol;
    sound.clip = _sound;
    effectType = _effectType;
    rareity = _rareity;
    itemIcon = _itemIcon;
}

public void PlaySound()
{
    sound.Play();
}
}

public class Item_Inventory : MonoBehaviour
{
private static Dictionary<string, Reward> rewardItemsOwned = new Dictionary<string, Reward>();
public static Reward GetSpecificItem(string _keyValue) { return rewardItemsOwned[_keyValue]; }

   private void TestPutToInventory()
{
    rewardItemsOwned.Add("LosenedBowels", new DeathSoundEffect("LosenedBowels", RewardAssetContainer.LosenedBowels, 0.5f, EffectTypes.DeathSoundEffect, Rareity.Rare, RewardAssetContainer.EpicExample));

}
}

I would like to, in a different class, be able to do something like:

  var tempRewardItem = Item_Inventory.GetSpecificItem("LosenedBowels");

    tempRewardItem .PlaySound();

But i can't figure out an elegant way to do this with one collection.

mech
  • 2,775
  • 5
  • 30
  • 38
  • In my mind, the best way to approach this is to have a virtual method that executes whatever logic is associated with the particular `Reward` you're using/receiving. In each of its inherited classes, override that method so they'll each behave differently. If none of your classes share enough similarities to be able to do this, perhaps lumping them all into a giant collection isn't the correct approach? – Serlite Sep 19 '17 at 14:01
  • I get what your saying, and you might be right, since the sub-types(inheriting classes of Reward) will be of one of either type or a variation hereoff: changing soundeffect, visual effect, playermodel. I could deffinetly argue for the case that it should be split up, but since there is 5 variables all of the the sub-types will use, it just seems like it would be ideal if i could have them inherit it from the same place(Reward). – K_Nielsen... Sep 19 '17 at 15:12

1 Answers1

0

Will you always know the original sub-type you expected ahead of time when pulling out an item, like in your example? If so, you can attempt to cast the object you pulled out before using it:

var tempRewardItem = Item_Inventory.GetSpecificItem("LosenedBowels") as DeathSoundEffect; // Could also use 'as isSoundEffect'
if (tempRewardItem != null) 
{
    tempRewardItem.PlaySound();
}
mech
  • 2,775
  • 5
  • 30
  • 38
  • Yeah i will know before picking the item what sub-type of item i will be looking for. In this case its the specific DeathSoundEffect "LosenedBowels". There is gonna be a random roll that selects what type should be picked, and then based on that, a random of the sub-type items in the collection will be picked. – K_Nielsen... Sep 19 '17 at 15:09
  • Ah, if you have to pick a random item of a certain sub-type, then you might want to reconsider the list-of-lists structure (maybe as a Dictionary of lists, with the key being each sub-type), as otherwise you will have to iterate through a bunch of bad/unsuitable items before you find all the ones of the right type, which is not very efficient. You could encapsulate it in a class/method so that, from the consuming code's perspective, it's still a single call (something like `Item_Inventory.GetRandomItemOfType(Type)`). – mech Sep 19 '17 at 15:22
  • @mech Check if the object retrieved [`is isSoundEffect`](https://stackoverflow.com/a/3561214/1663383) and if so, cast it to `isSoundEffect` and call the `PlaySound()` method. Also, `isSoundEffect` is a terrible name. `ISoundEffect` would be better. The `I` lets you (as the programmer) remember that it is an Interface. Then it follows the standard UpperCamelCase convention used for class names. – Draco18s no longer trusts SE Sep 19 '17 at 23:22
  • @Draco18s Agree on the interface naming convention, but I was following the provided code's naming scheme for brevity. – mech Sep 20 '17 at 03:32
  • Ha, whoops, I meant to mention @K_Nielsen... instead. – Draco18s no longer trusts SE Sep 20 '17 at 05:19
  • Agree on the interface name, it is what i usually do but for some reason havent done here hmm.. After considering your input, i have decided to go with a dictionary of lists, it seems to me as the better of the options at the moment. Thanks everyone for your input! Have a nice day! :) – K_Nielsen... Sep 20 '17 at 07:10