Войти
ПрограммированиеФорумОбщее

Детские вопросы по Unity ( В чем преимущество Scriptable Object как переменных? )

Страницы: 1 2 310 11 Следующая »
#0
(Правка: 16 мая 2019, 13:19) 0:42, 30 дек. 2018

  Здравствуйте. Не знал куда поместить - сюда или во флейм. Вопросы-то совсем нубские.
Ну, пусть пока здесь побудет) Если вдруг чего - прошу перенести в нужный раздел.

В общем, недели две назад начал учить C#, а для закрепления материала решил запилить маленькую консольную текстовую адвенчуру.


АКТУАЛЬНОЕ :

В чем преимущество Scriptable Object как переменных?

Собсно, основные моменты, описанные в этом видео я понимаю :

+ Показать

Мы уменьшаем зависимость, представляя переменную не как Player.Instance.playerHP, а создавая ее как сриптебл обджект, так что к playerHP обращается как Player, так и все кому нужно ( интерфейс и пр.), а playerHP у нас выходит где-то посерединке.


То есть вместо условного :

 public class Player 

    {

        public int playerHP;

    }

Мы делаем так :

    [CreateAssetMenu]
    public class IntVariable : ScriptableObject

    {

        public int value;

    }


    public class Player

    {

        public IntVariable playerHP;

    }

Но это хорошо когда Player у нас один и статический. А если у нас куча Enemy ( пусть Enemy также scriptable object ) - выходит на каждый экземпляр нужна отдельная переменная, т.е. условно skeletonHP, zombieHP, trollHP, я правильно понимаю? А если у нас не только здоровье, но и куча других показателей - для каждого показателя каждого врага придется создавать отдельный SO.

Выходит, имеет смысл делать переменные как сриптебл обджект только для единичных сущностей?

И чем еще такой подход полезен ( кроме немного более удобного обращения - без Player.Instance ) ? 


-——————————————————————————————————————————————————


СТАРОЕ :

+ Показать

Спасибо!


#1
(Правка: 7:20) 6:57, 30 дек. 2018

Jeaniro
> Подскажите, пожалуйста, как лучше в данном случае реализовать отдельные
> локации? Методами в одном классе или отдельными классами? Или, может есть
> какое-то более простое решение, а я до него никак не допру?
1) хм... первый шаг к ООП это заменить метки S1a/S1b на do ... while.

хотя цикл, на самом деле должен быть в другом месте - снаружи, а у scene, должен быть виртуальный метод Action() (а вот и это твоя абстракция!)
и от дубляжа всяких "help" и "stats" ты избавишься

2) Scene1 не должна вызывать Scene2 напрямую. Например если в сцене2 у тебя будет возможность вернуться на сцену1. И это сделано как:

  Scene1.Scene()
то ты создаёшь рекурсию. А это память на ветер, и потенциальная возможность получить переполнение памяти.
что самое ужасное ты не сможешь воткнуть progress bar для загрузки сцены№2! :( а так же толком не впихнуть будет рекламу между уровнями

3) У тебя каждый класс сцены реализует логику этой сцены.
Не самый лучший вариант, но как, имхо, на данный момент тебе следует продолжать ей пользоваться.
А раз каждый класс, реализует логику сцены, то тебе следует использовать экземпляры сцены. Просто чтобы хранить её состояние (особенно помогает если бегать со сцены туда обратно). Например, если ты на сцене1 подобрал ключ, ТО при возвращении в сцену1 она должна "помнить" что ключ уже взят, и повторная попытка результата не даст.

4) Если parameters и inventory должны переносится между комнатами, то нефиг их делать внутренними переменными scene, они должны быть внешними.

+ Как следует сделать, в твоём случае, как видеться с моей колокольни

Jeaniro
> Смотрел туториалы - все делают локации\комнаты в одном главном классе. Но
> что-то мне подсказывает что это дурной тон, получается в итоге такой
> спагетти-код, не хотелось бы с самого начала привыкать к плохому.
ссылочку может быть пару таких туториалов?

#2
(Правка: 7:38) 7:31, 30 дек. 2018

Внушительно, как за две недели с нуля.

Итак, сейчас каждая сцена/локация - уникальньій класс ручной работьі. Оно-то, конечно, поначалу супергибко в том смьісле, что легко будет добавлять новую необьічную логику, специфичную для локации, но совершенно немасштабируемо. Что, например, делать с кодом обработки stats, inventory и help, дублировать в каждой локации? А когда понадобится слегка изменить, изменять в каждом классе?

