Оптимизация длинного червя (змейки) при скручивании

Форум для самых маленьких, а так же тех, кому недосуг читать справку самостоятельно.

Оптимизация длинного червя (змейки) при скручивании

Сообщение Pokemoon 08 авг 2020, 16:16

Всем привет, делаю прототип на Unity про червей. Части червя двигаю и поворачиваю таким кодом:

Синтаксис:
Используется csharp
        dir = trans.position - target.position;
        dir = dir.normalized;
        trans.eulerAngles = new Vector3(0, 0, AngleBetweenVector(trans.position, target.position));

        trans.position = Vector3.SmoothDamp(trans.position, target.position, ref partList[num].vel, smoothSpeed);
 


Получается хорошее движение, но с большим недостатком, если часто поворачивать или крутиться долго - то образуются места скопления множества спрайтов в гармошку и накладываются друг на друга, что плохо сказывается на фпс на мобильных устройствах, особенно если червь большой и длинный. Вот так это выглядит:



Поэтому мне нужно узнать, как бы это оптимизировать, например, как это сделано в игре Worms Zone, там, когда происходит скрутка червя либо поворот - то он укорачивается, части как бы всасываются друг в друга, причем таким образом, что примерно сохраняется общее расстояние между частицами, а потом когда едешь ровно то хвост "раскручивается" обратно:



Когда я пробовал делать что-то подобное, то получилось не очень, не хватает ума понять, как это сделать правильно, поэтому может кто-то поможет мне с этим, или подскажет как это лучше сделать? Спасибо.
Pokemoon
UNец
 
Сообщения: 6
Зарегистрирован: 08 авг 2020, 16:11

Re: Оптимизация длинного червя (змейки) при скручивании

Сообщение samana 08 авг 2020, 19:57

Честно говоря, ваша реализация выглядит намного лучше, чем видео из игры. У вас даже "глубина" появилась. Так может это не баг а фича?

Для сохранения чёткой дистанции между частями змейки, нужно перемещать каждую часть конкретно на заданную величину.
Моя реализация чем-то похожа, на видео из игры к которой вы стремились, но повторяюсь, ваша змейка выглядит намного интереснее.

Это единственный скрипт, в который нужно добавить спрайт головы змейки со сцены и префаб для части хвоста. Управление будет стрелочками.
Синтаксис:
Используется csharp
using System.Collections.Generic;
using UnityEngine;

public class WormMovement : MonoBehaviour
{
    public Transform headFromScene;     // голова змейки со сцены (спрайт)
    public GameObject wormPartPrefab;   // префаб части змейки (спрайт)

    [Space]
    [Header("Worm props")]

    public float wormMoveSpeed = 0.2f;  // скорость перемещения змейки
    public float wormRotateSpeed = 8f;  // скорость поворота змейки
    public int wormTailLenth = 100;     // изначальное кол-во частей хвоста при старте игры
    public float distanceBetweenParts = 0.2f;   // растояние между частями змейки

    private List<Transform> _wormPartsList; // приватный массив всех частей змейки вместе с головой

    void Start()
    {
        // инициализировали массив частей змейки и засунули туда голову
        _wormPartsList = new List<Transform>();
        _wormPartsList.Add(headFromScene);

        // создали хвост заданой длины
        createWormTail(wormTailLenth);
    }

    void Update()
    {
        // поворот головы змейки стрелочками
        if (Input.GetKey(KeyCode.RightArrow)) headFromScene.Rotate(Vector3.forward * -wormRotateSpeed);
        else if (Input.GetKey(KeyCode.LeftArrow)) headFromScene.Rotate(Vector3.forward * wormRotateSpeed);

        // перемещение головый змейки в направлении её "взгляда" (ось right например).
        headFromScene.Translate(Vector2.right * wormMoveSpeed);
       
        // обновляем позиции всех частей хвоста
        updateTail();
    }

    // создаёт остальной хвост змейки (голова уже есть поэтому цикл начинаем с 1).
    private void createWormTail(int wormTailLenth)
    {
        for (int i = 1; i <= wormTailLenth; i++)
        {
            Transform part = Instantiate(wormPartPrefab).transform;
            part.position = Vector2.left * distanceBetweenParts * i;

            SpriteRenderer spriteRenderer = part.GetComponent<SpriteRenderer>();
            spriteRenderer.color = i % 2 == 0 ? Color.yellow : Color.green;
            spriteRenderer.sortingOrder = -i;

            _wormPartsList.Add(part);
        }
    }

