Dear all,
I wanted to do a ar multiplayer project using vuforia and photon.
I faced an issue on ARcamera.
I have that ARcamera in my scene so that every player can see the whole game through that ARcamera. But I also wanted player control its character naturally, so that I somehow hook ARcamera with character. I achieved to control the character such that no matter what direction character facing, once player pressed forward, character would turn into the direction the same as camera facing and go. I tested with single player, good! but when I came to multiplayer, I found camera will change its position to the second player so that in first player's phone, the whole world moved.
I tried to move ARcamera into character prefab, but the program crashed once I have second character joined, indicating I cannot use two or more arcamera in one scene.
What should I do? following is what I think suspicious scripts.
Any advice is appreciated. Thank you.
netControll.cs
==========================
using UnityEngine; using System.Collections;
public class NetControl : Photon.MonoBehaviour { Vector3 realPos = Vector3.zero; Quaternion realRot = Quaternion.identity; GameObject[] gameObj; Animator anim;
void Awake() { Debug.Log("================network awake=================="); gameObj = Resources.FindObjectsOfTypeAll<GameObject> (); int i = 0; foreach (GameObject c in gameObj) { i++; // Debug.Log (i + c.name + c.tag); if (c.name == "PreCamera") { c.SetActive (false); } if (c.tag == "arcam") { // Debug.Log ("I found arcam"); c.SetActive (true); } } } void Start() { anim = GetComponent<Animator> (); if (anim == null) Debug.Log ("Animation is not fetched");
Debug.Log("================network start=================="); }
void Update(){ if (photonView.isMine) { //Do nothing } else { transform.position = Vector3.Lerp (transform.position, realPos, 0.1f); transform.rotation = Quaternion.Lerp (transform.rotation, realRot, 0.1f); } }
void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info) { // Debug.Log ("I am here"); if (stream.isWriting) { //We own this player: send the others our data // stream.SendNext((int)controllerScript._characterState); stream.SendNext(transform.position); stream.SendNext(transform.rotation); stream.SendNext (anim.GetBool ("isRunning")); } else { //Network player, receive data //controllerScript._characterState = (CharacterState)(int)stream.ReceiveNext(); realPos = (Vector3)stream.ReceiveNext(); realRot = (Quaternion)stream.ReceiveNext(); anim.SetBool ("isRunning", (bool)stream.ReceiveNext ()); } }
}
=====================================
cameraController.cs
using UnityEngine; using System.Collections;
public class CameraController : MonoBehaviour {
int myid =-1; public Transform target; public float lookSmooth = 0.09f; CharacterController charController; float rotateVel = 0; GameObject player;
void Awake(){ myid = PhotonNetwork.player.ID; GameObject[] gameObj = Resources.FindObjectsOfTypeAll<GameObject> (); foreach (GameObject g in gameObj) { if (g.name == "Player(Clone)" && g.GetComponent<PhotonView>().owner.ID == myid) { player = g; } } target = player.transform; }
// Use this for initialization void Start () { SetCameraTarget (target); }
// set a camera a new target public void SetCameraTarget(Transform t) { target = t; if (target != null) { if (target.GetComponent<CharacterController> ()) { charController = target.GetComponent<CharacterController> (); } else { Debug.LogError ("The camera target needs a character controller."); } } else{ Debug.LogError ("Your camera needs a target."); } } void LateUpdate() {// happends only after update call, make the rotation based on the previous state of the character // turn the character corresponding to the camera if (charController.isForwarding ()) { rotateTarget (0); } else if (charController.isBackwarding ()) { rotateTarget (180); } else if (charController.isTurningLeft ()) { rotateTarget (90); } else if (charController.isTurningRight ()) { rotateTarget (270); } }
//rotate helper function void rotateTarget(float offset) { float eulerYAngle = Mathf.SmoothDampAngle (transform.eulerAngles.y + offset, target.eulerAngles.y, ref rotateVel, lookSmooth); target.rotation = Quaternion.Euler (0, eulerYAngle, 0); } }
=====================================
characterController.cs
using UnityEngine; using UnityEngine.UI; using System.Collections; using UnityStandardAssets.CrossPlatformInput;
public class CharacterController : Photon.MonoBehaviour {
[System.Serializable] // make the setting is visualizable in Inspector public class MoveSettings { public float forwardVel = 120; public float turnVel = 120; public float distToGround = 27f; public LayerMask ground; }
[System.Serializable] public class PhysSettings { public float downAccel = 0f; }
[System.Serializable] public class InputSettings { public float inputDelay = 0.1f; public string FORWARD_AXIS = "Vertical"; public string TURN_AXIS = "Horizontal"; public string JUMP_AXIS = "Jump"; }
[System.Serializable] public class TimerSettings { public float gameTime = 5f; }
[System.Serializable] public class Broadcast { public bool isWin = false; }
public MoveSettings moveSetting = new MoveSettings (); public PhysSettings physSetting = new PhysSettings (); public InputSettings inputSetting = new InputSettings (); public TimerSettings timerSetting = new TimerSettings (); public Broadcast broadCasting = new Broadcast ();
GameObject[] objArr;
Vector3 velocity = Vector3.zero; Quaternion targetRotation; Rigidbody rBody; float forwardInput, turnInput; Animator anim; static float startTime; Text winText; Text timerText; static bool timerStart;
public Quaternion TargetRotation { get { return targetRotation;} }
bool Grounded() { return Physics.Raycast (transform.position, Vector3.down, moveSetting.distToGround, moveSetting.ground); }
void Start () { // Get rigidbody if (GetComponent<Rigidbody> ()) { rBody = GetComponent<Rigidbody> (); } else { Debug.LogError ("The character needs a rigit body"); } anim = GetComponent<Animator> ();
// moving setting targetRotation = transform.rotation; forwardInput = turnInput = 0; moveSetting.forwardVel = moveSetting.turnVel = 0f;
//timer and result setting timerStart = false; timerText = GameObject.Find ("Timer").GetComponent<Text>() as Text; winText = GameObject.Find("WinText").GetComponent<Text>() as Text; }
void GetInput() { forwardInput = Input.GetAxis (inputSetting.FORWARD_AXIS);// from -1 to 1, interpolated turnInput = Input.GetAxis (inputSetting.TURN_AXIS);// interpolated // forwardInput = CrossPlatformInputManager.GetAxis (inputSetting.FORWARD_AXIS); // turnInput = CrossPlatformInputManager.GetAxis (inputSetting.TURN_AXIS);// interpolated }
// Update is called once per frame void Update () {// happens one time per frame if (photonView.isMine) { GetInput (); if (timerStart) { TimerElapse (); } } }
void FixedUpdate () {// happens multiple times per frame Run (); rBody.velocity = transform.TransformDirection(velocity); if (isForwarding () || isBackwarding () || isTurningLeft() || isTurningRight()) { anim.SetBool ("isRunning", true); } else { anim.SetBool ("isRunning", false); } }
void Run () { if (Mathf.Abs (forwardInput) > inputSetting.inputDelay) { velocity.z = moveSetting.forwardVel * Mathf.Abs(forwardInput); } else if (Mathf.Abs (turnInput) > inputSetting.inputDelay) { velocity.z = moveSetting.turnVel * Mathf.Abs(turnInput); } else { velocity.z = 0; } } public bool isForwarding() { return forwardInput > 0; }
public bool isBackwarding() { return forwardInput < 0; }
public bool isTurningLeft() { return turnInput > 0; }
public bool isTurningRight() { return turnInput < 0; }
void endGame() { timerText.text = "GameOver"; timerStart = false; moveSetting.forwardVel = 0f; moveSetting.turnVel = 0f; }
void TimerElapse() { float timeleft = timerSetting.gameTime - (Time.time - startTime); if (timeleft <= 0) { if (PhotonNetwork.isMasterClient) { winText.text = "You Win!"; photonView.RPC ("Listener", PhotonTargets.Others, false); endGame(); } return; } string minutes = ((int)timeleft / 60).ToString (); string seconds = (timeleft % 60).ToString ("f2"); timerText.text = minutes + ":" + seconds; } void OnCollisionEnter(Collision collision) { if (PhotonNetwork.isMasterClient) { winText.text = "You Lose!"; photonView.RPC ("Listener", PhotonTargets.Others, true); endGame(); } }
[PunRPC] public void Listener(bool isWin){ winText.text = isWin ? "You Win!" : "You Lose!"; endGame (); }
void OnGUI() { if (PhotonNetwork.room == null) return; //Only display this GUI when inside a room if (GUILayout.Button("Leave Room")) { PhotonNetwork.LeaveRoom(); } if (GUILayout.Button ("Start")) { photonView.RPC ("StartGame", PhotonTargets.All); } }
[PunRPC] void StartGame() { moveSetting.forwardVel = 120f; moveSetting.turnVel = 120f; startTime = Time.time; timerStart = true; winText.text = ""; } }