Здесь уместней, чтобьі класс бьіл обший - Scene, а каждая отдельно взятая сцена - єкземпляр єтого класса. То как реагировать на предмет, или куда игрок попадает, если поворачивает направо, определяется мемберами єтого класса. Там же будет и состояние комнатьі; как пример, бьіла ли она посещена ранее. Создать и проинициализировать все єти инстансьі можно, например, на старте игрьі, чтобьі не усложнять.
Єто уже даст, что настройка мира (какая комната с какой связана, где что лежит и т.д.) будет в одном месте, а общая логика - абстрагирована и сконцентрирована в классе Scene.
То есть, например, сейчас подбирание ключа захардкожено в Scene1. В моей схеме в классе Scene будет общий код в духе если в комнате есть предмет - вьівести сообщение с названием предмета на єкран и положить его в инвентарь. И убрать из комнатьі, чтобьі по второму разу не подбирался, а где-то в инициализации будет задано, что изначально в сцене №1 лежит skeleton key, а в сцене №3 - lock picks.

Обратная сторона обобщения - станет сложнее делать хитрую логику, по-настоящему уникальную. Для таких сцен можно делать классьі-наследники от базового Scene, или попробовать обойтись делегатами.

Успехов!

Правка: Пока набирал, skalogryz уже ответил, так что по сути повторяюсь. Ну пусть уже будет.

#3
12:26, 30 дек. 2018

Курсы можно поискать на Интуите.  Когда-то сам там все смотрел, много чего есть.
Есть еще очень хорошая книга, но к сожалению я на работе, не могу название подсказать. Через недельку вернусь, напишу.

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

#4
(Правка: 14:21) 14:10, 30 дек. 2018

skalogryz
krian
Unimat

Большое спасибо за ответы! Я просидел всю ночь и кажется что-то встает на места.
До класса-загрузчика\менеджера сцен в итоге докумекал. Как-то так :

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

Сразу все стало как-то логичней и исчезла эта идиотская цепочка, где каждый вызывал каждого, не создавая экземпляра.


skalogryz
> А раз каждый класс,
>реализует логику сцены, то тебе следует использовать
> экземпляры сцены. Просто чтобы хранить её состояние (особенно помогает если
> бегать со сцены туда обратно). Например, если ты на сцене1 подобрал ключ, ТО
> при возвращении в сцену1 она должна "помнить" что ключ уже взят, и повторная
> попытка результата не даст.

krian
> То есть, например, сейчас подбирание ключа захардкожено в Scene1. В моей схеме
> в классе Scene будет общий код в духе если в комнате есть предмет - вьівести
> сообщение с названием предмета на єкран и положить его в инвентарь. И убрать из
> комнатьі, чтобьі по второму разу не подбирался, а где-то в инициализации будет
> задано, что изначально в сцене №1 лежит skeleton key, а в сцене №3 - lock
> picks.

А вот теперь да, буду пытаться придумать предметы в комнате отдельно от комнаты.
Потому что сейчас у меня при нахождении ключа он просто записывается в стринговый массив. А чтобы избежать повторного появления варианта examine в уже обысканной комнате - приходится мудрить со счетчиком посещения.
Типа такого :

+ Показать

и соответственно если счетчик entRoom больше определенного значения - будет выводится текст без возможности обыскать комнату.

Но я аж прям физически чувствую какой-то это костыль. И пока не понимаю как это будет работать при возвращении из другой сцены обратно.


Счетчик сам у меня в классе Program, в который я перенес все счетчики :

+ Показать

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

b]skalogryz[/b]
> 1) хм... первый шаг к ООП это заменить метки S1a/S1b на do ... while.


Мне самому не нравятся это goto. Я интуитивно понимал, что там должен быть какой-то цикл, но под конец ночи уже ничего не соображал, поэтому впихнул неработающий do while , сегодня буду разбираться.

+ Показать

>[b]skalogryz[/b]
> ссылочку может быть пару таких туториалов?

Вот например. Тут даже мне понятно - так делать не стоит.
Бесконечные if else эти.

+ Показать

Продолжение ниже:

#5
(Правка: 14:54) 14:11, 30 дек. 2018

skalogryz
> 4) Если parameters и inventory должны переносится между комнатами, то нефиг их
> делать внутренними переменными scene, они должны быть внешними.


