- Home /
Unity Multiplayer Networking..... in 2D!?!? crazy i know!
Hey Everyone, Im prototyping a multiplayer game loosely following a tutorial i found here: **http://www.paladinstudios.com/2013/07/10/how-to-create-an-online-multiplayer-game-with-unity/**
I am trying to get smooth transitions over the network, but in 2D! Here is my PlayerMove Script.
using UnityEngine;
using System.Collections;
public class PlayerMovement : MonoBehaviour {
public float playerSpeed = 10;
public float jumpPower = 350;
public bool isGrounded = false;
private Vector3 moveX;
//network Variables
private float lastSynchronizationTime = 0f;
private float syncDelay = 0f;
private float syncTime = 0f;
private Vector2 syncStartPos = Vector2.zero;
private Vector2 syncEndPos = Vector2.zero;
void OnCollisionEnter2D(Collision2D Col){
if (Col.gameObject.layer == 8) {
isGrounded = true;
}
}
// Update is called once per frame
void Update () {
if (networkView.isMine){
Inputmanager ();
}
else
{
SyncedMovement();
}
}
void Inputmanager(){
moveX = Input.GetAxis("Horizontal") * transform.right * Time.deltaTime * playerSpeed;
transform.Translate (moveX);
if (Input.GetButtonDown ("Jump") && isGrounded == true){
Jump();
}
}
void Jump () {
gameObject.rigidbody2D.AddForce (Vector3.up * jumpPower);
isGrounded = false;
}
private void SyncedMovement()
{
syncTime += Time.deltaTime;
rigidbody2D.position = Vector2.Lerp(syncStartPos, syncEndPos, syncTime / syncDelay); //This is the error causing Line.
}
void OnSerializeNetworkView(BitStream stream, NetworkMessageInfo info){
Vector3 syncPos = Vector3.zero;
if (stream.isWriting){
syncPos = rigidbody2D.position;
stream.Serialize(ref syncPos);
}
if (stream.isReading){
stream.Serialize(ref syncPos);
rigidbody2D.position = syncPos;
}
else
{
stream.Serialize (ref syncPos);
syncTime = 0f;
syncDelay = Time.time - lastSynchronizationTime;
lastSynchronizationTime = Time.time;
syncStartPos = rigidbody2D.position;
syncEndPos = syncPos;
}
}
}
Currently when the second player is instantiated, he slowly falls down from where he is instantiated to the ground, as soon as he gets there he jolts back up to where he was instantiated. he cant be controlled and the other player is only visible in short blinks when you move him around sporadically.
If i comment out this line: rigidbody2D.position = Vector2.Lerp(syncStartPos, syncEndPos, syncTime / syncDelay); everything works dandy, he falls down and the physics look normal, except i don't get the smooth transitions i'm after. Does anyone know the work around for this problem?
If anyone gives me a solution i will award you 15 awesome points in my awesome game (.......its just where i give people online points for being awesome haha).
Thanks for giving this a look, you can contact me on twitter for your awesome points ;) **https://twitter.com/DavidMcdonald89**
Answer by Bunny83 · Sep 16, 2014 at 10:02 AM
Since every player is controlling his own character locally (and just broadcasting it's own state) there's no use of doing manual "smoothing / lerping / interpolation". All you have to do is adding the rigidbody's velocity as well. Also your OnSerializeNetworkView looks very strange. It looks like you serializing the position two times while you deserializing it only once. isReading and isWriting are actually never true at the same time. They actually follow the rule:
isReading = !isWriting;
I usually use it like this. I added the velocity:
void OnSerializeNetworkView(BitStream stream, NetworkMessageInfo info)
{
Vector3 syncPos = rigidbody2D.position;
Vector3 velocity = rigidbody2D.velocity;
stream.Serialize(ref syncPos);
stream.Serialize(ref velocity);
if (stream.isReading)
{
rigidbody2D.position = syncPos;
rigidbody2D.velocity = velocity;
}
}
Keep in mind that in case your object can rotate as well, you should add rotation and angularVelocity as well.
Now the other players get the position as well as it's velocity so the object will move the the same speed as it's counterpart. If you really want to implement snapshots it's a bit more tricky. Each snapshot should save it's timestamp and you would interpolate between the two last received snapshots based on the timestamps.
Thankyou SO much for your extensive answer but i get an error
So i fixed it by changing Vector2 to Vector3. but it still causes errors. as seen here: https://www.youtube.com/watch?v=S42NaIcJ_ZA
Yes, i'm sorry. I didn't remember that Serialize doesn't have an overload for Vector2. Changing to Vector3 should fix it, yes. I'll edit my answer.
I'm not sure what's wrong with your project. It looks like either the world is offset or your position data. Are you sure you load the same level on all peers and that you don't manipulate the position / velocity of foreign player objects besides in OnSerializeNetworkView?
Thank you so much for all your help. i really really appreciate it! the only other script that does any networking is:
using UnityEngine;
using System.Collections;
public class Network$$anonymous$$anager : $$anonymous$$onoBehaviour {
private const string gameID = "SecretName";
private const string roomName = "Daves Room";
private HostData[] hostList;
public GameObject player;
private string serverStatus = "Server Not Currently Active.......";
private bool isRefreshingHostList = false; //ADDED
void Update()//ADDED
{
if (isRefreshingHostList && $$anonymous$$asterServer.PollHostList().Length > 0)
{
isRefreshingHostList = false;
hostList = $$anonymous$$asterServer.PollHostList();
}
}
//Initialises a server!
private void StartServer(){
Network.InitializeServer(2, 25000, !Network.HavePublicAddress());
$$anonymous$$asterServer.RegisterHost(gameID, roomName);
}
//Runs when the server is initialised.
void OnServerInitialized(){
SpawnPlayer();
serverStatus = "Server Initialised";
}
//Runs when "Refresh Host List" button is pressed.
private void RefreshHostList(){
$$anonymous$$asterServer.RequestHostList(gameID);
serverStatus = "Requesting Host List...";
}
void On$$anonymous$$asterServerEvent($$anonymous$$asterServerEvent msEvent){
if (msEvent == $$anonymous$$asterServerEvent.HostListReceived){
hostList = $$anonymous$$asterServer.PollHostList();
serverStatus = "Host List Recieved";
}
}
// Connects a Host
private void JoinServer(HostData hostData){
Network.Connect(hostData);
serverStatus = "Connecting to Server.....";
}
// Runs when connection to the server
void OnConnectedToServer(){
serverStatus = "You are Connected to the Server!";
}
//Spawns Player
void SpawnPlayer(){
Network.Instantiate(player,new Vector3(0f, 1f, 0f),Quaternion.identity, 0);
}
//GUI Buttons, Notification
void OnGUI() {
if (!Network.isClient && !Network.isServer){
if (GUI.Button(new Rect(30, 60, 150, 50), "Start Server")){
StartServer ();
}
if (GUI.Button(new Rect(30, 120, 150, 50), "Refresh Host List")){
RefreshHostList ();
}
if (hostList != null){
for (int i = 0; i < hostList.Length; i++){
if (GUI.Button (new Rect(400, 100 + (110 * i), 300, 100), hostList[i].gameName)){
JoinServer(hostList[i]);
}
}
}
}
GUI.Label(new Rect(30, 30, 300, 20), serverStatus);
}
}
only other thing is just cam movement script ..... hmmm
@davidc: That's what i asked ;) Does your movement script distinguish between local and remote player? Also where and when do you instantiate the clients player objects? The server creates his own player object in line 31, but where do you create the other players? That's usually done in "OnConnectedToServer".
Also, like i said, how does your movement / cam scripts look like? Do you check for networkView.is$$anonymous$$ine? Usually you would simply disable the input scripts on all other player objects except your own.
Your answer
Follow this Question
Related Questions
GetComponent().enabled = true; 1 Answer
C# Procedural Tilemap Generation - Each instance of tilemap rendering the same 1 Answer
Unusual error regarding movement in a top down 2d sidescroller 1 Answer
Equivelant of GUI.DrawSprite() ? 0 Answers
The name 'Joystick' does not denote a valid type ('not found') 2 Answers