Форум Flasher.ru

Форум Flasher.ru (http://www.flasher.ru/forum/index.php)
-   ActionScript 3.0 (http://www.flasher.ru/forum/forumdisplay.php?f=83)
-   -   Вопрос по проектированию (http://www.flasher.ru/forum/showthread.php?t=214513)

undefined 24.09.2017 23:31

Цитата:

но он работает только для классов типа Object
Экземпяр любого класса в ас3 является наследником Object.Все,что умеет Object,умеет и любой другой объект.

Appleman 25.09.2017 00:27

Цитата:

Сообщение от undefined (Сообщение 1202069)
Экземпяр любого класса в ас3 является наследником Object.Все,что умеет Object,умеет и любой другой объект.

Вот и я так думал. Но почему тогда при попытке записать 'имя класса'.hasOwnProperty("имя свойства"), компилятор выдаёт ошибку обращения к несуществующему методу? Специально попробовал написать то же самое для класса типа Object, всё работает :(

undefined 25.09.2017 00:43

действительно странно,вроде скрывать методы в суперклассах штатными средствами никак нельзя,но зато можно так:
Код AS3:

(myInstance as Object).hasOwnProperty("myProperty");


Appleman 25.09.2017 00:50

Я в итоге проще придумал. Просто проверяю
Код AS3:

if (_propID in character)


Wolsh 25.09.2017 00:54

Потому что класс Object динамический.
Этот путь какой то странный, зачем по нему идти?
Ты как-то невероятно представляешь себе программу, что она НЕ ЗНАЕТ что хочет.
Я не понимаю, в какой ситуации программа может обращаться к длине бороды, не зная что ей нужна именно длина бороды.
Не надо нам таких программ, не пиши их.

undefined 25.09.2017 01:20

Цитата:

Потому что класс Object динамический.
А откуда автокомплит тогда знает об этом методе?

Appleman 25.09.2017 01:23

Цитата:

Сообщение от Wolsh (Сообщение 1202073)
Ты как-то невероятно представляешь себе программу, что она НЕ ЗНАЕТ что хочет.
Я не понимаю, в какой ситуации программа может обращаться к длине бороды, не зная что ей нужна именно длина бороды. Не надо нам таких программ, не пиши их.

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

Код AS3:

package language 
{
        import data.Character;
        import data.GlobalValues;
 
        public class AttributeHints
        {
 
                static private var _character: Character // Переменная для персонажа для использования внутри класса
                static private var _propID: String; //Идентификатор свойства как приватная переменная для использования внутри класса
                static private var _source:*; // Класс, содержащий оцениваемое свойство
                static private var _tresholds: Array; // Переменная для массива пороговых значений для выбранной шкалы
                static private var _hints: Array; // Переменная для массива cловесных описаний
                static private var _index: uint; // Индекс нужной позиции во всех связанных массивах
 
                static private const HINTS:Object =
                {
                        //Борода
                        (GlobalValues.CHARACTER_PARAM_BEARD + GlobalValues.GENDER_MALE as String): ["гладко выбрит", "секси", "трёхдневная щетина", "недельный запой", "капитан дальнего плавания", "военнопленный", "бомж", "волшебник"]
                }
 
                static public function getHint(propID:String, character:Character):String //Получить расшифровку по ID запрашиваемого свойства и персонажу
                {
                        AttributeHints._propID = propID;
                        AttributeHints._character = character;
                        AttributeHints.getSource();
                        AttributeHints.getTresholds();
 
                        for (var i:int = 0; i < _tresholds.length-1; i++)
                        {
                                if (_source[_propID]<=_tresholds[i])
                                {
                                        _index = i;
                                        break;
                                }
                        }
                        return (AttributeHints.HINTS[_propID+_character.gender.genderID][_index]);
                }
        }
 
                static public function getSource():void // Определяем, в каком классе находится искомое свойство
                {
                        if (_propID in _character) {_source = _character;}
                        if (_propID in _character.gender) {_source = _character.gender;}
                }
 
}

Чем плох такой подход? Если свойства персонажей, хранящиеся как в классе Character, так и в Gender, оцениваются одинаково, то в методах класса AttributeHints, я первым делом выясняю, к какому классу принадлежит искомое свойство, а потом выполняю идентичную процедуру выбора словесного описания для него.

Там на самом деле уже штуки 3 открытых методов: один просто возвращает словесное описание, другой возвращает само значение в виде NN/100, ещё один сразу упаковывает это удовольствие для вставки в текст в виде: [борода: 88/100, военнопленный]. Зачем всё переписывать дважды для свойств Character и Gender?

Wolsh 25.09.2017 01:37

Цитата:

А откуда автокомплит тогда знает об этом методе?
Каком этом? Если автокомплит знает, значит метод является членом Класса. А вот свойства, которые "видит" hasOwnProperty, членами класса быть не могут. Потому что никому по трезвянке в голову не придет спрашивать в коде, есть ли у класса такой-то метод или свойство. Об этом есть смысл спрашивать только в том случае, когда метод или свойство могут быть добавлены экземпляру в рантайме, и соответственно никто не может гарантировать их наличие в произвольный момент. В отличие от членов класса, которые либо сразу есть, либо их нет и никогда не будет.

Appleman 25.09.2017 01:50

Друзья!

У меня ещё вопрос про бороду и талию. Поправил гендерные классы, как советовал Wolsh. В частности, сеттеры и геттеры мужских свойств "уехали" в GenderMale, а женских - в GenderFemale.

Если в классе GenderMale имеем такой код:
Код AS3:

public function set beardLength(NewBeardLength:Number):void //Длина бороды
                {
                        _beardLength = NewBeardLength;
                }

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

_hero.gender = new GenderMale();
_hero.gender.beardLength(25);

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

caseyryan 25.09.2017 05:46

потому что сеттер/геттер - это не простые методы, к ним нужно обращаться как к переменным, без скобок
Код AS3:

_hero.gender.beardLength = 25;


Appleman 25.09.2017 10:17

Цитата:

Сообщение от caseyryan (Сообщение 1202078)
потому что сеттер/геттер - это не простые методы, к ним нужно обращаться как к переменным, без скобок
Код AS3:

_hero.gender.beardLength = 25;


Sorry, это я в ночи уже в форум фигню написал. Нет, естественно назначение идёт как положено:
Код AS3:

_hero.gender.beardLength = 25;

Но всё равно получаю ошибку:
Error: Access of possibly undefined property beardLength through a reference with static type Gender.

undefined 25.09.2017 11:34

Цитата:

Сообщение от Wolsh (Сообщение 1202076)
Каком этом? Если автокомплит знает, значит метод является членом Класса.

Если hasOwnProperty - член класса почему его не видно в потомках?Я думал что имеется в виду раз Object динамический,то и hasOwnProperty добавляется динамически,потому его и не видно в потомках.

Wolsh 25.09.2017 15:06

Цитата:

потому его и не видно в потомках.
Не смог найти в Хелпе ни одного класса, у которого бы не было этого метода.

Добавлено через 5 минут
Цитата:

Но всё равно получаю ошибку:
Error: Access of possibly undefined property beardLength through a reference with static type Gender.
Текст ошибки говорит сам за себя: "в классе Гендер нет свойства длинабороды."
И ведь они правы, нет.

undefined 25.09.2017 15:18

Цитата:

Не смог найти в Хелпе ни одного класса, у которого бы не было этого метода.
Оно там есть,но вот автокомлит его почему то не видит,хотя компиляции это не мешает.

caseyryan 25.09.2017 16:42

Цитата:

Оно там есть,но вот автокомлит его почему то не видит,хотя компиляции это не мешает.
В какой IDE? Это попахивает как раз багом IDE. У меня в FD такое бывало, пока кэш проекта вручную не почистил

Appleman 25.09.2017 16:51

Цитата:

Сообщение от Wolsh (Сообщение 1202082)
Текст ошибки говорит сам за себя: "в классе Гендер нет свойства длинабороды."
И ведь они правы, нет.

Тогда я ничего не понимаю. Ты несколькими сообщениями ранее обоснованно рекомендовал убирать свойства и методы подклассов (GenderMale и GenderFemale) из суперкласса (Gender), чтобы не получать "мужика с бородой и талией". Чего-то я по всей видимости в теории наследования не догоняю.

Но в любом случае не понимаю, на кой ляд он ломится в Гендер, если в public переменной character.gender на момент присвоения значения свойства уже хранится экземпляр класса GenderMale, т.е. именно подскласса, а не самого Гендера? Объясни плиз.

Wolsh 25.09.2017 17:38

Тогда почему тип свойства не GenderMale? Ага, чтобы там мог храниться экземпляр GenderFemale? Ну и как с бородой у неё?
Цитата:

на кой ляд он ломится в Гендер
потому что тип свойства — Gender. На эту ошибку тебе указал компилятор, она выявлена еще до запуска программы, поэтому никакого Male нигде не было, компилятор просто обнаружил что ты обращаешься к свойству экземпляра класса Gender, которого нет у этого класса (притом что класс static type и у него не может появиться это свойство на ходу) и довольно добродушно тебя об этом предупредил.

Appleman 25.09.2017 17:53

Цитата:

потому что тип свойства — Gender. На эту ошибку тебе указал компилятор, она выявлена еще до запуска программы, поэтому никакого Male нигде не было, компилятор просто обнаружил что ты обращаешься к свойству экземпляра класса Gender, которого нет у этого класса (притом что класс static type и у него не может появиться это свойство на ходу) и довольно добродушно тебя об этом предупредил.
Не поспоришь. Только тогда я совсем запутался, уже на концептуальном уровне. Идея разделить свойства пола состояла в том, чтобы не тянуть в каждый из подклассов несвойственные для него свойства, пардон за тавтологию, то есть чтобы не было тёток с бородой. Точно так же у нас могут быть разные профессии для персонажей игры, каждая со своим уникальным набором свойств, и много ещё чего. Смысл всё это раскидывать по разным классам, если обратиться к ним нельзя. :(

Выходит, возвращаемся к тому, с чего начинали: в Гендере прописываем и бороды, и сись талии, а потом делаем override в подклассах?

caseyryan 25.09.2017 18:53

А почему ты решил, что у женщины не может быть свойства "длина бороды"? Напиши beardLength = 0;
В твоем случае разделение можно сделать немного по-другому. Добавь в Gender свойство beardLength, которое будет задавать длину бороды, но в GenderFemale сделай его перезапись
Код AS3:

override public function set beardLength(value:Number):void {
  trace("Ой, всё! Нет у меня бороды!");
}
override public function get beardLength():Number {
  return 0;
}

Но это сам по себе подход не очень правильный. Ты сможешь обращаться к ним как объектам Gender, только там, где нужны их общие свойства. В частных случаях тебе все равно придется делать каст к GenderMale или GenderFemale.
Я бы, на твоем месте, лучше сделал класс Human, и добавил ему свойство gender. А где надо просто проверял бы
Код AS3:

if (human.gender == Human.MALE) {
    // это мужик, у него есть яй борода
} else {
  // не мужик.
}


п.с. У нашей училки по русскому в школе, была борода. При чем очень даже окладистая :D

Appleman 25.09.2017 19:10

Цитата:

Сообщение от caseyryan (Сообщение 1202093)
А почему ты решил, что у женщины не может быть свойства "длина бороды"? Напиши beardLength = 0;
В твоем случае разделение можно сделать немного по-другому. Добавь в Gender свойство beardLength, которое будет задавать длину бороды, но в GenderFemale сделай его перезапись
Код AS3:

override public function set beardLength(value:Number):void {
  trace("Ой, всё! Нет у меня бороды!");
}
override public function get beardLength():Number {
  return 0;
}


У меня так и было вначале. Но стали возникать закономерные вопросы. С таким подходом получается слишком много писанины: для каждого свойства (и мужского, и женского) потребуется в суперклассе Gender объявить переменную плюс написать пустые сеттер с геттером, чтобы потом переопределить их в классах Male и Female. И Wolsh мне на это указал среди прочих замечаний к коду, который я демонстрировал ранее в этой теме...

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

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

Wolsh 25.09.2017 20:45

Полиморфизм строится на переопределении, а то о чем говоришь ты — наличие одних свойств и отсутствие других — не имеет к нему отношения.
Полиморфизм это когда и мальчик и девочка имеют метод piss(), но реализуют его по-разному.
В твоем случае ты мог бы спокойно обращаться к .gender и вызывать этот метод, и если бы .gender хранил ссылку на экземпляр подкласса GenderMale, то выполнялся бы его метод, а GenderFemale делала бы это по-другому.
И тебе НИГДЕ не нужно было бы разбираться, мальчик там или девочка.

Добавлено через 20 минут
И еще. Когда ты пишешь "Wolsh сказал делать так, Wolsh сказал делать сяк" — Wolsh отвечает на ТВОИ вопросы. Я же не знаю всю подноготную. Мне, например, не кажется полезным разделение Гендера на Мужской и Женский, вроде как 1 и 0 было достаточно (к тому же позволяет расшириться, введя 2, 3 и 100500). А если бы в игре были еще и расы? Эльфы там, с "длиной ушей", орки с клыками, гномы — женщин которых никто никогда не видел?
Как справедливо заметил Кейси, и у женщины может быть борода, нет — значит ее длина ноль; и у мужчин есть и талия и грудь. Я бы не стал из-за ЭТИХ свойств делать разводку на два подкласса, НО. Я ведь не знаю предысторию этого разделения. Может как раз и подразумевалось переопределение методов в дальнейшем, чтобы мальчики и девочки делали одно и то же по-разному.

Appleman 25.09.2017 22:37

Цитата:

Сообщение от Wolsh (Сообщение 1202098)
И еще. Когда ты пишешь "Wolsh сказал делать так, Wolsh сказал делать сяк" — Wolsh отвечает на ТВОИ вопросы. Я же не знаю всю подноготную.

Я с конца отвечать начну :) Wolsh, я очень ценю твои рекомендации и искренне признателен за то, что ты уделяешь своё время и отвечаешь на все мои дилетантские вопросы подробно и содержательно. Просто то, что для профи является самим собой разумеющимся, для чайника - тёмный лес. И да, ты отвечаешь ровно на то, что я спрашиваю, не видя всего контекста. Так что не обессудь, я никак с больной головы на здоровую перевалить не пытаюсь :)

Цитата:

Полиморфизм строится на переопределении, а то о чем говоришь ты — наличие одних свойств и отсутствие других — не имеет к нему отношения. Полиморфизм это когда и мальчик и девочка имеют метод piss(), но реализуют его по-разному.
А как же подкласс может расширять и специализировать существующий класс, если он не может вводить своих собственных новых свойств? Насколько я понял философию ООП (выходит, не совсем правильно), что одним из преимуществ является возможность добавлять функциональность в существующей программе через расширение, а не модификацию существующих классов и модулей. А какое же получается расширение, если даже переменную в подкласс не выходит ввести, не изменив по факту его суперкласс? Как-то так я рассуждал, поэтому и удивляюсь.

Цитата:

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

Nooob 25.09.2017 23:00

Какая-то у вас товарищи абсурдная абстрактная задача Gender, никто в здравом уме не будет её таким образом решать. ООП не нужно делать ради ООП, нужно делать от задачи: удобства, расширяемости, управляемости, устойчивости, простоты, раскрепощенности, определенности, жесткости, все остальное лишь пыль, если не исполняет цели задачи

Wolsh 25.09.2017 23:46

Цитата:

А какое же получается расширение, если даже переменную в подкласс не выходит ввести, не изменив по факту его суперкласс?
Почему не получается? Вводи сколько влезет. Просто ты пытаешься к ним потом обращаться в классе Гендер, где их просто напросто нет.
Еще раз, этот мой спич касался полиморфизма. Полиморфизм это не всё ООП, это один из принципов, который можно также грубо переформулировать, как "класс-наследник может замещать суперкласс, используя свою реализацию". Наследник замещает суперкласс, но не наоборот! И если ты завел у наследника новые свойства и методы, для работы с ними ты должен обращаться с наследником конкретно, а не абстрактно. Возможно, ты как-то по-своему понял термин "расширяет", как будто наследник ИЗМЕНЯЕТ свой суперкласс, добавляя что-то к НЕМУ. Но нет, он добавляет только СЕБЕ, но добавляет к тому, что досталось ЕМУ в наследство, в этом смысле он "расширяет". Но "старая версия" остается как есть.
Вобщем, из всего этого хотя бы вынеси понимание полиморфизма, уже плюс к скиллам :)

Appleman 26.09.2017 14:08

Цитата:

Сообщение от Nooob (Сообщение 1202103)
Какая-то у вас товарищи абсурдная абстрактная задача Gender, никто в здравом уме не будет её таким образом решать. ООП не нужно делать ради ООП, нужно делать от задачи: удобства, расширяемости, управляемости, устойчивости, простоты, раскрепощенности, определенности, жесткости, все остальное лишь пыль, если не исполняет цели задачи

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

Цитата:

Наследник замещает суперкласс, но не наоборот! И если ты завел у наследника новые свойства и методы, для работы с ними ты должен обращаться с наследником конкретно, а не абстрактно.
Да, спасибо, понятно. Как всегда дьявол в деталях. До этого у меня уже использовалось наследование, но при создании экземпляра класса, там сразу явно указывался тип-наследник, и никаких проблем не возникало. А чуть только я добавил суперкласс в переменную экземпляра (как это получилось в случае с Gender), так началась фигня. Ещё раз благодарю за комментарии и объяснения.

Цитата:

Вобщем, из всего этого хотя бы вынеси понимание полиморфизма, уже плюс к скиллам
Воистину так, аминь!

Appleman 14.10.2017 13:53

Други!

Возвращаюсь в эту тему с очередным концептуальным вопросом. Каждый раз, когда мне требуется реализовать очередную функцию, я дико мучаюсь, куда её, пардон, вставлять. С одной стороны, имеем понятие "single responsibility", что несомненно есть благо. Но в пределе такой подход означает - "один метод - один класс" (причём иногда именно так и происходит).

Поэтому мой вопрос - о критериях выделения каких-то функций/методов в самостоятельные классы или, напротив, группировки их в один класс. И если с первым хоть как-то интуитивно понятно, то со вторым - полная каша в голове.

Вот например, обсуждаем в соседней теме вопросы многоязычности приложения. Понятно, что весь функционал загрузки данных из XML лучше выделить в отдельный класс и наладить с ним простое как грабли взаимодействие: ты ему ID-шник, он тебе обратно - фразу (в моём случае массив фраз, но это неважно). Никаких вопросов. Но вот, например, есть функционал (также обсуждавшийся в этой теме выше) подбора словесных расшифровок для свойств персонажа, типа "дурак - умный - гениальный". Там уже не просто запрос варианта, но и некая логика, основанная на текущих значениях свойств персонажа, таким образом, он взаимодействует с классом Character. Его можно выделить в полностью самостоятельный класс, можно создать что-то типа CharacterModel и поместить туда вместе с другими методами обработки свойств персонажа...

Или ещё пример. Для построения удобочитаемых фраз имеем алгоритм подстановки в полученный кусок текста имени собственного в нужном падеже. Он получает фразу из XML, плюс "знает" что должно быть в него подставлено вместо *$a1. Другой метод получает на входе оценку двух частей сложносочинённого предложения и выдаёт связующий союз (типа "ему охота, и ей охота" и "ему охота, но ей не хочется"). Вроде метод тоже языковой... Имеет смысл объединять их вместе или нет? Какая логика? Не чувствую её. :(

caseyryan 14.10.2017 20:05

Чувствую, скоро дойдет до того, что нужен будет метод, который должен будет определять, написать "поребрик" или "бордюр" в зависимости от текущей локации игрока)
Для игры, которая не имеет целью учить игрока русскому языку, всё это абсолютно излишне. Лучше сделать хороший и интересный гейплей, чем сделать скучную и унылую игру, но зато с правильным правописанием диалогов. Которые, по многочисленным личным наблюдениям, всё равно почти никто не читает. Диалоги в играх вообще должны сводиться к минимуму, это наводит на игрока скуку. Меньше текста, больше действия. Все предложения должны быть максимально короткими и простыми

Appleman 15.10.2017 15:45

Цитата:

Сообщение от caseyryan (Сообщение 1202396)
Чувствую, скоро дойдет до того, что нужен будет метод, который должен будет определять, написать "поребрик" или "бордюр" в зависимости от текущей локации игрока)

Ну, положим, петербуржца затроллить поребриком может каждый :victory:, но вопрос-то мой был весьма серьёзный касательно организации создаваемых классов.

Цитата:

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

Пока сам надумал немного. Есть мысль №1 о том что поскольку условий может быть много, и точное их количество неизвестно для различных случаев, это должен быть некий массив, который будет передаваться на входе в метод-определитель доступности, чтобы он - метод - пробегал по всем и давал итоговое заключение на выходе: либо всё соблюдено, либо № элемента, который "не проходит". Мысль №2, что если у нас все характеристики персонажей (и не только персонажей) заданы через строковые идентификаторы типа "character.intelligence", то их можно и запихивать в массив с условиями, чтобы быстро обратиться за соответствующим значением. А вот всё остальное (запись и хранение целевых значений, операторов сравнения и т.п.) пока не находит ответов.

caseyryan 16.10.2017 06:32

Цитата:

Пока сам надумал немного. Есть мысль №1 о том что поскольку условий может быть много, и точное их количество неизвестно для различных случаев, это должен быть некий массив, который будет передаваться на входе в метод-определитель доступности, чтобы он - метод - пробегал по всем и давал итоговое заключение на выходе: либо всё соблюдено, либо № элемента, который "не проходит". Мысль №2, что если у нас все характеристики персонажей (и не только персонажей) заданы через строковые идентификаторы типа "character.intelligence", то их можно и запихивать в массив с условиями, чтобы быстро обратиться за соответствующим значением. А вот всё остальное (запись и хранение целевых значений, операторов сравнения и т.п.) пока не находит ответов.
Тут сам диалог получается как отдельная мини игра.
Не приходилось такого делать, но представляю это себе примерно так:
Диалог представляет из себя объект, приблизительно такого вида
Код AS3:

{
  dialog1: [{skillLevel: 1, textID: "walkInThePark"}, {skillLevel: 2, textID: "killDragon"}, { skillLevel: 100500, textID: "changeTheWorld" }]
}

Дальше игрок, допустим, подходит к какому-то NPC, которому прописан ID диалога. В данном случае dialog1 и этот NPC выбирает что сказать в зависимости от текущих возможностей игрока. В базовом классе NPC должен быть механизм определения
Код AS3:

 
public function showDialog(dialogID:):void {
    var playerSkillLevel:int = _gameModel.selectedCharacter.skillLevel;
    var dialogVersions:Array = DialogManager.getDialogVersionsByID(dialogID); // какое-то централизированное хранилище диалогов
    for each (var dialog:Object in dialogVersions) {
      if (dialog.skillLevel == playerSkillLevel) {
          showDialog(dialog.textID);
          return; // дальше выполнять метод нельзя, так как диалог найден
      }
    }
    showDialog(null); // если в цикле ничего не нашлось, показываем диалог-пустышку
}
private function showDialog(textID:String):void {
      if (textID) {
          trace(i18n.getTextByID(textID))// "Иди, завали дракона, о игрок второго уровня!"
      } else {
          trace(i18n.getTextByID(DialogManager.NOTHING_TO_SAY)); // "Братуха, извини, но ты слишком крут для меня. Мне нечего тебе сказать"
      }
}

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

Appleman 16.10.2017 10:12

Цитата:

Сообщение от caseyryan (Сообщение 1202411)
Тут сам диалог получается как отдельная мини игра.

Ладно, это я уже в ответ троллить начал по части опции в диалоге в зависимости от скиллов.
На самом деле я тружусь над игрой в редком нынче жанре текстового квеста, как в Космических рейнджерах были. Мне явно пороху не хватит сейчас на более серьёзную реализацию. Поэтому вопрос качественных текстов имхо не менее важен, чем хорошие арты.

Цитата:

Не приходилось такого делать, но представляю это себе примерно так:
Диалог представляет из себя объект, приблизительно такого вида
Код AS3:

{
  dialog1: [{skillLevel: 1, textID: "walkInThePark"}, {skillLevel: 2, textID: "killDragon"}, { skillLevel: 100500, textID: "changeTheWorld" }]
}


Что это за форма записи, когда внутри квадратных скобок (типа литерал, да?) ещё и блоки фигурных?

Wolsh 16.10.2017 10:35

квадратные скобки — массив; а в нем лежат Обжекты.

Appleman 16.10.2017 13:56

Цитата:

Сообщение от Wolsh (Сообщение 1202418)
квадратные скобки — массив; а в нем лежат Обжекты.

Большое спасибо, теперь понятно. Да и дальше в коде действительно видно, что Обжекты.

Цитата:

Сообщение от caseyryan (Сообщение 1202411)
Код AS3:

{
  dialog1: [{skillLevel: 1, textID: "walkInThePark"}, {skillLevel: 2, textID: "killDragon"}, { skillLevel: 100500, textID: "changeTheWorld" }]
}

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

caseyryan, спасибо, весь код вдумчиво просмотрел. Но если честно, то такое я бы и сам наваял. Я изначально писал, что условия могут, во-первых, касаться разнообразных вещей (различные свойства персонажа, наличие/отсутствие некоторого предмета и т.п.), а во-вторых, сравниваются не обязательно по типу "равно", но также "больше" или "меньше". В этом вопрос.

Есть возможность каким-то образом так формулировать условия в этих самых обжектах, чтобы они сразу были указателями на нужные свойства и типы сравнения? Например, у нас есть строковые идентификаторы свойств персонажей, которые совпадают с именами переменных класса Character. Таким образом, если нам нужно "вытащить" значение свойства intelligence, которое хранится в нашем списке условий в переменной prop1:String = "intelligence", то мы просто обратимся character[prop1 as String] (если я ничего не путаю в синтаксисе по неопытности). Я думаю, понятно, что имеется в виду.

caseyryan 16.10.2017 16:36

Код AS3:

character[prop1 as String]

Так лучше не делать. Это сработает, только если prop1 действительно строка.
Лучше делать так:
Код AS3:

character[String(prop1)]

или так:
Код AS3:

character[prop1.toString()]


Appleman 19.10.2017 17:27

Друзья!

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

Помимо собственных игровых свойств, у персонажа есть свойства, получаемые от других объектов. Самый простой пример из RPG-жанра - всякие модификаторы от экипировки. Например, надетый на голову шлем "Толоконный лоб" даёт +1 к интеллекту, понятно. Раздумываю, как организовать это дело в программе. Явно напрашивается отдельный класс для шмоток Item, и наш шлем будет храниться в какой-нибудь переменной данного типа или его наследника (например ItemHat). Вопросы:

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

Во-вторых, чтобы "надеть" шлем на персонажа, его объект должен содержать соответствующий "слот". В моём понимании, это свойство hatUsed:ItemHat класса Character. Соответственно, оно может быть либо пустым, если ничего не надето, либо туда будет помещаться один из экземпляров класса ItemHat. Вопрос, правильно ли я рассуждаю и правильно ли я представляю, что подобные вещи прорабатываются сразу в пакете data (а не model).

В-третьих, создав классы для предметов, где-то в программе необходимо создать и сами предметы, т.е. экземпляры классов. Где и каким образом обычно это делается? Я пока прямо в Main нафигачил несколько для теста, но это не комильфо. Плюс встаёт вопрос идентификации этих экземпляров. Если мы говорим не о "генерёнке", а об "именных" предметах или NPC, то для них сразу резервируется некая переменная нужного типа, в которую записывается экземпляр, верно?

В-четвёртых, возник ещё любопытный вопрос. Допустим, у персонажа может быть свойство, принимающее одно из заранее определённых значений (отвлечённо - это знак зодиака, чтобы было понятно, о чём идёт речь). Присвоенное персонажу значение учитывается игровой механикой в определённых ситуациях. Здесь можно было бы по аналогии создать класс Zodiac с 12 экземплярами по числу знаков и присваивать персонажу один из них. Но в описанной ситуации кроме собственно имени экземпляра для корректной работы больше ничего не требуется, и городить целый класс кажется излишним. С другой стороны, коллега wolsh предостерегал от замены Strong-типизации на String-типизацию. Где истина?

Спасибо!

caseyryan 20.10.2017 10:54

Цитата:

В моём понимании, это свойство hatUsed:ItemHat класса Character.
Это не гибкий подход. Что если ты захочешь добавить какой-то новый предмет, например ItemCap, вместо ItemHat? Тоже одевается на голову, но класс уже другой и в эту переменную не записать. При таком подходе придется каждый раз добавлять и новые свойства персонажу. Я бы сделал массив, в котором хранил экземпляры добавленных предметов. Сами придметы должны все расширять какой-то базовый класс, например Item, и добавляться персонажу они тоже должны как Item. В самом классе можно сделать несколько констант, которые отвечают за те свойства, которые модифицирует предмет, например так
Код AS3:

// в классе Item
public static const TYPE_HEALTH:String = "health";
public static const TYPE_ARMOR:String = "armor";
 
public var type:String = null; // назначается в наследниках
public var value:Number = 0;
 
// в конструкторе наследника
public function HatItem() {
    type = Item.TYPE_ARMOR; // шапка увеличивает защищенность
    value = .15 // на 15% от текущей защищенности персонажа
}
 
// в классе персонажа
private var _items:Array = [];
private var _health:Number = 100; // базовая величина здоровья, без
private var _healthIncrease:Number = 0; // величина прироста, которую могут давать преметы
private var _armor:Number = 50;
private var _armorIncrease:Number = 0;
 
public function addItem(newItem:Item):void {
    if (item) {
        for each (var item:Item in _items) {
            if (item.type == item.type) {
                  trace("предмет такого типа уже надет, сначала нужно снять его"); // если не нужно, чтобы игрок использовал предметы одного типа несколько раз
                  return;
            }
        }
        _items.push(newItem);
        calculateValues(); // пересчитываем показатели игрока после добавления нового предмета
 
    }
}
public function removeItem(item:Item):void {
    if (item) {
        var index:int = _items.indexOf(item);
        if (index > -1) {
            _items.removeAt(index);
        }
        calculateValues();
    }
}
 
private function calculateValues():void {
      _healthIncrease = 0;
      _armorIncrease = 0; // обнуляем все показатели, чтобы записать новые без багов
      for each (var item:Item in _items) {
          switch (item.type) {
              case Item.TYPE_HEALTH:
                    _healthIncrease = item.value;
                    break;
              case Item.TYPE_ARMOR:
                    _armorIncrease = item.value;
                    break;
          }
      }
}
 
// используем где надо с учетом прибавок
public function get health():Number {
    return _health + (_health * _healthIncrease);
}
public function get armor():Number {
    return _armor + (_armor* _armorIncrease);
}

как-то так

Цитата:

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

Wolsh 20.10.2017 13:59

В Скайриме например считается, что на голову может быть надет только один предмет — надеваешь капюшон, обруч снимается, надеваешь шлем — снимается капюшон.
Но когда добавили расширения с новыми миссиями и новыми предметами, кто-то лоханулся и получилось так, что предметы из этой новой коллекции можно надеть "поверх" других. В частности, фалмерский шлем можно надеть поверх обруча или капюшона.
Казалось бы ну и фиг с ним, баг и баг. Но фишка в том, что предмет это не просто предмет. На него можно накладывать зачарования, которые дают нехилые бонусы к навыкам или статам. И, нацепив на голову два предмета, повышающих искусство Лучника, ты завалишь целого дракона одной ржавой стрелой.
Так что не надо тут))) Система должна быть четкой и не давать преференций свыше правил.

