将Unity可编写脚本的对象附加到GameObject

时间:2019-10-02 19:12:33

标签: unity3d gameobject

我已经从事Unity教程大约两个星期了,我做了一些非常基础的事情。抱歉,这是一个非常简单的问题,但是我花了最后5个小时来解决这个问题,并决定来这里。

到目前为止我所做的:

我做了一个非常基本的纸牌游戏,其中的纸牌具有“攻击”和“健康”之类的属性。这些值存储在每张卡的ScriptableObject中。

[CreateAssetMenu(fileName = "New Card", menuName = "Card")]
public class Card : ScriptableObject
{
public int instanceNumber;
public bool isDefaultCard = false;

public string cardName;
public string description;
public string flavorText;

public Sprite cardArt;

public int manaCost;
public int health;
public int attack;

public int characterClass;


public void printCardData()
{
    Debug.Log(cardName + ": " + description);
}
}

现在我还有一个卡片预制件,在Unity UI上,我可以将预制件拖到场景上,然后将ScriptableObject拖动到卡片显示脚本中,它会更新卡片并显示一切正常!

尽管如此,我还是无法弄清楚如何使用代码来实现这一目标。我不知道如何从代码访问我的ScriptableObject。

我知道我可以用这样的实例化预制件:

Instantiate(myPrefab, new Vector3(0, 0, 0), Quaternion.identity);

但是我该如何添加我的卡数据?我希望游戏在战斗结束时能获得奖励,每次显示随机选择的纸牌,然后您选择其中一张。因此,这意味着创建3个带有随机ScriptableObject的卡片对象。但是再说一次,无论我尝试什么,我似乎都找不到从代码访问我的ScriptableObjects。

如果这很简单,再次抱歉,但是我很迷茫。我需要一种随时创建任何ScriptableObjects卡的对象的方法。玩家将有很多次将更多的牌添加到其牌组中,但他们的牌组一次将仅具有20-30张牌。

3 个答案:

答案 0 :(得分:1)

因此,您具有Monobehaviour CardDisplayScript和ScriptableObject Card。在此之前的其他2条评论提到了Singleton和奖励卡列表。尽管它们都可以解决问题,但我已经成功使用了稍有不同的设计。我的方法允许敌人共享“公共奖励池”,并在死亡时退出该公共池。对于老板或稀有敌人,我喜欢创建一个稍有不同的“老板奖励池”。

此设计需要4个脚本:

卡片ScriptableObject

您所遇到的问题:

selects

CardRewardPool ScriptableObject

[CreateAssetMenu(fileName = "New Card", menuName = "Card")]
public class Card : ScriptableObject
{
public int instanceNumber;
public bool isDefaultCard = false;

public string cardName;
public string description;
public string flavorText;

public Sprite cardArt;

public int manaCost;
public int health;
public int attack;

public int characterClass;


public void printCardData()
{
    Debug.Log(cardName + ": " + description);
}
}

如果奖励池可能为空,则应通过检查列表中是否首先包含卡来处理此问题(如上面的代码所示)。如果奖励池永远不为空,则可以删除“ if”检查,并在列表为空时适当地处理错误。

CardDisplayScript单行为

[CreateAssetMenu(fileName = "DefaultRewardPool", menuName = "Card Reward Pool")]
public class CardRewardPool : ScriptableObject
{
    public List<Card> cards;

    public Card GetRandomCard()
    {
        if(cards.Count > 0)
            return cards[Random.Range(0,cards.Count)];
        else
            return null;
    }
}

LootableEntity Monobehaviour

此脚本可以附加到可以期望奖励卡的任何事物上(敌人,奖励箱,故事奖励等)。在这种情况下,如果战斗结束,那么您刚刚击败的任何敌人都应附加一个“ LootableEntity”(或您愿意使用的其他名称),该实体直接引用可以产生奖励的奖励池。

public class CardDisplayScript : Monobehaviour
{
    public Card card;
    //... other properties
    public void UpdateCard(Card _card)
    {
        card = _card;
        //... reload in game attributes using the new card
    }
}

最后的话

此设计使您可以为每个敌人分配一个唯一的奖励池,或者让一些敌人共享奖励池。如果您不希望将卡分成不同的奖励池,则可以使用具有相同设计的通用奖励池。此外,您不再需要在每个实体上保留一个ScriptableObjects列表,因此您确实节省了一些内存。

答案 1 :(得分:0)

会有一些猜测(因此这里的术语很可能与您在代码中实际所用的术语有所不同),但是作为示例。

您要在示例脚本中使用Card对象:

public class CardUser : MonoBehaviour
{
    public Card cardScriptableObject {get;set;}
}

几乎没有办法,最简单的方法是使用单例(卡的全局提供者),但是通常起作用的是总是在实例化实例后才分配引用,这是一个非常粗糙的示例:

public class CardUserInstancer : MonoBehaviour
{

    public CardUser cardUserPrefab;
    public Card mainCard;

    void Instantiate()
    {
        CardUser thisUser = Instantiate(cardUserPrefab, Vector3.zero, Quaternion.identity);
        thisUser.card = mainCard;
    }
}

或者,如果您不想在检查器中使用引用,则可以从“资源”文件夹中列出可用对象,然后选择一个对象

var cards= Resources.FindObjectsOfTypeAll(typeof(Card)) as Card[];

答案 2 :(得分:0)

我最近遇到了类似情况。我所做的是创建一个新的可编写脚本的对象“列表”数据类型。例如,您可以创建一个CardList类,该类是一个可编写脚本的对象,其中包含一个Cards数组(或List)。 (具有AddCard,RemoveCard,GetCard(int index)和GetRandomCard的方法。)

然后您可以创建一个新的CardList,然后在检查器中将所有潜在的奖励卡添加到列表中。将CardList添加到Card Display Script,现在您可以访问列表中的任何卡。

在旁注中,我将为玩家的牌组,解锁的卡,坟墓场等创建CardList。然后,您可以轻松地执行类似的操作

unlockedCardList.AddCard(rewardCardsList.GetRandomCard());