Форум Flasher.ru
Ближайшие курсы в Школе RealTime
Список интенсивных курсов: [см.]  
  
Специальные предложения: [см.]  
  
 
Блоги Правила Справка Пользователи Календарь Сообщения за день
 

Вернуться   Форум Flasher.ru > Flash > ActionScript 3.0

Версия для печати  Отправить по электронной почте    « Предыдущая тема | Следующая тема »  
Опции темы Опции просмотра
 
Создать новую тему Закрытая тема
Старый 14.09.2017, 11:46
Appleman вне форума Посмотреть профиль Отправить личное сообщение для Appleman Найти все сообщения от Appleman
  № 31  
Appleman
 
Аватар для Appleman

Регистрация: Dec 2014
Адрес: Санкт-Петербург
Сообщений: 479
Цитата:
Сообщение от Wolsh Посмотреть сообщение
Потому что в моем тексте нет именительного. "окажется дочкой Маши Шараповой" это Родительный.
И всё равно есть ошибка, т.к. i перебирается плоть до значения 6, а значит, включая 0 для именительного падежа, один должен быть лишний, т.к. падежей всего шесть

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

Уже кратко спрашивал, теперь постараюсь подробнее сформулировать суть моего вопроса и альтернатив. Продумывая игровых персонажей и их механики, вывел 3 группы: npc, ключевые npc и сам игрок. Количество свойств увеличивается от npc до игрока. Когда дошла очередь до проектирования классов, я нарисовал табличку, где в столбцы поставил эти группы, а в строки - свойства. А дальше ставил на пересечении галочки, используется ли данное свойство или нет. По итогу получился такой расклад: совсем небольшое количество базовых свойств попали во все три группы (имя, ID, пол и т.п.), некоторое количество оказалось уникальным для персонажа игрока, ещё небольшая группа оказалась общей для npc и ключевых npc, наконец, пачка уникальных свойств только для ключевых npc. Итого 4 "профиля вхождения". Они определили вот такую структуру наследования классов:

Код AS3:
Charactrer - базовые свойства, общие для всех персонажей
          |   |
          |    - Character_hero - главный герой
          |
           - Character_npc - общие свойства для неписей и ключевых неписей
                      |
                       - Character_npc_key - уникальные свойства для ключевых неписей
Важное замечание. Некоторые игровые действия могут осуществляться над персонажами каждой из групп, при этом их результаты будут вычисляться по-разному (т.е. несколько разные формулы для игрока, ключевого npc и прочего npc).

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

Что остаётся? Первое, оставить как есть сейчас, для расчётов игровой механики писать классы с абстрактными методами для каждого из подклассов персонажей, т.е. воспользоваться прелестями полиморфизма (или зря я столько книжек прочитал!). Но смущает, что во-первых, дерево наследование кривое получается (вопрос, повлияет ли этот факт на работу абстрактных методов и вообще, насколько подобный перекос допустим), плюс много писанины - по 3 подкласса на каждый класс с расчётами. При условии, что ни в близком, ни в отдалённом времени я не планирую вводить другие группы персонажей (для которых было бы как раз удобно добавить отдельных потомков), всё это выглядит перебором и необоснованным усложнением.

Вторая альтернатива - забить на наследование, собрать все свойства в один класс Character, а для того, чтобы различать, кто есть ху, добавить в класс соответствующее свойство-указатель, типа "player", "npc" или "key_npc" и присваивать его при создании каждого нового персонажа. Избавляемся от всего головняка с наследованием, но обрекаем себя на добавление конструкции switch или подобной во все методы, различающиеся для групп персонажей.

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

Буду признателен за развёрнутый ответ.

Старый 14.09.2017, 18:26
Wolsh вне форума Посмотреть профиль Отправить личное сообщение для Wolsh Найти все сообщения от Wolsh
  № 32  
Wolsh
Нуб нубам
 
Аватар для Wolsh

модератор форума
Регистрация: Jan 2006
Адрес: Бердск, НСО
Сообщений: 6,445
Цитата:
i перебирается плоть до значения 6
Это еще с какого перепугу? Учите язык.
__________________
Reality.getBounds(this);

Старый 14.09.2017, 21:23
Appleman вне форума Посмотреть профиль Отправить личное сообщение для Appleman Найти все сообщения от Appleman
  № 33  