Сейчас у меня Invenotry - отдельный класс  с массивом и методом его вывода. И с тупой проверкой на наличие предметов в инвентаре путем проверки первого элемента массива. Ну типа у меня все предметы в массиве имеют заданные им ячейки, и если нет ничего в первой, то нет и в остальных. Но я уверен что можно сделать проще, пока правда серьезно не думал.

+ Показать

Дальше идет класс Player в котором пока ничего нет кроме свойств полей параметров, и от которого наследуются другие игровые классы ( условно воин\вор\исследователь).

+ Показать

Класс воина :

+ Показать

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

Класс оружия ( наследуется от общего класса навыков ) :

+ Показать


Класс одноручного меча ( наследуется от класса Weapons ) :

+ Показать

Сегодня думал начать делать боевку ( по D&D ) и ввести класс врагов.

Unimat
> Класс Карта, например, будет хранить координаты локаций, их начинку
> (изменяемую, взято-не взято) и посещаемость.

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

krian
> Здесь уместней, чтобьі класс бьіл обший - Scene, а каждая отдельно взятая сцена
> - єкземпляр єтого класса.

Хм, то есть все в экземплярах?
Это мне в голову не приходило. Звучит интересно, подумаю)

Unimat
> Курсы можно поискать на Интуите.

Я сейчас смотрю в основном Александра Шевчука из ITVDN. У него такой, глубокий, обстоятельный подход. С объяснениями попутно про CLR, как что происходит на куче итд.
Но к десятому дню постоянного просмотра уже каша, поэтому пытаюсь освежить на ютубе.
Ну Интуит зашел - да, там есть по C#. Но там третьей версии - насколько я понимаю с тех пор много чего изменилось? Те же автосвойства добавили.
Имеет ли смысл проходить такие курсы?

И еще раз большое спасибо всем!

#6
16:23, 30 дек. 2018

Jeaniro
Я бы наверное посоветовал не торопиться, и до конца разобраться как работают классы. А то как-то много в коде странного.

Например, смущает, что всё везде статики. Это как бы означает, что мы не сможет в игровом мире иметь два вида оружия одновременно, так как у них будут общие проперти в Weapons! https://ideone.com/Kqbxho
Ну то есть это может и нормально, если у игрока по задумке стопудово всегда только одно оружие, и Sword.WeaponSword() оружие переключает, но тогда зачем там внутре

Sword sword = new Sword();
?

По "оопешному" это могло бы быть например так: https://ideone.com/M3ElWC
Или даже (на мой вкус) лучше https://ideone.com/GrDevP

Оговорюсь только, что я больше по С++, так что по деталям конкретно С# могу и плохого насоветовать :)

#7
(Правка: 17:37) 16:45, 30 дек. 2018

krian
О, спасибо большое за примеры. Буду разбираться.


Со статиком да, я толком не дошел еще до него.
То есть, в общем вроде и понимаю что это общее поле у объекта для всех экземпляров, и оно не изменяется, в отличии от полей экземпляра, но вот на практике не понимаю где он нужен\не нужен.

krian
> Sword.WeaponSword() оружие переключает, но тогда зачем там внутре

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


И я окончательно запутался с тем, что лучше и почему - один общий класс Scene, в котором находятся методы с экземплярами Scene? Или  класс-менеджер сцен Levels с вызовом оттуда каждой комнаты как отдельного класса ( Scene1, Scene2) и пр?.

правка : все, я ступил. Перечитал еще раз все что мне написали - везде речь идет об экземплярах класса Scene в одном и том же классе, насколько я понял. Попробую сделать так.

#8
21:04, 30 дек. 2018

Jeaniro
> Со статиком да, я толком не дошел еще до него.
> То есть, в общем вроде и понимаю что это общее поле у объекта для всех
> экземпляров, и оно не изменяется, в отличии от полей экземпляра, но вот на
> практике не понимаю где он нужен\не нужен.
нигде не нужен .. это борода от структурного программирования

#9
(Правка: 21:26) 21:23, 30 дек. 2018

Jeaniro
> И я окончательно запутался с тем, что лучше и почему - один общий класс Scene,
> в котором находятся методы с экземплярами Scene? Или  класс-менеджер сцен
> Levels с вызовом оттуда каждой комнаты как отдельного класса ( Scene1, Scene2)
> и пр?.
у тебя все неправильно, поэтому тут давать рекомендации сложно, чтобы не засмеяли ;)

