Hello & Good evening! now I have rethought it.. and my result looks like you can see on the following screenshot: One player is able to control the car and the other can control the tower and shoot. But I think the implementation/logic behind sucks My Idea: I have dragged a car model in the scene (just with a rigidbody, box collider, wheel collider etc.). And I spawn a player (empty Gameobject with the "CAR1" Script on it. Is there a better solution or an advice? Thank you Code (CSharp): using UnityEngine; using System.Collections; using System.Collections.Generic; using UnityEngine.Networking; [System.Serializable] public class AxleInfo11 { public WheelCollider leftWheel; public WheelCollider rightWheel; public bool motor; public bool steering; } public class CAR1 : NetworkBehaviour { public List<AxleInfo11> axleInfos; public float maxMotorTorque; public float maxSteeringAngle; private float LerpValue = 2; private float MinPosDist = 0.5F; public int playerMODE = 0; private CAR1 carScript; GameObject carCRAB; private Transform towerObject; private Transform cannon; private Transform gunTIP; private Vector3 lastTankpos; private Quaternion lastTankRot; //Geschützturm private float lsTowerRotationY; private float LerpTurningTower = 2; private float MinMovementTower = 2F; private float lsCannonRotZ; private float LerpTurningCannon = 2; private float MinMovmentCannon = 2F; //Motor-Steering private float lsTankSteering; private float LerpTankSteering = 0.5F; private float MinAngleSteering = 2F; private float lsTankMotor; private float LerpTankMotor = 0.5F; private float MinAngleMotor = 2F; [SyncVar] private Vector3 cTankPos; [SyncVar] private Quaternion cTankRot; [SyncVar] public float motorVar; [SyncVar] public float steeringVar; [SyncVar] public float towerRotationY; [SyncVar] public float cannonRotationZ; private float rotationZ = 0f; private float sensitivityZ = 2f; private AudioSource shootSound; private ParticleSystem particleShootingSmoke; void Start() { //FIND TANK carCRAB = GameObject.Find("CarLokal"); towerObject = GameObject.Find("Drehturm").transform; shootSound = towerObject.GetComponent<AudioSource>(); cannon = GameObject.Find("Drehkanone").transform; gunTIP = GameObject.Find("WEAPONTIP").transform; particleShootingSmoke = gunTIP.GetChild(0).transform.GetComponent<ParticleSystem>(); carScript = GetComponent<CAR1>(); carScript.axleInfos[0].leftWheel = carCRAB.transform.GetChild(1).transform.GetComponent<WheelCollider>(); ; carScript.axleInfos[0].rightWheel = carCRAB.transform.GetChild(2).transform.GetComponent<WheelCollider>(); ; carScript.axleInfos[1].leftWheel = carCRAB.transform.GetChild(3).transform.GetComponent<WheelCollider>(); ; carScript.axleInfos[1].rightWheel = carCRAB.transform.GetChild(4).transform.GetComponent<WheelCollider>(); ; //tank won't flip that easy Rigidbody rb = carCRAB.GetComponent<Rigidbody>(); rb.centerOfMass = new Vector3(0, -0.4F, 0); playerMODE = GameObject.Find("NETWORKMANAGER").GetComponent<CurrentPos>().playerMODE; if (playerMODE == 1) { rb.isKinematic = true; } } void Update() { if(playerMODE==1) { if (Input.GetButtonDown("Fire1")) { StopCoroutine("Shoot"); StartCoroutine("Shoot"); } } } // example unity public void ApplyLocalPositionToVisuals(WheelCollider collider) { if (collider.transform.childCount == 0) { return; } Transform visualWheel = collider.transform.GetChild(0); Vector3 position; Quaternion rotation; collider.GetWorldPose(out position, out rotation); visualWheel.transform.position = position; visualWheel.transform.rotation = rotation; } private void ChangeAxisValues(float steering1, float motor1) { foreach (AxleInfo11 axleInfo in axleInfos) { if (axleInfo.steering) { axleInfo.leftWheel.steerAngle = steering1; axleInfo.rightWheel.steerAngle = steering1; } if (axleInfo.motor) { axleInfo.leftWheel.motorTorque = motor1; axleInfo.rightWheel.motorTorque = motor1; } ApplyLocalPositionToVisuals(axleInfo.leftWheel); ApplyLocalPositionToVisuals(axleInfo.rightWheel); } } public void FixedUpdate() { //MODE == DRIVER if (playerMODE == 0) { float motor = maxMotorTorque * Input.GetAxis("Vertical"); float steering = maxSteeringAngle * Input.GetAxis("Horizontal"); ChangeAxisValues(steering, motor); Vector3 currPos = carCRAB.transform.position; ChangeCarPosition(currPos); Quaternion currRot = carCRAB.transform.rotation; ChangeCarRotation(currRot); if (isOverThreshold(lastTankpos, currPos, MinPosDist)) { CmdSendPosition(currPos); lastTankpos = currPos; CmdSendRotation(currRot); lastTankRot = currRot; CmdSendMotor(motor); lsTankMotor = motor; } //TOWER InterpolateTurretY(); InterpolateKanoneZ(); if (isOverThresholdFloat(lsTankSteering, steering, MinAngleSteering)) { CmdSendSteering(steering); lsTankSteering = steering; } } else //MODE == SHOOTER { Interpolate(); InterpolateRot(); ChangeAxisValues(InterpolateSteering(), motorVar); //ROTATION WHOLE TOWER towerObject.transform.Rotate(0.0f, Input.GetAxis("Horizontal") * 2, 0.0f); if (isOverThresholdTurret(lsTowerRotationY, towerObject.transform.localRotation.y, MinMovementTower)) { CmdSendTowerY(towerObject.transform.localEulerAngles.y); lsTowerRotationY = towerObject.transform.localEulerAngles.y; } //TOTATE CANNON rotationZ += Input.GetAxis("Vertical") * sensitivityZ; rotationZ = Mathf.Clamp(rotationZ, -20, 90); cannon.transform.localEulerAngles = new Vector3(cannon.transform.localEulerAngles.x, cannon.transform.localEulerAngles.y, -rotationZ); if (isOverThresholdDrehKanone(lsCannonRotZ, cannon.transform.localEulerAngles.z, MinMovmentCannon)) { CmdSendDrehKanoneZ(cannon.transform.localEulerAngles.z); lsCannonRotZ = cannon.transform.localEulerAngles.z; } } } //CAR POSITION [Command] private void CmdSendPosition(Vector3 pos) { cTankPos = pos; } [Client] private void ChangeCarPosition(Vector3 pos) { carCRAB.transform.position = pos; } [Command] private void CmdSendMotor(float motor) { motorVar = motor; } [Command] private void CmdSendSteering(float steering) { steeringVar = steering; } //CAR ROTATION [Command] private void CmdSendRotation(Quaternion rot) { cTankRot = rot; } [Client] private void ChangeCarRotation(Quaternion rot) { carCRAB.transform.rotation = rot; } //TOWER [Command] private void CmdSendTowerY(float rotY) { lsTowerRotationY = rotY; } [Command] private void CmdSendDrehKanoneZ(float rotZ) { lsCannonRotZ = rotZ; } //INTERPOLATION STUFF --> simplify later on private void Interpolate() { Vector3 pos = Vector3.Lerp(carCRAB.transform.position, cTankPos, Time.deltaTime * LerpValue); carCRAB.transform.position = pos; } private void InterpolateRot() { Quaternion rot = Quaternion.Lerp(carCRAB.transform.rotation, cTankRot, Time.deltaTime * LerpValue); carCRAB.transform.rotation = rot; } private void InterpolateTurretY() { towerObject.transform.localEulerAngles = new Vector3(towerObject.transform.localEulerAngles.x, Mathf.Lerp(towerObject.transform.localEulerAngles.y, lsTowerRotationY, LerpTurningTower), towerObject.transform.localEulerAngles.z); } private void InterpolateKanoneZ() { cannon.transform.localEulerAngles = new Vector3(cannon.transform.localEulerAngles.x, cannon.transform.localEulerAngles.y, Mathf.Lerp(cannon.transform.localEulerAngles.y, lsCannonRotZ, LerpTurningCannon)); } private float InterpolateSteering() { return Mathf.Lerp(lsTankSteering, steeringVar, LerpTankSteering); } private float InterpolateMotor() { return Mathf.Lerp(lsTankMotor, motorVar, LerpTankMotor); } private bool isOverThreshold(Vector3 old, Vector3 pos, float threshold) { return Vector3.Distance(old, pos) > threshold; } private bool isOverThresholdTurret(float old, float pos, float angleThreshold) { return (old - pos) > angleThreshold || (old - pos) < angleThreshold; } private bool isOverThresholdDrehKanone(float old, float pos, float angleThreshold) { return (old - pos) > angleThreshold || (old - pos) < angleThreshold; } private bool isOverThresholdFloat(float old, float pos, float angleThreshold) { return (old - pos) > angleThreshold || (old - pos) < angleThreshold; } IEnumerator Shoot() { while (Input.GetButton("Fire1")) { CmdShoot(); shootSound.Stop(); shootSound.Play(); particleShootingSmoke.Play(); Vector3 fwd = gunTIP.transform.TransformDirection(Vector3.forward); Debug.DrawRay(gunTIP.transform.position, fwd * 50, Color.green); RaycastHit hit; if (Physics.Raycast(gunTIP.transform.position, fwd, out hit, 100)) { Debug.DrawLine(gunTIP.transform.position, hit.point, Color.red); if (hit.transform.tag == "ENEMY") { Debug.Log("TEST"); } } particleShootingSmoke.Stop(); yield return new WaitForSeconds(0.1F); } } [Command] public void CmdShoot() { shootSound.Stop(); shootSound.Play(); particleShootingSmoke.Play(); Vector3 fwd = gunTIP.transform.TransformDirection(Vector3.forward); Debug.DrawRay(gunTIP.transform.position, fwd * 50, Color.green); RaycastHit hit; if (Physics.Raycast(gunTIP.transform.position, fwd, out hit, 100)) { Debug.DrawLine(gunTIP.transform.position, hit.point, Color.red); if (hit.transform.tag == "ENEMY") { Debug.Log("TEST"); } } particleShootingSmoke.Stop(); } } Spoiler: OLD THOUGHTS firstly I've found similar threads but unfortunately I can't really solve my problem I've tried several things but I'm.... stuck. Idea: I want the user to join a room and then walk to different vehicles and control them. Further more I want that player1 controls the car movement and player2 the rotation of the turret (or is able to control the radio etc..). Simplification: Empty Gameobject Player spawns: currentmode =0 --> Player can control the car currentmode =1 --> Player can control the turret Problem. I'm not sure about the logic behind the scenario. 1. My first thought was to create 1 car in my scene add a network identity, check Local Player Authority, add a network transform to that car. And when the game starts each player can control this 1 car. 2. Or do I instantiate for all player in that car 1 car object and disable the visibility and then sync. Player 1 --> syncs turret rotation/ receives car position Player 2 --> syncs car movement/ receives turret rotation Hmm appreciate some hints/help Short: I want two ore more player to control different car gadgets. And for those who aren't confused yet...: ____________________ My plan: 1. Empty Gameobject (Network Identity -> local player authority checked) assigned to the Network Manager Script Code (CSharp): using UnityEngine; using System.Collections; using UnityEngine.Networking; public class PlayerController : NetworkBehaviour { GameObject car; int currentmode = 0; public GUISkin guistyle; private CarController carcontroller; private CarShooter carShooter; void Start() { car = GameObject.Find("CarLokal"); carcontroller = car.GetComponent<CarController>(); carShooter = car.GetComponent<CarShooter>(); } void OnGUI() { if(!isLocalPlayer || isServer) { return; } GUI.skin = guistyle; GUI.color = Color.red; GUILayout.BeginArea(new Rect(Screen.width / 2 - 200, Screen.height - 100, 400, 400)); if (GUILayout.Button("Mode1")) { currentmode = 0; } if (GUILayout.Button("Mode2")) { currentmode = 1; } GUILayout.Label("MODE: " + currentmode); GUILayout.EndArea(); } void Update () { if (!isLocalPlayer) { return; } if(currentmode==0) { if(carcontroller !=null) { carcontroller.GiveVal(Input.GetAxis("Vertical"), Input.GetAxis("Horizontal")); // carcontroller.RpcGiveVal(Input.GetAxis("Vertical"), Input.GetAxis("Horizontal")); // carcontroller.CmdGiveVal(Input.GetAxis("Vertical"), Input.GetAxis("Horizontal")); } } else { if(carShooter !=null) { carShooter.GiveVal(Input.GetAxis("Vertical"), Input.GetAxis("Horizontal")); // carShooter.RpcGiveVal(Input.GetAxis("Vertical"), Input.GetAxis("Horizontal")); // carShooter.CmdGiveVal(Input.GetAxis("Vertical"), Input.GetAxis("Horizontal")); } } } } ___________________________ Car placed in the scene (Network Identity-> Local Player Authority checked + Car Shooter (Script) + Network Transform?!) Code (CSharp): using UnityEngine; using System.Collections; using System.Collections.Generic; using UnityEngine.Networking; [System.Serializable] public class AxleInfo2 { public WheelCollider leftWheel; public WheelCollider rightWheel; public bool motor; public bool steering; } public class CarController : NetworkBehaviour { public List<AxleInfo2> axleInfos; public float maxMotorTorque; public float maxSteeringAngle; private PlayerCamera playerCamera; void Start() { Rigidbody rb = GetComponent<Rigidbody>(); rb.centerOfMass = new Vector3(0, -0.4F, 0); } // finds the corresponding visual wheel // correctly applies the transform public void ApplyLocalPositionToVisuals(WheelCollider collider) { if (collider.transform.childCount == 0) { return; } Transform visualWheel = collider.transform.GetChild(0); Vector3 position; Quaternion rotation; collider.GetWorldPose(out position, out rotation); visualWheel.transform.position = position; visualWheel.transform.rotation = rotation; } [SyncVar] public float currentVert=0; [SyncVar] public float currentHori=0; //Now let's start the confusion party :) [Command] public void CmdGiveVal(float currentVert, float currentHori) { this.currentVert = currentVert; this.currentHori = currentHori; } public void GiveVal(float currentVert, float currentHori) { this.currentVert = currentVert; this.currentHori = currentHori; } [ClientRpc] public void RpcGiveVal(float currentVert, float currentHori) { this.currentVert = currentVert; this.currentHori = currentHori; } public void FixedUpdate() { // if (!isServer) // { // RpcSpreadVal(Input.GetAxis("Vertical"), Input.GetAxis("Horizontal")); // } // if (isLocalPlayer) // { // RpcGiveVal(Input.GetAxis("Vertical"), Input.GetAxis("Horizontal")); // } // if(!isLocalPlayer) // { // return; // } // GiveVal(Input.GetAxis("Vertical"), Input.GetAxis("Horizontal")); float motor = maxMotorTorque * currentVert; float steering = maxSteeringAngle * currentHori; foreach (AxleInfo2 axleInfo in axleInfos) { if (axleInfo.steering) { axleInfo.leftWheel.steerAngle = steering; axleInfo.rightWheel.steerAngle = steering; } if (axleInfo.motor) { axleInfo.leftWheel.motorTorque = motor; axleInfo.rightWheel.motorTorque = motor; } ApplyLocalPositionToVisuals(axleInfo.leftWheel); ApplyLocalPositionToVisuals(axleInfo.rightWheel); } } } Code (CSharp): using UnityEngine; using System.Collections; using UnityEngine.Networking; public class CarShooter : NetworkBehaviour { public Transform tower; public Transform towerBarrel; [SyncVar] public float currentVert = 0; [SyncVar] public float currentHori = 0; [Command] public void CmdGiveVal(float currentVert, float currentHori) { this.currentVert = currentVert; this.currentHori = currentHori; } // Use this for initialization void Start () { } float speed = 4; [ClientRpc] public void RpcGiveVal(float currentVert, float currentHori) { this.currentVert = currentVert; this.currentHori = currentHori; } public void GiveVal(float currentVert, float currentHori) { this.currentVert = currentVert; this.currentHori = currentHori; } private float rotationZ = 0f; private float sensitivityZ = 2f; // Update is called once per frame void Update () { // GiveVal(Input.GetAxis("Vertical"), Input.GetAxis("Horizontal")); // if(isLocalPlayer) // { // RpcGiveVal(Input.GetAxis("Vertical"), Input.GetAxis("Horizontal")); // } // if (!isServer) // { // RpcSpreadVal(Input.GetAxis("Vertical"), Input.GetAxis("Horizontal")); // } tower.transform.Rotate(0.0f, currentHori * speed, 0.0f); // towerBarrel.transform.Rotate(0.0f, -Input.GetAxis("V") * speed, 0.0f); // towerBarrel.transform.Rotate(0, Input.GetAxis("Vertical") * speed * Time.deltaTime, 0); //The function is Mathf.Clamp(value, min, max) rotationZ += currentVert * sensitivityZ; rotationZ = Mathf.Clamp(rotationZ, -20, 90); towerBarrel.transform.localEulerAngles = new Vector3(towerBarrel.transform.localEulerAngles.x, towerBarrel.transform.localEulerAngles.y, -rotationZ); /* if (Input.GetKey(KeyCode.A)) { transform.Rotate(Vector3.up * speed * Time.deltaTime); } if (Input.GetKey(KeyCode.D)) transform.Rotate(-Vector3.up * speed * Time.deltaTime); */ } } Regards Leo
Hmm ok now I have an idea Here's a small script for changing the color of one cube (every player in the scene can change it) (This is the same idea/just for movement right?) - Or is this script terrible (insecure?) Code (CSharp): using UnityEngine; using System.Collections; using UnityEngine.Networking; public class PlayerColor : NetworkBehaviour { GameObject cubeObj; private MeshRenderer meshRend; void Start () { cubeObj = GameObject.Find("Cube"); meshRend = cubeObj.GetComponent<MeshRenderer>(); } void Update () { if (isLocalPlayer) { if(Input.GetButtonDown("Fire1")) { Color32 colornew = GenColor(); ChangeMaterialColor(colornew); CmdSendColor(colornew); } } } [Command] private void CmdSendColor(Color32 materialColor) { meshRend.material.color = materialColor; RpcSyncMaterialcolor(materialColor); } Color32 GenColor() { return new Color32((byte)Random.Range(0, 255), (byte)Random.Range(0, 255), (byte)Random.Range(0, 255), 255); ; } [ClientRpc] private void RpcSyncMaterialcolor(Color32 materialColor) { ChangeMaterialColor(materialColor); } [Client] private void ChangeMaterialColor(Color32 materialColor) { meshRend.material.color = materialColor; } }