Добавлено через 4 минуты
Цитата:

В-третьих, создав классы для предметов, где-то в программе необходимо создать и сами предметы, т.е. экземпляры классов. Где и каким образом обычно это делается?
Да по-сути предмет это просто ID. В инвентаре надо будет показать картинку — создашь экземпляр картинки. Надо показать свойства — вытащишь из справочника свойства.
Другое дело, если у предметов есть свой жизненный цикл, если они изнашиваются при каждом применении и т.п. То есть МЕНЯЮТСЯ свойства конкретных экземпляров.

Appleman 20.10.2017 18:16

Цитата:

Сообщение от caseyryan (Сообщение 1202497)
Это не гибкий подход. Что если ты захочешь добавить какой-то новый предмет, например ItemCap, вместо ItemHat? Тоже одевается на голову, но класс уже другой и в эту переменную не записать. При таком подходе придется каждый раз добавлять и новые свойства персонажу.

Ты меня неправильно понял. Если будет ItemHat, то никаких Cap-ов уже не будет, разумеется. И шлем, и шапка, и бандана будут относиться к одному наследнику Item. Итого получается ItemHat, ItemCoat, ItemBoots и так далее. А экземпляры каждого из классов - это уже сами предметы.

Цитата:

Ну, например в резделе инвентаря в магазине. И там же отображется что из них используется в данный момент
Цитата:

