This is part eleven of a tutorial series about hexagon maps. It adds wall towers, bridges, and special features to our terrain.

Wall Towers

We added support for walls in the previous tutorial. They're simple straight wall segments, without any distinguishing features. Now we're going to make the walls more interesting, by adding towers to them.

The wall segments had to be created procedurally, to fit the terrain. This is not required for the towers. We can use a simple prefab.

You can created a simple tower shape with two cubes that have the red urban material. The tower base is 2 by 2 units wide and 4 units high, so it's both thicker and taller than the wall. Above this cube, put a unit cube to represent the top of the tower. Like the other prefabs, these cubes don't need colliders.

Because the tower model consists of multiple objects, make them children of a root object. Position them so the root's local origin sits at the base of the tower. That way, we can place the towers without having to worry about their height.

Wall tower prefab.

Add a reference to this prefab to HexFeatureManager and hook it up.

public Transform wallTower;

Referencing the wall tower prefab.

Building Towers Let's begin by placing a tower in the middle of every wall segment. To do this, instantiate a tower at the end of the AddWallSegment method. Its position is the average of the left and right points of the segment. void AddWallSegment ( Vector3 nearLeft, Vector3 farLeft, Vector3 nearRight, Vector3 farRight ) { … Transform towerInstance = Instantiate(wallTower); towerInstance.transform.localPosition = (left + right) * 0.5f; towerInstance.SetParent(container, false); } One tower per wall segment. We get a lot of towers along the wall, but their orientation doesn't vary. We have to adjust their rotation so they align themselves with the wall. As we have the left and right points of the wall, we know which direction is right. We can use this to determine the orientation of the wall segment, and thus that of its tower. Rather than compute the rotation ourselves, we can just assign a vector to the Transform.right property. Unity's code will take care of adjusting the object's rotation so its local right direction aligns with the provided vector. Transform towerInstance = Instantiate(wallTower); towerInstance.transform.localPosition = (left + right) * 0.5f; Vector3 rightDirection = right - left; rightDirection.y = 0f; towerInstance.transform.right = rightDirection; towerInstance.SetParent(container, false); Towers aligned with the wall. How does setting Transform.right work? It uses the Quaternion.FromToRotation method to derive the rotation. Here is the code of the property. public Vector3 right { get { return rotation * Vector3.right; } set { rotation = Quaternion.FromToRotation(Vector3.right, value); } }

Fewer Towers One tower per wall segment is way too much. So let's make adding a tower optional, by adding a boolean parameter to AddWallSegment . Give it a default value of false . That will make all the towers disappear. void AddWallSegment ( Vector3 nearLeft, Vector3 farLeft, Vector3 nearRight, Vector3 farRight , bool addTower = false ) { … if (addTower) { Transform towerInstance = Instantiate(wallTower); towerInstance.transform.localPosition = (left + right) * 0.5f; Vector3 rightDirection = right - left; rightDirection.y = 0f; towerInstance.transform.right = rightDirection; towerInstance.SetParent(container, false); } } Let's limit towers to the wall segments places at the cell corners. That will result in a few towers with fairly regular distances between them. void AddWallSegment ( Vector3 pivot, HexCell pivotCell, Vector3 left, HexCell leftCell, Vector3 right, HexCell rightCell ) { … AddWallSegment(pivot, left, pivot, right , true ); … } Towers at cell corners only. This look quite good, but you might want less regular wall placement than this. Like with the other features, we can use the hash grid to decide whether we place a tower at a corner. To do so, use the center of the corner to sample the grid, then compare one of the hash values with a tower threshold. HexHash hash = HexMetrics.SampleHashGrid( (pivot + left + right) * (1f / 3f) ); bool hasTower = hash.e < HexMetrics.wallTowerThreshold; AddWallSegment(pivot, left, pivot, right, hasTower ); The threshold value belongs in HexMetrics . A value of 0.5 would spawn towers about half of the time, although you could get walls with many or no towers at all. public const float wallTowerThreshold = 0.5f; Occasional towers.

No Towers on Slopes We're currently placing towers regardless off the shape of the terrain. However, towers don't make much sense on slopes. The walls are at an angle there, and might cut through the top of the tower. Towers on slopes. To avoid slopes, check whether the left and right cell of the corner have the same elevation. Only then do we allow a potential tower. bool hasTower = false; if (leftCell.Elevation == rightCell.Elevation) { HexHash hash = HexMetrics.SampleHashGrid( (pivot + left + right) * (1f / 3f) ); hasTower = hash.e < HexMetrics.wallTowerThreshold; } AddWallSegment(pivot, left, pivot, right, hasTower); No more towers on sloped walls.