地图的数据以及区域的信息是场景的重要组成部分,这些数据同时存在客户端和服务器,而且都是由编辑器生成的。那么保存的文件数据结构是怎样的?一张3D的场景地图又是怎样处理这些数据的?同时告诉大家这里同样只是讲的理论与设计,理论和设计往往都很空洞,但是却很灵活,需要靠每个人怎么运用。

一些图片

区域和格子

从上面的截图可以看出游戏场景其实是由格子来区分的,不管是矩形的格子还是其他形状的格子也好,一张地图不可能只有一个点(即多点组成一张地图)。在3D场景中似乎格子的位置总伴随着高度信息,所以让人感觉有些迷茫,其实我们可以将这些格子平铺成一张图。

如上面的最后一张图,是地形的剖面图,不过是横切面,如果我们看一下纵切面的话,就可以将3D的地图进行2D的转换。其实地图还是由一张平面图组成,只是多了Y轴的数据,也就是我们常说的地表高度。

地图数据

由指定格式的数据组成,在服务器和客户端的主要作用是用来寻路(点击地图走路,以及自动寻路)。

地图区域

一个场景一般情况下会有区域的划分,因为这些区域会有自己特殊的事件,如一个玩家加入该区域会产生某个事件,就像我们玩游戏的时候忽然触发了剧情一样,这都是区域的事件。

数据结构

有了指定的数据结构后,文件才能被正常的读取,而地图的数据一般是由编辑器生成,所以也必须规定文件的数据结构。

1、地图

1. 文件数据

武侠世界/天龙八部的场景地图数据格式为:[文件头][单元数据][单元数据]…… 单元数据的数量为地图横长* 地图纵长。

code.
typedef struct map_header_struct {
int16_t flag; //文件标记,用来区分是不是地图数据文件
int32_t xsize; //X方向大小 横长
int32_t zsize; //Y方向大小 纵长
} map_header_t; //文件头信息 typedef struct map_unit_struct {
int16_t flag; //标识信息
//00000000|00000000
// ||_ WalkDisable -是否禁止地面上行走的OBJ穿越 [0 可穿越 1不可穿越]
// |__ FlyDisable -是否禁止空中飞行的OBJ穿越 [0 可穿越 1不可穿越]
int8_t height; //高度
int8_t reserved; //预留字段
} map_unit_t; //单元数据信息

2. 对象数据

整个对象也就是整张地图的数据,在武侠世界/天龙八部中采用的是左手坐标系,而在服务器其实用不着空间的坐标也就是Y轴的数据,将地图切割后就是一张平面的图,这张平面的图一般都是矩形。

X坐标 左为0、右为最大(也可以说是地图横长)

Y坐标 上为0、下为最大(也可以说是地图纵长)

code.
/* 完整的地图示意图 */
// (0, z) (x, z)
// ___________
// y z | |
// | / | |
// |/ | |
// +-------x |_________|
//
// (0, 0) (x, 0)

2、区域

地图划分成一个个格子,而组成区域的也是格子,以下为一个区域的基本数据。

1. RECT(矩形格子)

left 左、top 高度、right 右、bottom 底部。

2. 区域ID

3. 脚本ID

算法(选择排序)

1、简单选择排序

简单选择排序基本思想是将最小的数据移动到第一个位置并交换数据,比如有N个元素,一次将最小的元素移动到第一个位置并交换数据,那么剩下的就只剩下N-1个数据,将剩下的N-1的序列的数据最小的数据移动到该剩下序列的第一个位置,这样移动N次之后,序列便成了有序的序列。

code.

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h> /**
* 简单选择排序基本思想是将最小的数据移动到第一个位置并交换数据,比如有N个元素,
* 第一次将最小的元素移动到第一个位置并交换数据,那么剩下的就只剩下N-1个数据
* 再将剩下的N-1的序列的数据最小的数据移动到该剩下序列的第一个位置,这样移动N次
* 之后,序列便成了有序的序列。
*/ //简单选择排序
void selectsort(int32_t array[], int32_t length);
//数组打印
void displayarray(int32_t array[], int32_t length); int32_t main(int32_t argc, char *argv[]) {
int32_t array[] = {, , , , , , , , };
int32_t length = sizeof(array) / sizeof(array[]);
selectsort(array, length);
printf("sort result: ");
displayarray(array, length);
return ;
} void selectsort(int32_t array[], int32_t length) {
int32_t i, j, k;
int32_t temp;
//将第i个元素与第i+1...length个元素比较,将最小的元素放在第i个位置
for (i = ; i < length - ; ++i) {
j = i;
for (k = i + ; k < length; ++k) { //最小元素的序号为j
if (array[k] < array[j])
j = k;
}
if (j != i) { //如果序号i不等于j,则需要加序号i和序号j的元素交换
temp = array[i];
array[i] = array[j];
array[j] = temp;
}
printf("the %d times sort result: ", i + );
displayarray(array, length);
}
} void displayarray(int32_t array[], int32_t length) {
int32_t i;
for (i = ; i < length; ++i)
printf("%4d", array[i]);
printf("\n");
}