Appleman
 
Аватар для Appleman

Регистрация: Dec 2014
Адрес: Санкт-Петербург
Сообщений: 479
Цитата:
Сообщение от Wolsh Посмотреть сообщение
Это еще с какого перепугу? Учите язык.
Ещё раз посмотрел. Не прав. Сам дурак.

Старый 23.09.2017, 01:43
Appleman вне форума Посмотреть профиль Отправить личное сообщение для Appleman Найти все сообщения от Appleman
  № 34  
Appleman
 
Аватар для Appleman

Регистрация: Dec 2014
Адрес: Санкт-Петербург
Сообщений: 479
Друзья!

Я продолжил свои изыскания в проектировании классов будущей игры и возник новый вопрос. Появился он при переходе от базовых свойств персонажа к специфическим: которые выделяются для пола, профессии и т.п. Пусть условно для мужчин учитывается длина бороды, а для женщин - объём талии. У меня получилось следующее. Я создал новый класс Gender с единственным свойством genderID, которое может принимать значения 0 для женского пола и 1 для мужского, и унаследовал от него два класса GenderMale и GenderFemale. В первом соответственно свойство beardLength, во втором - waistVolume, плюс set- и get-методы для каждого.

Тогда в классе персонажа Character добавился такой set-метод:
Код AS3:
public function set gender(newGenderID:uint):void //Пол
		{
		switch (newGenderID) 
			{
				case 1:
					_gender = new GenderMale(newGenderID);
					break;
				case 0:
					_gender = new GenderFemale(newGenderID);
					break;
				default:
					throw new Error ("Пол персонажа может иметь значение 0-female или 1-male");
			}
		}
Экземпляр класса Character теперь имеет экземпляр класса-потомка Gender в приватной переменной _gender.
Вопрос такой. Чтобы задать либо получить значения свойства, связанного с полом, приходится писать такой код. Например, для нашей бороды:

В классе Character:
Код AS3:
public function set beardLength(bewBeardLength:Number):void {_gender.beardLength = bewBeardLength; }
Теперь в Gender:
Код AS3:
public function set beardLength(bewBeardLength:Number):void {}
Наконец, в GenderMale:
Код AS3:
override public function set beardLength(bewBeardLength:Number):void {_beardLength = bewBeardLength}
Аналогично с get-методом. В принципе работает, но как-то чересчур громоздко выглядит. И этим активно не нравится. Если на каждое подобное свойство писать методы в трёх местах, то это получится мясо и фарш, а не код. Обращаться напрямую character._gender.beardLength тоже не выходит, т.к. переменная _gender объявлена как private и менять её статус не вижу никакого резона. в общем, need help. Заранее спасибо.

Старый 23.09.2017, 12:18
Wolsh вне форума Посмотреть профиль Отправить личное сообщение для Wolsh Найти все сообщения от Wolsh
  № 35  
Wolsh
Нуб нубам
 
Аватар для Wolsh

модератор форума
Регистрация: Jan 2006
Адрес: Бердск, НСО
Сообщений: 6,445
1. Если у тебя в Gender объявлена function set beardLength() то она будет и у Женщин, так?
2. Зачем в конструкторы Мужского и Женского пола передается еще и идентификатор? Ты же не собираешься делать экземпляр Мужчины со значением "женщина"? Да вроде и switch не позволит. Тогда зачем?
3. Конвенции просят не называть параметр сеттера как Бог черепаху, но всегда просто "value". Почему так? Потому что название сеттера уже несет необходимый смысл, а если нет то это плохое название сеттера. Он принимает значение для свойства с этим названием — ведь он хоть и функция, но прикидывается свойством. Поэтому как-то еще глубокомысленно называть параметр, который станет этим самым свойством с этим самым названием как-то очень странно. Так же принято называть внутреннее хранилище (приватную переменную, к которой доступ через геттер/сеттер) точно так же, как геттер/сеттер (только с подчеркиванием), потому что она собственно и есть это самое СВОЙСТВО. У тебя, в частности, грубейшее нарушение этого принципа: есть сеттер gender типа uint, а свойство _gender имеет тип Gender. Таким образом у твоего характера снаружи "гендер" это просто число 1 или 0, а внутри это целый экземпляр Мужика с бородой и талией.

