Модульный объект: как это работает в «Аллодах Онлайн».
description
Transcript of Модульный объект: как это работает в «Аллодах Онлайн».
www.mail.ru
Михаил Казаков Старший программист, команда «Аллодов Онлайн»
Модульный объект: как это работает в Аллодах
www.mail.ru 2
Организация игровых объектов
???
www.mail.ru 3
Игровой объект с позиции ООП
• Жесткая иерархия объектов• Разрабатывается на этапе планирования игры• Легко поддерживается– Логика внутри объекта– Зависимости видны явно
• Если дизайн не менять
• А если менять?
www.mail.ru 4
• В конечном итоге– Class UberObject– Весь код в одном классе– Непонятно, где чья логика– Каша из зависимостей– Трудно что-то добавить
• Не доводите до такого { }Игровой объект с позиции ООП
class MyObject
www.mail.ru 5
Объекты в «Аллодах»
Entity
Creature Device Ship
Avatar Mob
www.mail.ru 6
Объекты в «Аллодах»
Entity
Creature Device Ship
Avatar Mob
AstralMob
www.mail.ru 7
Объект «Астральный моб»
• Мозг• Сотворение заклинаний
• Атака кораблей• Перемещение
• Он же Ктулха
www.mail.ru 8
Объект «Обломки корабля»
• Движение• Стрельба• Перевозка игроков• Взаимодействие с ктулхами
• Подбор кораблями
www.mail.ru 9
Модульный объект Аллодов
• Общий контейнер– Хранит компоненты, предоставляющие интерфейсы– Отображение интерфейсов в их компоненты– Интерфейс указывается явно при добавлении– Умеет get() и put()– Больше ничего не умеет
• Интерфейс компонент– Сам по себе не умеет ничего
www.mail.ru 10
Модульный объект Аллодов
• Создание объекта
Bunch createMyObject() {final Bunch myObj = new Bunch();final Health health = new Health(100);myObj.addPart(Health.class, health);return myObj;
}
www.mail.ru 11
Модульный объект Аллодов
• Получение определенной запчасти
void doSomething(@NotNull Bunch obj) {final Health health
= obj.getPart(Health.class);health.consume(30);
}
www.mail.ru 12
Модульный объект Аллодов
• Не спрашивайте, что это за объект• Спросите, умеет ли он то, что вам нужно?
if(myObj instanceof MyClass) {// Wrong way :(
}if(myObj.getPart(MyPart.class)!=null) {
// Right way :)}
www.mail.ru 13
Объекты можно собирать «на лету»
void assemble(@NotNull Bunch myObj) {myObj.addPart(Health.class, new Health(100));myObj.addPart(IFFOwner.class, new IFFOwner());<...>
}
• Таких функций может быть много
www.mail.ru 14
Знаем только про то, что нам нужно
void affect(@NotNull Bunch myObj) {final Mortal mortal = myObj.getPart(Mortal.class);final Health health = myObj.getPart(Health.class);if(health.getLevel() < 50.f)
mortal.die();}
• Нет зависимостей на тип объекта• Нет зависимостей, полученных «в нагрузку»
www.mail.ru 15
Взаимодействия - между компонентами
Object
Part
Part
Part
Object
Part
Part
Part
Part
www.mail.ru 16
void transform(@NotNull Bunch myObj) {myObj.removePart(CannonTargetInfo.class);
myObj.removePart(ShipCollisionHandler.class);myObj.addPart(WreckCollisionHandler.class,
new WreckCollisionhandler());}
• Можно заменять реализации интерфейсов
Можно изменять поведение объекта
www.mail.ru 17
void mortalTest () {final Mortal mortal = new Mortal();Assert.assertFalse(mortal.isDead());mortal.die();Assert.assertTrue(mortal.isDead());
}• Объект целиком создавать не обязательно• Можно и более сложные функциональные тесты
Легко тестировать
www.mail.ru 18
Куда положить редко нужную логику
Объект
Объект
ОбъектОбъект
Объект
Объект
Объект
Объект
www.mail.ru 19
Куда положить редко нужную логику
Какое-то событие
Объект
Объект
ОбъектОбъект
Объект
Объект
Объект
Объект
www.mail.ru 20
• В стандартном подходеvoid someInternalProcessing() {<...>if(eventActive)
doExtraLogic();<...>
}void itHappened(@NotNull MyObj obj) {obj.eventActive = true;
}
Куда положить редко нужную логику
www.mail.ru 21
• В модульном подходеclass ExtraLogic implements BunchPart {void doExtraLogic() {
// Extra logic goes here}
}
void itHappened(@NotNull Bunch obj) {obj.addPart(ExtraLogic.class, new ExtraLogic());
}
Куда положить редко нужную логику
www.mail.ru 22
Пример использования «редкой логики»
Обновление позиции
Сканирование
www.mail.ru 23
Можно применять и для других целей
Сервис
Сервис
Сервис
Компонент
Компонент
Компонент
www.mail.ru 24
Недостатки
www.mail.ru 25
void process(@NotNull Bunch obj) {if(obj.getPart(RequiredPart.class) == null) {
// И что теперь делать?}<...>
}
• Например, заклинания, наносящие урон по площади
Подходит нам объект или нет?
www.mail.ru 26
void assebleObj(@NotNull Bunch obj) {obj.addPart(Part1.class, new Part1());obj.addPart(Part2.class, new Part2());obj.addPart(Part3.class, new Part3());
}
• Мы точно ничего не забыли?• Эти запчасти между собой не конфликтуют?
Заработает ли собранное?
www.mail.ru 27
• В классическом подходе
class MyObj {@NotNullpublic MyPart part = new MyPart();
}
void process(@NotNull MyObj obj) {obj.part.doSomething();
}
Нет проверок @NotNull
www.mail.ru 28
• В модульном подходеBunch assembleMyObj() {final Bunch myObj = new Bunch();myObj.addPart(MyPart.class, new MyPart());return myObj;
}void process(@NotNull Bunch obj) {final MyPart part = obj.getPart(MyPart.class);if(part == null) return; /* Never happens */part.doSomething();
}
Нет проверок @NotNull
www.mail.ru 29
<spell><targetImpacts>
<Item type = “ImpactKill” /></targetImpacts>
</spell>• Что нужно от цели воздействию ImpactKill?– Нужно ли ему здоровье?– А что будет, если его нет?
В данных тоже есть проблемы
www.mail.ru 30
Как это улучшить?Несколько мыслей
www.mail.ru 31
<ObjectProfile name=“Смертный”><persistentParts>
<Item type=“Mortal” /><Item type=“Health” />
</persistentParts></ObjectProfile>• Возможно, стоит уметь использовать несколько
профилей в одном объекте
Нужна типизация объектов
www.mail.ru 32
<spell><casterProfile name=“” /><targetProfile name=“Смертный” />
</spell>
• Воздействия должны декларировать свои требования
А также операций с ними
www.mail.ru 33
@ObjProfile(name = “Смертный”)class MyObj extends Bunch {void assempleParts() {
<...> }
}
• Что-то вроде типизации в легкой форме.
Не обязательно в данных
www.mail.ru 34
• Не забывайте про дизайнеров!• Как что работает должно быть понятно из редакторов– Разумеется, они должны быть
• Лучше – из самих данных– Текстовый редактор F4
• Билд-система тоже полезна
Нужна поддержка в данных
Михаил КазаковСтарший программист,
Команда «Аллодов Онлайн»[email protected]
СПАСИБО!
www.mail.ru
Mail.RuРазработчик игр и сервисов №1Крупнейший работодатель в отрасли
Работайте у нас[email protected]://corp.mail.ru/career/vacancies/voronezh