服务器使用recast navigation

  在3D MMO或者其他类型的游戏中,通常需要进行寻路处理,地图针对寻路有多种方案,比如划分格子,凸多边形等,本篇介绍一种比较常用的navigation mesh的方式来进行寻路。不过整套navmesh的算法比较复杂,没有深入的研究写不出来,我们使用网上开源的解决方案,google的recast方案。我们使用的开发环境是win7 + vs2013.

  一、服务器端recast的安装和使用

  1、先从github上面下载recast的源代码

  2. 源代码下载下来之后,需要我们自己进行编译,recast使用预编译工具premake,需要premake.lua。先下载lua,然后单独下载premake5,否则premake5.lua不能使用。将下载好的premake.exe放到和premake5.lua的同一目录下,然后在控制台运行premake.exe vs2013(根据自己的IDE版本号),就会生成vs2013的解决方案sln文件。

  2. recast的测试程序中,用到了SDL的相关库,这个比较简单,下载一个SDL-devel的库就可以了,然后看下RecastDemo里面的配置目录,copy进去就可以编译通过了。中间编译的时候,可能由于vs2013版本,会提示min,max这些函数没有定义,只要#include对应的STL库头文件<algorithm>就可以了

  3. 成功编译了recast相关的库,Detour,Recast等,我们一开始对于如何使用recast可能一点概念都没有,不过recast已经考虑到了这一点,工程中有一个RecastDemo程序,是用来示例如何使用recast的。

  4. 使用recastDemo,我们可以根据场景的.obj文件,来生成navmesh,和导入我们自己生成的navmesh,不过这都是我们通过recast开源工具生成的。实际的游戏中,我们需要的是从客户端生成的navmesh,然后导入到服务器中进行解析。

  二、Unity3D客户端的navmesh生成

  unity3D是自带navmesh agent的,可以自己生成navmesh,并且导出navmesh,不过它的导出navmesh,我查下来是需要自己写代码的,而且navmesh agent是修改过导出navmesh文件格式的,也就是说我们recast C++代码是不能直接使用的。后来我又搜索了一下recast for Unity这个插件,这个插件是有源代码的,不过如果正常购买需要$50。

  对于这个插件当时研究了比较长的时间,一开始导出了一下它的navmesh格式,然后用C++recast导入试了一下,发现格式肯定是不一样的了。然后就仔细研究了一下两边生成navmesh时的格式差异,针对TileMesh存储的时候,两边是不一致的,本来想直接修改C#代码来达到两边一致,不过由于对C#的序列化不够熟悉,就放弃了。不过应该可以直接改成一致,这个后面有时间可以再深入研究一下。

  后来使用了KBEngine修改过的CritterAI,它导出来的navmesh文件,在KBEngine中是能直接使用的。然后把我们服务器中解析navmesh的格式,改成和KBEngine一致就可以了。代码还是非常简单的,代码如下:

    bool NavMeshLoader::load_cai(const char* path) {
        FILE* fp = fopen(path, "rb");
        if (!fp) return false;

        // Read header.
        NavMeshSetHeader_CAI header;
        size_t readLen = fread(&header, sizeof(NavMeshSetHeader_CAI), 1, fp);
        if (readLen != 1)
        {
            fclose(fp);
            return false;
        }

        if (header.version != NAVMESHSET_VERSION)
        {
            fclose(fp);
            return false;
        }

        dtNavMesh* mesh = dtAllocNavMesh();
        if (!mesh)
        {
            fclose(fp);
            return false;
        }
        dtStatus status = mesh->init(&header.params);
        if (dtStatusFailed(status))
        {
            fclose(fp);
            return false;
        }

        // Read tiles.
        for (int i = 0; i < header.tileCount; ++i)
        {
            NavMeshTileHeader tileHeader;
            readLen = fread(&tileHeader, sizeof(tileHeader), 1, fp);
            if (readLen != 1)
            {
                fclose(fp);
                return false;
            }

            if (!tileHeader.tileRef || !tileHeader.dataSize)
                break;

            unsigned char* data = (unsigned char*)dtAlloc(tileHeader.dataSize, DT_ALLOC_PERM);
            if (!data) break;
            memset(data, 0, tileHeader.dataSize);
            readLen = fread(data, tileHeader.dataSize, 1, fp);
            if (readLen != 1)
            {
                fclose(fp);
                return false;
            }

            mesh->addTile(data, tileHeader.dataSize, DT_TILE_FREE_DATA, tileHeader.tileRef, 0);
        }

        fclose(fp);
        m_navMesh = mesh;
        m_navQuery = dtAllocNavMeshQuery();

        status = m_navQuery->init(m_navMesh, 2048);
        if (dtStatusFailed(status))
        {
            return false;
        }

        return true;
    }

  KBEngine中和RecastDemo中解析navmesh主要就是NavMeshSetHeader头结构不一致,其他的都一样,所以还是比较简单的。

  能正常解析navmesh文件之后,就是对地图进行寻路了,在这里主要使用了RecastDemo中寻路的代码,进行了本地化的修改。

  

  三、 使用recast navigation遇到的问题

  1、其中有段时间,我对于客户端生成的navmesh,和服务器生成的navmesh在坐标系上不一致,感觉很困惑,甚至想要不要自己用3DMax之类的工具重新导入地图模型,然后修改坐标系,这现在看来很可笑,主要还是对于navmesh的生成原理不是很懂。其实客户端生成的navmesh是带有自身坐标系和相对坐标的。之前之所以有那种困惑,是因为服务器用的是recastDemo中生成的navmesh,客户端生成了自己的,根本就是两种世界,两种坐标,当然不一致了!!

  2、其实CritterAI的底层是C++写的dll,通过unity导入进工程,然后生成navmesh的,只要符合unity使用dll的规则,我们其实也可以使用recast的源码,然后改成unity能够使用的dll来导出navmesh。这个后面可以试试

