Sign In Register

How can we help you today?

Start a new topic

Unreal Engine Real Time Third Person Tutorial

Hello,

I'm in the process of shifting my Unity game to Unreal Engine, and also shifting from using PlayFab + Photon (PUN) to using GameSparks, since GameSparks seem to be a more powerful tool after reading about it and testing it. So far so good.


What I'm trying to make a third person real time multiplayer. Now the problem is that I can't seem to find proper documentation for the unreal part for the real time multiplayer. I tried to see the Tetris Example, but I don't think it has what I need, or maybe it does but I can't seem to know what it is.


Can someone explain to me or guide me through the following:

After connecting to Gamesparks and logging in as 2 different users, and after matchmaking is complete, I start a session and I switch both clients to the game level (the game level consists of the normal "ThirdPersonExampleMap" that comes as a default with unreal engine's new third person project). When both clients join this level the third person character can't be controlled by the user. What I want to know is should I create a third person character manually for each player when the scene is loaded? and how can I make that character load on the other clients so they can see him, and how can I sync their position.


Thanks in advance!


Regards,


Elie


Hey Chris, I was able to create a scenario where all players' positions are synced while lerping their movement. But I have noticed that it will require a lot of work to make my game since it depends a lot on quick actions and physics and so on.


I made a thread about comparing Unreal's networking and GameSparks' Realtime SDK to check which is better/easier for my game:

https://support.gamesparks.net/support/discussions/topics/1000081426?page=1

That's great to hear! Sorry for the delay. It sounds like it's possessing the actor because the camera jumps to it, so it might just be an issue of controls. That part would just be on the Unreal side, so it might be a good idea to try the Unreal answers site

FINALLY! The spawn packet was received! All I had to do was add an "Create GS RT Data" and attach it to the Send's Data variable. It seems it needs an empty Data to be sent, can't leave it empty.


Now I just have to figure out how to take control of each client's player so I check if the location packets are sent when the character moves so I duplicate them on the other clients.

Hey Omar, thank you for pointing out about the OpCode 0.

I've changed the send spawn OpCode to 2, but still isn't being received on the other clients. This is giving me a hard time starting my project. Also taking control of the player is not working (possessing).

Hi guys, you shouldn't use packet with an OpCode 0, it does not work. Similar to having anything with the index 0 in the data object of a packet. 

Anything from 1 up works. 


I am aware that Unreal's server GameMode is only relevant to the Server and clients cant access it. For the base SDK (Normal requests) it's best practise to first connect in the clients GameMode (Main menu before joining a session) this will ensure that they are connected and able to make calls. For the real time SDK, it was never meant to work side by side with Unreal's networking layer. Every player will have their own game, they are the server authority of that game and the packets ensure replication. This is the intended use of the real-time SDK. This is not the only practical use, but this how we design it to be as it is agnostic of Unity, Unreal and any future IDEs SDKs we plug it into.


Hope this helps,

Omar

I just tried changing where the pawn spawns, and the camera jumps to where the pawn is spawn, but I just can't seem to control him.

I've attached the console of both clients, packet 0(player spawned) is not received by anyone, but packet 1(set player location) is received by only 1 client (the client that received that a player has connect).

I feel like I have a very silly mistake, but hoping to learn something out of this when it is solved.

Really appreciate your support Chris! Thank you.

I hope Omar maybe can help us solve this too.

Elie,


Regarding your comment on my actor tracking idea, I'll see what I can do to have it update every time someone joins or leaves the session.


Regarding your possess pawn issue, does the camera correctly follow/jump to the new actor and your controls simply aren't working? Or the camera isn't working either?


Regarding the GameMode on the server, that is just referring to Unreal networking. Because there is only one player in Unreal's eyes, your device IS the server. So because we are using GS for networking, the fact that the GameMode is only on the server is irrelevant for most situations.


Regarding the elusive Packet 0, I'm not sure what could be causing it, since everything looks good to me. Omar might have some ideas, but you might just need to start moving things around to see how it changes.

Hey Omar, Thank you for clearing some things up.


Everything seems good so far, but still missing the packet 0 that is not being received by the other clients, although it is being sent. Any idea why? I've got my blueprints attached in the above posts.

Hi guys,


The ID variable can be found in the shapes actors, I shape, L shape and T shape. Each have an ID to help identify them in a simple way. The I shape has an ID of 0 which should be 1, I didnt realise this before I pushed the sample. The variable is inherited form the the Shape parent class. 

The OP Code 100 is sent from the cloud script when 2 players are ready to play. This is the script:


______________________________________________________________________________________

var playersJoined = []; // this is only used at the start to make sure each player is connected

var timeLeft = 60;

var playerData = {};



function contains(a, obj) { // this is a simple method that just checks if an element is in an array or not

    for (var i = 0; i < a.length; i++) {

        if (a[i] === obj) {

            return true;

        }

    }

    return false;

}


RTSession.onPacket("101", function(packet){

   

   var rtData = RTSession.newData().setNumber(1, packet.getData().getNumber(1)).setNumber(2, new Date().getTime());

   

   RTSession.newPacket().setData(rtData).setOpCode(101).setTargetPeers(packet.getSender().getPeerId()).send();

   

          // RTSession.newPacket().setOpCode(6).setTargetPeers().setData( RTSession.newData().setString(1, "testing from cloud")).send();


})


RTSession.onPlayerConnect(function(player){

    // first we check to see if the player has already joined the match

    if(!contains(player.getPeerId(), playersJoined)){

        playersJoined.push(player.getPeerId()); // and add them if not

    }

    

    RTSession.getLogger().debug(playersJoined.length);

    // next we check to see the max (or min) number of players has joined that match

    if(playersJoined.length === 2){

        RTSession.newPacket().setOpCode(100).setTargetPeers().send(); // send an empty pack back to all players

       

        RTSession.setInterval(function(){ // send current server time to all players every 1second

           // RTSession.getLogger().debug(new Date().getTime());

            RTSession.newPacket().setOpCode(102).setTargetPeers().setData( RTSession.newData().setNumber(1, new Date().getTime() )).send();


        }, 1000);

        

        RTSession.setInterval(function(){ // send current server time to all players every 1second

            

            if(timeLeft > 0){

            timeLeft--;

            RTSession.newPacket().setOpCode(103).setTargetPeers().setData( RTSession.newData().setNumber(1, timeLeft )).send();

            } else{

                RTSession.newPacket().setOpCode(104).setTargetPeers().send();

            }



        }, 1000);

        

    }

});

________________________________________________________________


Hope that helps. The reason why everything is in the GameMode is because every player will be the owner of their own world/level. The packets simply replicate what other players do in their own world. Server authority will have to be done through RT cloud script.


Cheers,

Omar

BTW, all these blueprints are in the GameMode blueprint, should it be there or not?

It says that the GameMode blueprint is executed on the server, how is it possible?

Sorry the strings that are printed are the following:

1. Sending Player Spawn OpCode 0

2. Spawn Sent

3. Packet 1 Received


"Enter" mistake :p

To answer your first post these are the strings that are being printed:
1. Sending Player Spawn
2. OpCode 0 Spawn Sent
3. Packet 1 Received

I've attached the Start Game blueprint.

As for the way you are tracking the actors/players, well it's a good idea to keep them in an arraylist and having the peer as the id so you know which player to change his position/data that was sent. Though what if a player drops out and another player join back? Then you'll have to know that you have to spawn his character. As I can see your method is made statically on start of the game by getting the list of players from the MatchDetailsRequest.
But i guess this can be solved by requesting the MatchDetails again when a player connects.

I'll give it a try but i'm still trying to receive the OpCode 0 for spawning players..

P.S.: In the start game blueprint I have attached, I can't seem to be able to control the actor that I have just spawned, although I have added the possess when he is spawned. Do you have any idea why?

I think I found a way to keep track of players/actors without having to do tons of math and checks every time data is sent. I have a screenshot attached, but this is essentially the flow:


  1. Open the level blueprint.
  2. On BeginPlay, spawn your pawn's actor and a placeholder actor (I created a default actor blueprint to accomplish this), and Cast to Game Mode to add both actors to an array variable ("ActorList"). Be sure to add the placeholder first so it can be assigned Index 0.
  3. Open the Game Mode blueprint and create nodes to accomplish the following:
  4. Start the RT session.
  5. Grab the array of opponents from the match details.
  6. Send that through ForEachLoop.
  7. Within the loop, spawn an actor for the opponent and insert that actor into the ActorList array with the index being the player's peerId.

Now that this is set up, I can plug the Sender variable from the OnData delegate into the index of a Get node, which will instantly pull up the actor associated with that player. This should allow me to efficiently update actor locations and other data.

What do you think?

Which of these strings are getting printed when you test?


  1. Sending Player Spawn OpCode 0
  2. Spawn Sent
  3. Packet 0 Received

Forgot to attach the blueprints

Login to post a comment