@nika09

Как сделать случайную генерацию объектов по координатам заданным в массиве unity?

Есть определенные места, где ложны быть объекты но мест больше чем объектов и у них есть координаты. подскажите пожалуйста как сделать случайную генерацию предметов в заранее заданных местах в Unity????
например в массив записать координаты мест, и рандомом создать предметы в некоторых из этих мест например в 5 из 10 мест, как это реализовать???
  • Вопрос задан
  • 20715 просмотров
Решения вопроса 2
MrMureno
@MrMureno Куратор тега Unity
VR for all
В общем то проще простого
- как создать объекты я так понимаю вы знаете.
- как создать список координат тоже

Код не точный , а просто показать принцип
- цилк - по количеству объектов , которые хотим сгенерировать.
- выбирает рандомную позицию в списке
- генерируем в этой позиции объект
- удаляем эту позицию из списка (в этом месте больше уже не сгенерируем, и в следующих раз выбирать будет из меньшего числа доступных позиций)
for(i=0;i<NeededNumdersOfObject;i++)
{
     int randomNumber = RandomRange(0,listOfTransforms.Count);
     Instantiate(Object,listOfTransforms[randomNumber ].position,....);
     listOfTransforms.RemoveAt(randomNumber)
}


только проверьте что точек размещения в списке больше, чем число объектов которые хотите сгенерировать.
и еще можно делать копию списка , так как после удаления из него элементов в процессе генерации - повторно его уже не используешь.
Ответ написан
BasmanovDaniil
@BasmanovDaniil
Геймдизайнер-телепат
Простейший способ выбора точки спавна - это дёргать Random.Range до тех пор, пока не получите нужное количество противников.
using System.Collections.Generic;
using UnityEngine;

public class Spawner : MonoBehaviour
{
    public List<Transform> spawnPoints = new List<Transform>();
    public List<GameObject> enemyPrefabs = new List<GameObject>();
    public int amountEnemies = 20;

    private void Start()
    {
        SpawnEnemies();
    }

    public void SpawnEnemies()
    {
        for (int i = 0; i < amountEnemies; i++)
        {
            Transform spawnPoint = GetRandomSpawnPoint();
            GameObject enemy = SpawnEnemy(spawnPoint);
        }
    }

    private Transform GetRandomSpawnPoint()
    {
        return spawnPoints[Random.Range(0, spawnPoints.Count)];
    }

    private GameObject SpawnEnemy(Transform spawnPoint)
    {
        // Сюда можно дописать использование пула для врагов или более сложный алгоритм выбора противника
        var prefab = enemyPrefabs[Random.Range(0, enemyPrefabs.Count)];
        return Instantiate(prefab, spawnPoint.position, spawnPoint.rotation);
    }
}

Важно понимать, что рандом это рандом, а значит враги будут распределены по всем доступным точкам спавна равномерно, а это не всегда то, что требуется для геймплея. Косвенно плотностью спавна можно управлять добавлением нескольких близких точек, но лучше для этого использовать взвешенный рандом.
public T GetRandom<T>(List<T> list, List<float> weights)
{
    if (list == null)
    {
        throw new ArgumentNullException("list");
    }
    if (list.Count == 0)
    {
        throw new ArgumentException("Empty list");
    }
    if (weights == null)
    {
        throw new ArgumentNullException("weights");
    }
    if (weights.Count == 0)
    {
        throw new ArgumentException("Empty weights");
    }
    if (list.Count != weights.Count)
    {
        throw new ArgumentException("List sizes must be equal");
    }

    if (list.Count == 1)
    {
        return list[0];
    }

    var cumulative = new List<float>(weights);
    for (int i = 1; i < cumulative.Count; i++)
    {
        cumulative[i] += cumulative[i - 1];
    }

    float random = Random.Range(0, cumulative[cumulative.Count - 1]);
    int index = cumulative.FindIndex(a => a >= random);
    if (index == -1)
    {
        throw new ArgumentException("Invalid weights");
    }
    return list[index];
}

Даже со взвешенным рандомом легко может случиться так, что все враги заспавнятся в одном месте, поэтому лучше использовать какой-то алгоритм ротации точек спавна. Для этого можно использовать Shuffle Bag, либо можно просто выкидывать использованные точки спавна из списка.
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 1
@MasterYoDaDa
Если объединить все что тут написали то получится вот так. Вроде компактно и работает на ура.
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class Spawner : MonoBehaviour
{
    public List<Transform> spawnPoints = new List<Transform>();
    public List<GameObject> lootPrefabs = new List<GameObject>();
    public int amountEnemies = 5;

    private void Start()
    {
        SpawnEl();
    }

    public void SpawnEl()
    {
        for(int i=0; i < amountEnemies; i ++){
            int randomNumber = Random.Range(0,spawnPoints.Count);
            GameObject loot = SpawnLoot(spawnPoints[randomNumber]);
            spawnPoints.RemoveAt(randomNumber);
            }
    }
    private GameObject SpawnLoot(Transform spawnPoint)
    {
       var prefab = lootPrefabs[Random.Range(0, lootPrefabs.Count)];
        return Instantiate(prefab, spawnPoint.position, spawnPoint.rotation);
    }
}
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы