Ваша проблема в том, что вы вычисляете значение curColOfThisObject
на стороне клиента, но в то же время используете для него [SyncVar]
.
Из [SyncVar]
Документ :
Значения этих переменных будут синхронизированы от сервера к клиентам
-> Не изменять значения на клиентах в RpcNextColor
, а уже на сервере в CmdNextColor
. В противном случае curColOfThisObject
будет немедленно перезаписано значением по умолчанию, которое никогда не изменялось на сервере. Я бы передал значение клиентам в качестве параметра в [ClientRpc]
, так что технически вам даже не понадобится [SyncVar]
.
В CamMovement
[Command]
public void CmdNextColor(GameObject hitObject)
{
RPC_ColorChange colorChange = hitObject.GetComponent<RPC_ColorChange>();
if (colorChange != null)
{
colorChange.NextColor();
// after calculating a new curColOfThisObject send it to clients (doesn't require [SyncVar] anymore)
colorChange.RpcNextColor(curColOfThisObject);
}
}
В RPC_ColorChange
// Make the calculation of the value on the server side
[Server]
private void NextColor()
{
if (material.Length > 0)
{
Material curMaterial = this.GetComponent<MeshRenderer>().material;
curColOfThisObject++;
if (curColOfThisObject >= material.Length)
curColOfThisObject = 0;
// set the material also on the server
curMaterial = material[curColOfThisObject];
}
}
[ClientRpc]
public void RpcNextColor(int newValue)
{
if (!isClient) return;
// easier to debug if you keep the curColOfThisObject variable
curColOfThisObject = newValue;
if(newValue=> material.Length)
{
Debug.LogError("index not found in material");
return;
}
// instead of curColOfThisObject you could also just use the newValue
// but this is easier to debug
curMaterial = material[curColOfThisObject];
}
Если вы хотите придерживаться [SyncVar]
, вы также можете полностью пропустить ClientRpc
и сделать его hook
для [SyncVar]
вместо этого:
В CamMovement
[Command]
public void CmdNextColor(GameObject hitObject)
{
RPC_ColorChange colorChange = hitObject.GetComponent<RPC_ColorChange>();
if (colorChange != null)
{
colorChange.NextColor();
}
}
В RPC_ColorChange
[SyncVar(hook = "OnNextColor")]
private int curColOfThisObject;
// Make the calculation of the value on the server side
[Server]
private void NextColor()
{
if (material.Length > 0)
{
Material curMaterial = this.GetComponent<MeshRenderer>().material;
curColOfThisObject++;
if (curColOfThisObject >= material.Length)
curColOfThisObject = 0;
// set the material also on the server
curMaterial = material[curColOfThisObject];
}
}
// This method automatically gets called when the value of
// curColOfObject is changed to newValue on the server
private void OnNextColor(int newValue)
{
if (!isClient) return;
// easier to debug if you keep the curColOfThisObject variable
curColOfThisObject = newValue;
if(newValue=> material.Length)
{
Debug.LogError("index not found in material");
return;
}
// instead of curColOfThisObject you could also just use the newValue
// but this is easier to debug
curMaterial = material[curColOfThisObject];
}
Немного больше: я бы проверил наличие RPC_ColorChange
компонента до того, как Я отправлю материал по сети.
if (Input.GetMouseButtonDown(0))
{
Ray ray = cam.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if (Physics.Raycast(ray, out hit))
{
if(hit.GetComponent<RPC_ColorChange>()!=null)
{
CmdNextColor(hit.transform.gameObject);
}
}
}
Имейте в виду, что вы можете ударить ребенка или родителя вместо реального объекта, который вы хотели бы ударить .. так что evtl. вам придется искать компонент RPC_ColorChange
в потомках или родителях, используя GetComponentInChildren
или GetComponentInParent
.