модель ничего не должна знать о контроллере и о вьюхе, контроллер ничего не знает о вьюхе, он только управляет данными в модели, ну а вьюха сама берет модель и по данным из нее уже рисует объект
prog, согласен. Но я даже не стал выбирать между способами реализации связи модели и представления, а просто отказался от отдельных объектов представления и в жирном отрисовщике жестко распределяю кого как рисовать. Дёшево и сердито. :)
alexprey, ага, понял. Ты как хранилку его и задумывал. Меня абстрактность сбила. Самое интересное как раз в том, как его собрать - как сопоставить модели с остальными потрохами, если они динамически появляются и исчезают в процессе игры.
>Хотя на самом деле я считаю, что модель и вьюха этого игрового объекта не разделима.
Гради Буч смотрит на тебя с укором. :)
alexprey, потому что это перемешивание логики и представления. Разнос этого всего по интерфейсам делает перемешивание ещё более явным, AGameObject говорит нам прямым текстом: я и модель, и отрисовщик, и даже пользовательский ввод разбирать умею! Плевал я на вашу инкапсуляцию с четвёртого этажа. :)
...впрочем что-то такое вполне можно использовать в качестве сборной хранилки данных об объекте из разных мест. Т.е. после того, как мы сопоставили модель и её отрисовщик, можно положить это всё в подобную структурку. Но, конечно, не абстрактную, без публичных сеттеров и без разбора объектом конкретных нажатых кнопок клавиатуры - этим должен заниматься кто-то другой.
Map во внешнем менеджере. Это более ресурсоемкий вариант, зато позволяет полностью абстрагировать логику от представления.
Боюсь, при отрисовке придётся шерстить этот несчастный map'а для получения каждого объекта. Линейный рост трудоёмкости с увеличением количества объектов умножается на логарифмический рост сложности выборки из map'а. Я бы предпочёл за это не платить вовсе, сопоставив модель и представление только один раз при создании представления.
awesomesk1ll, ку3 тут не будет ни при каком раскладе. :) Управление я уже перебалансировал, но суть осталась та же.
Я просто упростил разгон, т.к. человек со скиллом всё равно также разгоняется до максимальной скорости не задумываясь и не ощущая этого, в итоге плохо только новичкам.
Я ликвидировал багу, когда после прямого куска пытаешься делать петлю, а она не разгоняет, т.к. направлена в ту же сторону что и предыдущий поворот.
Сделал плавнее рост максимальной скорости от длины червя, раньше там скачками было
При подготовке к прыжку, когда червь поднимает голову над землёй теперь можно ей крутить на 360 градусов, чтобы выбирать направление прыжка.
Сделал немасштабирующуюся с ростом червя плавность управления прыжком в полёте
Если червь продолжает маневрировать, то он не теряет скорости, только набирает. Раньше он постоянно тормозил, а изгибами получал компенсирующее ускорение. В итоге игрок каждое движение чувствовал, что червь замедляется, что нужно давить его вперёд. Даже у меня от этого ощущения деревенели пальцы от желания разогнаться быстрее. Сделал бесштрафное скольжение в поворотах - скорость червя не изменилась, поменялась динамика и ощущение от неё - меньше фрустрации.
Короче, упрощение управления не есть упрощение концепции управления, просто я плавненько шлифую углы, которые досаждают новичкам. Скоро будет релиз альфы 3.5 - там кроме деревьев и коррекции управления ничего нового не будет, вот там затестишь. :)
По идее, если для отрисовки объекта не нужно хранить состояния переменных специфичных для отрисовки, то в игровом движке никаких забот о рендере и быть не должно. Просто есть набор игровых объектов, по которым пробегается отрисовщик и так или иначе решает вопросы рисования.
Если хранить состояние нужно, то придётся чуть-чуть испачкаться. В минимальном варианте игровой объект должен уметь прицепить к себе внешнюю ссылку и предоставлять её по требованию. Я бы назвал это IBindable (потому как слов IRenderable в игровом движке не должно быть). Пробегаясь по объектам отрисовщик приделывает к игровым объектам объекты отрисовки из параллельной иерархии. Если у игрового объекта уже ассоциирован объект отрисовки - тогда не трогать, если нет (значит только что создали его) - создать и прицепить.
Например:
Игровой объект - зомби, у него есть координата и направление движения. Объект его отрисовки хранит у себя номер текущей анимации ходьбы и при отрисовке выводит нужный спрайт с нужным углом поворота.
Теперь представляем пачку зомби на карте. Как только в отрисовщик приходит игровой объект "Зомби" без ассоциированного объекта отрисовки, к нему приделывается свежый объект отрисовки, начинающий считать кадры анимации. Зомбаков много, ои находятся в разных стадиях анимации, которые хранятся в ассоциированных с ними объектами отрисовки. Мы разделили логику (координата, направление движения) от представления (выбор спрайта, номер кадра анимации) ценой одной внешней ссылки в игровом объекте.
По слоям разбрасывается раньше, тут этого просто нет. DrawWorm просто рисует червя на текущем слое и вызывается ровно только раз, на скольких слоях есть объект Worm. А вся кухня по слоению, бантчингу и сортировке находится внутри метода DrawScene() до прохода по слоям и вызовов DrawXXX().
Я бы сделал почти аналогично, но ... наследование использовал и ... всё рисование ... в классах игровых объектов
В данном случае "почти", это перемешивание логики с представлением. Покайся, пока не поздно! :)
Жирный плюс за разделение логики объекта и его отображения.
Спасибо :) На самом деле можно разделять и с методом Draw, просто получается морока с двумя параллельными иерархиями объектов. Одна иерархия в игровом движке - это сугубо логика, а вторая иерархия уже с объектами отрисовки. Причём иерархии разные. Я в одном своём проекте так заморачивался, пользуясь возможностями C++ по множественному наследованию, но в текущем, "Несыти", не стал. Оставил только иерархию объектов в игровом движке + жирный класс отрисовщика, который всё про то, как рисовать игровые объекты знает.
А можешь небольшой примерчик кода как эта штука работает? С жирным отрисовщиком и конкретным объектом.
Кода дать не могу, окно треснет, а словами опишу. У меня движок спрайтовый, сцена слоёная. Например, есть слой с ландшафтом, есть слой с тенями наземных существ, есть слой с наземными существами, дальше тени высоких объектов, отбрасываемые на наземных существ и т.д. Некоторые объекты занимают несколько слоёв - у фонаря есть основание со своей тенью, спрайт света и верхняя часть. Внутри некоторых слоёв требуется сортировка спрайтов по тому или иному признаку - иногда просто по координате Y, иногда сложнее - звенья у червя, например, должны отрисовываться от хвоста к голове, чтобы наложения корректные были.
Имеем коллекцию объектов из игрового движка, которые нам нужно отрисовать в виде сцены. Есть полтора десятка слоёв - таких же коллекций объектов.
В зависимости от типа объекта заталкиваем его в каждый слой, в котором он отрисовывается.
Сортируем нужные слои нужным способом
Отрисовываем слои последовательно снизу вверх, рисуя от объекта в слое только его соответствующую часть.
Этим всем занимается отрисовщик. Пока различных объектов и слоёв было немного, я всё разруливал на switch'ах, но, в итоге, пришел к пачке методов у отрисовщика типа DrawXXX(Layer layer), где XXX - имя объекта. Короче, к одному методу Draw я и пришел, только при отсутствии иерархии отрисовываемых объектов - методы отрисовки плавают в воздухе, а применяются к объектам из игрового движка, в которые отрисовка не вмешивается, это вообще другая сборка.
но думаю во всех самописных движках что-то вроде этого ))
Нет. У меня, например, объекты сами себя рисовать не умеют. За них это делает жирный клас отрисовщика, который их сортирует, группирует, солит по вкусу и только потом рисует. Но можно и с методом Draw у каждого. Каждый онанирует, как ему импонирует.
Я это называю графическим движком. А отрисовщик, это тот, кто конкретные игровые сущности на экран рисует, используя графический движок. Тот самый, который говорит "нарисуй мне здесь круг".
sb3d, если учесть плотность, с которой ты пишешь код (я видел скрин на Геймдеве), то в этом 1,5 мегабайтном файлике должно быть несколько "Войн и Миров". Можно сделать шмап-скроллер, где нужно лететь по твоему исходнику, отстреливать комментарии и поедать операторы. :)
Я под «бонусом» имею в виду кратковременный рандомный эффект меняющий геймплей. Из разряда отравлений, потери цветного зрения и прочего. Встряхнуть игрока, чтобы он снова почувствовал удовольствие от простых вещей типа контроля над червём. :)
У меня похожий процесс в проекте. На работе я делаю как положено - дроблю на функции, оборачиваю в объекты, а в домашнем проекте можно не думать о тех, кто будет читать код, и делать всё под себя. Я разделяю объекты/методы на части только тогда, когда они перестают умещаться в моей голове. А это сильно реже, чем требуется по этикету.
В итоге объектный подход потихоньку вырождается в процедурный. Есть большие жирные классы типа "Отрисовщик сцены", "Графический движок", "Игровой движок" внутри которых просто вызовы процедур-методов. Местами, конечно, есть наследование, иерархия и прочее, но только при необходимости. Не перед кем демонстрировать трушность ООП.
Кет, он совсем не прикольный, это отрицательный бонус. В таком режиме вряд ли кто-то станет играть. А бонусом это можно время от времени включать для разнообразия. Чтобы не всё коту масленица.
LongbowMan, может оно в динамике и не так пёстро? Хотя на скрине, согласен, кажется что задний план, это передний и главный герой будет ползти по стене, цепляясь за края этих листов металла.
sb3d, привет! Думал, первоначально так и вообще и было. Но оказалось, что это лишает игрока возможности делать виражи, складываться в кольца, игрок вынужден постоянно мониторить свой хвост и быть в напряге. Короче, удовольствия мало, движения скованы и ограничены. Выбросил и всё завертелось.
Когда я доберусь до рандомных бонусов (от спец. жуков или ягодок) я сделаю ретро-бонус. Вот там, думаю, будет и временное отъедание собственного хвоста и повороты под прямым углом. Причём под прямым углом относительно начального угла, т.е. червь будет немного под углом к сторонам экрана, но внутри траектория будет с прямыми углами (кроме мест, где наткнётся на препятствие).
Nikson12, тут уже четыре страницы комментов, там много чего было. Не повод ругаться, мне приятно рассказать о своей игре ещё немножко. :)
Ред. Kozinaka
» Бродилка / [Лог #7] Класс рисовальщика.
» Бродилка / [Лог #7] Класс рисовальщика.
Гради Буч смотрит на тебя с укором. :)
Ред. Kozinaka
» Бродилка / [Лог #7] Класс рисовальщика.
Ред. Kozinaka
» Несыть / Переработка существ (часть 1)
» Несыть / Несыть
Ред. Kozinaka
» Бродилка / [Лог #7] Класс рисовальщика.
» Бродилка / [Лог #7] Класс рисовальщика.
Ред. Kozinaka
» Бродилка / [Лог #7] Класс рисовальщика.
Ред. Kozinaka
» Бродилка / [Лог #7] Класс рисовальщика.
Ред. Kozinaka
» Программирование / Новведения в C# 6.0
» Несыть / Переработка существ (часть 1)
» Бродилка / [Лог #7] Класс рисовальщика.
» Бродилка / [Лог #7] Класс рисовальщика.
Ред. Kozinaka
» Роглайк «Долго и трудно» / Роглайк «Долго и трудно»
» Блог им. AlexPrey'я / XGM Update Log
» Несыть / Несыть
Ред. Kozinaka
» Роглайк «Долго и трудно» / Роглайк «Долго и трудно»
» Несыть / Несыть
Ред. Kozinaka
» Роглайк «Долго и трудно» / Роглайк «Долго и трудно»
» Программирование / Обработка событий SFML
Мода не слишком быстро перетекает в реальную эксплуатацию.
» Ootahice / Отчет #3 (29/01/15)
» Роглайк «Долго и трудно» / Роглайк «Долго и трудно»
Ред. Kozinaka
» Роглайк «Долго и трудно» / Роглайк «Долго и трудно»
» Роглайк «Долго и трудно» / Роглайк «Долго и трудно»
» Несыть / Несыть