но начать тебе надо с разделения управления от логики сцен. Управление в switch типа инвентарь, направо/налево, ждать - одинаково для всех сцен и тут надо ввести класс InputControl. Специфику сцены надо вынести по отдельным классам Scene1, Scene2, выделив каждое 'действие' как метод, вместо case .. небойся надублировать, в твоем случае, это сейчас не проблема, зато появится возможно логика архитектуры ..
а потом показывай что получилось .. рано думать о ООП когда такой гавнокод :)

#10
(Правка: 23:13) 22:40, 30 дек. 2018

tac
> тебя все неправильно, поэтому тут давать рекомендации сложно, чтобы не
> засмеяли ;)
> но начать тебе надо с разделения управления от логики сцен. Управление в switch
> типа инвентарь, направо/налево, ждать - одинаково для всех сцен и тут надо
> ввести класс InputControl. Специфику сцены надо вынести по отдельным классам
> Scene1, Scene2, выделив каждое 'действие' как метод, вместо case .. небойся
> надублировать, в твоем случае, это сейчас не проблема, зато появится возможно
> логика архитектуры ..
> а потом показывай что получилось .. рано думать о ООП когда такой гавнокод :)

Спасибо за советы!
Мне только что вот показалось что меня осенило и что я нашел простое решение, а потом я понял что меня осенило тем, что мне все тут и говорили)
Скорее всего, до меня просто дошло наконец)

В общем, да, я посмотрел так со стороны на свои классы с описаниями и на то, сколько в них дублирующегося функционала ( вроде того же ожидания, вывода статистики и пр ).
Да и сам switch\case который повторяется в каждой сцене ( а их до фига ).

Так что я решил сделать один класс Scenes в котором будет метод с общим поведением для всех сцен ( все switch\case, выводы на экран и пр. ). А потом достаточно просто создавать экземпляры этого класса в разных методах и скармливать ему данные вроде поля desription, событий для свитчкейсов итп. Я убрал эти бездумные static так что теперь у каждого экземпляра, насколько я понимаю, будет свой собственный description. В итоге размер код уменьшается в разы. Сцена теперь представляет просто описание, а всю логику делает объект класса.


Единственное что, пришлось создать отдельно класс для событий в сценах  - вроде вычета здоровья, приобретения навыка и пр.. Это уже вызывается из экземляра сцены ( ведь для каждой сцены события уникальны ).
Думаю, сюда же можно и проверку инвентаря включить ( есть ключик в комнате или уже забрали ).

Пока еще не все заработало, но должно заработать.

#11
23:24, 30 дек. 2018

Jeaniro
> public static void LevelsScene1()
> public static void LevelsScene2()
ох и жесть. Не делай так!
ты просто сделал рекурсию глубже на один шажок.

не пиши все дополнительные классы, сделай одну простую адвентюру. с таким содержимым!

комната1
  дверь1
  ключ серебрянный
  дверь серебрянная (ведёт в комнату 2)
  дверь золотая (если игрок вошёл в неё, то выиграл)
комната 2
  ключ золотой
Т.е. всё просто - нужно взять серебрянный ключ, войти во вторую комнату, взять второй ключ, вернутся, и выйти победно.
Как видишь, много классов тут не нужно.

#12
23:42, 30 дек. 2018

skalogryz
Да, я уже понял что нельзя разбрасываться модификаторами.

Насчет сложности - ну, в том и смысл. Больше опыта, больше знаний. Ну и мне просто интересно.

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

#13
1:18, 31 дек. 2018

Jeaniro
> Поэтому лучше я пока побьюсь башкой о стенку, может чет выйдет.
Оке. Имеешь право на собственные шишки

#14
1:43, 31 дек. 2018

Все переделал. По крайней мере, работает. И писать значительно быстрее.

Но, блин, как-то совсем оно костыльно.

Логика такая :

- класс Levels - главный класс, принимает ввод от игрока и,
  в зависимости от  значения переменной передает аргумент в методы других классов.
  Здесь же все экземпляры этого класса, с переменными и описаниями.

+ Показать

- класс Map - сюда попадает аргументы от Levels. Здесь тоже свитчкейсы, но теперь они зависят от аргумента переданного главным классом
( а эти аргументы зависят, в свою очередь, от номера сцены на которой мы находимся ). Приняв эти аргументы, Map понимает на какой мы сцене что делаем и дальше уже обращается к Logic или делает что-либо иное.

+ Показать

- класс Logic - все игровые события вроде минус к хп или новый скилл
+ Показать

Это сильно ужасно? Хоть чем-то лучше предыдущего?

Страницы: 1 2 310 11 Следующая »
ПрограммированиеФорумОбщее