How can I have multiple players control one pawn and show characters inside?

I’m developing a row boat racing game and I’m struggling to figure out how I can have multiple players controlling one boat. Currently I have gotten everything working pretty smooth as a single player game by having the row boat pawn essentially acting as the character. When the game starts the player automatically posses the row boat and can press “spacebar” to trigger a row event that adds a force in the forward vector of the boat. The amount force is determined by the timing of the players input. Super simple. However now comes the hard part.

I need to have 4 players rowing the boat as a team and each individual player can trigger a row to add force to the boat.

Additionally, I want each individual player to show up in the boat in their respective seats.
There is no entering/exiting of the boat since the game only takes place inside the boat, so I don’t have any character models implemented yet. However eventually down the road I would like the give players the ability to customize the look of their character, so I need to be able to see each players character model inside. The game is also in the first person point of view, so their camera has to align with the head of their character model.

How would I go about achieving this? I think I should start by just getting this working in single-player first by showing the players character model in the boat, then work on implementing the multiplayer mechanics, but maybe since the end result is multiplayer I should just jump right into that?

any advice is appreciated.

since the end result is multiplayer I should just jump right into that?

that’s the case, you should plan architecture with multiplayer\goal in mind from the start

player automatically posses the row boat

That fine for singleplayer, but in multiplayer your boat can’t have multiple owners. Hence, you don’t need to posses it and it can be just an actor (though it’s still better to keep it as ACharacter, since CharacterMovementComponent does a tons of work for proper multipler movement replication to clients. Note: i didn’t work with buoyancy so can’t say how it works in regards to multiplayer). As for default pawn - make some intermediate pawn, something like camera-only pawn.

players character model inside

Since you want the models, add the mesh to that default pawn. You even can attach your default pawns to boat’s sockets.

After this point, when you have a 4 controllers, 4 default camera-only pawns and a single boat:

  1. catch the input for player inside of default pawn (or stright in controller no differences in simple scenarios)
  2. when input happens - call a server-rpc (client->server call)
    note: you can send to server raw input [click happend] or click result [the force we should apply to boat]. Sending [click happend] is more cheat-proof by the cost of click being affected by latency. Sending click result [the force we should apply] is vulnerable to cheats but left better user experience. This choice is up to you, unless you going for more advanced techniques, like custom prediction, which in simple case like yours is likely excessive
  3. In this call’s handler on server - add movement input to boat on server only
  4. CharacterMovementComponent will handle automatic movement replication to all clients

Alternative scenario:
2. same as [2] above + prediction. Does the same but also add movement input locally on client. That’s the tricky technique, since there are a lot of corner cases and improper implementation may introduce the excessive rubberbanding that will be worse than the simplest way. So i just outline that such method exist without going in details.

A player controller doesn’t HAVE to control a pawn, and a moving object doesn’t HAVE to have a player controller.

If you have animated characters for each player, then perhaps the best way to do this is to make the boat be a fifth actor, which isn’t a pawn. Instead, each character is a pawn. The connection to the boat can go through the character, ALTHOUGH you’d probably want to make the animation for those characters be driven by oar movement, rather than the other way around.

So, Player controller gets input, forward the input as some abstract “stroke position/forward” data to the Character; the Character then knows which Boat it’s anchored to (if any,) and forwards its stroke to the boat; the boat would simulate adding forces for each of the input characters in its step.

If there aren’t any people/characters, then you can use player controllers without any direct Pawn; instead just find the boat somehow (maybe get objects of class) and tell it directly how much each player is contributing and when.

And, yes, I agree: When building a networked game, gameplay, architecture, and implementation all need to be designed from the ground up to work in a networked environment. Anything else just leads to de-sync, lag, and glitches.

Thank you for the detailed response! I am very new to unreal and this is my first game. What I have so far took me over a week to put together, albeit there was no tutorials for a game like this, so most of that time was understanding how all these nodes work so that I could put this together on my own. That being said, apologies in advance for all the questions I’m about to ask lol.

From what I understand from your response, I need a default pawn for each player to control. Instead of having players posses the boat, instead the players control their pawn which will cast their inputs to the physics actor (which is the boat). ie, player0 controls a default pawn and when they input, it triggers a “row event” in the boat blueprint that adds force to the boat. Each player pawn is attached to the boat so that they move along with it. This also means that the players camera can be part of their own pawn so that their pov lines up to where they are placed in the boat, rather than having the camera as a part of the boats blueprint.

Do I need separate pawn blueprint for each and every character, or do I just make one blueprint that somehow gets duplicated/instanced for every player in the game?