result.

2、堆排序

堆排序算法实现比较复杂,它主要适用于大规模的数据排序,比如在10万个数据元素中找出前10个最小或是最大的元素,使用该算法效率最高。

code.

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h> /**
* 堆排序算法实现比较复杂,它主要适用于大规模的数据排序,比如在10万个数据元素
* 中找出前10个最小或是最大的元素,使用该算法效率最高。
*/ //数组打印
void displayarray(int32_t array[], int32_t length);
//调整array[pos1...pos2],使其成为一个大顶堆
void adjustheap(int32_t array[], int32_t pos1, int32_t pos2);
//创建大顶堆
void createheap(int32_t array[], int32_t length);
//利用堆排序算法对数组进行排序
void heapsort(int32_t array[], int32_t length); int32_t main(int32_t argc, char *argv[]) {
int32_t array[] = {, , , , , , , , };
int32_t length = sizeof(array) / sizeof(array[]);
printf("before sort: ");
displayarray(array, length);
heapsort(array, length);
printf("after sort: ");
displayarray(array, length);
return ;
} void displayarray(int32_t array[], int32_t length) {
int32_t i;
for (i = ; i < length; ++i)
printf("%4d", array[i]);
printf("\n");
} void adjustheap(int32_t array[], int32_t pos1, int32_t pos2) {
int32_t i;
int32_t temp;
temp = array[pos1]; //临时存放根节点
for (i = * pos1 + ; i <= pos2; i *= + ) {
if (i < pos2 && array[i] < array[i + ]) //从关键字较大的子节点向下筛选
++i; //i为关键字较大的节点的下标
if (temp > array[i]) break; //如果子节点的值小于根节点的值,则不进行交换
array[pos1] = array[i];
pos1 = i;
}
array[pos1] = temp; //将根节点插入到正确的位置
} void createheap(int32_t array[], int32_t length) {
int32_t i;
for (i = length / - ; i >= ; --i) //从序号length / 2 - 1开始建立大顶堆
adjustheap(array, i, length - );
} void heapsort(int32_t array[], int32_t length) {
int32_t i;
int32_t temp;
createheap(array, length); //创建堆
for (i = length - ; i > ; --i) { //将堆顶元素与最后一个元素交换,重新调整堆
temp = array[];
array[] = array[i];
array[i] = temp;
printf("the %d sort times: ", length - i);
displayarray(array, length);
adjustheap(array, , i - ); //将array[0...i-1]调整为大顶堆
}
}

result.