Теперь о смысловой нагрузке.
Я думаю ты и сам видишь, что вместо абстрагирования получилась какая-то каша. До тех пор, пока пол Характера не имеет значения, все прекрасно, ты можешь обращаться с ним как просто с Человеком. Но как только встает вопрос пола, начинается катавасия — тебе приходится протаскивать в класс Характер ВСЕ половые признаки, и мужские и женские, и совершенно непонятно зачем вообще был нужен класс Gender, да еще и с подклассами Джентельмен и Мадмуазель, если ВСЕ их свойства вынужден представлять класс Характер, и даже как транспортный дата-обжект (для обмена данными) эти гендеры использовать нельзя, ибо доступ к ним как объектам наглухо закрыт.
Лично мне ошибкой видится именно эта паническая инкапсуляция Гендера. Надо открыть к нему доступ напрямую, а не прокидывать все сеттеры/геттеры в Характер. В чем смысл, если доступ к этим свойствам ВСЕ-РАВНО есть, только с бубном вокруг деревни. Скрывать надо то, что другим НЕ НУЖНО знать. В чем смысл сокрытия гендера, мне непонятно.
Сама идея собирать какие-то свойства определенного назначения в отдельные блоки нормальная. Это используется в нативных классах, например такие свойства визуальных объектов как .filters или .transform, или .defaultTextFormat у TextField.
__________________
Reality.getBounds(this);

Старый 23.09.2017, 16:43
Appleman вне форума Посмотреть профиль Отправить личное сообщение для Appleman Найти все сообщения от Appleman
  № 36  
Appleman
 
Аватар для Appleman

Регистрация: Dec 2014
Адрес: Санкт-Петербург
Сообщений: 479
Wolsh, спасибо за очередную порцию ликбеза. Отвечаю по пунктам:

Цитата:
1. Если у тебя в Gender объявлена function set beardLength() то она будет и у Женщин, так?
Типа того, я опять перепутал тёплое с мягким Оставляем бороду только для мужиков, а талию - только для женщин. Вопрос снят.

Цитата:
2. Зачем в конструкторы Мужского и Женского пола передается еще и идентификатор? Ты же не собираешься делать экземпляр Мужчины со значением "женщина"? Да вроде и switch не позволит. Тогда зачем?
Разумеется, не собираюсь. Я исходил из того, что должен быть идентификатор. Если посмотреть эту тему выше, то например, у нас есть класс-хранитель расшифровок к значениям свойств. Мне кажется, очень удобно и логично добавлять к идентификатору свойства идентификатор пола, чтобы получать:

Код AS3:
static private const HINTS:Object =
{
("Intelligence" + GlobalValues.GENDER_MALE as String): 	["умный", "дурак"],
("Intelligence" + GlobalValues.GENDER_FEMALE as String): 	["умная", "дура"]
}
Сделал без передачи в конструктор. Объявил переменную _genderID как protected и в подклассы добавил назначение идентификатора прямо в метод-конструктор:

Код AS3:
public function GenderMale():void 
		{
			_genderID = GlobalValues.GENDER_MALE;
 
		}
Цитата:
3. Конвенции просят не называть параметр сеттера как Бог черепаху, но всегда просто "value". Почему так? Потому что название сеттера уже несет необходимый смысл, а если нет то это плохое название сеттера. Он принимает значение для свойства с этим названием — ведь он хоть и функция, но прикидывается свойством. Поэтому как-то еще глубокомысленно называть параметр, который станет этим самым свойством с этим самым названием как-то очень странно. Так же принято называть внутреннее хранилище (приватную переменную, к которой доступ через геттер/сеттер) точно так же, как геттер/сеттер (только с подчеркиванием), потому что она собственно и есть это самое СВОЙСТВО. У тебя, в частности, грубейшее нарушение этого принципа: есть сеттер gender типа uint, а свойство _gender имеет тип Gender. Таким образом у твоего характера снаружи "гендер" это просто число 1 или 0, а внутри это целый экземпляр Мужика с бородой и талией.
Всё, сообразил. Получается, что метод для присвоения пола лучше обозвать как-то иначе, раз он не подходит под понятие сеттера. А геттер в таком случае должен выдавать непосредственно хранящийся в переменной _gender экземпляр одного из подклассов Gender, верно? То есть правильный код для геттера:

Код AS3:
		public function get gender():Gender
		{
			return _gender;
 
		}
Хотя в контексте того, что ты написал далее, само наличие сеттеров и геттеров для гендера в классе Character вызывает вопрос.

Цитата:
Лично мне ошибкой видится именно эта паническая инкапсуляция Гендера. Надо открыть к нему доступ напрямую, а не прокидывать все сеттеры/геттеры в Характер.
Спасибо, разобрался. Переименовал переменную _gender в gender и объявил её как public в классе Character, чтобы напрямую обращаться к свойствам как character.gender.'имя свойства'. Ты ведь это подразумевал?

Теперь появилась проблема. Если раньше было легко по идентификатору вытащить значения свойства, написав character[propID], где строковая переменная propID содержит название соответствующей переменной в классе Character, например "intelligence", то теперь, указав в propID = "gender.beardLength", выдаёт ошибку Можно как-то подтянуть?


Последний раз редактировалось Appleman; 23.09.2017 в 18:01.
Старый 23.09.2017, 21:38
Wolsh вне форума Посмотреть профиль Отправить личное сообщение для Wolsh Найти все сообщения от Wolsh
  № 37  
Wolsh
Нуб нубам
 
Аватар для Wolsh

модератор форума
Регистрация: Jan 2006
Адрес: Бердск, НСО
Сообщений: 6,445
Цитата:
объявил её как public
Тут есть одна проблема, аж двухэтажная. Этаж первый: даже если ты полностью заменишь экземпляр Гендер на другой, Характер об этом не узнает. Он просто будет хранить на борту этот новый гендер. Для того и делаются сеттеры, чтобы что-то предпринять в случае замены значения свойства, например активировать перерисовку бабы в мужика. Второй этаж точно такой же, но еще тоньше) Характер никогда не узнает о изменении какого-то из свойств своего гендера. Это общая проблема всех свойств со сложным типом: всегда приходится "вручную" делать обновление, если требуется моментальное применение новых свойств сложного свойства То есть, если объект, хранящий сложное свойство, должен как-то среагировать на изменение одного из параметров этого свойства. Недостаточно написать _textField.defaultTextFormat.bold = true; ведь TextField никак не узнает об этом изменении свойства bold. Применение свойств объекта TextFormat в текстФилде происходит в сеттере set defaultTextFormat(value:TextFormat), то есть когда текстФилду назначается новый текстФормат, его свойства "разбираются" и применяются. А изменение какого-то свойства "на ходу" никак не отрабатывается текстФилдом — он об этом даже не узнает. Приходится делать не очень красивый финт типа
Код AS3:
_textField.defaultTextFormat.bold = true;
_textField.defaultTextFormat = _textField.defaultTextFormat;
Как более продвинутый вариант можно устроить отправку События CHANGE из такого объекта (гендера, например) и в обработчике выполнить заново сеттер set gender(value:Gender) с разбором и применением всех свойств объекта гендер.

По поводу character[propID] — ну чтож, теперь надо считаться с тем что это свойства не Характера а Гендера, то есть character.gender[propID].
__________________
Reality.getBounds(this);

Старый 24.09.2017, 01:17
Appleman вне форума Посмотреть профиль Отправить личное сообщение для Appleman Найти все сообщения от Appleman
  № 38  
Appleman
 
Аватар для Appleman

Регистрация: Dec 2014
Адрес: Санкт-Петербург
Сообщений: 479
Цитата:
Сообщение от Wolsh Посмотреть сообщение
Тут есть одна проблема, аж двухэтажная. Этаж первый: даже если ты полностью заменишь экземпляр Гендер на другой, Характер об этом не узнает.
Идею понял, но в деталях пока разбираться не стал. Полагаю, рано или поздно у меня произойдёт встреча с этой проблемой, тогда плотнее подумаю над этим. На данном этапе операций по перемене пола персонажа не планируется

Цитата:
Приходится делать не очень красивый финт типа
Код AS3:
_textField.defaultTextFormat.bold = true;
_textField.defaultTextFormat = _textField.defaultTextFormat;
Не совсем понял результат выполнения данного кода. Получается, в первой строке мы изменили значение какого-то отдельного свойства экземпляра класса, а затем обновили сам экземпляр, чтобы сохранить там произведённое изменение. Так?

