UE4 - C++:如何设计角色具有不同输入方案的本地合作游戏?

UE4 - C++: How to design a local coop game where characters have different input schemes?

这是我的第一个 post,在 post 来到这里之前我确实对这个主题做了很多研究。但现在我找到了几种可能的解决方案,但我不确定哪种方法才是正确的。

问题

我们目前正在开发一款本地合作游戏,该游戏混合了一个玩家的动作游戏和第二个玩家的益智游戏。我们的实际问题是当前由播放器控制器处理的输入,播放器控制器在接收到的每个动作映射委托上进行投射,以确定拥有的 Pawn 是来自类型 PlayerA 还是 PlayerB,然后调用正确的函数。

举个具体的例子:

我们有两个按钮 B(XBox 控制器)的动作绑定,当前称为 "B"

当委托被调用时,我们施放 possessedPlayer 来检查它是否应该调用 PlayerA->Jump 或 PlayerB->Blink

每次我们收到输入只是为了检查我是否拥有 action/puzzle char

时我必须施放的情况我完全不满意

解决方案

1) 创建 2 个 PlayerControllers 并使用 GameMode::SwapPlayerController(Old, New)

交换它们

我在研究过程中发现了这个功能,但我不喜欢用 PlayerControllerA 创建一个 Player 以立即将其切换为使用 PlayerControllerB,

2) 将责任转移给角色class

另一种想法是通过将 E_BUTTON_B 这样的枚举值从 PlayerController 传递给角色,从而将决策权委托给角色 class。我们可以编写一个宏来根据我们的输入映射创建此枚举,然后将决定委托给通用的 Character->ProcessInput(EnumValue) 函数。我也不太高兴,因为那时 PC 对我来说意义不大。

3)缓存拥有的Pawn以避免施法

另一个想法是在 PC 拥有 Pawn 时缓存拥有的角色的类型。这将消除每次输入委托调用的强制转换。

如果您能提供建议和任何提示,我将非常高兴你们如何解决游戏中的此类问题。我们的主要目标是关注点分离、良好的可维护性和输入重新绑定。

干杯,祝你有美好的一天,

帕齐瓦尔

您可以像这样创建结构(用 C++ 编写,但这种方法也可以在蓝图中轻松实现):

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 之类的东西(或者您可以使用更广泛的 class PlayerPawn)并且您的 PlayerControllers 将调用适当的方法。那么你存储的对 MyGameCharacter 的引用可以存储在 MyGameBasePlayerController.

或者您也可以使用继承,因此您将拥有 PuzzleCharacter : public MyGameCharacterActionCharacter : MyGameCharacter 以及一些通用的基本实现和扩展方法或使用虚方法覆盖。

根据您的最终结构,您可以使用覆盖的 Possess 方法 (UE Docs) 获取实际的 pawn 实例,将其转换为适当的 class(例如 PuzzleCharacterPuzlePawn in PuzzlePlayerController) 并存储参考供以后使用。 请注意,在这种情况下,您还应该实施 Unpossess,这样您就可以清除存储的引用并在任何给定情况下都能正确运行。