LTagKirov, уважаемый, я готов ответить на любые вопросы, давайте только они будут начинаться не со слов: "смотрите все, тут ООП-шная охинея, я нашел элементарную архитектурную ошибку", а со слов "я не понимаю, как взаимодействуют эти модули, и почему тут сделано так-то, объясните". Иначе будет выглядеть нелепо.
ООП - не волшебная пилюля, и не гарантирует понимание кода кем угодно за 3 минуты. Также, возможности у девайса Джима и у моего девайса мягко говоря различаются, поэтому и код различается, и его количество. Для первого ознакомления сделайте, как любой программист: запустите doxygen, посмотрите графы взаимоотношений классов и многие вопросы прояснятся сами собой. В критичных местах в моём коде присутствует doxygen-разметка. Ну и задавайте вопросы, пусть даже в теме с таким забавным называнием
А теперь поехали.
Вопрос 1.LTagKirov писал(а):
Примерно так приделывается логика обработки нашего волшебного объектного ружья
Почему состояние игрока меняет метод оружия, а не игрок даёт команду ружью сменить своё состояние - потратить патроны.
Странно игрок же важнее ружья...
Код:
m_tasksPool.add(
[this]() {
playerState.print();
updatePlayerState();
},
5000000
);
и тд
Наше волшебное объектное ружьё не меняет состояние игрока, как можно заметить, если прочитать на йоту больше кода. Эти строки заставляют оружие, грубо говоря, каждые 5 секунд запрашивать у повязки переменные, которые его интересуют, чтобы вывести их потом на дисплей. Эти переменные хранятся в playerState - экземпляре класса PlayerPartialState. Никакого управления состоянием игрока здесь не происходит. Предвосхищая ваш вопрос, отвечу, что повязка сама оповещает оружие, как только что-то меняется. Данный код лишь для повышения надежности.
Вопрос 2LTagKirov писал(а):
Сигнализация о попадании - попробуем определить откуда пришло событие
Код:
void Rifle::riflePlayEnemyDamaged(uint8_t state)
{
info << "Player damaged with state: " << state;
playDamagerNotification(state);
}
А пришло оно отсюда из другого устройства HeadSensor !
Код:
void HeadSensor::notifyIsDamager(DamageNotification notification)
{
info << "By the time " << notification.damager << " damaged " << notification.target;
if (notification.damager != playerConfig.plyerMT2Id)
return;
if (!playerState.weaponsList.weapons().empty())
{
uint8_t sound =
(notification.damagedTeam == playerConfig.teamId) ? // testing for friendly fire
>>> И вот сюда(или не сюда?) то мы можем добавить чит с определённым ИД игрока
NotificationSoundCase::friendInjured :
notification.state;
// Now notifying over first attached weapon
RCSPStream::remoteCall(playerState.weaponsList.weapons().begin()->first, ConfigCodes::Rifle::Functions::riflePlayEnemyDamaged, sound);
}
}
>> RCSPStream::remoteCall(
playerState.weaponsList.weapons().begin()->first,
ConfigCodes::Rifle::Functions::riflePlayEnemyDamaged, sound);
Почему проигрывание звука поражения игрока зависит от вида оружия которое он держит в руках ?
В данном случае речь идёт о сигнализации, что ранен враг. Пусть у нас 2 игрока, у каждого одно оружие.
Логика такая:
- Оружие игрока 1 поражает повязку игрока 2.
- Повязка игрока 2 посылает широковещательный пакет: в меня попал игрок с id таким-то из команды такой-то.
- Повязка игрока 1 принимает этот пакет, и автоматически вызывается функция HeadSensor::notifyIsDamager. Там проверяется: это моё оружие стреляло, или нет? И видит: да ведь это же моё оружие стреляло! И посылает своему оружию команду "проиграй звук попадания": RCSPStream::remoteCall(playerState.weaponsList.weapons().begin()->first, ConfigCodes::Rifle::Functions::riflePlayEnemyDamaged, sound);
- У оружия, когда приходит пакет с такой командой, автоматически вызывается функция Rifle::riflePlayEnemyDamaged(uint8_t state). При этом state хранит информацию о том, что произошло именно: ранили врага, убили врага, или попали в своего.
Цитата:
Почему проигрывание звука поражения игрока зависит от вида оружия которое он держит в руках ?
Не понимаю, где вы это взяли. Уведомление о попадании проигрывается первым оружием в списке присоединенных - это пока заглушка на будущее. Потом сделаю, чтобы именно тем, из которого произведены выстрелы, но это low priority.
Вопрос 3LTagKirov писал(а):
Почему респаун головной повязки, вызывает респаун оружия ? Эти два класса никак особо не связаны между собой, описанны в разных файлах не являются потомками, а мы переплетаем их зависимостями, которые в целом не очевидны - если незнать логики (лазертага) почему должно быть именно так. Логичнее их изолировать, сделать класс игрок у которого есть повязка + оружие. Класс игрок уже вызывает методы повязки(надел) и методы оружия(подобрал с земли, зарядил), а когда повязка сама командует оружию зарядись без участия игрока и тд ...
У меня почти так и сделано. Информация об игроке хранится в PlayerConfiguration и PlayerState. Инстансы этих классов есть у HeadSensor. Такая иерархия логична. У повязки есть всё об игроке. Список подсоединенного оружия хранится внутри PlayerState - "оружие принадлежит игроку". Принципы ООП здесь не нарушены. Состояние и характеристики игрока инкапсулированы в PlayerConfiguration и PlayerState. Конечно, можно сделать как-то по-другому, но это вряд-ли будет существенно "правильней". Ну есть ещё много аргументов, почему здесь сделано так, но нужно знать много нюансов, чтобы о них говорить.
Если повязка ловит команду на респаун (по ИК, или радио), то она:
- говорит игроку (=PlayerState), что пора респавниться (он оживает, восстановливает здоровье и т.п.)
- говорит всем оружиям, которыми обладает игрок, что пока респавнится, а именно: проигрываеть звук респауна, обновляють патроны, да и просто активирлваться (если было деактивировано в связи со смертью игрока).
Не вижу противоречий здравому смыслу.
Код:
void Rifle::rifleRespawn()
{
rifleReset();
rifleTurnOn();
updatePlayerState();
m_respawnSound.play();
info << "Rifle respawned\n";
}
Таким образом два независимых класса, которые даже инстанциированы на двух независимых устройствах, просто обмениваются сообщением, всё логично. Повязка знает всё об игроке. Оружие - только о своих параметрах и состоянии, плюс - иногда получает информацию об игроке, чтобы вывести на экран и в дебаг-канал, на всякий случай.
Ваше желание разделить игрока и повязку в разные классы понятно, в моём случае почти так и сделано. Но игрок, как класс, не может жить без реального физического устройства с микроконтроллером, которым является повязка
LTagKirov писал(а):
Или это нифига не ООП ... тише тише - глубоко вдохните ... или я просто непонимаю
Всё нормально. Это ООП. Рекомендую более вдумчиво читать код.
Но с чем я точно соглашусь - это что названия некоторых методов и классов не самые прозрачные. При разработке в одиночку трудно уследить за тем, чтобы всё называется правильно, потому что привыкаешь.
В дальнейшем, давайте будем вежливее друг к другу. У меня нет секретов и взаправду всё работает.