// ------------------------------------------------------------------------------------------------------------ #region update/ input protected void Update() { if (Input.GetMouseButtonDown(0) && GUIUtility.hotControl == 0 && unitMoving == false) { // Check what the player clicked on. I've set Tiles to be on Layer 8 and Unit on Layer 9. // Each tile has its own collider attached but I could have used a big invisible collider // that stretches the whole map as a catch all for clicks that did not fall on a unit. // The only reason the tiles each have a collider is because they are used in other // samples too that requires it. RaycastHit hit; Ray r = Camera.main.ScreenPointToRay(Input.mousePosition); if (Physics.Raycast(r, out hit, Mathf.Infinity, clickMask)) { if (hit.transform.gameObject.layer == 8) { // a tile was clicked Sample4Tile n = map.NodeAtWorldPosition <Sample4Tile>(hit.point); //Sample4Tile n = (Sample4Tile)map.NodeAtWorldPosition(hit.point); if (n != null) { Debug.Log("Clicked on: " + n.tileName); // check if a tile that the active unit may move to if (activeUnit != null && validMoveNodes.Contains(n)) { // get the path List <MapNavNode> path = map.Path <MapNavNode>(activeUnit.tile, n, OnNodeCostCallback); if (path != null) { unitMoving = true; // need to wait while unit is moving ClearMoveMarkers(); activeUnit.Move(path, OnUnitMoveComplete); } } } } else { // a unit was clicked. first clear the previously selected unit if (activeUnit != null) { activeUnit.UnitDeSelected(); ClearMoveMarkers(); } activeUnit = hit.transform.GetComponent <Sample4Unit>(); if (activeUnit != null) { // tell the unit it was selected so that it can change colour activeUnit.UnitSelected(); // show the player the area that the unit may move to UpdateMoveMarkers(); } } } } }
/// <summary> /// I override this callback so that I can respond on the grid being /// changed and place/ update the actual tile objects /// </summary> public override void OnGridChanged(bool created) { // The parent object that will hold all the instantiated tile objects Transform parent = gameObject.transform; // Remove existing tiles and place new ones if map was (re)created // since the number of tiles might be different now if (created) { for (int i = parent.childCount - 1; i >= 0; i--) { // was called from editor Object.DestroyImmediate(parent.GetChild(i).gameObject); } // Place tiles according to the generated grid for (int idx = 0; idx < grid.Length; idx++) { // make sure it is a valid node before placing tile here if (false == grid[idx].isValid) { continue; } // create the visual tile GameObject go = (GameObject)Instantiate(tileFab); go.name = "Tile " + idx.ToString(); go.layer = tileLayer; // set the layer since I will need it in Sample4Controller to check what the player clicked on go.transform.position = grid[idx].position; go.transform.parent = parent; // MapNav created the node as the custom Sample4Tile type // Now init the tileName property in it Sample4Tile node = grid[idx] as Sample4Tile; node.tileName = go.name; node.tileObj = go; } } // else, simply update the position of existing tiles else { for (int idx = 0; idx < grid.Length; idx++) { // make sure it is a valid node before processing it if (false == grid[idx].isValid) { continue; } // Since I gave the tiles proper names I can easily find them by name GameObject go = parent.Find("Tile " + idx.ToString()).gameObject; go.transform.position = grid[idx].position; } } }
protected bool unitMoving = false; // set when a unit is moving and no input should be accepted #endregion // ------------------------------------------------------------------------------------------------------------ #region start protected void Start() { // get reference to the mapnav map map = GameObject.Find("Map").GetComponent <Sample4Map>(); // also used in sample4b if (map == null) { map = GameObject.Find("Map").GetComponent <Sample4bMap>(); } // in this sample I will simply spawn 10 units on random locations of the map for (int i = 0; i < 10; i++) { Sample4Tile selectedTile = null; // find a tile to place the unit on. I will randomly select one. // but I need to check if there is not already a unit on the // selected tile before accepting it. while (true) { int idx = Random.Range(0, map.grid.Length); // make sure this is a valid node if (map.ValidIDX(idx)) { // now check if there is not already a unit on it selectedTile = map.grid[idx] as Sample4Tile; if (selectedTile.unit == null) { // no unit on it, lets use it break; } } } // create the unit and place it on the tile GameObject go = (GameObject)Instantiate(unitFab); go.transform.position = selectedTile.position; go.layer = 9; // in this sample Units must be in layer 9 // be sure to tell the tile that this Unit is on it Sample4Unit unit = go.GetComponent <Sample4Unit>(); unit.Resetunit(); // reset its moves now too unit.LinkWithTile(selectedTile); units.Add(unit); // keep a list of all units for quick access } }
/// <summary> /// I use this to link the tile and unit with each other so that the /// tile and unit knows which unit is on the tile. I will pass null /// to simply unlink the tile and unit. /// </summary> public void LinkWithTile(Sample4Tile t) { // first unlink the unit from the tile if (tile != null) { tile.unit = null; } tile = t; // if t == null then this was simply an unlink and it ends here if (tile == null) { return; } // else tell the tile that this unit is on it tile.unit = this; }
private bool CheckIfValidNode(MapNavNode toNode) { Sample4Tile n = toNode as Sample4Tile; // this will help prevent a border being drawn around the active unit's tile // also see the IF(neighbours[j] != activeUnit.tile ...) that must be used above if (n == activeUnit.tile) { return(true); } // can't move to a tile that has a unit on it if (n.unit != null) { return(false); } // finally, return tile's default state return(toNode.isValid); }