You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity中如何确保每个GameObject被实例化偶数次?

解决方案

核心思路

要保证每个tilePrefabs中的预制体被实例化偶数次,得先锁定每个预制体的生成次数(必须是偶数),再把这些实例随机分配到地图的可用位置上——原代码靠随机概率判断的逻辑完全没法控制生成次数,这是问题根源。

具体实现步骤

  1. 先收集所有可放置的坐标位置,避免重复遍历浪费性能;
  2. 给每个预制体设定偶数的生成次数(可以固定值,也可以随机生成偶数);
  3. 批量生成所有需要的实例,打乱实例和位置的顺序后再分配,既保证随机性又严格控制次数。

修改后的完整代码

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

public class LevelGenerator : MonoBehaviour
{
    public int width = 10;
    public int height = 10;
    public GameObject[] tilePrefabs;
    // 每个预制体最少生成的偶数次数,可按需调整
    public int minEvenCountPerPrefab = 2;
    // 每个预制体最多生成的偶数次数,可按需调整
    public int maxEvenCountPerPrefab = 8;

    void Start()
    {
        GenerateLevel();
    }

    void GenerateLevel()
    {
        // 第一步:收集所有可用放置位置
        List<Vector2> availablePositions = new List<Vector2>();
        for (int x = -10; x < width; x++)
        {
            for (int y = -4; y < height; y++)
            {
                availablePositions.Add(new Vector2(x, y));
            }
        }

        // 第二步:给每个预制体分配偶数生成次数
        Dictionary<GameObject, int> prefabCountMap = new Dictionary<GameObject, int>();
        int totalRequiredInstances = 0;
        foreach (var prefab in tilePrefabs)
        {
            // 生成min到max之间的随机偶数
            int randomEven = Random.Range(minEvenCountPerPrefab / 2, maxEvenCountPerPrefab / 2 + 1) * 2;
            prefabCountMap[prefab] = randomEven;
            totalRequiredInstances += randomEven;
        }

        // 检查位置是否足够,不够就自动调整(取位置总数的偶数部分分配)
        if (totalRequiredInstances > availablePositions.Count)
        {
            totalRequiredInstances = availablePositions.Count - (availablePositions.Count % 2);
            int perPrefab = totalRequiredInstances / tilePrefabs.Length;
            // 确保每个预制体的次数是偶数
            perPrefab = perPrefab - (perPrefab % 2);
            foreach (var prefab in tilePrefabs)
            {
                prefabCountMap[prefab] = perPrefab;
            }
            // 处理总数剩余的情况(比如预制体数量是奇数),给前几个预制体各加2次(保持偶数)
            int remaining = totalRequiredInstances - perPrefab * tilePrefabs.Length;
            for (int i = 0; i < remaining / 2; i++)
            {
                prefabCountMap[tilePrefabs[i]] += 2;
            }
        }

        // 第三步:批量生成实例并打乱顺序
        List<GameObject> instancesToPlace = new List<GameObject>();
        foreach (var kvp in prefabCountMap)
        {
            for (int i = 0; i < kvp.Value; i++)
            {
                GameObject instance = Instantiate(kvp.Key, Vector3.zero, Quaternion.identity);
                instancesToPlace.Add(instance);
            }
        }

        // 洗牌算法打乱实例和位置的顺序,保证随机放置
        ShuffleList(instancesToPlace);
        ShuffleList(availablePositions);

        // 第四步:把实例分配到随机位置
        for (int i = 0; i < instancesToPlace.Count; i++)
        {
            instancesToPlace[i].transform.position = availablePositions[i];
        }
    }

    // 通用洗牌方法,用于打乱列表
    void ShuffleList<T>(List<T> list)
    {
        int n = list.Count;
        while (n > 1)
        {
            n--;
            int k = Random.Range(0, n + 1);
            T temp = list[k];
            list[k] = list[n];
            list[n] = temp;
        }
    }

    void FixedUpdate()
    {
        if ((GameControl.control.matches >= 69) && (GameControl.control.matches < 207))
        {
            SceneManager.LoadScene("Level2");
        }
    }
}

代码关键点说明

  • 位置收集:一次性把所有坐标存入列表,避免原代码三层循环的无效遍历;
  • 偶数次数控制:通过*2的方式确保生成次数是偶数,同时做了位置不足的容错处理;
  • 随机分配:用洗牌算法打乱实例和位置,既保留随机性,又不会出现次数失控的情况。

简化版方案(固定偶数次数)

如果不需要随机次数,只想让每个预制体固定生成偶数次(比如每个生成2次),可以用更简单的逻辑:

void GenerateLevel()
{
    List<Vector2> availablePositions = new List<Vector2>();
    for (int x = -10; x < width; x++)
    {
        for (int y = -4; y < height; y++)
        {
            availablePositions.Add(new Vector2(x, y));
        }
    }

    // 每个预制体固定生成2次(偶数)
    int fixedEvenCount = 2;
    int totalInstances = tilePrefabs.Length * fixedEvenCount;
    if (totalInstances > availablePositions.Count)
    {
        Debug.LogError("可用位置不足,无法生成指定数量的实例");
        return;
    }

    ShuffleList(availablePositions);
    int posIndex = 0;
    foreach (var prefab in tilePrefabs)
    {
        for (int i = 0; i < fixedEvenCount; i++)
        {
            Instantiate(prefab, availablePositions[posIndex], Quaternion.identity);
            posIndex++;
        }
    }
}

内容的提问来源于stack exchange,提问作者BevvyOfFun

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 15:15:04