2015-01-25 22:22:47 book_longssl 阅读数 4180


2.制做一张灰度图:

需求:Photoshop 
          GIMP

先Google 搜 WorldMap-A_non-Frame.png  这个地图下载一张到你pc

然后gimp打开它, 右键图片,弹出菜单——选择——按颜色

这张图的好处在于海洋就是几种蓝色,按照颜色分别  左键 选取这几个蓝色,按下delete键删除颜色,清理干净后如图


然后 菜单栏 图像——模式——灰度
然后 菜单栏  颜色——反向
保存,用ps打开它,,,,用 滤镜——模糊——高斯模糊

有个问题需要注意!图像必须是边长相等的正方形!

做完,这个地图的灰度图一定要  点菜单栏 的编辑——变换——水平变换  (你肯定问为啥要这样!地图反了?对,反了,因为导入raw后会水平翻转,所以你要翻转高度图进引擎才是正的。)
保存为.raw

3.地形

运行,前面怎么可以找找教程,创建完工程后,新的场景里,我们开始地图工作, 左上角找到Create ,菜单里面选 Terrain.



于是我们得到了一个地形,如下图,找到那个齿轮图标

我们叫这个图标设置,其他我们不管,找下面的Resolution

然后Wides 宽度 Length长度 都设置为高度图的边长像素,也就是图片的长宽

Height可以随时调节,是地图的最大高度。

然后下面的Import raw...导入咱的高度图,然后弹出小窗口,其他别动,把默认的mac设置为windows.然后import,然后我们的地形就进去了。




调整到你认为合适吧,然后我们说下如何导出为 obj格式的。。。
这个我们需要导出脚本了:http://wiki.unity3d.com/index.php?title=TerrainObjExporter

