从图像创建边框和可点击区域

十字军国王,欧罗巴Universalis和其他几个战略游戏使用基于地图的地图,其中“瓷砖”不是正方形或六边形。 边框样式表示不同的队伍/所有者。

在这里输入图像描述


我已经做了一些研究,这是我从modding指南中发现的:他们似乎使用源图像来dynamic生成用于分离条款的边界,但也指示当前选定的区域(边框更改颜色或闪烁 )我敢肯定,同样的文件是用于“可点击区域”(点击提供省得到详细信息屏幕)。

源图像包含所有用纯色绘制的省份。 这幅图像与高度图(水体和陆地块)的大小相同,以便与各省的地理形状保持一致。

在这里输入图像描述

然后是某种字典文件(文本,JSON ),它具有将这些颜色映射到关于该省的元数据的所有省份的颜色。 它也使游戏引擎的各省成为“loopable”,以便将它们添加到游戏内数据库中,并使用颜色从图像中find正确的形状。

JSON中的示例:

// "key" is RGB color that points to correct province in previous image "253:28:37": { "name": "Kent", "otherStuff": 13 }, "142:133:150": { "name": "Oxford", "otherStuff": 54 } 

如何从源图像创建可引用的边框和可点击的区域?

我所建议的是读取省地图的逐个像素,并匹配从JSON文件中定义的颜色值的像素获得的颜色值(为简单起见使用Color32)。 这样,每个省都有一个它控制的像素(瓷砖)列表。

此时,点击地图时,如果使用光线投射,则可以计算出瓦片坐标,从而找出哪个省被点击。

至于边界,我相信LineRenderers(或者它的一些优化forms)是走向边界的路。 如果你仔细看看你发布的参考图片(例如,Solent,Winchester和Dorset在哪里见面),你会发现边界不完全匹配,留下这些锯齿状的边缘,这对于表演者来说是很典型的。

为了实现这一点,一些半疯狂的algorithm必须运行。 如果你把内存中的每个“瓦片”,并问他们的邻居瓦片是否属于同一省,你可以找出哪些瓦片是“边界瓦片”。 您也可以跟踪他们所在的省份,如果您以后需要不同的边界样式,这将非常有用。

一旦你有了边框,你基本上有你需要input到渲染器的点。 你想要顺时针/逆时针先sorting点,但这是另一个问题。

在这一点上,你有一个大的“连锁”点,在全省范围内创建一条线。 如果你想为不同省份的邻居devise更薄/更粗的边界types,你可以将链条分成较小的部分(每个邻省一个部分)。 如果你把海洋作为一个省份,你的边界网格也应该和海岸线一致。

如果您使用的是3D地形,您也可能想要取消线条点的Y值来反映地形的高度。 这可以通过光线投射完成,或者直接从高度图上读取。

这应该带你90%。 其余的则取决于你使用的是什么样的地形。 起初,你会得到块状(可能未alignment)的边界,只是因为你如何直接将二维平铺pos转换为3D世界位置。 但通过使用一些花哨的样条曲线,你可能会得到一个像样的结果。 此外,为了优化和一般的漂亮,你可能要考虑在各省之间“分享”边界网格。

这是我将如何做到这一点:

你需要两个纹理,一个是你的“真实”的世界,另一个是每个国家代表一种颜色(你提供的图像是完美的)。 后者纹理必须在导入器选项中标记为“读取/写入”。

然后,创建一个脚本,根据你hover/点击的颜色find国家:

 private Camera cam; void Start() { cam = Camera.main; } void Update() { RaycastHit hit; if (!Physics.Raycast(cam.ScreenPointToRay(Input.mousePosition), out hit)) return; Renderer rend = hit.transform.GetComponent<Renderer>(); MeshCollider meshCollider = hit.collider as MeshCollider; if (rend == null || rend.sharedMaterial == null || rend.sharedMaterial.mainTexture == null || meshCollider == null) return; Texture2D tex = rend.material.mainTexture as Texture2D; Color countryColor = tex.GetPixel(hit.textureCoord * tex.width, pixelUV.y * tex.height); // Then, find the country based on the color. // You can use ColorUtility.TryParseHtmlString if you want to store an hexadecimal representation of your color in your data file (JSON / Database) // https://docs.unity3d.com/ScriptReference/ColorUtility.TryParseHtmlString.html // Highlight the real texture with a custom shader // This shader would take two textures : the displayed one and the colored one, and a color // The color would help you highlight the correct texel. Something like : /* fixed4 frag (v2f i):SV_Target{ fixed4 mainCol=tex2D(_MainTex,i.uv); fixed4 countryCol=tex2D(_ColoredTex,i.uv); // if( countryCol == _HighlightCol ) // Make mainCol brighter return mainCol; } */ }