时间: 2024-08-27 03:10:39

服务器使用recast navigation的相关文章

Recast Navigation 学习笔记(一)

RecastNavigation下载地址 https://github.com/recastnavigation/recastnavigation CritterAI 下载地址 http://www.critterai.org/

Recast Navigation 学习笔记(二)

核心构建过程 http://www.critterai.org/projects/cainav/doc/html/e72bd1ee-04b0-4bbb-a21d-d8d7ecaa11af.htm 本文涵盖 NMGen 构建导航网格的核心处理过程.网格的生成处理有许多变种,但他们都包含这些步骤. IncrementalBuilder 扩展实现了这些处理. 处理过程如下: 体素化:用源几何模型生成 "solid heightfield" 代表阻挡空间. 生成域:探测 "solid

Recast &amp; Detour &amp; TerrainExport Study Feeling

Recast Navigation和Terrain Export终于算是有点成果了.今天作一个简单的总结,顺便写一些话激励自己. 这个项目的成功对于我这个算法又烂,而又不懂3d图形学的人来说,感觉真是个奇迹.我说的成功是技术成果上的成功,而不是靠这个赚钱了. 总体来说,技术贵在坚持,还要加那么一点点激情. 这个项目牵的知识面比较广而偏向底层,其中不乏有一些连专业3d游戏设计者都比较难懂的.学习这个我买了四本书<DirectX 9.0 3D游戏开发编程基础>.<DirectX 9PROGR

UE4的NavArea,AreaFlags和Recast的dtPoly的关系

UE的导航网格底层使用的是Recast Navigation,而Recast将网格划分为一个个凸多边形,平时寻路基本上都是使用这些多边形. /// Defines a polyogn within a dtMeshTile object. /// @ingroup detour struct dtPoly { /// Index to first link in linked list. (Or #DT_NULL_LINK if there is no link.) unsigned int f

php项目------浏览器导航开发

最近项目不是很急,把以前做的php项目分享一些给大家,希望对各位有所帮助:很简单的一个项目,本人用来练习ThinPHP框架的. 浏览器导航开发,php+mysql+apache,ThinkPHP3.2框架开发, 以前本人练习的项目,也是参考自己购买的资料来练习的,适合新手练习. 后台界面: 前台界面: 项目如何运行: 新建数据库,运行SQL文件,如下图:     clone项目,更改Application/Common/Conf/config.php 的配置文件 /**** * 数据库配置 */

(ros/navigation/slam_gmapping) map_server地图服务器

http://wiki.ros.org/map_server 概述 map_server提供map_server ROS节点,它提供地图数据作为一个ROS服务器.也提供map_saver命令行功能,能动态生成保存到文件中的地图. 地图格式 包中通过工具操作的地图是以成堆的文件存储的.YAML文件描述地图的元数据,并命名image文件.Image文件编码占用数据. Image 格式 Image 以对应单元的颜色描述世界中每个单元的占用状态.白色单元格表示自由,黑色单元格表示占用,两种颜色之间的单元

搭建QQ聊天通信的程序:(1)基于 networkcomms.net 创建一个WPF聊天客户端服务器应用程序 (1)

搭建QQ聊天通信的程序:(1)基于 networkcomms.net 创建一个WPF聊天客户端服务器应用程序 原文地址(英文):http://www.networkcomms.net/creating-a-wpf-chat-client-server-application/ 注意:本教程是相当广泛的,如果你是在短请也看到我们的东西 开始和 如何在几分钟内创建一个客户端服务器应用程序教程. 注2:本例中包括,明显延长进一步证明功能,在包中包含的示例 包下载. 在我们开始之前确保您已经安装了Vis

7.1SportsStore:Navigation and Checkout

准备示例项目 使用真实的产品数据 现在,要切换到使用真实的数据,从Deployd服务器获取. AngularJS通过一个叫做$http的服务,为Ajax请求提供支持.作者将在第三部分详细讲解它是怎么工作的,在第23章讲解$http服务.现在有个简单的认识,修改顶级控制器sportsStoreCtrl: angular.module("sportsStore") .constant("dataUrl", "http://localhost:5500/prod

RHEL7部署ISCSI TARGET服务器

一.配置yum源 [[email protected] yum.repos.d]# vi /etc/yum.repos.d/local.repo [local] name=local baseurl=file:///mnt/media/ enable=1 gpgcheck=0 二.挂载光盘 [[email protected] yum.repos.d]# mkdir /mnt/media/ [[email protected] yum.repos.d]# mount /dev/cdrom /mn