Do you mean the “character” blueprint class has this functionality? Currently the blueprint class of my boat is just a “pawn”. If so, should the boat or the players have the “character” blueprint class?

A bit confused here. Are you saying at this point I should have 9 total blueprints?

Is there a best way to determine which boat a player is in? Like if for example its a race between 2 boats, each boat includes 4 players, how would specify to add force to the boat they are currently in and not both boats?

Makes sense, but I haven’t used server or client nodes yet. Is there any multiplayer setup I have to do before starting?

Finally, how should I implement my UI? From my blueprints you can see that almost all the boats functionality is driven by the UI. When the player inputs a “row event” I determine where the UI slider is to add the appropriate force. Additionally, a lot of the UI is also driven by the boats speed. ie the faster the boat is moving, the faster the slider moves to make inputs more difficult. Would this functionality have to be completely reworked or can I make it work with multiplayer with some alterations?

Thank you for all the help, your original post gives me an amazing starting point for figuring all this out and I don’t expect anyone to answer all my questions. Just thought it couldn’t hurt to throw it all up and see if I could get some extra help.

Thank you for the help! from what I can tell it seems like you and @IrSoil have very similar solutions to my question. I replied to his post with some follow up questions if you are interested in taking a look. Either way your response is very much appreciated and I feel like I have some sort of footing now to get started.

A blueprint is a class. You can create multiple instances (actors) from the same class; they will be independent.

The ACharacter class has a lot of replicated movement functionality, as well as skeletal mesh animation hook-ups. However, a Character moves noting at all like a boat, so I would recommend against making the boat based on Character. The CharacterMovementComponent does a bunch of stuff about air jump control and trying to seat itself onto surfaces (rather than in water bodies) and such – I don’t think it’s a good match.

A blueprint is a class. For each player, there will be a PlayerController object instance on that players computer, as well as on the server. For each player, there will also likely be some Pawn instance – on each of the player’s client computers, as well as on the server. And, finally, there will be a boat instance, which can be a regular actor, perhaps with Simulate Physics turned on, and perhaps with some custom MovementController that you yourself implement.

There are only three classes here: The “player controller” class, the “player pawn” class, and the “boat” class.

This depends entirely on your specific gameplay mechanics. If players are just “assigned” to boats, then you can keep a property on the player controller (or pawn) which is “MyBoat” and just set it when spawning. If you are more like an open world game, where players walk up to a boat, and “press E to get in,” then the action you implement for entering would assign this boat property to the pawn, or controller. (I’d probably put it on the controller, to be honest.)

Typically your UI is some widget blueprint, and the player controller will create the UI instance and add to the player screen, only on the machine where that controller is local. You don’t want a server to have four copies of the UI! The UI typically isn’t involved much in controlling characters, although it can generate RPCS by calling the player controller and the player controller in turn issuing those RPC events to the server (where the server player controller instance will receive them.)

1 Like

Thank you so much, you have no idea how much this helps me! Considering I’m so new to this there are some things that I don’t quite comprehend, but just like what I’ve done so far I’m sure ill start to understand as I go.

The only thing I would have a follow up question on is the UI. Like I said, the boats movement is almost completely driven by my widget blueprint. Essentially the slider in the widget moves from left to right (from 0 to 1) and wherever the slider is at when the “row event” is triggered, that determines the amount of force added. Also the speed of the boat determines how fast the slider moves and how quickly it restarts after it stops at 1.

Are you saying that I would have to add this functionality directly into one of the three classes (contoller, player pawn, or boat) instead of the widget blueprint, then have the widget blueprint just display the information?

No, no – just that, normally, the "UI’ isn’t really part of “game control” (because it comes from a game controller, or keyboard/mouse axes.)

If your rowing mechanic is similar to something like a golf swing mechanic in a typical golf game, then it makes sense that the UI is involved in generating the rowing input.

There are two ways of implementing this. One is that the UI widget is the “driver” of the mechanic, does the timing and threshold detection, and forwards its information to the player controller. (You typically want the UI to have a property of which player controller it affects, and hook that up when you create the UI widget and adds it to the player screen.)

The other is to have the “phase” and “speed” and “trigger” bits to actually be animated inside the player controller, and have the UI simply be a mostly reactive display-er of the state of that input state machine.

There’s not a huge difference between these two options, so either way can probably work fine. Personally, I find that the more reactive and display-only I make my UI, and the less state and decision making is in the UI, the fewer bugs and design challenges I run into, but that’s likely more of a personal style thing than a hard-and-fast rule.

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.