    // перемещаем каждую часть на заданное расстояние к предыдущей части, начиная с первой части от головы
    private void updateTail()
    {
        for (int i = 1; i < _wormPartsList.Count; i++)
        {
            Vector2 prevPartPos = _wormPartsList[i - 1].position;
            Vector2 currentPartPos = _wormPartsList[i].position;

            Vector2 directionToPrevPart = prevPartPos - currentPartPos;

            Vector2 newPosForCurrentPart = prevPartPos - (directionToPrevPart.normalized * distanceBetweenParts);
            _wormPartsList[i].position = newPosForCurrentPart;

        }
    }
}
 
Аватара пользователя
samana
Адепт
 
Сообщения: 4738
Зарегистрирован: 21 фев 2015, 13:00
Откуда: Днепропетровск

Re: Оптимизация длинного червя (змейки) при скручивании

Сообщение Pokemoon 08 авг 2020, 20:27

samana писал(а):Честно говоря, ваша реализация выглядит намного лучше, чем видео из игры. У вас даже "глубина" появилась. Так может это не баг а фича?


Спасибо, проверю вашу реализацию чуть позже. Самая главная проблема в том, что в моей реализации если будет длинный хвост - то будет очень много спрайтов на экране, и соотвественно начинает проседать фпс, так что парочка немного закрученных жирных ботов (порядка 100-150 длина хвоста) напрочь убивают фпс (речь о мобильных устройствах конечно же).. Поэтому мне нужен такой метод, при котором бы всегда сохранялось оптимальное количество спрайтов на экране, независимо от длины хвоста, и вот в woms zone как раз реализовано это путем поглощения спрайтов при поворотах или скрутке, и потом они обратно разворачиваются, когда едешь ровно.
Pokemoon
UNец
 
Сообщения: 6
Зарегистрирован: 08 авг 2020, 16:11

Re: Оптимизация длинного червя (змейки) при скручивании

Сообщение 1max1 08 авг 2020, 20:31

Vector3.SmoothDamp

Вот это прожорливое чудовище, лучше лерп юзай)
п.с. спрайты можно скрывать, но даже 1000+ спрайтов не должны создавать нагрузку, я имею ввиду отрисовку, возможно стоит глянуть в профайлер что там.
Аватара пользователя
1max1
Адепт
 
Сообщения: 5505
Зарегистрирован: 28 июн 2017, 10:51

Re: Оптимизация длинного червя (змейки) при скручивании

Сообщение samana 08 авг 2020, 20:49

Pokemoon писал(а):Поэтому мне нужен такой метод, при котором бы всегда сохранялось оптимальное количество спрайтов на экране, независимо от длины хвоста, и вот в woms zone как раз реализовано это путем поглощения спрайтов при поворотах или скрутке, и потом они обратно разворачиваются, когда едешь ровно.

Та ладно? Вы точно в этом уверены? Может просто спрайты находятся друг за другом и создаётся впечатление, что их меньше?
Просто какой смысл делать такую сложную логику - скрывать спрайты, которые чисто визуально находятся чётко друг за другом? А если змейка ползает по всему экрану и все её части в любом случае должны быть видны, то что делать, что скрывать?
Я не думаю, что в той игре какие-то части змейки скрываются.
Аватара пользователя
samana
Адепт
 
Сообщения: 4738
Зарегистрирован: 21 фев 2015, 13:00
Откуда: Днепропетровск

Re: Оптимизация длинного червя (змейки) при скручивании

Сообщение Pokemoon 08 авг 2020, 20:53

1max1 писал(а):
Vector3.SmoothDamp

Вот это прожорливое чудовище, лучше лерп юзай)
п.с. спрайты можно скрывать, но даже 1000+ спрайтов не должны создавать нагрузку, я имею ввиду отрисовку, возможно стоит глянуть в профайлер что там.

спасибо за совет. По поводу спрайтов, тут многое зависит от размера спрайта, чем больше спрайт занимает экранного пространства - тем он прожорливее. А большие черви у меня там и спрайт имеет соответсвующий, и соответственно когда их много одновременно - беда. При том при тестах я заметил не имеет разницы особой будет ли сама текстура большая либо маленькую увеличить scale, или просто каемру приблизить, чем больше спрайт получается на экране - тем жрет больше.
Pokemoon
UNец
 
Сообщения: 6
Зарегистрирован: 08 авг 2020, 16:11

Re: Оптимизация длинного червя (змейки) при скручивании

Сообщение Pokemoon 08 авг 2020, 20:55

