-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy path_ex2.html
71 lines (71 loc) · 12.9 KB
/
_ex2.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
<meta name="generator" content="Doxygen 1.8.14"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>HexMapLibrary: Example 2: Line of sight</title>
<link href="tabs.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="dynsections.js"></script>
<link href="doxygen.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<div id="titlearea">
<table cellspacing="0" cellpadding="0">
<tbody>
<tr style="height: 56px;">
<td id="projectalign" style="padding-left: 0.5em;">
<div id="projectname">HexMapLibrary
</div>
</td>
</tr>
</tbody>
</table>
</div>
<!-- end header part -->
<!-- Generated by Doxygen 1.8.14 -->
<script type="text/javascript" src="menudata.js"></script>
<script type="text/javascript" src="menu.js"></script>
<script type="text/javascript">
/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&dn=gpl-2.0.txt GPL-v2 */
$(function() {
initMenu('',false,false,'search.php','Search');
});
/* @license-end */</script>
<div id="main-nav"></div>
<div id="nav-path" class="navpath">
<ul>
<li class="navelem"><a class="el" href="index.html">HexMap Library Documentation</a></li> </ul>
</div>
</div><!-- top -->
<div class="header">
<div class="headertitle">
<div class="title">Example 2: Line of sight </div> </div>
</div><!--header-->
<div class="contents">
<div class="textblock"><p>In this Example we want to create a simple vision system. If we click on a tile we want to highlight all those tiles which are visible. There will be 2 rules: <br />
1) there is a limited vision range <br />
2) certain tiles block vision to anything behind them</p>
<p>To decide which tiles are visible we are going to use the following approach: We draw a ring around the center tile and then draw lines to each tile of the ring, stopping each line after it hit a vision blocker. Every tile which at least one line reaches is considered visible. As we use the ring just as a helper to create the lines we want to also get those ring tiles which are out of the map bounds, so we will use HexGrid.GetTiles.Ring which does operate on the infinite plane.</p>
<p>Before we continue we need to talk a bit about symmetry. If you take a look at that picture:</p>
<div class="image">
<img src="LineLeftRight.png" alt="LineLeftRight.png"/>
</div>
<p> you can see that sometimes there are 2 equally valid solutions to draw a line from A to B. Therefore we get more consistent results if we use both possible lines to determine our vision. The GetLines method has a parameter which allows us to nudge the origin position a tiny bit to the left or right which results in getting either the more "left" or the more "right" line. This also works for all diagonal lines.</p>
<p>We once again create the variables we need:</p>
<div class="fragment"><div class="line">[SerializeField] <span class="keyword">private</span> <span class="keywordtype">int</span> mapRadius = 11; <span class="comment">// the mapSize, can be set in inspector </span></div><div class="line">[SerializeField] <span class="keyword">private</span> GameObject tilePrefab = null; <span class="comment">// the prefab we use for each Tile -> use TilePrefab.prefab</span></div><div class="line">[SerializeField] <span class="keyword">private</span> GameObject tileVisionMarker = null; <span class="comment">// the prefab we use for each Tile -> use TilePrefab.prefab</span></div><div class="line">[SerializeField] <span class="keyword">private</span> GameObject edgeVisionBorder = null;</div><div class="line">[SerializeField] <span class="keyword">private</span> List<Material> materials = null; <span class="comment">// the materials we want to assign to the tiles for visualisation purposes -> set size to 4 in inspector and add TileMat1 to TileMat4</span></div><div class="line"><span class="keyword">private</span> HexMap<int> hexMap; <span class="comment">// our map. For this example we create a map where an integer represents the data of each tile </span></div><div class="line"><span class="keyword">private</span> HexMouse hexMouse = null; <span class="comment">// the HexMouse component we add to keep track of the mouse position</span></div><div class="line"><span class="keyword">private</span> GameObject[] tileObjects; <span class="comment">// this will contain all the GameObjects for visualisation purposes, their array index corresponds with the index of our Tiles</span></div><div class="line"><span class="keyword">private</span> List<GameObject> visionMarkers; <span class="comment">//we will use this to display the border of the vision range</span></div></div><!-- fragment --><p>Next step is one again creating the map and initializing mouse and camera. We now put map initialisation in its own method.</p>
<div class="fragment"><div class="line"><span class="keywordtype">void</span> Start ()</div><div class="line">{</div><div class="line"> hexMap = <span class="keyword">new</span> HexMap<int>(HexMapBuilder.CreateHexagonalShapedMap(mapRadius), null); <span class="comment">//creates a HexMap using one of the pre-defined shapes in the static MapBuilder Class </span></div><div class="line"> hexMouse = gameObject.AddComponent<HexMouse>(); <span class="comment">//we attach the HexMouse script to the same gameObject this script is attached to, could also attach it anywhere else</span></div><div class="line"> hexMouse.Init(hexMap); <span class="comment">//initializes the HexMouse </span></div><div class="line"> </div><div class="line"> InitMap();</div><div class="line"> SetupCamera(); <span class="comment">//set camera settings so that the map is captured by it</span></div><div class="line"> </div><div class="line">}</div><div class="line"></div><div class="line"><span class="keywordtype">void</span> InitMap()</div><div class="line">{</div><div class="line"> tileObjects = <span class="keyword">new</span> GameObject[hexMap.TilesByPosition.Count]; <span class="comment">//creates an array with the size equal to the number on tiles of the map</span></div><div class="line"> visionMarkers = <span class="keyword">new</span> List<GameObject>();</div><div class="line"></div><div class="line"> <span class="keywordflow">foreach</span> (var tile <span class="keywordflow">in</span> hexMap.Tiles) <span class="comment">//loops through all the tiles, assigns them a random value and instantiates and positions a gameObject for each of them.</span></div><div class="line"> {</div><div class="line"> tile.Data = (Random.Range(0, 4));</div><div class="line"> GameObject instance = GameObject.Instantiate(tilePrefab);</div><div class="line"> instance.GetComponent<Renderer>().material = materials[tile.Data];</div><div class="line"> instance.name = <span class="stringliteral">"MapTile_"</span> + tile.Position;</div><div class="line"> instance.transform.position = tile.CartesianPosition;</div><div class="line"> tileObjects[tile.Index] = instance;</div><div class="line"> }</div><div class="line">}</div></div><!-- fragment --><p>Now we add our method which calculates the visible tiles:</p>
<div class="fragment"><div class="line"><span class="keyword">private</span> HashSet<Vector3Int> CalculateVisibleTiles(Vector3Int origin, <span class="keywordtype">int</span> range)</div><div class="line">{</div><div class="line"> List<Vector3Int> ringTiles = HexGrid.GetTiles.Ring(origin, range, 1); <span class="comment">//we use hexGrid because we want to get the whole ring as intermediate resulst even if some tiles are out of bound</span></div><div class="line"> HashSet<Vector3Int> reachedTiles = <span class="keyword">new</span> HashSet<Vector3Int>();</div><div class="line"></div><div class="line"> <span class="keywordflow">foreach</span>(var ringTile <span class="keywordflow">in</span> ringTiles)</div><div class="line"> {</div><div class="line"> <span class="comment">//we use 2 lines, one slightly nudged to the left, one slightly nudged to the right because for some origin->target lines there are 2 valid/mirrored solutions</span></div><div class="line"> List<Tile<int>> lineA = hexMap.GetTiles.Line(origin, ringTile, <span class="keyword">true</span>, +0.001f);</div><div class="line"> List<Tile<int>> lineB = hexMap.GetTiles.Line(origin, ringTile, <span class="keyword">true</span>, -0.001f);</div><div class="line"></div><div class="line"> List<List<Tile<int>>> lines = <span class="keyword">new</span> List<List<Tile<int>>> { lineA, lineB};</div><div class="line"> <span class="keywordflow">foreach</span>(var line <span class="keywordflow">in</span> lines)</div><div class="line"> {</div><div class="line"> <span class="keywordflow">for</span> (<span class="keywordtype">int</span> i = 0; i < line.Count; i++)</div><div class="line"> {</div><div class="line"> reachedTiles.Add(line[i].Position);</div><div class="line"> <span class="keywordflow">if</span> (line[i].Data == 0) <span class="keywordflow">break</span>; <span class="comment">//0 = wall</span></div><div class="line"> </div><div class="line"> }</div><div class="line"> } </div><div class="line"> }</div><div class="line"> <span class="keywordflow">return</span> reachedTiles;</div><div class="line">}</div></div><!-- fragment --><p>And another method with which we visualise the result:</p>
<div class="fragment"><div class="line"><span class="keyword">private</span> <span class="keywordtype">void</span> UpdateVisionMarkers(IEnumerable<Vector3Int> visibleTiles)</div><div class="line">{</div><div class="line"> <span class="keywordflow">foreach</span>(GameObject g <span class="keywordflow">in</span> visionMarkers)</div><div class="line"> {</div><div class="line"> Destroy(g);</div><div class="line"> }</div><div class="line"> visionMarkers.Clear();</div><div class="line"> </div><div class="line"> <span class="keywordflow">foreach</span>(var tilePos <span class="keywordflow">in</span> visibleTiles)</div><div class="line"> {</div><div class="line"> GameObject tileObj = Instantiate(tileVisionMarker, HexConverter.TileCoordToCartesianCoord(tilePos,0.1f), Quaternion.identity); </div><div class="line"> <span class="comment">//0.1f = explicitly set y-Coord of the tile so it is slightly above the tiles of the map</span></div><div class="line"> visionMarkers.Add(tileObj); </div><div class="line"> }</div><div class="line"></div><div class="line"> List<Vector3Int> borderEdges = hexMap.GetEdgePositions.TileBorders(visibleTiles);</div><div class="line"></div><div class="line"> <span class="keywordflow">foreach</span>(var edgePos <span class="keywordflow">in</span> borderEdges)</div><div class="line"> {</div><div class="line"> EdgeAlignment orientation = HexUtility.GetEdgeAlignment(edgePos);</div><div class="line"> <span class="keywordtype">float</span> angle = HexUtility.anglebyEdgeAlignment[orientation];</div><div class="line"> GameObject edgeObj = Instantiate(edgeVisionBorder, HexConverter.EdgeCoordToCartesianCoord(edgePos), Quaternion.Euler(0, angle, 0));</div><div class="line"> visionMarkers.Add(edgeObj);</div><div class="line"> }</div><div class="line">}</div></div><!-- fragment --><p>Finally we create the update method:</p>
<div class="fragment"><div class="line"><span class="keywordtype">void</span> Update ()</div><div class="line">{ </div><div class="line"> <span class="keywordflow">if</span> (!hexMouse.CursorIsOnMap) <span class="keywordflow">return</span>; <span class="comment">// if we are not on the map we won't do anything so we can return</span></div><div class="line"></div><div class="line"> Vector3Int mouseTilePosition = hexMouse.TileCoord;</div><div class="line"></div><div class="line"> <span class="keywordflow">if</span> (Input.GetMouseButtonDown(0)) <span class="comment">// change a tile when clicked on it</span></div><div class="line"> {</div><div class="line"> var visibleTiles = CalculateVisibleTiles(mouseTilePosition, 5);</div><div class="line"> UpdateVisionMarkers(visibleTiles);</div><div class="line"> }</div><div class="line">}</div></div><!-- fragment --> </div></div><!-- contents -->
<!-- start footer part -->
<hr class="footer"/><address class="footer"><small>
Generated by  <a href="http://www.doxygen.org/index.html">
<img class="footer" src="doxygen.png" alt="doxygen"/>
</a> 1.8.14
</small></address>
</body>
</html>