Задать вопрос
  • Ревью проекта, кто сможет глянуть?

    K0TlK
    @K0TlK
    KraGen, Интерфейсы - это контракт. Все, кто реализует интерфейс, обязуются соблюдать этот контракт. Когда ты выделяешь интерфейс, то у тебя все взаимодействие происходит через этот интерфейс. Ты не зависишь от какой-то конкретной реализации этого интерфейса. Пример. Есть интерфейс IWindow
    public interface IWindow
    {
        void Open();
        void Close();
    }


    И есть несколько его реализаций:
    public class InventoryWindow : IWindow{}
    public class HealthWindow : IWindow{}
    public class HouseWindow : IWindow{}

    Первый - ui окно инвентаря, второй - окно отображения хп, третий окно в каком-то доме на сцене.

    И есть какой-то объект, который может эти окна открывать:
    public class SomeObject
    {
        public void OpenWindow(IWindow window)
        {
            window.Open();
        }
    }


    И этому объекту абсолютно не важно какое окно ему подсунут. Будь то ui или окно на сцене. Он не зависит от реализации окна, он зависит от абстракции окна.

    зачем интерфейсы нужны если их прийдёться постоянно писать

    Куда проще что-либо переделать/расширить, когда у тебя зависимости не от конкретной реализации, а от какой-то абстракции. Может показаться, что, если есть только одна реализация у интерфейса, то можно этот интерфейс и не писать вовсе, но, когда потребуется что-то изменить/расширить, то это сделать будет сложнее, если этого интерфейса у тебя не будет.

    А на счёт архитектуры то игра впринципе не сложная и я толком пока не понимаю какая может быть архитектура

    Всю игру можно сделать, поместив на пустую сцену всего один монобех, который будет являться точкой входа. И там будут инициализироваться все компоненты и передаваться все зависимости
  • Ревью проекта, кто сможет глянуть?

    K0TlK
    @K0TlK
    KraGen, Ну и нет никакой архитектуры вообще. Все работает на монобехах.
  • Ревью проекта, кто сможет глянуть?

    K0TlK
    @K0TlK
    KraGen,
    [SerializeField] private float movementSpeed;
        [SerializeField] private float jumpForce;
    
        [SerializeField] private GameObject playerModel;
    
        public bool play = false;
        
        private PlayerInput _playerInput;
        private Transform player;

    Нет определенного код стайла. Где-то есть нижнее подчеркивание у private полей, где-то нет. Паблик поле с маленькой буквы. Существуют общепринятые нормы, следуй им, если нет каких-то других.
    https://docs.microsoft.com/en-us/dotnet/csharp/fun...
    https://github.com/dotnet/runtime/blob/main/docs/c...

    [SerializeField] private GameObject startScreen;
        [SerializeField] private GameObject loseScreen;
        
        public delegate void UIEvents();
        public static event UIEvents TapOnScreen;


    Взаимодействие с геймобжектами, а не с конкретными компонентами. Статика. Ненужный делегат, для всего того, что ты делаешь, существует Action.

    public class CubeController
    public static event CubeEvent ModifiedCubesCount
    public static event CubeEvent CollectCube

    Невнятный нейминг. С первого взгляда не понятно что эти ивенты из себя представляют. Что такое ModifiedCubesCount? Количество кубов? Почему тогда это ивент, а не свойство? Что такое CollectCube? Метод? Если нет, то почему как метод назван? Что он делает? Куб собирает? CubesCountChanged и CubeCollected их следовало назвать. Что такое контроллер? Что он контролирует? Название объекта должно показывать не то что он делает, а то кем он является. CubesStack или что-то типа этого.

    if (other.gameObject.CompareTag("Cube") && !other.gameObject.GetComponent().collected && collected)

    Тэги. Могу поспорить, что одной из главных причин отказа были тэги. Не надо их использовать. Вместо этого огромного условия можно было сделать одно - TryGetComponent(out Cube cube>. Всё.

    var higherCube = holder.transform.GetChild(0)
    holder.transform.childCount
    holder.transform.GetChild(i).localPosition.y

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

    _builder = FindObjectOfType()
    Зачем использовать Find..., когда можно просто прокинуть зависимость через инспектор?

    gameObject.transform.position = new Vector3(Mathf.Clamp(position.x + (_playerInput.axisHorizontal / 4) * Time.deltaTime,-2,2), position.y, position.z + movementSpeed * Time.deltaTime);

    Ты сам то понимаешь что здесь происходит? Нечитабельно. Что за магические числа? Откуда 4, откуда -2, 2?

    axisHorizontal = Mathf.Clamp(Input.mousePosition.x - startPos,-50,50);
    Почему именно -50 и 50? Почему не от 0 до 1?

    Весь инпут в одном файле. Не выделен интерфейс под инпут, чтобы его потом можно было подменить другим. В будущем этот класс разрастется до 2000 строк. По 1000 на каждый #if
  • Как я могу создать несколько рэйкастов для одного объекта?

    K0TlK
    @K0TlK
    Student_PNIPU, Если не надо выяснить, попадает ли объект в угол обзора, а нужно просто лучи нарисовать, то можешь определить минимальный и максимальный углы и между ними просто пускать нужное количество лучей через промежуток.
  • Как я могу создать несколько рэйкастов для одного объекта?

    K0TlK
    @K0TlK
    Если тебе угол обзора нужен, находи через скалярное произведение векторов попадает ли объект в fov, затем пускай к нему один луч, чтобы проверить есть ли препятствия между капсулой и объектом. Это гораздо лучше, чем делать миллион лучей и пускать их все в апдейте.
  • Как сделать прыжок в unity3d с помощью Rigidbody?

    K0TlK
    @K0TlK
    vkvk, Тебе ничего не надо подбирать. Во-первых, инпут выноси в апдейт, физику в FixedUpdate. Во-вторых, тебе здесь AddForce не нужен, либо прибавляй к rb.velocity.y нужную тебе скорость, либо просто устанавливай rb.velocity.y на нужное значение, зависит от того какой прыжок тебе нужен. В-третьих,
    rb.velocity = ((transform.right * horizontal) + (transform.forward * vertical)) * speed;

    здесь у тебя обнуляется скорость по y, поэтому он у тебя падает медленно
    var velocity = rb.velocity;
    velocity......изменяешь скорость по осям, которые тебе нужны
    rb.velocity = velocity; присваиваешь скорость

    В-четвертых, выдели метод Jump, где ты точно так же, как и в примере выше устанавливаешь нужную тебе скорость по оси y и вызывай его, когда нажимается прыжок.
    Чуть ли ни каждый день один и тот же вопрос задают, ответ на который лежит на первой странице гугла.
  • Как сделать управление 3д персонажем с помощью Rigidbody в unity?

    K0TlK
    @K0TlK
    vkvk, Ну да, когда тебе нужна постоянная скорость, ты делаешь rigidbody.velocity = velocity, если нужно разгоняться на определенную скорость, то rigidbody.velocity += velocity. Ты скорее всего делаешь второе, ожидая увидеть первое. Если через AddForce делаешь, то прочитай название метода - Add = добавить, ты применяешь силу и никак не ограничиваешь скорость, поэтому он у тебя бесконечно разгоняется. В твоем случае, тебе нужно либо через velocity делать передвижение либо напрямую изменять позицию через rigidbody.MovePosition. Про AddForce забудь, он здесь не нужен.
  • Как сделать управление 3д персонажем с помощью Rigidbody в unity?

    K0TlK
    @K0TlK
    Делал с помощью RigidBody.velocity и AddForce(), но оно работает некорректно

    Что именно работает некорректно то? И что в твоем случае корректно?
  • Соответсвует ли код принципам солид?

    K0TlK
    @K0TlK
    Герман Коффман,
    И то и то связано с тем что я эксперементирую и сам еще не решил что нужно использовать. Ну и конечно постоянные правки и переименования в которых тоже что то теряется.

    Тебе и не надо экспериментировать, есть конвенции, следуй им:
    https://docs.microsoft.com/en-us/dotnet/csharp/fun...
    https://github.com/dotnet/runtime/blob/main/docs/c...
  • Соответсвует ли код принципам солид?

    K0TlK
    @K0TlK
    Герман Коффман,
    Или все должно быть как в примере с помощью функции Get() и функции Set()?

    Публичные поля/свойства/методы get, set это все нарушение иммутабельности/инкапсуляции объекта. Это то же самое, если бы у тебя сердце можно было просто достать рукой и заменить его на другое. Удобно, но это может сделать кто угодно, когда угодно, откуда угодно.
    Объект это не мешок с данными и методами для взаимодействия с ними. Взаимодействовать нужно с объектом, а не с данными, которые он содержит.
    Как пример:
    public class Document
    {
        public string Text { get; set; }
    }


    В этом случае Document просто какое-то DTO(Data transfer object), а не объект, взаимодействие с ним будет соответствующим:
    public class Human
    {
        public void ReadDocument(Document document)
        {
            Debug.Log(document.Text);
        }
    }

    Human взаимодействует с данными, которые содержит Document, а не с самим объектом Document.
    И другой пример:
    public class Document
    {
        private readonly string _text;
    
        public Document(string text)
        {
            _text = text;
        }
    
        public void Print()
        {
            Debug.Log(_text);
        }
    }

    Теперь объект Document иммутабельный. Его текст устанавливается единожды при создании объекта, через конструктор. Изменить это поле нельзя, поэтому он всегда будет сохранять свое состояние. И, благодаря методу Print теперь не нужно взаимодействовать с данными объекта напрямую. Соответственно, теперь взаимодействие будет происходить с объектом, а не с его данными:
    public class Human
    {
        public void ReadDocument(Document document)
        {
            document.Print();
        }
    }
  • Почему бот идет к цели не всегда?

    K0TlK
    @K0TlK
    Герман Коффман, За спираченный ассет в некоммерческом учебном проекте, который увидят 10 человек от силы, тебя никто не засудит. Если это проект для резюме, то, увидев то, что ты понаписал, твое резюме просто откинут в сторону и дальше смотреть не будут. Хочешь через код - делай свою реализацию Behaviour Tree, гугли как оно работает, учись.
  • Почему бот идет к цели не всегда?

    K0TlK
    @K0TlK
    spoiler

    using BehaviorDesigner.Runtime.Tasks;
    using UnityEngine;
    
    namespace BehaviourTree.Brain
    {
        public class LocateTarget : Action
        {
            public float Fov;
            public float CheckRadius;
            public LayerMask TargetMask;
            public Bot Bot;
            public SharedTarget Target;
    
            public override TaskStatus OnUpdate()
            {
                var foundTarget = FindTarget(CheckRadius, TargetMask);
                
                if (foundTarget == null) return TaskStatus.Failure;
    
                var eye = new Eye(Fov, Bot.transform);
    
                if (eye.InSight(foundTarget) == false) return TaskStatus.Failure;
    
                Target.Value = foundTarget;
                return TaskStatus.Success;
            }
    
            private SomeTarget FindTarget(float radius, LayerMask mask)
            {
                var results = new Collider[64];
                SomeTarget target = null;
                if (Physics.OverlapSphereNonAlloc(Bot.transform.position, radius, results, mask) == 0) return target;
    
                foreach (var collider in results)
                {
                    if (collider == null) break;
                    if (collider.TryGetComponent(out SomeTarget found) == false) continue;
                    
                    target = found;
                    break;
                }
    
                return target;
            }
        }
    }


    Проверяем сферой, есть ли в определенном радиусе таргет, проверяем, виден ли он, устанавливаем таргет. Код всё. Далее дизайнер.
    Создаем в дизайнере переменные (Variables):
    target типа Target,
    locateCooldown типа float,
    direction типа Vector3
    Всего должно быть 4 переменные, включая BotInput, который был добавлен ранее.
    62c00dc0e62eb314912433.png

    В дизайнере есть 4 вкладки:
    Behaviour - настройки поведения,
    Tasks - ноды,
    Variables - переменные,
    Inspector - то же самое что и инспектор для обычных геймобжектов, только инспектор для нод, нажимаешь на ноду в дизайнере -> открывается ее инспектор.

    Описывать ноды и что они делают я не буду. В Дизайнере есть описание каждой ноды при нажатии на нее.
    Вот скрин того что я накидал, делай то же самое.
    62c01127163fe207284385.png
    Чтобы ставить ноды - заходишь в Tasks и выбираешь нужную, ноды, у которых значок -------> это sequence ноды, я их переименовал. Ноды с треугольником - Actions (на самом деле Leaf, но разработчик дизайнера, по всей видимости, не очень умный).
    Итак первый репитер:
    в инспекторе выставляешь Repeat forever в тру, end on failure - false
    Далее сиквенса Try Locate Target:
    Locate target
    62c012ab235e3130651811.png
    Wait
    62c012d2565fd740710121.png

    Далее сиквенса Walk Around и настройки всех ее нод
    62c015ba42f28572464848.jpeg

    Правый репитер:
    count 0,
    repeat forever true,
    end on failure true

    Follow Target и ее ноды:
    62c0167189a09819272961.jpeg

    Таким образом можно из простых скриптов создавать сложное поведение гораздо быстрее и удобнее, чем делать все это через код.

    Вот так все в итоге выглядит: https://imgur.com/a/RpnFCku
  • Почему бот идет к цели не всегда?

    K0TlK
    @K0TlK
    Мне хочется плакать. Надеюсь кто-нибудь тебе поможет. Напиши какой функционал у бота должен быть, если никто до завтра ничего дельного не напишет, покажу как чуть получше сделать это все.
  • Как отслеживать состояние компонента через систему событий в Unity?

    K0TlK
    @K0TlK
    Если нет возможности модифицировать плагин, то самое простое - проверять в update/fixedupdate/корутине, главное, чтобы таких объектов на сцене не много было. Какой-то не очень плагин, если он взаимодействует напрямую с канвасгруп, а не с какой-то абстракцией.
  • Как сделать передвижение и прыжок игрока?

    K0TlK
    @K0TlK
    Владимир Юрченков,
    Да и спотыкаться лучше ему самому

    Ты ему сейчас грабли под ноги положил.
    и улучшать код

    А не проще ли изначально учиться писать нормальный код, чем потом сидеть и переучиваться? Как я и написал выше, пустая трата времени, видео тип делал чтобы впихнуть туда рекламу курса по юнити, как популяризатор он, может быть, еще и пойдет, но как учитель он ничто.
  • Как сделать передвижение и прыжок игрока?

    K0TlK
    @K0TlK
    Владимир Юрченков, Нет. В том то и дело, что оно даже для новичков не пойдет. Чел 2 часа пытается понять как работает юнити, у него что-то ломается, а как пофиксить он не понимает. "#Профессионал" из него как из Майка Тайсона балерина. Пустая трата времени, лучше ссылку замени на https://learn.unity.com/