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

问题描述 投票:0回答:3

我已经从事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拖动到卡显示脚本中,它会更新卡并显示一切正常!

尽管我一生都无法弄清楚如何用代码来做到这一点。我不知道如何从代码访问我的ScriptableObjects。

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

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

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

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

unity3d gameobject
3个回答
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[];

0
投票

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

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

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

unlockedCardList.AddCard(rewardCardsList.GetRandomCard());

0
投票

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

此设计需要4个脚本:

Card 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);
}
}

CardRewardPool ScriptableObject

[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;
    }
}

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

CardDisplayScript Monobehaviour

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

LootableEntity Monobehaviour

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

public class LootableEntity : Monobehaviour
{
    public CardRewardPool cardRewardPool;

    public Card GetBattleReward()
    {
        return cardRewardPool.GetRandomCard();
    }
}

最后发言

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

© www.soinside.com 2019 - 2024. All rights reserved.