Словарь классов с разными типами - PullRequest
0 голосов
/ 23 июня 2019

Я пытаюсь создать систему, которая делает заклинания из меньших частей заклинания. Например, компонент урона и компонент исцеления. Для этого я создал классы урона и исцеления, и я хочу сохранить их в словаре. Затем я хочу вызвать функцию в этих классах, когда они взяты из словаря. Функция всегда называется «Использовать».

У меня большие проблемы с принятием классов в словаре, так как каждый класс имеет свой тип. Кроме того, когда я вызываю Use, мне говорят, что «Type не содержит определения для Use».

Я искал вокруг, и я не могу понять, что я делаю неправильно.

public class MakeAbility : MonoBehaviour
{
    public BlockScriptableObject block;

    public IDictionary<string, Type> abilities_parts = new Dictionary<string, Type>();

    public PartAttack part_attack;

    private void Start()
    {
        abilities_parts.Add("part_attack", part_attack.GetType(PartAttack));
    }

    public void make_ability()
    {
        foreach (string i in block.ability_parts) // This is a string list of all the component parts. The idea is that For each entry, say "attack", it would call the class in the dictionary with the keyword "attack" and enact it's .Use method.
        {
            abilities_parts[i].Use();
        }
    }
}


using System.Collections;
using System.Collections.Generic;
using UnityEngine;


[System.Serializable]
public class PartAttack
{
    public Targeting target_manager;

    public int block_attack_damage = 0;
    public int block_attack_repeats = 0;

    void Use()
    {
        foreach (Combatant enemy in target_manager.list_of_targetable)
        {
            int repeats = block_attack_repeats;
            while (repeats >= 0)
            {
                enemy.health = enemy.health - block_attack_damage;
                block_attack_repeats -= 1;
            }

        }
    }

}

1 Ответ

0 голосов
/ 24 июня 2019

Прежде всего, ваша реализация Use, как

void Use()
{
    ...
}

автоматически делает его private, поэтому он не может быть вызван из другого класса. Сделай это

public void Use()
{
    ...
}

Функция всегда называется «Использовать».

Это точный пример использования интерфейса

public interface IAbility
{
    // interface method are automatically public
    void Use();
}

Теперь каждый класс, реализующий этот интерфейс , должен реализовать метод Use(), как

[System.Serializable]
public class PartAttack, IAbility
{
    public Targeting target_manager;

    public int block_attack_damage = 0;
    public int block_attack_repeats = 0;

    // has to implement this because of IAbility
    public override void Use()
    {
        foreach (Combatant enemy in target_manager.list_of_targetable)
        {
            int repeats = block_attack_repeats;
            while (repeats >= 0)
            {
                enemy.health = enemy.health - block_attack_damage;
                block_attack_repeats -= 1;
            }
        }
    }
}

Если вы уже хотите иметь возможность иметь некоторые предопределенные методы с определенной функциональностью и сделать так, чтобы классы также использовали одни и те же поля, сделайте его абстрактным классом

[System.Serializable]
public abstract class Ability
{
    // this can not be changed or accessed not even by any inheritor
    private float aValueOnlyThisClassCanSee;

    // this can changed/accessed by inheritors but not from the outside
    protected string SomeProtectedValue;

    // this can accessed/changed by everyone
    public Targeting target_manager;

    // the same keywords can be used on methods ... I skip this ;)

    // This method HAS TO BE implemented by every inheritor
    public abstract void Use();

    // This method CAN BE implemented in order to extend or overwrite it by inhertors
    public virtual void SaySomething()
    {
        Debug.Log("I basically do nothing.");
    }
}

Теперь вы наследуете как

[System.Serializable]
public class PartAttack : Ability
{
    // inherit target_manager and can use it in every inheritor

    public int block_attack_damage = 0;
    public int block_attack_repeats = 0;

    // Has to be implemented otherwise throws compiler-error
    public override void Use()
    {
        foreach (Combatant enemy in target_manager.list_of_targetable)
        {
            int repeats = block_attack_repeats;
            while (repeats >= 0)
            {
                enemy.health = enemy.health - block_attack_damage;
                block_attack_repeats -= 1;
            }
        }
    }

    // CAN BE implemented in order to extend
    public override void SaySomething()
    {
        Debug.Log("I'm creating some debug logs but ..");

        base.SaySomething();
    }
}

Теперь в зависимости от того, с кем вы идете, ваш словарь либо

public Dictionary<string, IAbility> abilities_parts = new Dictionary<string, IAbility>();

или

public Dictionary<string, Ability> abilities_parts = new Dictionary<string, Ability>();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...