forum.boolean.name

forum.boolean.name (http://forum.boolean.name/index.php)
-   Общие вопросы (http://forum.boolean.name/forumdisplay.php?f=166)
-   -   Очередные вопросы от меня по игровой логике и скриптингу (http://forum.boolean.name/showthread.php?t=20854)

Crystal 15.10.2020 00:08

Ответ: Очередные вопросы от меня по игровой логике и скриптингу
 
Короче с небольшими переделками сцена боя переехала на 15 метров
под открытый мир. Запихал сцену боя в ассет, некоторые правки в половину скриптов внёс.
Теперь будет так как есть, это решение лучше постоянного сохранения с загрузкой.


Crystal 17.10.2020 05:13

Ответ: Очередные вопросы от меня по игровой логике и скриптингу
 
Цитата:

Сообщение от ABTOMAT (Сообщение 317753)
Ты имеешь в виду, каждый объект в Update проверяет каждый кадр, не пора ли ему удолиться? Это не самый производительный вариант, потому что проверка будет идти каждый кадр. Это не очень хорошо.

Вообще такое можно сделать 2 способами:

Через эвенты.

1. Создаёшь UnityEvent battleOver и вызываешь его battleOver.Invoke() в момент, когда битва завершена.
2. Каждому объекту, который имеет отношение к, в OnEnable делаешь подписку (лайк, колокольчик) на этот эвент:

PHP код:

battleOver.AddEventListener(() => {Debug.Log("Я отреагировал на завершение битвы!");}); 

Ну и соответственно в листенере можешь делать то действие, какое надо при завершении битвы (например, удалять этот объект).

Вариант с эвентами хорош тем, что можно создать эвенты на все ключевые события, а потом объекты "подписывать" на них по мере надобности.


Второй способ через списки:

Иметь список всех однотипных объектов и при надобности перебирать их все.
public static List<Monster> allMonsters = new List<Monster>(); // Глобальный список

PHP код:

Monster.allMonsters.Add(this); // Каждого монстра при создании (OnEnable) заносим в список 

PHP код:

Monster.allMonsters.Remove(this); // Каждого монстра при удалении (OnDisable) убираем из списка 

Соответственно при создании и удалении у тебя автоматом будут заноситься или убираться монстры в список.
Если тебе надо удалить всех монстров (или что-то с ними сделать) то перебираешь список:

PHP код:

Monster.allMonsters.ForEach(monster => {Debug.Log($"А мы тут монстров перебираем: {monster}!");}); 


Способ со списками более простой, но я бы советовал раздуплить как работают эвенты, полезная штука.

Я вымучился уже с этим уродским списком. Эти списки говно ужасное.

В общем создал список:

Код:

    public static List<GameObject> Units = new List<GameObject>(); // Список монстров + игрок.
Запихиваю в него монстров:

Код:

FightScene.Units.Add(Monster); // Монстра заносим в список.
Если я из скрипта самого монстра хочу удалить его из листа и дестройнуть,
то пожалуйста, легко:

Код:

FightScene.Units.Remove(Monster);
Destroy(Monster);

но вот если я из другого следящего скрипта хочу
почистить всё из листа, без прямых ссылок на префаб монстра,
просто перебором, то я смогу только дестройнуть монстров,
оставив пустые строки в листе:

Код:

private int Listalo;
FightScene.Units.ForEach(Listalo => { if (Listalo == true) { Destroy(Listalo); }});

(да можно без if, не суть)

Так вот, конструкция выше прекрасно выпиливает все объекты в листе,
но оставляет вместо них пустышки, которые никуда из списка не исчезают.

Казалось бы, сделаем вот так и ок:

Код:

FightScene.Units.ForEach(Listalo => { if (Listalo == true) { Destroy(Listalo); FightScene.Units.Remove(Listalo); }});
И хрен, всё крашится в ошибку (Коллекция была изменена; операция перечисления может не выполняться.):
Цитата:

InvalidOperationException: Collection was modified; enumeration operation may not execute.
System.ThrowHelper.ThrowInvalidOperationException (System.ExceptionResource resource) (at <437ba245d8404784b9fbab9b439ac908>:0)
System.Collections.Generic.List`1[T].ForEach (System.Action`1[T] action) (at <437ba245d8404784b9fbab9b439ac908>:0)
GAMECONTROL.Update ()
Я бился с этим говном 10 часов, и не победил никакими способами.

pax 17.10.2020 08:59

Ответ: Очередные вопросы от меня по игровой логике и скриптингу
 
Сделай так:
PHP код:

FightScene.Units.ForEach(Listalo => { if (Listalo)  Destroy(Listalo); });
// удалить все уничтоженные объекты списка
FightScene.Units.RemoveAll(Listalo => Listalo == null); 

Так же если тебе нужно удалить все элементы, то вызови FightScene.Units.Clear(); после уничтожения объектов. Т.е.
PHP код:

FightScene.Units.ForEach(Listalo => { if (ListaloDestroy(Listalo);});
// очистить список
FightScene.Units.Clear(); 

Я иногда перебираю список в обратном порядке, чтобы уничтожить только нужные объекты:
PHP код:

for(int i FightScene.Units.Count-1i>=0i--)
{
    if(
FightScene.Units[i].IsDead// проверка юнита на смерть
    
{
          
Destroy(FightScene.Units[i]);
          
FightScene.Units.RemoveAt(i);
    }


Т.к. в этом случае не используется foreach, который создает энумератор при переборе элементов списка, то не происходит исключения при изменении коллекции.

Crystal 17.10.2020 15:29

Ответ: Очередные вопросы от меня по игровой логике и скриптингу
 
Код:

FightScene.Units.RemoveAll(Listalo => Listalo == null);
Это не работает, ночью я пробовал такой вариант.
Сейчас тоже попробовал, и тоже не работает.

Код:

FightScene.Units.Clear();
Это работает. Спасибо, спас.

Код:

for(int i = FightScene.Units.Count-1; i>=0; i--)
{
    if(FightScene.Units[i].IsDead) // проверка юнита на смерть
    {
          Destroy(FightScene.Units[i]);
          FightScene.Units.RemoveAt(i);
    }
}

Здесь "IsDead" это что и откуда? Я тут не понял где это должно быть вбито у объекта.

pax 17.10.2020 23:40

Ответ: Очередные вопросы от меня по игровой логике и скриптингу
 
Цитата:

Сообщение от Crystal (Сообщение 317774)
Это не работает, ночью я пробовал такой вариант.
Сейчас тоже попробовал, и тоже не работает.

А можешь показать пример как ты это используешь? По идее должно работать...

Цитата:

Сообщение от Crystal (Сообщение 317774)
Здесь "IsDead" это что и откуда? Я тут не понял где это должно быть вбито у объекта.

Не обратил внимания, что твой список это GameObject. Вот пример при котором я предполагаю, что у тебя на каждом юните висит одноименный класс Unit:
PHP код:

for(int i FightScene.Units.Count-1i>=0i--)
{
    if(
FightScene.Units[i] == null || FightScene.Units[i].GetComponent<Unit>().IsDead)
    {
          
Destroy(FightScene.Units[i]);
          
FightScene.Units.RemoveAt(i);
    }


А вот пример класса Unit (свойство IsDead в виде лямбда функции):
PHP код:

using UnityEngine;

public class 
UnitMonoBehaviour
{
        public 
int health 100;

        public 
bool IsDead => health <= 0;



Пример класса Unit (свойство IsDead в виде обычного свойства только для чтения)
PHP код:

using UnityEngine;

public class 
UnitMonoBehaviour
{
        public 
int health 100;

        public 
bool IsDead
        
{
               
get
               
{
                      return 
health <= 0;
               }
        }




Crystal 18.10.2020 11:15

Ответ: Очередные вопросы от меня по игровой логике и скриптингу
 
Цитата:

Сообщение от pax (Сообщение 317777)
А можешь показать пример как ты это используешь? По идее должно работать...



Не обратил внимания, что твой список это GameObject. Вот пример при котором я предполагаю, что у тебя на каждом юните висит одноименный класс Unit:
PHP код:

for(int i FightScene.Units.Count-1i>=0i--)
{
    if(
FightScene.Units[i] == null || FightScene.Units[i].GetComponent<Unit>().IsDead)
    {
          
Destroy(FightScene.Units[i]);
          
FightScene.Units.RemoveAt(i);
    }


А вот пример класса Unit (свойство IsDead в виде лямбда функции):
PHP код:

using UnityEngine;

public class 
UnitMonoBehaviour
{
        public 
int health 100;

        public 
bool IsDead => health <= 0;



Пример класса Unit (свойство IsDead в виде обычного свойства только для чтения)
PHP код:

using UnityEngine;

public class 
UnitMonoBehaviour
{
        public 
int health 100;

        public 
bool IsDead
        
{
               
get
               
{
                      return 
health <= 0;
               }
        }




Пример показать не могу, к сожалению я бэкапнулся на 14 октября,
на момент до соединения двух сцен в одну. Да и собственно тыб там не разобрался,
скрипты содержащие нужные участки огромные. В принципе пост 17 это и есть вырезки из существовавшего кода.
17


Нет у меня на каждом юните класса юнит,
висит отдельный скрипт в монобехавере с переменными,
хранщими в себе нужные цифры. Переменная смерти там есть.


Код:

public class MonsterInfo : MonoBehaviour
{
    public int MonsterNumber; //Порядковый номер монстра
    public int ThreatLevel; //Уровень угрозы монстра
    public int MonsterControl = 0; //Статус выделения монстра, по умолчанию "0" не выделен.
    public float MAXHP;
    public float HP;
    public int MonsterDeath = 0; // Смерть монстра, 1 - это труп.
    public float SilaMin;
    public float SilaMax;
    public float Udacha;
    public float LEVEL; // Уровень монстра.
    public float EXPAMAX; // Максимальная экспа до левелапа.
    public float EXPA; // Текущая экспа.
    public float VALUATION; // Ценность в экспе за убийство этого монстра
    public int Storona; // Чей монстр: 1. Дикий, 2. Вражеский, 3. Наш, 4. Союзнический.
    public int NomerHoda; // Номер под которым ходит наш монстр.

    public float GKU = 0f; // Готовность монстра к удару

    public int MonsterSkill1;
    public int MonsterSkill1Range;
    public int MonsterSkill1Position;
    public int MonsterSkill2;
    public int MonsterSkill2Range;
    public int MonsterSkill2Position;
    public int MonsterSkill3;
    public int MonsterSkill3Range;
    public int MonsterSkill3Position;
    public int MonsterSkill4;
    public int MonsterSkill4Range;
    public int MonsterSkill4Position;
    public int MonsterSkill5;
    public int MonsterSkill5Range;
    public int MonsterSkill5Position;
    public int MonsterSkill6;
    public int MonsterSkill6Range;
    public int MonsterSkill6Position;
}



З.ы. Меня устроил твой вариант с полной очисткой листа, так и будет когда снова дойду до этого дела.

pax 18.10.2020 11:41

Ответ: Очередные вопросы от меня по игровой логике и скриптингу
 
Тогда просто меняй в моем пример Unit на MonsterInfo. Вот тебе еще пример)

PHP код:

for(int i FightScene.Units.Count-1i>=0i--)
{
    
// если в списке уже уничтоженный объект
    
if(FightScene.Units[i] == null)
    {
          
// просто его удаляем из списка
          
FightScene.Units.RemoveAt(i);
    }
    else
    {
           
// объект в списке не уничтожен
           // берем с объекта компонент MonsterInfo
           
var monsterInfo FightScene.Units[i].GetComponent<MonsterInfo>(); 

           
// если компонента нет, то это не монстр, если это монстр, то смотрим его жизни, 
           // если сдох, уничтожаем и выкидываем из списка
           
if(monsterInfo != null && monsterInfo.HP <= 0)
           {
                 
Destroy(FightScene.Units[i]);
                 
FightScene.Units.RemoveAt(i);
           }
    }



Crystal 18.10.2020 13:51

Ответ: Очередные вопросы от меня по игровой логике и скриптингу
 
Спасибо, на следующей неделе попробую применить.
В данный момент не могу, у меня вчера ОРВИ дало осложнение на глаза
(покраснение, ощущение инородного тела, сморщивание коньюктивы при повороте глаза).
Вчера пришлось отказаться от программирования, закапать глаза, и лечь в постель...
Сегодня наверное тоже не смогу напрягать глаза.


Часовой пояс GMT +4, время: 02:36.

vBulletin® Version 3.6.5.
Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
Перевод: zCarot