【问题标题】:assigning GameObjects to a list and giving them an index将 GameObjects 分配给列表并给它们一个索引
【发布时间】:2020-05-06 02:30:43
【问题描述】:

所以基本上,我有一个每个数字有 2 个的列表,我想将其中一个数字随机分配给每张实例化的卡片。这是一个益智记忆游戏,您可以在其中找到匹配项。

当我有 2 个 gridRows 和 4 个 gridCols 时,游戏运行良好,但如果我更改行数或列数,我会得到:ArgumentOutOfRangeException:索引超出范围。必须是非负数且小于集合的大小。参数名:index,阻止我扩展游戏。我尝试在当前列表中添加额外的数字,但这似乎不起作用,而且如果我想要有很多行和列,这种方式似乎也不是很有效

我想要做的是获取一个列表,然后在每次开始比赛时对其内容进行洗牌,然后在我实例化时按顺序循环索引(内容已经洗牌),这是我的逻辑,但无法做到它出于某种原因工作....

有人可以帮我扩展它并找到存储索引的更好方法吗?

代码如下:

 public const int gridRows = 2;
public const int gridCols = 4;
public const float offsetX = 4f;
public const float offsetY = 5f;

public MainCard originalCard;
public Sprite[] images;


private void Start()
{
    Vector3 startPos = originalCard.transform.position;
    List<int> numbers = new List<int> { 0, 0, 1, 1, 2, 2, 3, 3 };
    numbers = Shuffle(numbers);

    for (int i = 0; i < gridCols; i++)
    {
        for (int x = 0; x < gridRows; x++)
        {
            MainCard card;
            if (i == 0 && x == 0)
            {
                card = originalCard;
            }
            else
            {
                card = Instantiate(originalCard) as MainCard;
            }

            int index = x * gridCols + i;
            int id = numbers[index];
            card.ChangeSprite(id, images[id]);

            float posX = (offsetX * i) + startPos.x;
            float posY = (offsetX * x) + startPos.y;
            card.transform.position = new Vector3(posX, posY, startPos.z);
        }
    }

    List<T> Shuffle<T>(List<T> cards)
    {
        for (int i = 0; i < cards.Count; i++)
        {
            T temp = cards[i];
            int randomIndex = Random.Range(i, cards.Count);
            cards[i] = cards[randomIndex];
            cards[randomIndex] = temp;
        }

        return cards;
    }

}

}

【问题讨论】:

  • 当有人回答时,您不应该删除您的问题。 Stack Overflow 被设计成一个可搜索的存储库;如果您删除您的问题,人们不太可能找到您的问题或理解答案。

标签: c# oop unity3d


【解决方案1】:

一种解决方案是将您的项目分成更多部分:

using System.Linq;//to Add

public int gridRows = 2;
public  int gridCols = 4;
public List<int> numbers;
public void Start()
{
    int[,] cards = new int[gridRows, gridCols];
    //just put different numbers not needed to duplicate 
    //except if you want to increase the probability
    // to have lot of same number
    numbers = new List<int> { 0, 1, 2, 3 };
    InitializeGame(cards);
}

private void InitializeGame(int[,] cards)
{
    //1 you could shuffle your number if you want
    //numbers = Shuffle(numbers);

    //2 you initialize cards to value not used (-1 here)
    for (int r = 0; r < gridRows; r++)
    {
        for (int c = 0; c < gridCols; c++)
        {
            cards[r, c] = -1;
        }
    }

    // Test if you have filled up all cards
    //Is there again one card with the value -1?
    while (cards.Cast<int>().Any(x => x == -1))
    {
        //3 you pick randomnly a number
        var numCard = numbers[Random.Range(0, numbers.Count)];

        //4 you fill same number to 2 different cards here
        var nbcardTofill = 2;
        while (nbcardTofill != 0)
        {
            //you choose randomny card (row and col) which is free (value = -1) not need but add fun
            var colRandom = Random.Range(0, gridCols);
            var rowRandom = Random.Range(0, gridRows);
            if(cards[rowRandom, colRandom] == -1)
            {
                nbcardTofill--;
                cards[rowRandom, colRandom] = numCard;
            }
        }
    }
}

现在你有了填满数字的数组卡片,你现在可以抽奖了..

这样您就可以根据需要更改列数/行数和数字列表...

只是一种编程方式,但我认为它更具可读性。我添加了很多随机化来增加乐趣...

另一种方法是按顺序填写你的牌(2 x 2 相同的数字)并在最后将所有牌洗牌......

【讨论】:

  • 这不是一个最佳解决方案,因为当大部分网格被填满时,您将花费大量时间挑选无法使用的随机列/行。
  • @AKX,它只是为了好玩,它在不到 1 秒的时间内填充 500 x 500...
  • @Frenchy 大声笑 1 秒对于应该以 60 fps 运行的应用程序来说是巨大的 => 每帧最多 0.017 秒 ;)
  • @Frenchy 我只是说这没有任何意义;)如果您说的时间少于 0.01 秒,那将是一个有意义的指标;)
  • 对不起,你猜我是法国人,我的英语知识很差...我没听懂这个笑话!你有权利小于0.01更好!
【解决方案2】:

我建议更改您的循环以迭代打乱的数字而不是预期的网格大小。如果没有足够的卡片,一些卡片将被排除在网格的“末端”。

然后您可以使用除法和余数来计算给定卡片索引的正确网格 X/Y 坐标。

for (int i = 0; i < numbers.Length; i++) {
    int y = Math.Floor(i / gridCols);  // the floor is likely redundant but drives the point home
    int x = i % gridCols;
    var card = (i == 0 ? originalCard : Instantiate(originalCard) as MainCard);
    int id = numbers[i];
    card.ChangeSprite(id, images[id]);
    float posX = (offsetX * y) + startPos.x;
    float posY = (offsetY * x) + startPos.y;
    card.transform.position = new Vector3(posX, posY, startPos.z);
}

【讨论】:

    【解决方案3】:

    编辑:没关系,正如有人在评论中所说 Random.Range 是整数独有的

    我根本不知道这是否会导致您的问题,但我注意到在您的 Shuffle 方法中您有以下行:

    int randomIndex = Random.Range(i, cards.Count);
    

    在我看来,这可能会导致错误,因为 Random.Range 中的最大值包含在内,因此您可能会为某些卡片生成无效索引。

    例如,如果您有一个包含 5 张卡片的列表,那么您希望生成的最大索引为 4,而不是 5(这将是计数)。

    我会尝试将该行更改为:

    int randomIndex = Random.Range(i, cards.Count-1);
    

    【讨论】:

    • max value in Random.Range is inclusive => 不,不是:Random.Range(int, int)Return a random integer number between min [inclusive] and max [exclusive]
    • 你是对的 derHugo,我注意到它包含整数而排除浮点数。我将编辑我的评论。
    猜你喜欢
    • 2023-03-19
    • 2021-03-01
    • 2021-04-11
    • 1970-01-01
    • 2020-06-12
    • 2019-09-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多