Цитата:
По поводу character[propID] — ну чтож, теперь надо считаться с тем что это свойства не Характера а Гендера, то есть character.gender[propID].
Получается, написать в строковом идентификаторе "gender.'имя свойства'" не прокатит. Тогда мне видится два возможных варианта. Либо создавать отдельный класс для подбора и вывода словесных описаний для гендерных свойств, по факту полный дубликат уже имеющегося класса, где вместо обращения character[propID] будет прописано character.gender.[propID]. Либо всё-таки "протаскивать" гендерные свойства через класс character, то есть например, для нашей бороды писать в классе Character:

Код AS3:
public function get beardLength():Number
{
return(gender.beardLength);
}
Что будет предпочтительнее? Вернее, чем будет определяться выбор того или иного варианта?

Старый 24.09.2017, 21:55
Wolsh вне форума Посмотреть профиль Отправить личное сообщение для Wolsh Найти все сообщения от Wolsh
  № 39  
Wolsh
Нуб нубам
 
Аватар для Wolsh

модератор форума
Регистрация: Jan 2006
Адрес: Бердск, НСО
Сообщений: 6,445
Цитата:
Не совсем понял результат выполнения данного кода.
В первой строке меняется значение свойства bold объекта TextFormat, который хранится в данном экземпляре TextField. При этом сам TextField ничего об изменении не знает, ведь его собственным свойствам никакие новые значения не присваивались и его методы не вызывались.
Во второй строке вызывается сеттер самого TextField: "_textField.defaultTextFormat = " и ему отдается объект TextFormat, полученный из геттера _textField.defaultTextFormat. То есть тот самый объект, в котором значение свойства .bold теперь true. Cеттер это функция, она не просто присваивает этот ТекстФормат внутреннему хранилищу (он итак там лежит). Сеттер делает что-нибудь еще: считывает свойства переданного ему объекта ТекстФормат и "применяет" их "прямо сейчас".
(может пример с ТекстФорматом и не совсем корректен ввиду того что там не требуется это "прямо сейчас", но вот если ты захочешь рычажком слайдера менять длину бороды в редакторе персонажа, то просто менять одно из свойств объекта Гендер будет недостаточно, чтобы видеть изменение в реальном времени).

Цитата:
Что будет предпочтительнее?
Знать, что в этом месте программы тебе нужны настройки внешности персонажа и они лежат в объекте класса Гендер. Не надо чрезмерно увлекаться "String-типизацией" в ущерб strong-типизации. Не лишай себя удовольствия получать сообщения об ошибках на этапе компиляции, а не где-то в глубине игрового процесса.
__________________
Reality.getBounds(this);

Старый 24.09.2017, 22:55
Appleman вне форума Посмотреть профиль Отправить личное сообщение для Appleman Найти все сообщения от Appleman
  № 40  
Appleman
 
Аватар для Appleman

Регистрация: Dec 2014
Адрес: Санкт-Петербург
Сообщений: 479
Цитата:
Знать, что в этом месте программы тебе нужны настройки внешности персонажа и они лежат в объекте класса Гендер. Не надо чрезмерно увлекаться "String-типизацией" в ущерб strong-типизации. Не лишай себя удовольствия получать сообщения об ошибках на этапе компиляции, а не где-то в глубине игрового процесса.
Получается, всё-таки рекомендуешь более прямолинейно писать методы по отдельности для character и gender. В принципе, ничего экстраординарного тут нет, т.к. заранее всегда известно, какие свойства где живут. Просто не хотелось дублировать код.

Мне тут ещё один вариант придумался. Может быть в классе AttributeHints первым делом выяснять, в каком классе "живёт" нужное нам свойство, и в зависимости от результата формировать обращение либо в character, либо в character.gender. Единственное, что смог найти, это метод hasOwnProperty(), но он работает только для классов типа Object. Есть ли что-то подобное для использования в своих классах?

Создать новую тему Закрытая тема Часовой пояс GMT +4, время: 10:28.
Быстрый переход
  « Предыдущая тема | Следующая тема »  

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.


 


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


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