это мой первый пост, и я действительно много исследовал эту тему, прежде чем писать здесь. Но теперь я нашел несколько возможных решений, и я просто не уверен, что это правильный путь.
проблема
В настоящее время мы разрабатываем местную кооперативную игру, которая представляет собой смесь экшн-игры для одного игрока и головоломки для второго. Наша настоящая проблема — это ввод, который в настоящее время обрабатывается контроллером игрока, который вызывает каждого полученного делегата отображения действия, чтобы определить, принадлежит ли принадлежащая Пешка из типа PlayerA или PlayerB, чтобы затем вызвать нужную функцию.
Позвольте мне привести конкретный пример:
У нас есть две привязки действия для кнопки B (XBox Controller), в настоящее время называемой «B»
Когда делегат вызывается, мы приводим possessPlayer, чтобы проверить, должен ли он вызывать PlayerA-> Jump или PlayerB-> Blink.
Я совершенно недоволен ситуацией, которую я должен разыгрывать каждый раз, когда мы получаем вход, просто чтобы проверить, владею ли я действием / головоломкой
Решения
1) Создайте 2 PlayerControllers и поменяйте их местами, используя GameMode :: SwapPlayerController (Старый, Новый)
Я нашел эту функцию во время исследования, но я не доволен созданием Player с PlayerControllerA, чтобы немедленно переключить его на использование PlayerControllerB,
2) перенести ответственность на класс Charatcer
Другой мыслью было бы делегировать принятие решения классу Character, передав значение enum, например E_BUTTON_B, из PlayerController в Character. Мы могли бы написать макрос, который создает это перечисление на основе наших входных отображений, а затем делегировать решение универсальной функции Character-> ProcessInput (EnumValue). Я тоже не совсем счастлив, потому что тогда ПК не имеет для меня особого смысла.
3) Кэшируйте одержимую пешку, чтобы избежать броска.
Другая идея состояла в том, чтобы кэшировать тип одержимого персонажа всякий раз, когда у ПК есть пешка. Это избавило бы от приведения за входной вызов делегата.
Я был бы очень рад за совет и любой намек, как вы, ребята, решаете такие проблемы в своих играх. Наши главные цели — разделение задач, хорошая ремонтопригодность и повторная привязка ввода.
Ура и хорошего дня,
Парсифаль
Вы можете создать такую структуру (написанную на C ++, но этот подход также может быть легко реализован в Blueprints):
class MyGameBasePlayerController : public PlayerController
{
// TODO methods common for both controllers (for example Escape key handling)
}
Теперь конкретные контроллеры:
class PuzzlePlayerControler : public MyGameBasePlayerController
{
UPROPERTY(BlueprintReadWrite, Transient, Category = "MyCat"PuzzleCharacter* puzzleChar;
// TODO handle specific actions for Puzzle chararacter and control handling.
// TODO override base methods / input bindings if necesary
virtual void Possess(APawn* pawn) override;
}
То же самое касается ActionPlayerCharacter
,
Вам нужно решить, насколько ваши персонажи будут отличаться. Если они одинаковые, вы можете использовать что-то вроде MyGameCharacter : public PlayerCharacter
(или вы можете использовать более широкий класс PlayerPawn
) и ваш PlayerControllers
вызовет соответствующие методы. Тогда ваша сохраненная ссылка на MyGameCharacter
может храниться в MyGameBasePlayerController
,
Или вы можете использовать наследование, так что вы будете иметь PuzzleCharacter : public MyGameCharacter
а также ActionCharacter : MyGameCharacter
с некоторыми общими базовыми реализациями и методами расширения или использования переопределения виртуальных методов.
В зависимости от вашей окончательной структуры, вы можете использовать переопределение Possess
метод (UE Docs) чтобы получить реальный экземпляр пешки, приведите его к соответствующему классу (например, PuzzleCharacter
или же PuzlePawn
в PuzzlePlayerController
) и сохраните ссылку для последующего использования. Знать что в этом случае вы должны реализовать Unpossess
также вы можете очистить сохраненную ссылку и вести себя корректно в любой ситуации.
Других решений пока нет …