用法我简单说下吧,懂英语的可以看懂上面网址里面说的用法。
如下图那是个管理资源的窗口,右侧那个大窗口的空白部分右键一下,菜单里点show in explorer  你发现资源管理器能打开一个文件夹,没错这是在你电脑文件夹里都有的(这一行文字只是让你了解构造。。。
so。。右键右侧空白部分,菜单里点 create....然后选 c# script 或  java script

然后如果你用c#了,刚才那个地址里的你就复制c的代码,往里面粘贴(新脚本都有几行代码,全删掉然后再粘贴。) JS 就粘贴JS的。




然后的菜单栏的就会多一个Terrain选项,点一下选 Export to obj....

然后没什么了。。。。
    export format  为Triangles    三角形默认的不用碰

    resolution 很重要: 
                           Full  当前地形网格的完整面数
                           Half 当前地形网格面数的一半
                           Quarter  四分之一
                           Eighth    八分之一
                           Sixteenth 十六分之一


注意: obj地图模型要先导入max,再往max导入一个native的地图的obj(别问我怎么把骑砍地图弄obj导出),对比着骑砍的地图obj旋转 移动 ,校准网格坐标。然后往编辑器导入才能正确。 

矫正坐标后导出obj到你的编辑器的map data里,然后编辑器就能导入了。。。。

一般导出后进max看看有几十万面以上的就不要导入编辑器了。。。。

细节大家自己摸索摸索吧

还有如果对手绘地图比较偏好的同学,你们可以结合着地图编辑器和unity用,具体你们看看。
但是纯属手绘的虽然细节你很爽,但是面数你会不爽。。。。


有些基础的东西我没说那么详细,不过摸索下就会了



补俩截图: 



2014-04-14 00:41:14 qinyuanpei 阅读数 5841

        大家好,我是秦元培,欢迎大家关注我的博客,我的博客地址是blog.csdn.net/qinyuanpei

       在我之前的文章《Unity3D游戏开发之小地图的实现》一文中,我为大家讲解了基于OnGUI()方法绘制贴图实现小地图的方法。那么,今天呢,博主再来为大家分享一种实现小地图的方法。在正式开始今天的文章之前,我们先来了解下Unity3D中的相机吧。在Unity3D中,相机是一个能够为玩家捕获并显示游戏世界的设备。通过操纵相机,我们可以使得我们的游戏场景以更加真实和独特的方式显示出来。在Unity3D中默认有一个主相机Main Camera用来显示我们设计的游戏场景,其实呢,在一个游戏场景中我们是可以设置多个相机对象的,而且它们可以被设置为任意的渲染序列、任意的渲染部分和任意的渲染位置。下面我们来讲解一些比较重要的东西吧!

      1、Clera  Flags:决定场景的哪个部分需要清除。当需要使用多个相机以显示不同的游戏元素时这是非常有用的。

      2、Background Color:处于所有对象之后的背景颜色,设置此属性后,天空盒子(SkyBox)将失效。

      3、Normalized View Port Rect:在屏幕坐标系下使用四个值来确定相机的哪些部分将显示在屏幕上。

      4、Near Clip Plane:相对于相机昀近绘制点。

      5、Far Clip Plane:相对于相机昀远的绘制点。

      6、Field of view:沿着局部 Y轴的相机视角宽度。

      7、Is orthographic:打开或关闭相机的景深效果

      8、正交视大小(Orthographic size):在正交模式下的视口大小。

      9、Depth:相机的绘制顺序,相当于ZIndex属性,具有较高深度的相机将绘制在较低深度相机的上面。

      好了,有了上面的基础,我们就可以开始今天的正式内容了,如图是博主自己创建的一个游戏场景,游戏场景是在一个没有光照的黑暗的屋子里面,我们的游戏主角头顶上添加了一个点光源,所以当游戏主角运动的时候,其经过的场景会被主角头顶上的光源照亮,我们现在要做的就是为这个游戏场景添加一个小地图,以保证玩家在玩游戏的时候不会在黑暗的屋子里迷路。


        好,现在我们开始来做小地图,我们在场景中添加一个Camera,然后设置其旋转角度使其垂直于XOZ平面,命名为TopCamera,这时候我们设置摄像机的投影方式为正交投影,相信根据前面提到的关于Camera的一些内容,大家已经猜到这个小地图的制作原理了,不错,这个小地图就是根据Normalized View Port Rect属性来制作的。我们可以自己调整Normalized View Port Rect的四个数值来让小地图在合适的位置显示合适的内容,下面是博主对TopCamera的一些设置数值,供大家参考:

       

        那么这样,我们的小地图就做好了,我们一起来看看效果吧!图中红框表示出了游戏场景和地图中的相互对应关系。当我们移动人物的时候,地图上的角色位置会同步更新!今天的小地图没有写一行代码啊,这时多么给力的一件事情啊。哈哈


      喜欢我请记住我的名字:秦元培,我的博客地址是:blog.csdn.net/qinyuanpei!
      转载请注明出处,本文作者:秦元培,本文出处:http://blog.csdn.net/qinyuanpei/article/details/23628275

      大家晚安!

2015-02-16 13:16:55 book_longssl 阅读数 1949



  1.创建一个项目
  2.将Camera设置为正交投影
  游戏的输出画面是通过摄像机所观察的场景来实现的,将场景呈现到2D的计算机屏幕上具有两种不同的投影方式:透视投影和正交投影,默认状态下是透视投影.
  透视投影
  

  正交投影
  

  3.添加相关对象模型
  移动摄像机物体,灯光到如下效果
  

  添加游戏物体移动超出边框的控制
  using UnityEngine;
  using System.Collections;
  public class Player:MonoBehaviour {
  public float playerSpeed;
  // Use this for initialization
  void Start () {
  }
  // Update is called once per frame
  void Update () {
  float amtToMove = Input.GetAxis("Horizontal")*Time.deltaTime*playerSpeed;
  gameObject.transform.Translate(Vector3.right*amtToMove);
  if(transform.position.x-7.5){
  //如果方块移动超出游戏窗体右边,方框将从左边窗口进入
  transform.position = new Vector3(5.25f,transform.position.y,transform.position.z);
  }
  if(transform.position.x5.25){
  //如果方块移动超出游戏窗体右边,方框将从左边窗口进入
  transform.position = new Vector3(-7.5f,transform.position.y,transform.position.z);
  }
  }
  }
  4.创建炮弹[create-Capsule]
  

  根据需要调整炮弹的大小


  选择炮弹模型,单机Component菜单,选择Physics-RigidBody,将炮弹设置为刚体,以便后面实现碰撞检测.
  为炮弹添加移动操作脚本
  using UnityEngine;
  using System.Collections;
  public class bulletTile : MonoBehaviour {
  public float bulletSpeed ;
  private Transform mytransform;
  // Use this for initialization
  void Start () {
  mytransform = gameObject.transform;
  }
  // Update is called once per frame
  void Update () {
  //定义炮弹移动速度
  float amtToMove = bulletSpeed * Time.deltaTime;
  //让炮弹垂直向上移动
  mytransform.Translate(Vector3.up * amtToMove);
  //如果炮弹移动超出游戏场景则销毁炮弹
  if(mytransform.position.y5.15){
  Destroy(this.gameObject);    //销毁当前对象
  }
  }
  }
  对象重用
  在Project中创建一个Prefab对象,然后将要重用的对象模型拖动到该Prefab对象上,即可实现模型对象的重用.
  发射子弹的实现
  在Player脚本中创建Prefab可重用对象实例
  using UnityEngine;
  using System.Collections;
  public class Player:MonoBehaviour {
  public float playerSpeed;
  public GameObject bulletPrefab;
  // Use this for initialization
  void Start () {
  }
  // Update is called once per frame
  void Update () {
  float amtToMove = Input.GetAxis("Horizontal")*Time.deltaTime*playerSpeed;
  gameObject.transform.Translate(Vector3.right*amtToMove);
  if(transform.position.x-7.5){
  //如果方块移动超出游戏窗体右边,方框将从左边窗口进入
  transform.position = new Vector3(5.25f,transform.position.y,transform.position.z);
  }
  if(transform.position.x5.25){
  //如果方块移动超出游戏窗体右边,方框将从左边窗口进入
  transform.position = new Vector3(-7.5f,transform.position.y,transform.position.z);
  }
  //获取发射器位置 发射器的正上方
  Vector3 position = new Vector3(transform.position.x,transform.position.y+transform.localScale.y/2.0f,transform.position.z);
  //按下空格键发射子弹
  if(Input.GetKeyDown("space")){
  //实例化一个炮弹对象
  Instantiate(bulletPrefab,position,Quaternion.identity);
  }
  }
  }
  

  拖动表示将属性实例化,因为我们脚本中定义的是public属性,在这里我们可以手动为public属性赋值,此时运行程序,用左右键控制发射器的移动,用space发射子弹.
  

  应用实例:
  游戏中声音的添加与控制
  支持的声音文件:*.aiff,*.wav,*.mp3,*.ogg
  .AIFF
  转换为无压缩音频导入,最适合短音效果。可以在编辑器中按需求压缩。
  .WAV
  转换为无压缩音频导入,最适合短音效果。可以在编辑器中按需求压缩
  .MP3
  转换成Ogg格式导入,最适合较长的音乐曲目。
  .OGG
  压缩音频格式(与iPhone设备和某些Android设备不兼容),最适合较长的音乐曲目。
  添加声音控制按钮,
  void OnGUI(){
  GUI.Button (new Rect (10,10,100,35), "播放音乐");
  GUI.Button (new Rect (10,60,100,35), "暂停播放");
  GUI.Button (new Rect (10,110,100,35), "停止音乐");
  }
  

  为按钮添加事件
  void OnGUI(){
  if(GUI.Button (new Rect (10,10,100,35), "播放音乐")){
  gameObject.audio.Play();
  }
  if(GUI.Button (new Rect (10,60,100,35), "暂停播放")){
  gameObject.audio.Pause().
  }
  if(GUI.Button (new Rect (10,110,100,35), "停止音乐")){
  gameObject.audio.Stop();
  }
  }
  5.为发射炮弹添加声音
  选中bulletPrefab,单机窗体中的Component-Audio-AudionSource
  

  



2019-06-07 17:53:19 kongxinyue 阅读数 1096

本项目的部分代码参考自下面博客

https://www.cnblogs.com/lan-yt/p/9200621.html

 

最近项目中涉及到使用Unity3D来进行地图上国家的渲染,比如把中国圈起来染成红色的这样的需求。

Unity3D把区域渲染是用的MeshRender,关于MeshRender的用法我就不详细讲解了。

最终问题卡在一个点上,对于中国边界这样的凹多边形,如何将其剖分为一系列三角形。

本来以为这是个最常见的问题,应该会有很多求解方法的,结果我找了半天,就找到了上面给出网址的那个博客,而没找到成形的源码。

还好那个博客上有代码,就按照那个博客上的代码,运行了一下,反正在我电脑上有点小的BUG。

不过这个BUG很容易修改,虽然我忘记我是怎么修改的了,后来运行成功了。

于是,我就找到中国边界数据,把它读进去,然后运行。

等了一会儿,系统爆栈了,因为那个博客中算法用到了递归,而中国边界有八千多个点,一个点递归一次,需要递归八千次。

不得已,只好自己写代码了。

后来看到了一个翻译来自日本的凹多边形剖分算法,耳切法。

博客地址:

https://blog.csdn.net/u010019717/article/details/52753855

根据第二个博客中的思想,来设计如下算法:

步骤一:将多边形的所有点读入数组V中。

步骤二:判断该多边形是否为凸多边形,如果为凸多边形,按照凸多边形剖分算法进行处理,算法结束,否则转到步骤三。

步骤三:将所有顶点的序号读入一个数组A中保存起来,然后遍历多边形的顶点,判断每个顶点是否为“耳朵节点”,然后将所有“耳朵节点”保存到数组B。

步骤四:如果耳朵节点数组B为空或者顶点数组V的顶点数组小于三,则算法结束。否则,取出耳朵节点中的第一个顶点P来。

步骤五:找到该节点的前序节点M和后序节点N,这三个点MPN组成一个三角形,保存到结果数组R中,然后,把当前顶点P从耳朵节点中去掉,从数组V中去掉,从序号数组B中去掉。

步骤六:前序节点M和后序节点N,成为了“耳朵节点”的候选。则分别判断M与N是不是耳朵节点,如果是耳朵节点,且没有在当前的耳朵节点数组B中,则将判断为耳朵节点的点放入耳朵节点数组B中。

步骤七:跳转到步骤四。

 

然后通过以上算法,就得到了最终的结果,这个算法没有使用递归,算法的效率还行。

 

这个是我算法运行的结果。

算法源码:

https://download.csdn.net/download/kongxinyue/11230469

 

 

 

2018-01-09 16:21:08 qq_35528646 阅读数 458

看到好多小伙伴似乎都想做六边形地图,我刚好在之前的demo里基于Unity3d实现了一个。

六边形地图编辑器怎么弄我就不发了,可以看看TX爸爸出的这篇博客http://gad.qq.com/program/translateview/7173811。

主要是关于寻路,AStar寻路有很多的优化方法,想要优化什么的自行百度,我就发个基础的代码(哪天我得空了可以再放一下分步讲解)。

using UnityEngine;
using System.Collections.Generic;
using System;

/// <summary>
/// 六边形地图的A*寻路,在使用时先调用AstarMainFunc方法,之后会根据输入的起始点下表改变路径上需要考虑的cell的父节点;
/// 之后该方法将父节点从终点寻址储存到移动功能类中;
/// 因为该节点是从终点寻址到起点,存在先进后出的读取要求,所以推荐用栈存储;
/// 在存储完后在移动功能类中调用ClearFValueAndGValue方法;
/// 在ClearFValueAndGValue方法被调用后才可以再进行下一次寻路;
/// 因此可以有单位同时移动,但不可以有单位同时寻路=》除非所有节点的父节点元素是一个数组;
/// 如果所有节点的父节点元素是一个数组,则在修改本类源码后,可以有该数组长度的数量的单位同时寻路。
/// 2017年12月14日 14:07:03
/// 最后一次修改人:朱珂杰
/// </summary>
class AStarMain : MonoBehaviour
{
    private HexCell[] cellsForAll;
    private List<int> cellsForOpenContainer;
    private List<int> cellsForOpen;
    private List<int> cellsForClose;
    private int currentCellIndex;
    private int hValue;
    /// <summary>
    /// HexGrid中的width,需要在代码中赋值
    /// </summary>
    private int width = 0;
    private int height = 0;

    /// <summary>
    /// 某一点四周所有点的集合,第一个是该点右上角的点,然后按照顺时针直至该点左上角,y坐标为-x-z
    /// 以下为备用元素,在地图大改时可能会需要
    /// </summary>
    //private HexCoordinates[] aroundHexCoordinates = {
    //    new  HexCoordinates (0, 1),
    //    new HexCoordinates(1, 0),
    //    new HexCoordinates(1, -1),
    //    new HexCoordinates(0, -1),
    //    new HexCoordinates(-1, 0),
    //    new HexCoordinates(-1, 1),
    //};
    //private int[] aroundHexCellForIndex;
    public void Awake()
    {
        cellsForOpenContainer = new List<int>();
        cellsForOpen = new List<int>();
        cellsForClose = new List<int>();
    }
    public void Start()
    {
        GetCells();
        width = GameObject.Find("HexPlaneRoot").GetComponent<HexGrid>().width;
        height = GameObject.Find("HexPlaneRoot").GetComponent<HexGrid>().height;
        Debug.Log("得到cells");
    }
    private void GetCells()
    {
        cellsForAll = GameObject.Find("HexPlaneRoot").transform.GetComponentsInChildren<HexCell>();
    }
    /// <summary>
    /// 寻路主函数,先不考虑行数很低时的情况;
    /// 在运行结束后,根据cellForEndIndex下标对应的cell的父节点寻踪直至起始点得到路径
    /// </summary>
    /// <param name="cell">起始点</param>
    public void AstarMainFunc(int cellForBeginIndex, int cellForEndIndex)
    {
        //1,将cellForBegin添加到关闭列表
        cellsForClose.Add(cellForBeginIndex);
        currentCellIndex = cellForBeginIndex;
        AddCellsToOpen();
        while (!cellsForOpen.Contains(cellForEndIndex))
        {
            //遍历开放列表找出所有点中F最小的点
            int fValueMinIndexInOpen = 0;
            if (cellsForOpen.Count > 1)
                for (int i = 1; i < cellsForOpen.Count; i++)
                {
                    //hValue
                    hValue = cellsForAll[cellForEndIndex].coordinates - cellsForAll[cellsForOpen[i]].coordinates;
                    cellsForAll[cellsForOpen[i]].fValue = cellsForAll[cellsForOpen[i]].gValue + hValue;
                    if (cellsForAll[cellsForOpen[i]].fValue < cellsForAll[cellsForOpen[fValueMinIndexInOpen]].fValue)
                        fValueMinIndexInOpen = i;
                }
            //将该点添加到关闭列表中
            cellsForClose.Add(cellsForOpen[fValueMinIndexInOpen]);
            //将该点从开放列表移除
            //没做,忘了,记得补=。=
            currentCellIndex = cellsForOpen[fValueMinIndexInOpen];
            cellsForOpen.RemoveAt(fValueMinIndexInOpen);
            AddCellsToOpen();
        }
        cellsForOpenContainer.Clear();
        cellsForOpen.Clear();
        cellsForClose.Clear();
        ClearFValueAndGValue();
    }
    private void ClearFValueAndGValue()
    {
        foreach (HexCell cell in cellsForAll)
        {
            cell.fValue = 0;
            cell.gValue = 0;
        }
    }
    /// <summary>
    /// 清理所有节点的父节点,在储存完栈后,于调用寻路的类中被调用
    /// </summary>
    public void ClearCellsFather()
    {
        foreach (HexCell cell in cellsForAll)
        {
            cell.hexCellFather = null;
        }
    }
    /// <summary>
    /// 添加当前点四周可添加的点进入开放列表,这个方法结束后,会针对新添加的点和重复的点刷新它内部的父节点和gValue;
    /// 在调用此方法前,需要先对当前点的下表进行标定。
    /// </summary>
    private void AddCellsToOpen()
    {
        //行数,0开始计数
        int row = currentCellIndex / width;
        //取出当前点四周所有的新点进入开放列表
        //这些写完后抽象成方法,因为这部分可能随着地图生成频繁修改
        //左列
        if (currentCellIndex % width == 0)
        {
            //底行,加两个
            if (currentCellIndex / width == 0)
            {
                cellsForOpenContainer.Add(currentCellIndex + width);
                cellsForOpenContainer.Add(currentCellIndex + 1);
            }
            //顶行
            if (currentCellIndex / width == height - 1)
            {
                //偶行,0开始计数,加两个
                if (row % 2 == 0)
                {
                    cellsForOpenContainer.Add(currentCellIndex - width);
                    cellsForOpenContainer.Add(currentCellIndex + 1);
                }
                //奇行,0开始计数,加三个
                else
                {
                    cellsForOpenContainer.Add(currentCellIndex - width);
                    cellsForOpenContainer.Add(currentCellIndex - width + 1);
                    cellsForOpenContainer.Add(currentCellIndex + 1);
                }
            }
            //中间行
            if (currentCellIndex / width > 0 && currentCellIndex / width < height - 1)
            {
                //偶行,0开始计数,加三个
                if (row % 2 == 0)
                {
                    cellsForOpenContainer.Add(currentCellIndex - width);
                    cellsForOpenContainer.Add(currentCellIndex + 1);
                    cellsForOpenContainer.Add(currentCellIndex + width);
                }
                //奇行,0开始计数,加五个
                else
                {
                    cellsForOpenContainer.Add(currentCellIndex - width);
                    cellsForOpenContainer.Add(currentCellIndex - width + 1);
                    cellsForOpenContainer.Add(currentCellIndex + 1);
                    cellsForOpenContainer.Add(currentCellIndex + width);
                    cellsForOpenContainer.Add(currentCellIndex + width + 1);
                }
            }
        }
        //右列
        if (currentCellIndex % width == width - 1)
        {
            //底行,加三个
            if (currentCellIndex / width == 0)
            {
                cellsForOpenContainer.Add(currentCellIndex + width);
                cellsForOpenContainer.Add(currentCellIndex - 1);
                cellsForOpenContainer.Add(currentCellIndex + width - 1);
            }
            //顶行
            if (currentCellIndex / width == height - 1)
            {
                //偶行,0开始计数,加三个
                if (row % 2 == 0)
                {
                    cellsForOpenContainer.Add(currentCellIndex - width);
                    cellsForOpenContainer.Add(currentCellIndex - 1);
                    cellsForOpenContainer.Add(currentCellIndex - width - 1);
                }
                //奇行,0开始计数,加两个
                else
                {
                    cellsForOpenContainer.Add(currentCellIndex - width);
                    cellsForOpenContainer.Add(currentCellIndex - 1);
                }
            }
            //中间行
            if (currentCellIndex / width > 0 && currentCellIndex / width < height - 1)
            {
                //偶行,0开始计数,加五个
                if (row % 2 == 0)
                {
                    cellsForOpenContainer.Add(currentCellIndex - width);
                    cellsForOpenContainer.Add(currentCellIndex - width - 1);
                    cellsForOpenContainer.Add(currentCellIndex - 1);
                    cellsForOpenContainer.Add(currentCellIndex + width);
                    cellsForOpenContainer.Add(currentCellIndex + width - 1);
                }
                //奇行,0开始计数,加三个
                else
                {
                    cellsForOpenContainer.Add(currentCellIndex - width);
                    cellsForOpenContainer.Add(currentCellIndex - 1);
                    cellsForOpenContainer.Add(currentCellIndex + width);
                }
            }
        }
        //中间列
        if (currentCellIndex % width < width - 1 && currentCellIndex % width > 0)
        {
            //底行,加四个
            if (currentCellIndex / width == 0)
            {
                cellsForOpenContainer.Add(currentCellIndex + width);
                cellsForOpenContainer.Add(currentCellIndex + 1);
                cellsForOpenContainer.Add(currentCellIndex - 1);
                cellsForOpenContainer.Add(currentCellIndex + width - 1);
            }
            //顶行,加四个
            if (currentCellIndex / width == height - 1)
            {
                cellsForOpenContainer.Add(currentCellIndex + 1);
                cellsForOpenContainer.Add(currentCellIndex - 1);
                cellsForOpenContainer.Add(currentCellIndex - width + (int)Math.Pow(-1, row + 1));
                cellsForOpenContainer.Add(currentCellIndex - width);
            }
            //中间行,加六个
            if (currentCellIndex / width > 0 && currentCellIndex / width < height - 1)
            {
                cellsForOpenContainer.Add(currentCellIndex + width + (int)Math.Pow(-1, row + 1));
                cellsForOpenContainer.Add(currentCellIndex + width);
                cellsForOpenContainer.Add(currentCellIndex + 1);
                cellsForOpenContainer.Add(currentCellIndex - 1);
                cellsForOpenContainer.Add(currentCellIndex - width + (int)Math.Pow(-1, row + 1));
                cellsForOpenContainer.Add(currentCellIndex - width);
            }
        }
        //判断容器中所有的点是否是可以添加的点,是就添加到开放列表中,全部判断完清空容器
        for (int i = 0; i < cellsForOpenContainer.Count; i++)
        {
            //关闭列表和不允许通过的地型都不考虑
            if (cellsForAll[cellsForOpenContainer[i]].isEnable == false || cellsForClose.Contains(cellsForOpenContainer[i]))
                continue;
            int currentGValue = GetCurrentGValue(cellsForOpenContainer[i]);
            if (!cellsForOpen.Contains(cellsForOpenContainer[i]))
            {
                cellsForOpen.Add(cellsForOpenContainer[i]);
                cellsForAll[cellsForOpenContainer[i]].hexCellFather = cellsForAll[currentCellIndex];
                cellsForAll[cellsForOpenContainer[i]].gValue = currentGValue;
                continue;
            }
            if (cellsForOpen.Contains(cellsForOpenContainer[i]) && cellsForAll[cellsForOpenContainer[i]].gValue <= GetCurrentGValue(cellsForOpenContainer[i]))
                continue;
            if (cellsForOpen.Contains(cellsForOpenContainer[i]) && cellsForAll[cellsForOpenContainer[i]].gValue > GetCurrentGValue(cellsForOpenContainer[i]))
            {
                cellsForOpen.Add(cellsForOpenContainer[i]);
                cellsForAll[cellsForOpenContainer[i]].hexCellFather = cellsForAll[currentCellIndex];
                cellsForAll[cellsForOpenContainer[i]].gValue = GetGValue(cellsForOpenContainer[i]);
                continue;
            }
        }
        cellsForOpenContainer.Clear();
    }

    /// <summary>
    /// 计算cellsForALL列表中某个点的gValue并且返回
    /// </summary>
    /// <param name="i">该点在列表中的序号</param>
    private int GetGValue(int i)
    {
        int gValue = 0;
        HexCell cellContainer = cellsForAll[i];
        while (cellContainer.hexCellFather != null)
        {
            gValue += cellContainer.mapAssessValue;
            cellContainer = cellContainer.hexCellFather;
        }
        return gValue;
    }
    /// <summary>
    /// 假设列表下标为i的点的父节点为当前点,计算出此时的GValue并且不改变该点的父节点
    /// </summary>
    /// <param name="i"></param>
    private int GetCurrentGValue(int i)
    {
        int gValue = 0;
        HexCell cellContainer = cellsForAll[i];
        gValue += cellContainer.mapAssessValue;
        cellContainer = cellsForAll[currentCellIndex];
        while (cellContainer.hexCellFather != null)
        {
            gValue += cellContainer.mapAssessValue;
            cellContainer = cellContainer.hexCellFather;
        }
        return gValue;
    }
}

我在添加一个地格四周的地格时使用的是笨办法,有经验的读者可以自行优化(比如直接获得四周所有的地格,但如果是NULL就剔除什么的),由于六边形地图每次移动和计算的量并不大,我就不做了。

然后是我地格的类HexCell类,这个类大家看看就好,有一些写得不够好的地方请轻喷,本人还是个萌新。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public enum CellTypeForTown
{
    townCenter, //城镇中心
    townCell,   //城镇普通地格
    normalCell,  //野外地格
    buildCell   //已经建有建筑物的地格
}

public class HexCell : MonoBehaviour
{
    public CellTypeForTown cellTypeForTown = CellTypeForTown.normalCell;
    private Town town;
    public HexCoordinates coordinates;
    /// <summary>
    /// 父方格,用于A星寻路
    /// </summary>
    //[System.NonSerialized]
    public HexCell hexCellFather;
    public Color color;
    /// <summary>
    /// 地型评估值,表示到达该地需要付出的地形惩罚,负数表示越走行走值越多;
    /// 比如A点到B点,根据B点地型计算惩罚
    /// </summary>
    public int mapAssessValue = 1;
    public bool isEnable = true;
    /// <summary>
    /// 用于ASTAR寻路
    /// </summary>
    public int fValue = 0;
    public int gValue = 0;
    public void SetTownForCell(Town town)
    {
        this.town = town;
    }
    public Town GetTownForCell()
    {
        return this.town;
    }
    public static HexCell FindCellByCoordinates(HexCell[] cells, HexCoordinates coordinates)
    {
        int row = coordinates.Z * Global.instance.width;
        int colum = coordinates.X + coordinates.Z / 2;
        if (colum < 0 || colum > Global.instance.width - 1)
            return null;
        if (row + colum >= 0 && row + colum < cells.Length)
            return cells[row + colum];
        return null;
    }
    public static HexCell FindCellByCoordinates(HexCoordinates coordinates)
    {
        HexCell[] cells = Global.instance.cells;
        int row = coordinates.Z * Global.instance.width;
        int colum = coordinates.X + coordinates.Z / 2;
        if (colum < 0 || colum > Global.instance.width - 1)
            return null;
        if (row + colum >= 0 && row + colum < cells.Length)
            return cells[row + colum];
        return null;
    }
    /// <summary>
    /// 返回-1表示数组越界
    /// </summary>
    public static int GetCellIndexByCoordinates(HexCell[] cells, HexCoordinates coordinates)
    {
        int row = coordinates.Z * Global.instance.width;
        int colum = coordinates.X + coordinates.Z / 2;
        if (colum < 0 || colum > Global.instance.width - 1)
            return -1;
        if (row + colum >= 0 && row + colum < cells.Length)
            return row + colum;
        return -1;
    }
    /// <summary>
    /// 返回-1表示数组越界
    /// </summary>
    public static int GetCellIndexByCoordinates(HexCoordinates coordinates)
    {
        HexCell[] cells = Global.instance.cells;
        int row = coordinates.Z * Global.instance.width;
        int colum = coordinates.X + coordinates.Z / 2;
        if (colum < 0 || colum > Global.instance.width - 1)
            return -1;
        if (row + colum >= 0 && row + colum < cells.Length)
            return row + colum;
        return -1;
    }
    /// <summary>
    /// 根据一个基础cell和附加坐标,得到基础cell坐标+附加坐标的cell对象;如果数组越界,就返回Null
    /// </summary>
    public static HexCell GetCellByAddCoordinatesVector(HexCell[] cells, HexCell basicCell, HexCoordinates addCoordinates)
    {
        HexCoordinates mHexCoordinates = basicCell.coordinates + addCoordinates;
        return FindCellByCoordinates(cells, mHexCoordinates);
    }

    public static List<HexCell> GetCellsAroundCentetByDistance(HexCell[] cells, HexCell centerCell, int distance)
    {
        List<HexCell> townCells = new List<HexCell>();
        int count = distance * distance * 3 + distance * 3 + 1;
        HexCell[] mCells = new HexCell[count];
        int i = 0;
        for (int z = -distance; z <= distance; z++)
            for (int x = -distance; x <= distance; x++)
            {
                int y = -z - x;
                if (y < -distance || y > distance)
                    continue;
                mCells[i] = HexCell.GetCellByAddCoordinatesVector(Global.instance.cells, centerCell, new HexCoordinates(x, z));
                i++;
            }
        for (i = 0; i < count; i++)
        {
            if (mCells[i] != null)
            {
                townCells.Add(mCells[i]);
            }
        }
        return townCells;
    }
    public bool CanSetEntityObjToCell(GameObject obj)
    {
        return CanSetEntityObjToCell(obj.transform);
    }
    public bool CanSetEntityObjToCell(Transform obj)
    {
        return CanSetEntityObjToCell(obj.tag);
    }
    public bool CanSetEntityObjToCell(string objTagName)
    {
        if (objTagName == "Untagged")
            return true;
        Transform[] sons = transform.GetComponentsInChildren<Transform>();
        for (int i = 0; i < sons.Length; i++)
        {
            if (sons[i].CompareTag(objTagName))
                return false;
        }
        return true;
    }
}


没有更多推荐了,返回首页