I was trying to make a checkers game in unity but with multiplayer mode. I'm using unity 2022.3.8 version and Mirror plugin.
The problem is that I don't know how to force server to destroy object that I want to be destroyed on the client, and on the host.
I tried using [Command] and [ClientRpc] but it didn't work.
PlayerPrefabManager and GhostScript are the most important here in my opinion.
What's also worth notice is that mainObj.ObjectToDestroy isn't null because I tried to Debug it's name before calling CallServerToDestroy() fun. and it worked as it should. But doing the same in RpcDebug() fun, ends with null result. What's weird in my opinion is that when I'm replacing mainObj.ObjectToDestroy with static GameObject, like transform.GetChild(0).gameObject it works normally.
At first I thought that is because mainObj.ObjectToDestroy is null but as I wrote it isn't. I might misunderstand something, I'm still learning unity multiplayer features.
Please I need your help.
PlayerPrefabManager
public class PlayerPrefabManager : NetworkBehaviour
{
private void Awake()
{
if(GameObject.FindGameObjectsWithTag("WhitePlayer").Length == 0)
{
transform.tag = "WhitePlayer";
transform.GetChild(1).gameObject.SetActive(false);
}
else
{
transform.tag = "BlackPlayer";
transform.GetChild(0).gameObject.SetActive(false);
}
}
void Update()
{
if (PlayerPrefs.GetInt("DestroyObject") == 1)
{
CallServerToDestroy();
PlayerPrefs.SetInt("DestroyObject", 0);
}
}
[Command]
void CallServerToDestroy()
{
RpcDebug();
}
[ClientRpc]
void RpcDebug()
{
CircleScript[] circleScriptList = FindObjectsOfType<CircleScript>();
foreach(CircleScript mainObj in circleScriptList)
{
if(mainObj.ObjectToDestroy != null)
{
NetworkServer.Destroy(mainObj.ObjectToDestroy.gameObject);
// Also tried using Destroy() without any success.
}
}
}
}
GhostScript
public class GhostScript : NetworkBehaviour
{
private Transform MainCircle;
private CircleScript circleScript;
public void CircleParent()
{
circleScript = transform.parent.GetComponent<CircleScript>();
MainCircle = transform.parent;
}
private void OnMouseDown()
{
MainCircle.position = transform.position;
MainCircle.GetComponent<CircleScript>().isActive = false;
if (circleScript.IsHitPossible()) PlayerPrefs.SetInt("DestroyObject", 1);
}
}
Here you have the rest of the code.
CornerScript
public class CornerScript : MonoBehaviour
{
private string deftag;
[NonSerialized] public bool Empty, Red, White;
[NonSerialized] public Transform OtherCircle;
private void Awake()
{
OtherCircle = null;
Empty = true;
}
void OnTriggerEnter2D(Collider2D collision)
{
deftag = collision.tag;
if (deftag == "UpRight" || deftag == "UpLeft" || deftag == "DownRight" || deftag == "DownLeft"
|| deftag == "Ghost" || deftag == "Corner") return;
Empty = false;
if(collision.transform.parent.parent.tag == "WhitePlayer")
{
White = true;
OtherCircle = collision.transform;
}
if (collision.transform.parent.parent.tag == "BlackPlayer")
{
Red = true;
OtherCircle = collision.transform;
}
}
private void OnTriggerExit2D(Collider2D collision)
{
deftag = collision.tag;
if (deftag == "UpRight" || deftag == "UpLeft" || deftag == "DownRight" || deftag == "DownLeft"
|| deftag == "Ghost" || deftag == "Corner") return;
White = false;
Red = false;
Empty = true;
OtherCircle = null;
}
public void WriteData() //Only for debug purposes
{
if (Empty) Debug.Log(transform.name + " " + transform.parent.name + " value 'Empty': " + Empty);
if (White) Debug.Log(transform.name + " " + transform.parent.name + " value 'White': " + White);
if (Red) Debug.Log(transform.name + " " + transform.parent.name + " value 'Red': " + Red);
}
}
CircleScript
public class CircleScript : NetworkBehaviour
{
public Transform RedGhost, WhiteGhost;
[NonSerialized] public GameObject ObjectToDestroy;
[NonSerialized] public bool isActive;
private Transform CirclesHandler;
private Transform UpperLeftCopy, UpperRightCopy, DownLeftCopy, DownRightCopy;
private static float lenght = 0.67f;
private bool GhostsInstantiated;
private Color DefColor;
private CornerScript UpRightCorner, UpLeftCorner, DownRightCorner, DownLeftCorner;
private CornerScript FarUpRightCorner, FarUpLeftCorner, FarDownRightCorner, FarDownLeftCorner;
private void Awake()
{
ObjectToDestroy = null;
CirclesHandler = transform.parent.parent;
DefColor = transform.GetComponent<SpriteRenderer>().color;
UpRightCorner = transform.GetChild(0).GetComponent<CornerScript>();
UpLeftCorner = transform.GetChild(2).GetComponent<CornerScript>();
DownLeftCorner = transform.GetChild(4).GetComponent<CornerScript>();
DownRightCorner = transform.GetChild(6).GetComponent<CornerScript>();
FarUpRightCorner = transform.GetChild(1).GetComponent<CornerScript>();
FarUpLeftCorner = transform.GetChild(3).GetComponent<CornerScript>();
FarDownLeftCorner = transform.GetChild(5).GetComponent<CornerScript>();
FarDownRightCorner = transform.GetChild(7).GetComponent<CornerScript>();
}
private void Update()
{
if (IsHitPossible()) transform.GetComponent<SpriteRenderer>().color = Color.black;
if (!IsHitPossible()) transform.GetComponent<SpriteRenderer>().color = DefColor;
if (!isActive)
{
if (GhostsInstantiated) GhostDestroy();
return;
}
}
private void OnMouseDown()
{
SetActiveInParent(CirclesHandler.GetChild(0));
SetActiveInParent(CirclesHandler.GetChild(1));
if (!GhostsInstantiated) GhostInstantiate();
isActive = true;
}
void SetActiveInParent(Transform transform)
{
int child_count = transform.childCount;
for(int i = 0; i < child_count; i++)
{
transform.GetChild(i).GetComponent<CircleScript>().isActive = false;
}
}
void GhostInstantiate()
{
if(IsHitPossible() == false)
{
switch (CirclesHandler.tag)
{
case "WhitePlayer":
if (UpLeftCorner.Empty)
{
UpperLeftCopy = Instantiate(WhiteGhost,
new Vector2(transform.position.x - lenght, transform.position.y + lenght), Quaternion.identity);
UpperLeftCopy.tag = "Ghost";
UpperLeftCopy.SetParent(transform);
UpperLeftCopy.GetComponent<GhostScript>().CircleParent();
ObjectToDestroy = null;
InRange(UpperLeftCopy);
}
if (UpRightCorner.Empty)
{
UpperRightCopy = Instantiate(WhiteGhost,
new Vector2(transform.position.x + lenght, transform.position.y + lenght), Quaternion.identity);
UpperRightCopy.tag = "Ghost";
UpperRightCopy.SetParent(transform);
UpperRightCopy.GetComponent<GhostScript>().CircleParent();
ObjectToDestroy = null;
InRange(UpperRightCopy);
}
break;
case "BlackPlayer":
if (DownRightCorner.Empty)
{
UpperLeftCopy = Instantiate(RedGhost,
new Vector2(transform.position.x - lenght, transform.position.y - lenght), Quaternion.identity);
UpperLeftCopy.tag = "Ghost";
UpperLeftCopy.SetParent(transform);
UpperLeftCopy.GetComponent<GhostScript>().CircleParent();
ObjectToDestroy = null;
InRange(UpperLeftCopy);
}
if (DownLeftCorner.Empty)
{
UpperRightCopy = Instantiate(RedGhost,
new Vector2(transform.position.x + lenght, transform.position.y - lenght), Quaternion.identity);
UpperRightCopy.tag = "Ghost";
UpperRightCopy.SetParent(transform);
UpperRightCopy.GetComponent<GhostScript>().CircleParent();
ObjectToDestroy = null;
InRange(UpperRightCopy);
}
break;
}
}
else
{
switch (CirclesHandler.tag)
{
case "WhitePlayer":
if (FarUpLeftCorner.Empty && UpLeftCorner.Red)
{
UpperLeftCopy = Instantiate(WhiteGhost,
new Vector2(transform.position.x - 2 * lenght, transform.position.y + 2 * lenght), Quaternion.identity);
UpperLeftCopy.tag = "Ghost";
UpperLeftCopy.SetParent(transform);
UpperLeftCopy.GetComponent<GhostScript>().CircleParent();
ObjectToDestroy = UpLeftCorner.OtherCircle.gameObject;
InRange(UpperLeftCopy);
}
if (FarDownLeftCorner.Empty && DownLeftCorner.Red)
{
DownLeftCopy = Instantiate(WhiteGhost,
new Vector2(transform.position.x - 2 * lenght, transform.position.y - 2 * lenght), Quaternion.identity);
DownLeftCopy.tag = "Ghost";
DownLeftCopy.SetParent(transform);
DownLeftCopy.GetComponent<GhostScript>().CircleParent();
ObjectToDestroy = DownLeftCorner.OtherCircle.gameObject;
InRange(DownLeftCopy);
}
if (FarUpRightCorner.Empty && UpRightCorner.Red)
{
UpperRightCopy = Instantiate(WhiteGhost,
new Vector2(transform.position.x + 2 * lenght, transform.position.y + 2 * lenght), Quaternion.identity);
UpperRightCopy.tag = "Ghost";
UpperRightCopy.SetParent(transform);
UpperRightCopy.GetComponent<GhostScript>().CircleParent();
ObjectToDestroy = UpRightCorner.OtherCircle.gameObject;
InRange(UpperRightCopy);
}
if (FarDownRightCorner.Empty && DownRightCorner.Red)
{
DownRightCopy = Instantiate(WhiteGhost,
new Vector2(transform.position.x - 2 * lenght, transform.position.y + 2 * lenght), Quaternion.identity);
DownRightCopy.tag = "Ghost";
DownRightCopy.SetParent(transform);
DownRightCopy.GetComponent<GhostScript>().CircleParent();
ObjectToDestroy = DownRightCorner.OtherCircle.gameObject;
InRange(DownRightCopy);
}
break;
case "BlackPlayer":
if (FarDownRightCorner.Empty && DownRightCorner.White)
{
DownRightCopy = Instantiate(RedGhost,
new Vector2(transform.position.x - 2 * lenght, transform.position.y + 2 * lenght), Quaternion.identity);
DownRightCopy.tag = "Ghost";
DownRightCopy.SetParent(transform);
DownRightCopy.GetComponent<GhostScript>().CircleParent();
ObjectToDestroy = DownRightCorner.OtherCircle.gameObject;
InRange(DownRightCopy);
}
if (FarUpRightCorner.Empty && UpRightCorner.White)
{
UpperRightCopy = Instantiate(RedGhost,
new Vector2(transform.position.x + 2 * lenght, transform.position.y + 2 * lenght), Quaternion.identity);
UpperRightCopy.tag = "Ghost";
UpperRightCopy.SetParent(transform);
UpperRightCopy.GetComponent<GhostScript>().CircleParent();
ObjectToDestroy = UpRightCorner.OtherCircle.gameObject;
InRange(UpperRightCopy);
}
if (FarDownLeftCorner.Empty && DownLeftCorner.White)
{
DownLeftCopy = Instantiate(RedGhost,
new Vector2(transform.position.x - 2 * lenght, transform.position.y - 2 * lenght), Quaternion.identity);
DownLeftCopy.tag = "Ghost";
DownLeftCopy.SetParent(transform);
DownLeftCopy.GetComponent<GhostScript>().CircleParent();
ObjectToDestroy = DownLeftCorner.OtherCircle.gameObject;
InRange(DownLeftCopy);
}
if (FarUpLeftCorner.Empty && UpLeftCorner.White)
{
UpperLeftCopy = Instantiate(RedGhost,
new Vector2(transform.position.x - 2 * lenght, transform.position.y + 2 * lenght), Quaternion.identity);
UpperLeftCopy.tag = "Ghost";
UpperLeftCopy.SetParent(transform);
UpperLeftCopy.GetComponent<GhostScript>().CircleParent();
ObjectToDestroy = UpLeftCorner.OtherCircle.gameObject;
InRange(UpperLeftCopy);
}
break;
}
}
GhostsInstantiated = true;
}
void GhostDestroy()
{
//if (HitPossible) return; // Debug.
if (UpperLeftCopy != null) Destroy(UpperLeftCopy.gameObject);
if (UpperRightCopy != null) Destroy(UpperRightCopy.gameObject);
if (DownLeftCopy != null) Destroy(DownLeftCopy.gameObject);
if (DownRightCopy != null) Destroy(DownRightCopy.gameObject);
GhostsInstantiated = false;
}
void InRange(Transform transform)
{
if(!(transform.position.x >= -2.65f && transform.position.x <= 2.65f &&
transform.position.y >= -2.65f && transform.position.y <= 2.65f))
{
Destroy(transform.gameObject);
}
}
public bool IsHitPossible()
{
if(CirclesHandler.tag == "WhitePlayer")
{
if (UpRightCorner.Red && FarUpRightCorner.Empty) return true;
if (UpLeftCorner.Red && FarUpLeftCorner.Empty) return true;
if (DownRightCorner.Red && FarDownRightCorner.Empty) return true;
if (DownLeftCorner.Red && FarDownLeftCorner.Empty) return true;
}
if(CirclesHandler.tag == "BlackPlayer")
{
if (UpRightCorner.White && FarUpRightCorner.Empty) return true;
if (UpLeftCorner.White && FarUpLeftCorner.Empty) return true;
if (DownRightCorner.White && FarDownRightCorner.Empty) return true;
if (DownLeftCorner.White && FarDownLeftCorner.Empty) return true;
}
return false;
}
void DebugFunction() //Only for debug purposes.
{
UpRightCorner.WriteData();
UpLeftCorner.WriteData();
DownRightCorner.WriteData();
DownLeftCorner.WriteData();
FarUpLeftCorner.WriteData();
FarUpRightCorner.WriteData();
FarDownLeftCorner.WriteData();
FarDownRightCorner.WriteData();
}
}
As I wrote I tried to use [Command] and [Rpc]. Also tried with some tutorials from YouTube, and spend few hours analysing Unity Manual without result.