Да по-сути предмет это просто ID. В инвентаре надо будет показать картинку — создашь экземпляр картинки. Надо показать свойства — вытащишь из справочника свойства.
Другое дело, если у предметов есть свой жизненный цикл, если они изнашиваются при каждом применении и т.п. То есть МЕНЯЮТСЯ свойства конкретных экземпляров.
Джентльмены, вы меня по-моему неправильно поняли. Я имел в виду в каком месте кода, текста программы, создавать непосредственно экземпляры классов? То есть где писать var goodOldBandanna:ItemHat = new ItemHat и далее по тексту значения свойств?

Wolsh 20.10.2017 19:56

В чем его ответственность, этого экземпляра хорошей старой банданы?
Что он вообще должен уметь делать?
Не слишком ли много чести создавать для него класс?
Другими словами, что это вообще? Когда ты говоришь про этот экземпляр, что ты видишь? Что имеешь в виду?

caseyryan 21.10.2017 10:16

Цитата:

Ты меня неправильно понял. Если будет ItemHat, то никаких Cap-ов уже не будет, разумеется. И шлем, и шапка, и бандана будут относиться к одному наследнику Item. Итого получается ItemHat, ItemCoat, ItemBoots и так далее. А экземпляры каждого из классов - это уже сами предметы.
В чём тогда вопрос? Я целую схему написал, как это у меня работает
Цитата:

