Объединение объектов Unity: исключение IndexOutOfRangeException при одновременном выпуске нескольких объектовC#

Место общения программистов C#
Ответить Пред. темаСлед. тема
Anonymous
 Объединение объектов Unity: исключение IndexOutOfRangeException при одновременном выпуске нескольких объектов

Сообщение Anonymous »

Я сталкиваюсь с исключением IndexOutOfRangeException в своем проекте Unity, когда несколько объектов одновременно освобождаются из пула объектов.
Для контекста: я работаю над проектом Unity, где танки стреляют снарядами, используя систему объединения объектов для управления производительностью. Когда танки находятся близко друг к другу, они быстро стреляют, в результате чего объекты в луже активируются и быстро высвобождаются. Кажется, это быстрое взаимодействие вызывает исключение.
Вот моя реализация пула объектов:

Код: Выделить всё

using System.Collections;
using System.Collections.Generic;
using TMPro;
using Unity.VisualScripting;
using UnityEditor.EditorTools;
using UnityEngine;

public class GameManager : MonoBehaviour
{
private int poolSize;
//drag the object to pool in the game menu to this slot
public GameObject ObjectToPool;
public static GameManager manager;
public GameObject[] pools;
public short poolIndex;
public GameObject activePlayer;
public Camera activeCamera;
void Awake()
{
//if the static instance of the class does not exist, create one
if(manager==null){
manager=this;
}

//tag is hardcoded but i will change that later
poolSize=3*GetPooledObjectUserCount("Tank");
poolIndex=0;
InitializePool();
}

private int GetPooledObjectUserCount(string tag){
return GameObject.FindGameObjectsWithTag(tag).Length;
}

private void InitializePool(){
pools=new GameObject[poolSize];
GameObject tmp;
for(short i=0; i
            tmp=Instantiate(ObjectToPool);
tmp.SetActive(false);
tmp.AddComponent().PoolIndex = i;
pools[i]=tmp;
}
}

public GameObject GetObjectFromPool(){
GameObject gameObject=pools[poolIndex];
poolIndex++;
return gameObject;
}

public void ReleaseObject(GameObject gameObject){
gameObject.SetActive(false);
GameObject latestActive=pools[poolIndex-1];

//getting release and lastest active object index in pool by getting their component
PooledObject releaseComponent=gameObject.GetComponent();
PooledObject activeComponent=latestActive.GetComponent();
int releaseIndex=releaseComponent.PoolIndex;
int activeIndex=activeComponent.PoolIndex;

//swap their index component value before swapping them in the array
releaseComponent.PoolIndex=activeIndex;
activeComponent.PoolIndex=releaseIndex;

//switch their place in the pool
pools[activeIndex]=gameObject;
pools[releaseIndex]=latestActive;
poolIndex--;
}
}
А вот реализация класса PooledObject, который прикрепляется как компонент к каждой объединенной оболочке, потому что я не хотел объявлять переменную в скрипте Shell.cs, чтобы отслеживать ее индекс пула:

Код: Выделить всё

using UnityEngine;

public class PooledObject : MonoBehaviour
{
public int PoolIndex;
}
Наконец, реализация сценария оболочки.cs, прикрепленного к оболочкам:

Код: Выделить всё

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

public class Shell : MonoBehaviour
{
public float speed=40;
public Rigidbody rb;
public GameObject explosion;
public Transform shellTransform;

// Start is called before the first frame update
void Awake()
{
rb=gameObject.GetComponent();
shellTransform=gameObject.GetComponent();
}

// Update is called once per frame

void OnCollisionEnter(Collision collision)
{
GameManager.manager.ReleaseObject(gameObject);
GameObject shockwave=Instantiate(explosion, shellTransform.position, shellTransform.rotation);
Destroy(shockwave, 0.5f);
}
void Update()
{
shellTransform.forward=rb.velocity.normalized;
}
}
Сообщение об ошибке:

Код: Выделить всё

Exception caught: Index was outside the bounds of the array.
StackTrace:   at GameManager.ReleaseObject (UnityEngine.GameObject gameObject) [0x0000a] in /Users/tripham/Desktop/Unity/AI Projects/AI Tank prototype/Assets/Scripts/GameManager.cs:56
UnityEngine.Debug:LogError (object)
GameManager:ReleaseObject (UnityEngine.GameObject) (at Assets/Scripts/GameManager.cs:73)
Shell:OnCollisionEnter (UnityEngine.Collision) (at Assets/Scripts/Shell.cs:23)
UnityEngine.Physics:OnSceneContact (UnityEngine.PhysicsScene,intptr,int) (at /Users/bokken/build/output/unity/unity/Modules/Physics/ScriptBindings/PhysicsContact.bindings.cs:49)
Я заметил, что эта реализация пула не вызывает проблем даже с большим количеством вызывающих объектов (танков на сцене). PoolIndex при возникновении ошибки также всегда равен 0, поэтому я исключил возможность превышения PoolIndex значения PoolSize. Ошибка возникает только тогда, когда танки сгруппированы очень близко друг к другу, следовательно, снаряды активируются и выбрасываются очень быстро из-за попадания снаряда друг в друга и в танки, находящиеся в непосредственной близости.
Я рассмотрел логику и действительно не могу найти крайних случаев. Это заставляет меня подозревать, что это может быть из-за состояния гонки в потоках, из-за которых несколько вызывающих ReleaseObject() одновременно получают доступ к PoolIndex.`

Подробнее здесь: https://stackoverflow.com/questions/792 ... -objects-s
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «C#»