samana писал(а):
Pokemoon писал(а):Поэтому мне нужен такой метод, при котором бы всегда сохранялось оптимальное количество спрайтов на экране, независимо от длины хвоста, и вот в woms zone как раз реализовано это путем поглощения спрайтов при поворотах или скрутке, и потом они обратно разворачиваются, когда едешь ровно.

Та ладно? Вы точно в этом уверены? Может просто спрайты находятся друг за другом и создаётся впечатление, что их меньше?
Просто какой смысл делать такую сложную логику - скрывать спрайты, которые чисто визуально находятся чётко друг за другом? А если змейка ползает по всему экрану и все её части в любом случае должны быть видны, то что делать, что скрывать?
Я не думаю, что в той игре какие-то части змейки скрываются.

А что, если спрайт четко друг за другом - они не создают такой нагрузки как если были немного различной позиции друг от друга? В любом случае в моем движении спрайты не накладываются четко друг на друга, а образуют эдакую гармошку, миллион спрайтов в миллиметре друг от друга.
Pokemoon
UNец
 
Сообщения: 6
Зарегистрирован: 08 авг 2020, 16:11

Re: Оптимизация длинного червя (змейки) при скручивании

Сообщение Jarico 08 авг 2020, 21:36

Я думаю что просадки у тебя из-за того что GPU instancing не включен на материале + для 300% оптимизации можно заюзать TransformAccessArray + Jobs (многопоточный вариант изменения позиции трансформа)
Github: _https://github.com/redheadgektor
Discord: Конь! Чаю!#9382 (сижу редко)
YouTube: _https://www.youtube.com/channel/UCPQ04Xpbbw2uGc1gsZtO3HQ
Telegram: _https://t.me/redheadgektor
Аватара пользователя
Jarico
Адепт
 
Сообщения: 1084
Зарегистрирован: 06 янв 2019, 17:37
Откуда: 0xDEAD
Skype: none
  • Сайт

Re: Оптимизация длинного червя (змейки) при скручивании

Сообщение Pokemoon 08 авг 2020, 21:54

Jarico писал(а):Я думаю что просадки у тебя из-за того что GPU instancing не включен на материале + для 300% оптимизации можно заюзать TransformAccessArray + Jobs (многопоточный вариант изменения позиции трансформа)

А где этот GPU Instancing включается? Я использую простые спрайты дефолтные юнитовские. Насчет TransformAccessArray + Jobs - слишком страшные слова для меня, наверное не осилю такое.. и на что они влияют? Сам код перемещения червей я думаю у меня не особо много жрет, ведь он действует постоянно и фпс при этом хороший, но как только в экран влазят много скрученных червей (то есть много спрайтов в экране оказывается) - то все просадка идет.

Да и еще вся графика у меня одним атласом и на все про все 3 draw calls.
Pokemoon
UNец
 
Сообщения: 6
Зарегистрирован: 08 авг 2020, 16:11

Re: Оптимизация длинного червя (змейки) при скручивании

Сообщение Jarico 08 авг 2020, 22:27

Просадка как раз из-за этого и может быть..
GPU Instancing включается на материале и он будет использоваться 1 раз на всех мешах в сцене (аналог атласа)
Поэтому попробуй внедрить TransformAccessArray и сравнить результаты
Github: _https://github.com/redheadgektor
Discord: Конь! Чаю!#9382 (сижу редко)
YouTube: _https://www.youtube.com/channel/UCPQ04Xpbbw2uGc1gsZtO3HQ
Telegram: _https://t.me/redheadgektor
Аватара пользователя
Jarico
Адепт
 
Сообщения: 1084
Зарегистрирован: 06 янв 2019, 17:37
Откуда: 0xDEAD
Skype: none
  • Сайт

Re: Оптимизация длинного червя (змейки) при скручивании

Сообщение Pokemoon 08 авг 2020, 22:40

Jarico писал(а):Просадка как раз из-за этого и может быть..
GPU Instancing включается на материале и он будет использоваться 1 раз на всех мешах в сцене (аналог атласа)
Поэтому попробуй внедрить TransformAccessArray и сравнить результаты

Как я уже сказал я испоьлзую стандартный unity sprite, там материал Deafult-Sprite, и немного погуглив я нашел что на всех стандартных материалах юнити и так включен GPU Instancing. А про TransformAccessArray - я про jobs, ecs вообще ничего не знаю, так что врядли получится что-то так взять и внедрить, это еще изучить надо.
Pokemoon
UNец
 
Сообщения: 6
Зарегистрирован: 08 авг 2020, 16:11


Вернуться в Почемучка

Кто сейчас на конференции

Сейчас этот форум просматривают: Yandex [Bot] и гости: 32