Не слишком ли много чести создавать для него класс?
А по мне так наоборот, хорошо бы класс создать для него. И там же сразу указать, какая вьюшка будет использоваться и настроить все необходимые параметры, от того, что он изменяет, до его персонального ID, который будет храниться в базе. Чтобы потом это все не прописывать там, где он создался (к примеру в инвентаре), а просто написать так:
Код AS3:

var _inventory = [
    new ItemHat(),
    new ItemCoat(),
    new ItemBoot(),
    // ...
];


Wolsh 21.10.2017 11:15

Я имел ввиду как то так
Код AS3:

//... Model / InventoryModel
_inventory.hat = 0xFD3490;
_inventory.boots = 0x5539A2;
_inventory.robe = 0xCA4D23;
//... InventoryView
_headSlot.add(_model.character.inventory.hat); // function add(itemID:uint)
//... InventoryCharacterSlot
this.image = Assets.getImage(itemID);
this.data = Items.getData(itemID);

Экземпляр должен что-то делать. Нет смысла в экземпляре(!) хранить какие-то неизменные данные, для этого максимум хватит класса со статическими константами. Экземпляры нужны только тогда, когда у них есть индивидуальность, жизненный цикл с сохранением изменений свойств. Если экземпляр всего лишь хранит набор неизменных свойств, то вместо класса достаточно идентификатора и таблиц со свойствами по идентификатору — тем более, когда таких "классов" подразумевается 100500 и все они хранят более-менее одинаковый набор свойств.


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

Copyright © 1999-2008 Flasher.ru. All rights reserved.
Работает на vBulletin®. Copyright ©2000 - 2026, Jelsoft Enterprises Ltd. Перевод: zCarot
Администрация сайта не несёт ответственности за любую предоставленную посетителями информацию. Подробнее см. Правила.