I am pretty savvy now when it comes to singleplayer coding. I recently took up an interest in trying to convert my singleplayer Resident Evil clone to multiplayer. I read the docs, and tried to come up with a little tech demo already. While it works somewhat how I want it there are quite a few problems…
Problems:
-
For some reason, the ClientRPC’s only work for the host, but do not work for the client connecting to the host. Adding identical Commands seems to do nothing.
-
Using Network Transform; the host’s movements are extremely laggy / choppy. He sort of just teleports around.
-
The camera doesn’t affect the individual players, despite being apart of the prefab, when a client connects the camera will follow the client on the host’s window instead of the host when he connects…
-
Audio works only for the host.
-
Animations only display for the host character on both the client and host windows, the animations do not work for the client except from his own perspective.
I’m sure it has something to do with my code, but I have no idea how to change it so it’ll reflect my singleplayer implementations for multiplayer… This code works 100% perfectly for offline play, just not online.
My code:
// Resident Evil style network controls by VirusPunk
using UnityEngine;
using UnityEngine.Networking;
public class PlayerScript : NetworkBehaviour
{
private Animation anim;
private CharacterController controller;
private float speed;
private float turnSpeed;
private float idleTimeOut = 10.0f;
private float idleTimeOutTimer = 0.0f;
private Vector3 mydir;
private bool isWalking = false;
private bool isRunning = false;
public AudioClip[] walk;
public AudioClip[] run;
public Camera myCam;
public override void OnStartLocalPlayer()
{
GameObject.Find("Object_0").GetComponent<MeshRenderer>().material.color = Color.red;
}
void Start()
{
anim = GetComponent<Animation>();
controller = GetComponent<CharacterController>();
myCam = Camera.current;
if (isLocalPlayer)
{
myCam.enabled = true;
}
if (!isLocalPlayer)
{
myCam.enabled = false;
}
}
// Update is called once per frame
void Update()
{
if (!isLocalPlayer)
{
return;
}
float hor = Mathf.Abs(Input.GetAxis("Dpad_Horizontal"));
float ver = Mathf.Abs(Input.GetAxis("Dpad_Vertical"));
// Movement
if (Input.GetKey(KeyCode.Joystick1Button0) && ver > 0.1
&& Input.GetAxis("Dpad_Vertical") < 0)
{
isWalking = false; isRunning = true;
speed = 170f;
turnSpeed = 230f;
transform.Rotate(0, Input.GetAxis("Dpad_Horizontal") * turnSpeed
* Time.deltaTime, 0);
mydir = transform.forward * Input.GetAxis("Dpad_Vertical") * speed;
controller.Move(mydir * Time.deltaTime - Vector3.up * 0.2f);
}
else
{
isWalking = true; isRunning = false;
speed = 70f;
turnSpeed = 230f;
if (anim["WalkBack"].enabled)
{
speed = 55f;
}
transform.Rotate(0, Input.GetAxis("Dpad_Horizontal") * turnSpeed
* Time.deltaTime, 0);
mydir = transform.forward * Input.GetAxis("Dpad_Vertical") * speed;
controller.Move(mydir * Time.deltaTime - Vector3.up * 0.2f);
}
// Animations
if (ver < 0.1 && hor < 0.1 && isWalking)
{
RpcIdleAnim();
idleTimeOutTimer += Time.deltaTime;
if (idleTimeOutTimer > idleTimeOut)
{
anim.CrossFade("Idle2");
}
else if (idleTimeOutTimer < idleTimeOut)
{
anim.CrossFade("Idle");
}
}
else
{
RpcWalkAnim();
idleTimeOutTimer = 0.0f;
anim.CrossFade("Walk");
}
if (isRunning)
{
RpcRunAnim();
idleTimeOutTimer = 0.0f;
anim.CrossFade("Run", 0.1f);
}
if (Input.GetAxis("Dpad_Vertical") > 0)
{
RpcWalkBackAnim();
idleTimeOutTimer = 0.0f;
anim.CrossFade("WalkBack");
}
// Audio
if (isRunning && ver > 0.1 && !anim["Idle"].enabled)
{
Invoke("RunningFootstepTimer", 0.32f);
}
if (isWalking && ver > 0.1 && !anim["Idle"].enabled
|| isWalking && hor > 0)
{
Invoke("WalkingFootstepTimer", 0.48f);
}
}
[ClientRpc]
void RpcIdleAnim()
{
idleTimeOutTimer += Time.deltaTime;
if (idleTimeOutTimer > idleTimeOut)
{
anim.CrossFade("Idle2");
}
else if (idleTimeOutTimer < idleTimeOut)
{
anim.CrossFade("Idle");
}
}
[ClientRpc]
void RpcWalkAnim()
{
idleTimeOutTimer = 0.0f;
anim.CrossFade("Walk");
}
[ClientRpc]
void RpcRunAnim()
{
idleTimeOutTimer = 0.0f;
anim.CrossFade("Run", 0.1f);
}
[ClientRpc]
void RpcWalkBackAnim()
{
idleTimeOutTimer = 0.0f;
anim.CrossFade("WalkBack");
}
// Timers
void RunningFootstepTimer()
{
if (anim["Run"].enabled)
{
GetComponent<AudioSource>().PlayOneShot(run[0]);
}
CancelInvoke();
}
void WalkingFootstepTimer()
{
if (anim["Walk"].enabled)
{
GetComponent<AudioSource>().PlayOneShot(walk[0]);
}
CancelInvoke();
}
}