MMORPG大型游戏设计与开发(服务器 游戏场景 地图和区域)的更多相关文章

  1. MMORPG大型游戏设计与开发(游戏服务器 游戏场景 概述 updated)

    我们在玩游戏的时候,我们进入游戏后第一眼往往都是看到游戏世界中的场景,当然除了个别例外,因为那些游戏将游戏场景隐藏了起来,如文字游戏中的地点一样.既然我们接触了游戏世界的核心,那么作为核心的场景又包括 ...

  2. MMORPG大型游戏设计与开发(服务器 AI 概述)

    游戏世界中我们拥有许多对象,常见的就是角色自身以及怪物和NPC,我们可以见到怪物和NPC拥有许多的行为,比如说怪物常常见到敌对的玩家就会攻击一样,又如一些NPC来游戏世界中走来走去,又有些怪物和NPC ...

  3. MMORPG大型游戏设计与开发(服务器 游戏场景 动态场景与副本)

    场景的内容讲解到今天算是暂时划上一个句号了,接下来为大家讲解的是AI部分(大型AI),如果有兴趣的朋友不妨持续关注这些文章,大家一起学习和进步.动态场景和副本是场景中特殊的类型,副本在这里想必已经是无 ...

  4. MMORPG大型游戏设计与开发(概述)updated

    1.定义 MMORPG,是英文Massive(或Massively)Multiplayer Online Role-PlayingGame的缩写,即大型多人在线角色扮演游戏. 2.技术与知识 在这系列 ...

  5. MMORPG大型游戏设计与开发(客户端架构 part8 of vegine)

    脚本模块是游戏设计中争论比较多的话题,那是因为作为脚本本身所带来的利弊.其实这都无关紧要,取舍是人必须学会的一项技能,如果你不会取舍那么就让趋势给你一个满意的答复.自从魔兽世界以及传奇(世界)问世以来 ...

  6. MMORPG大型游戏设计与开发(服务器 游戏场景 多线程)

    多线程在随着cpu发展应用的是越来越多,游戏场景因为其在服务器所占的数据量与逻辑复杂度的原因必须依赖于它.为什么场景要采用多线程?场景的线程是怎样的?场景的线程又是如何创建的?场景的线程又是怎样管理的 ...

  7. MMORPG大型游戏设计与开发(服务器 游戏场景 核心详述)

    核心这个词来的是多么的高深,可能我们也因为这个字眼望而却步,也就很难去掌握这部分的知识.之所以将核心放在最前面讲解,也可以看出它真的很重要,希望朋友们不会错过这个一直以来让大家不熟悉的知识,同我一起进 ...

  8. MMORPG大型游戏设计与开发(服务器 AI 事件)

    AI中的事件与场景中的事件大致相同,都是由特定的条件触发的.只不过AI的事件与其他事件不同的是,对于AI的事件往往是根据不同的AI类型,和动态的触发条件下才产生的.其实不管AI多么智能,它对应的触发条 ...

  9. MMORPG大型游戏设计与开发(服务器 AI 基础接口)

    一个模块都往往需要统一的接口支持,特别是对于非常大型的模块,基础结构的统一性非常重要,它往往决定了其扩展对象的通用性.昨天说了AI的基本概述以及组成,作为与场景模块中核心一样重要的地位,基础部分的设计 ...

随机推荐

  1. 怎样操作WebAPI接口(显示数据)

    就在去年Insus.NET已经写好的一个WebAPI项目,并且发布在IIS中.参考<创建与使用Web API>http://www.cnblogs.com/insus/p/5019088. ...

  2. cors解决webapi post时报错405 method not allowed

    nuget控制台敲入以下命令:Install-Package Microsoft.AspNet.WebApi.Cors –IncludePrerelease 打开WebApiConfig.cs添加如下 ...

  3. Linux查看CPU和内存使用情况(转)

    在系统维护的过程中,随时可能有需要查看 CPU 使用率,并根据相应信息分析系统状况的需要.在 CentOS 中,可以通过 top 命令来查看 CPU 使用状况.运行 top 命令后,CPU 使用状态会 ...

  4. eclipse中怎么添加Hibernate tools

    最近在学习Hibernate框架,但是用eclipse的时候发现自己安装的过程不是很顺利,因此记下来,供自己和别人参考. Hibernate Tools是由JBoss推出的一个Eclipse集成开发工 ...

  5. 聊聊JVM的年轻代

    1.为什么会有年轻代 我们先来屡屡,为什么需要把堆分代?不分代不能完成他所做的事情么?其实不分代完全可以,分代的 唯一理由就是优化GC性能.你先想想,如果没有分代,那我们所有的对象都在一块,GC的时候 ...

  6. php文件之间传值的三种主流并且常用的方式

    一.表单传值 在<form>中的action填入要跳转页面的路径,method填入POST或者GET方法.表单中的提交按钮按下后,就会把<form>中有value都传到要跳转的 ...

  7. H5中的touch事件

    touch中共有touchstart.touchmove和touchend三个事件: touchstart:触摸开始的时候触发 touchmove:手指在屏幕上滑动的时候触发 touchend:触摸结 ...

  8. Linux安全基础:配置network

    在 Linux 系统中,TCP/IP 网络是通过若干个文本文件进行配置的,需要编辑这些文件来完成联网工作.系统中重要的有关网络配置文件有以下几项: /etc/sysconfig/network/etc ...

  9. Android—Bundle传递ArrayList<T>

    Android开发中Activity传值特别普遍,最贱开发需要传递集合List到另一个Activity,在此作出总结. 首先创建自己的实体类:我的暂命名为Gate. 声明List集合时候泛型中是你声明 ...

  10. Android Couldn't load BaiduMapSDK

    什么都不用多说,看代码 Couldn't load BaiduMapSDK_v3_2_0_15 from loader dalvik.system.PathClassLoader[DexPathLis ...