problem is: in the project I am working on, it’s not a simple variable that needs to get synced, but many gameobjects (think: hex-tiles) stored to an 2d-array (called Map).
the hex tiles have this script:
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Networking;
using System.Collections;
using System.Collections.Generic;
////////////////////////////////////////////////////////////
/// base class for all tiles
////////////////////////////////////////////////////////////
public class Tile : NetworkBehaviour
{
// reference to game grid
protected GFHexGrid grid;
protected TileSystem tileSystem;
protected PlayerSystem playerSystem;
protected GUIController gui;
public SpriteRenderer tileGraphic;
public SpriteRenderer flagGraphic;
public Sprite[] tileGraphics;
[SyncVar]
public int ownerNumber = -1;
[SyncVar]
protected int ownerIndex = -1;
public int OwnerIndex
{
get { return ownerIndex; }
set
{
ChangeOwner(value);
}
}
private int upgradeLevel;
public int UpgradeLevel
{
get { return upgradeLevel; }
set
{
ChangeUpgradeLevel(value);
}
}
private int strength;
public int Strength
{
get { return strength; }
set
{
strength = value;
}
}
private bool changedOwner;
public bool ChangedOwner
{
get { return changedOwner; }
set
{
changedOwner = value;
}
}
private bool upgradedThisTurn = false;
public bool UpgradedThisTurn
{
get { return upgradedThisTurn; }
set
{
upgradedThisTurn = value;
}
}
public Vector2 MapCoords;
////////////////////////////////////////////////////////////
/// Awake
////////////////////////////////////////////////////////////
protected void Awake()
{
grid = GameObject.FindGameObjectWithTag("Grid").GetComponent<GFHexGrid>();
gui = GameObject.FindGameObjectWithTag("GUI").GetComponent<GUIController>();
GameObject game = GameObject.FindGameObjectWithTag("GameController");
tileSystem = game.GetComponent<TileSystem>();
playerSystem = game.GetComponent<PlayerSystem>();
upgradeLevel = 0;
}
////////////////////////////////////////////////////////////
/// Start
////////////////////////////////////////////////////////////
protected void Start()
{
// align object to grid
transform.position = grid.AlignVector3(transform.position);
}
////////////////////////////////////////////////////////////
/// Update
////////////////////////////////////////////////////////////
protected void Update()
{
}
////////////////////////////////////////////////////////////
/// OnMouseDown
////////////////////////////////////////////////////////////
void OnMouseDown()
{
if (EventSystem.current.IsPointerOverGameObject())
{
// nothing to do here, because GUI elements will handle
}
else // normal behaviour
{
if (this != null)
{
gui.showPopupMenu(this, tileSystem.isTileAttackable(this), tileSystem.isTileClaimable(this), tileSystem.isTileUpgradable(this));
//Debug.Log(grid.WorldToGrid(transform.position));
}
else
{
Debug.Log("something went horribly wrong: this is null (or at least not not null)");
}
}
}
////////////////////////////////////////////////////////////
/// ChangeOwner
////////////////////////////////////////////////////////////
protected void ChangeOwner(int playerIndex)
{
// if there is a previous owner
if (ownerIndex != -1)
{
// remove this ressource from him
playerSystem.Players[ownerIndex].RemoveRessource(this.transform.name);
}
else
{
UpgradeLevel = 1;
}
// add this ressource to new owner
playerSystem.Players[playerIndex].AddRessource(this.transform.name);
// set new flag
SetOwnerFlag(playerSystem.Players[playerIndex]);
// set new owner
ownerIndex = playerIndex;
ownerNumber = playerSystem.Players[playerIndex].PlayerNumber;
changedOwner = true;
}
private void SetOwnerFlag(Player newOwner)
{
flagGraphic.sprite = playerSystem.playerFlags[newOwner.PlayerNumber];
flagGraphic.color = Color.white;
}
private void ChangeUpgradeLevel(int value)
{
upgradeLevel = value;
tileSystem.AddTileToUpdateQueue(this);
SetBuilding();
}
private void SetBuilding()
{
tileGraphic.sprite = tileGraphics[upgradeLevel];
}
}
and are managed by this script, which would be the script attached to the scene object… the method I am having problems with is at line 208 and adds the tiles to the map (or at least should)
using UnityEngine;
using UnityEngine.Networking;
using System.Collections;
using System.Collections.Generic;
public class TileSystem : NetworkBehaviour
{
private GameController game;
private GameObject tileParent;
public GameObject clay;
public GameObject grain;
public GameObject grassland;
public GameObject stone;
public GameObject water;
public GameObject wood;
private Tile[,] map;
public Tile[,] Map
{
get { return map; }
}
private int mapSizeX;
private int mapSizeY;
private int mapMaxIndexX;
private int mapMaxIndexY;
private List<Tile> tileUpdateQueue;
////////////////////////////////////////////////////////////
/// Awake
////////////////////////////////////////////////////////////
protected void Awake()
{
game = GameObject.FindGameObjectWithTag("GameController").GetComponent<GameController>();
tileParent = GameObject.FindGameObjectWithTag("TileParent");
tileUpdateQueue = new List<Tile>();
mapSizeX = -(int)Mathf.RoundToInt(game.grid.renderFrom.x) + 1 + (int)Mathf.RoundToInt(game.grid.renderTo.x);
mapSizeY = -(int)Mathf.RoundToInt(game.grid.renderFrom.y) + 1 + (int)Mathf.RoundToInt(game.grid.renderTo.y);
map = new Tile[mapSizeX, mapSizeY];
mapMaxIndexX = mapSizeX - 1;
mapMaxIndexY = mapSizeY - 1;
}
internal void SpawnTiles()
{
if (hasAuthority)
{
CmdSpawnTiles();
}
}
////////////////////////////////////////////////////////////
/// CmdSpawnTiles
////////////////////////////////////////////////////////////
[Command]
internal void CmdSpawnTiles()
{
Debug.Log("CmdSpawnTiles");
if (true)
{
for (int x = (int)game.grid.renderFrom.x; x <= (int)game.grid.renderTo.x; x++)
{
for (int y = (int)game.grid.renderFrom.y; y <= (int)game.grid.renderTo.y; y++)
{
if (x == game.grid.renderFrom.x
|| x == game.grid.renderTo.x
|| y == game.grid.renderFrom.y
|| y == game.grid.renderTo.y)
{
GameObject go = InstantiateWaterTile(x, y);
NetworkServer.Spawn(go);
//AddTileToMap(x, y, go);
//RpcAddTileToMap(x, y, go);
}
else if (
(x == game.grid.renderFrom.x + 3 && y == game.grid.renderFrom.y + 3)
|| (x == game.grid.renderFrom.x + 3 && y == game.grid.renderTo.y - 3)
|| (x == game.grid.renderTo.x - 3 && y == game.grid.renderFrom.y + 3)
|| (x == game.grid.renderTo.x - 3 && y == game.grid.renderTo.y - 3)
|| (x == game.grid.renderFrom.x + 2 && y == game.grid.renderFrom.y + 1)
|| (x == game.grid.renderFrom.x + 2 && y == game.grid.renderTo.y - 1)
|| (x == game.grid.renderTo.x - 2 && y == game.grid.renderFrom.y + 1)
|| (x == game.grid.renderTo.x - 2 && y == game.grid.renderTo.y - 1)
)
{
GameObject go = InstantiateClayTile(x, y);
NetworkServer.Spawn(go);
AddTileToMap(x, y, go);
RpcAddTileToMap(x, y, go);
}
else if (
(x == game.grid.renderFrom.x + 1 && y == game.grid.renderFrom.y + 1)
|| (x == game.grid.renderFrom.x + 1 && y == game.grid.renderTo.y - 1)
|| (x == game.grid.renderTo.x - 1 && y == game.grid.renderFrom.y + 1)
|| (x == game.grid.renderTo.x - 1 && y == game.grid.renderTo.y - 1)
|| (x == game.grid.renderFrom.x + 3 && y == game.grid.renderTo.y - 4)
|| (x == game.grid.renderTo.x - 3 && y == game.grid.renderTo.y - 4)
|| (x == game.grid.renderFrom.x + 3 && y == game.grid.renderFrom.y + 4)
|| (x == game.grid.renderTo.x - 3 && y == game.grid.renderFrom.y + 4)
)
{
GameObject go = InstantiateGrainTile(x, y);
NetworkServer.Spawn(go);
AddTileToMap(x, y, go);
RpcAddTileToMap(x, y, go);
}
else if (
(x == game.grid.renderFrom.x + 1 && y == game.grid.renderFrom.y + 2)
|| (x == game.grid.renderFrom.x + 2 && y == game.grid.renderTo.y - 2)
|| (x == game.grid.renderTo.x - 1 && y == game.grid.renderFrom.y + 2)
|| (x == game.grid.renderTo.x - 2 && y == game.grid.renderTo.y - 2)
|| (x == game.grid.renderFrom.x + 4 && y == game.grid.renderTo.y - 4)
|| (x == game.grid.renderTo.x - 4 && y == game.grid.renderTo.y - 4)
|| (x == game.grid.renderFrom.x + 4 && y == game.grid.renderFrom.y + 3)
|| (x == game.grid.renderTo.x - 4 && y == game.grid.renderFrom.y + 3)
)
{
GameObject go = InstantiateWoodTile(x, y);
NetworkServer.Spawn(go);
AddTileToMap(x, y, go);
RpcAddTileToMap(x, y, go);
}
else if (
(x == game.grid.renderFrom.x + 4 && y == game.grid.renderFrom.y + 4)
|| (x == game.grid.renderFrom.x + 4 && y == game.grid.renderTo.y - 5)
|| (x == game.grid.renderTo.x - 4 && y == game.grid.renderFrom.y + 4)
|| (x == game.grid.renderTo.x - 4 && y == game.grid.renderTo.y - 5)
|| (x == game.grid.renderFrom.x + 5 && y == game.grid.renderTo.y - 4)
|| (x == game.grid.renderFrom.x + 5 && y == game.grid.renderFrom.y + 4)
|| (x == game.grid.renderFrom.x + 5 && y == game.grid.renderFrom.y + 5)
)
{
GameObject go = InstantiateStoneTile(x, y);
NetworkServer.Spawn(go);
AddTileToMap(x, y, go);
RpcAddTileToMap(x, y, go);
}
else
{
GameObject go = InstantiateGrasslandTile(x, y);
NetworkServer.Spawn(go);
AddTileToMap(x, y, go);
RpcAddTileToMap(x, y, go);
}
}
}
}
}
private GameObject InstantiateWaterTile(int x, int y)
{
GameObject go = Instantiate(water, game.grid.GridToWorld(new Vector3(x, y, 0)), Quaternion.Euler(0, 0, 0)) as GameObject;
go.transform.parent = tileParent.transform;
go.name = "Water";
return go;
}
private GameObject InstantiateClayTile(int x, int y)
{
GameObject go = Instantiate(clay, game.grid.GridToWorld(new Vector3(x, y, 0)), Quaternion.Euler(0, 0, 0)) as GameObject;
go.transform.parent = tileParent.transform;
go.name = "Clay";
return go;
}
private GameObject InstantiateGrainTile(int x, int y)
{
GameObject go = Instantiate(grain, game.grid.GridToWorld(new Vector3(x, y, 0)), Quaternion.Euler(0, 0, 0)) as GameObject;
go.transform.parent = tileParent.transform;
go.name = "Grain";
return go;
}
private GameObject InstantiateWoodTile(int x, int y)
{
GameObject go = Instantiate(wood, game.grid.GridToWorld(new Vector3(x, y, 0)), Quaternion.Euler(0, 0, 0)) as GameObject;
go.transform.parent = tileParent.transform;
go.name = "Wood";
return go;
}
private GameObject InstantiateStoneTile(int x, int y)
{
GameObject go = Instantiate(stone, game.grid.GridToWorld(new Vector3(x, y, 0)), Quaternion.Euler(0, 0, 0)) as GameObject;
go.transform.parent = tileParent.transform;
go.name = "Stone";
return go;
}
private GameObject InstantiateGrasslandTile(int x, int y)
{
GameObject go = Instantiate(grassland, game.grid.GridToWorld(new Vector3(x, y, 0)), Quaternion.Euler(0, 0, 0)) as GameObject;
go.transform.parent = tileParent.transform;
go.name = "Grassland";
return go;
}
[ClientRpc]
private void RpcAddTileToMap(int x, int y, GameObject go)
{
Debug.Log("RpcAddTileToMap");
Tile tile = go.GetComponent<Tile>();
map[makeArraySafeX(x), makeArraySafeY(y)] = tile;
tile.MapCoords.x = makeArraySafeX(x);
tile.MapCoords.y = makeArraySafeY(y);
}
private void AddTileToMap(int x, int y, GameObject go)
{
Debug.Log("AddTileToMap");
Tile tile = go.GetComponent<Tile>();
map[makeArraySafeX(x), makeArraySafeY(y)] = tile;
tile.MapCoords.x = makeArraySafeX(x);
tile.MapCoords.y = makeArraySafeY(y);
}
public int makeArraySafeY(int y)
{
return y + (-(int)Mathf.RoundToInt(game.grid.renderFrom.y));
}
public int makeArraySafeX(int x)
{
return x + (-(int)Mathf.RoundToInt(game.grid.renderFrom.x));
}
////////////////////////////////////////////////////////////
/// Attack the tile
////////////////////////////////////////////////////////////
public void Attack()
{
Debug.Log("attack");
}
////////////////////////////////////////////////////////////
/// Claim the tile
////////////////////////////////////////////////////////////
public void Claim()
{
//Debug.Log("claim");
Tile tile = game.gui.getTile();
if (tile != null)
{
if (tile.OwnerIndex == -1)
{
Player player = game.playerSystem.Players[game.playerSystem.CurrentPlayer];
tile.OwnerIndex = game.playerSystem.CurrentPlayer;
tile.UpgradeLevel = 1;
player.UseRessource("Clay");
player.UseRessource("Grain");
player.UseRessource("Wood");
}
}
else
{
Debug.Log("something went horribly wrong: Claim working with null tile");
}
}
////////////////////////////////////////////////////////////
/// Upgrade the tile
////////////////////////////////////////////////////////////
public void Upgrade()
{
Tile tile = game.gui.getTile();
if (tile != null)
{
//Debug.Log("upgrade");
if (tile.UpgradeLevel < 3)
{
tile.UpgradeLevel += 1;
Player player = game.playerSystem.Players[game.playerSystem.CurrentPlayer];
player.UseRessource("Clay");
player.UseRessource("Grain");
player.UseRessource("Wood");
player.UseRessource("Stone");
tile.UpgradedThisTurn = true;
AddTileToUpdateQueue(tile);
Debug.Log(tile.UpgradeLevel);
}
}
else
{
Debug.Log("something went horribly wrong: Upgrade working with null tile");
}
}
////////////////////////////////////////////////////////////
/// returns wether the tile is able to attack or not
////////////////////////////////////////////////////////////
public bool isTileAbleToAttack(Tile tile)
{
if (tile != null)
{
return true;
}
else
{
Debug.Log("something went horribly wrong: isTileAbleToAttack got null tile");
return false;
}
}
////////////////////////////////////////////////////////////
/// returns wether the tile is attackable or not
////////////////////////////////////////////////////////////
public bool isTileAttackable(Tile tile)
{
if (tile != null)
{
if (!isTileOwnedByCurrentPlayer(tile)
&& tile.OwnerIndex != -1
&& isTileAdjacentToTerritory(tile))
{
return true;
}
else
{
return false;
}
}
else
{
Debug.Log("something went horribly wrong: isTileAttackable got null tile");
return false;
}
}
////////////////////////////////////////////////////////////
/// returns wether the tile is claimable or not
////////////////////////////////////////////////////////////
public bool isTileClaimable(Tile tile)
{
if (tile != null)
{
if (!isTileOwnedByCurrentPlayer(tile)
&& tile.OwnerIndex == -1
&& isTileAdjacentToTerritory(tile)
&& game.playerSystem.isPlayerAbleToBuild())
{
return true;
}
else
{
return false;
}
}
else
{
Debug.Log("something went horribly wrong: isTileClaimable got null tile");
return false;
}
}
////////////////////////////////////////////////////////////
/// returns wether the tile is upgradable or not
////////////////////////////////////////////////////////////
public bool isTileUpgradable(Tile tile)
{
if (tile != null)
{
if (isTileOwnedByCurrentPlayer(tile)
&& tile.UpgradeLevel < 3
&& game.playerSystem.isPlayerAbleToUpgrade()
&& !tile.ChangedOwner
&& !tile.UpgradedThisTurn)
{
return true;
}
else
{
return false;
}
}
else
{
Debug.Log("something went horribly wrong: isTileUpgradable got null tile");
return false;
}
}
////////////////////////////////////////////////////////////
/// returns wether the tile is owned by the current player or not
////////////////////////////////////////////////////////////
private bool isTileOwnedByCurrentPlayer(Tile tile)
{
if (tile != null)
{
if (tile.OwnerIndex == game.playerSystem.CurrentPlayer)
{
return true;
}
else
{
return false;
}
}
else
{
Debug.Log("something went horribly wrong: isTileOwnedByCurrentPlayer got null tile");
return false;
}
}
////////////////////////////////////////////////////////////
/// returns wether the tile is adjacent to territory (2 tiles) or not
////////////////////////////////////////////////////////////
private bool isTileAdjacentToTerritory(Tile tile)
{
if (tile != null)
{
// counter has to be 2 or higher!
int counter = 0;
if (tile.MapCoords.x % 2 == 0)
{
// check clockwise, beginning in the north
// N => 0 1
if (isNeighbourUnderControl(tile, 0, 1))
{
//Debug.Log("neighbour found N");
counter++;
}
// NE => 1 1
if (isNeighbourUnderControl(tile, 1, 1))
{
//Debug.Log("neighbour found NE");
counter++;
}
// SE => 1 0
if (isNeighbourUnderControl(tile, 1, 0))
{
//Debug.Log("neighbour found SE");
counter++;
}
// S => 0 -1
if (isNeighbourUnderControl(tile, 0, -1))
{
//Debug.Log("neighbour found S");
counter++;
}
// SW => -1 0
if (isNeighbourUnderControl(tile, -1, 0))
{
//Debug.Log("neighbour found SW");
counter++;
}
// NW => -1 1
if (isNeighbourUnderControl(tile, -1, 1))
{
//Debug.Log("neighbour found NW");
counter++;
}
}
else
{
// check clockwise, beginning in the north
// N => 0 1
if (isNeighbourUnderControl(tile, 0, 1))
{
//Debug.Log("neighbour found N");
counter++;
}
// NE => 1 0
if (isNeighbourUnderControl(tile, 1, 0))
{
//Debug.Log("neighbour found NE");
counter++;
}
// SE => 1 -1
if (isNeighbourUnderControl(tile, 1, -1))
{
//Debug.Log("neighbour found SE");
counter++;
}
// S => 0 -1
if (isNeighbourUnderControl(tile, 0, -1))
{
//Debug.Log("neighbour found S");
counter++;
}
// SW => -1 -1
if (isNeighbourUnderControl(tile, -1, -1))
{
//Debug.Log("neighbour found SW");
counter++;
}
// NW => -1 0
if (isNeighbourUnderControl(tile, -1, 0))
{
//Debug.Log("neighbour found NW");
counter++;
}
}
if (counter >= 2)
{
return true;
}
else
{
return false;
}
}
else
{
Debug.Log("something went horribly wrong: isTileAdjacentToTerritory got null tile");
return false;
}
}
////////////////////////////////////////////////////////////
/// returns wether the neighbour is under control of the current player or not
////////////////////////////////////////////////////////////
private bool isNeighbourUnderControl(Tile tile, int x, int y)
{
if (tile != null)
{
int mapX = (int)Mathf.RoundToInt(tile.MapCoords.x);
int mapY = (int)Mathf.RoundToInt(tile.MapCoords.y);
if (mapX + x > 0
&& mapX + x < mapMaxIndexX
&& mapY + y > 0
&& mapY + y < mapMaxIndexY)
{
if (isTileOwnedByCurrentPlayer(map[mapX + x, mapY + y]))
{
return true;
}
else
{
return false;
}
}
else
{
return false;
}
}
else
{
Debug.Log("something went horribly wrong: isNeighbourUnderControl got null tile");
return false;
}
}
public void AddTileToUpdateQueue(Tile tile)
{
if (tile != null)
{
tileUpdateQueue.Add(tile);
}
else
{
Debug.Log("something went horribly wrong: AddTileToUpdateQueue got null tile");
}
}
public void ProcessUpdateQueue()
{
for (int i = 0; i < tileUpdateQueue.Count; i++)
{
tileUpdateQueue[i].Strength = tileUpdateQueue[i].UpgradeLevel;
tileUpdateQueue[i].ChangedOwner = false;
tileUpdateQueue[i].UpgradedThisTurn = false;
}
}
}