MMORPG大型游戏设计与开发(服务器 游戏场景 地图和区域)
地图的数据以及区域的信息是场景的重要组成部分,这些数据同时存在客户端和服务器,而且都是由编辑器生成的。那么保存的文件数据结构是怎样的?一张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大型游戏设计与开发(服务器 游戏场景 地图和区域)的更多相关文章
- MMORPG大型游戏设计与开发(游戏服务器 游戏场景 概述 updated)
我们在玩游戏的时候,我们进入游戏后第一眼往往都是看到游戏世界中的场景,当然除了个别例外,因为那些游戏将游戏场景隐藏了起来,如文字游戏中的地点一样.既然我们接触了游戏世界的核心,那么作为核心的场景又包括 ...
- MMORPG大型游戏设计与开发(服务器 AI 概述)
游戏世界中我们拥有许多对象,常见的就是角色自身以及怪物和NPC,我们可以见到怪物和NPC拥有许多的行为,比如说怪物常常见到敌对的玩家就会攻击一样,又如一些NPC来游戏世界中走来走去,又有些怪物和NPC ...
- MMORPG大型游戏设计与开发(服务器 游戏场景 动态场景与副本)
场景的内容讲解到今天算是暂时划上一个句号了,接下来为大家讲解的是AI部分(大型AI),如果有兴趣的朋友不妨持续关注这些文章,大家一起学习和进步.动态场景和副本是场景中特殊的类型,副本在这里想必已经是无 ...
- MMORPG大型游戏设计与开发(概述)updated
1.定义 MMORPG,是英文Massive(或Massively)Multiplayer Online Role-PlayingGame的缩写,即大型多人在线角色扮演游戏. 2.技术与知识 在这系列 ...
- MMORPG大型游戏设计与开发(客户端架构 part8 of vegine)
脚本模块是游戏设计中争论比较多的话题,那是因为作为脚本本身所带来的利弊.其实这都无关紧要,取舍是人必须学会的一项技能,如果你不会取舍那么就让趋势给你一个满意的答复.自从魔兽世界以及传奇(世界)问世以来 ...
- MMORPG大型游戏设计与开发(服务器 游戏场景 多线程)
多线程在随着cpu发展应用的是越来越多,游戏场景因为其在服务器所占的数据量与逻辑复杂度的原因必须依赖于它.为什么场景要采用多线程?场景的线程是怎样的?场景的线程又是如何创建的?场景的线程又是怎样管理的 ...
- MMORPG大型游戏设计与开发(服务器 游戏场景 核心详述)
核心这个词来的是多么的高深,可能我们也因为这个字眼望而却步,也就很难去掌握这部分的知识.之所以将核心放在最前面讲解,也可以看出它真的很重要,希望朋友们不会错过这个一直以来让大家不熟悉的知识,同我一起进 ...
- MMORPG大型游戏设计与开发(服务器 AI 事件)
AI中的事件与场景中的事件大致相同,都是由特定的条件触发的.只不过AI的事件与其他事件不同的是,对于AI的事件往往是根据不同的AI类型,和动态的触发条件下才产生的.其实不管AI多么智能,它对应的触发条 ...
- MMORPG大型游戏设计与开发(服务器 AI 基础接口)
一个模块都往往需要统一的接口支持,特别是对于非常大型的模块,基础结构的统一性非常重要,它往往决定了其扩展对象的通用性.昨天说了AI的基本概述以及组成,作为与场景模块中核心一样重要的地位,基础部分的设计 ...
随机推荐
- 自己实现简单的AOP(四)自动初始化代理对象
前面三篇随笔,已经完成了AOP的核心功能,但 代理对象的初始化还是有些麻烦,本文将解决该问题. Demo 片段如下: public class HomeController : Controller ...
- MySQL 快速创建索引
用SELECT INTO OUTFILE导出记录,TRUNCATE 此TABLE,建立索引,用LOAD DATA INIFILE再导入 缺点:不支持热操作
- [Q&A] 应用程序清单生成失败
当在 Silverlight 客户端属性里(如下图),添加"允许在浏览器外运行应用程序"和"在浏览器内运行时需要提升的信任"时, 图1 目录下会自动生成如下两个 ...
- 在Hibernate框架中详谈一级缓存
在学习Hibernate的过程中我们肯定会碰上一个名词---缓存,一直都听说缓存机制是Hibernate中的一个难点,它分为好几种,有一级缓存,二级缓存和查询缓存 今天呢,我就跟大家分享分享我所理解的 ...
- 生成树形结构的json字符串代码(c#)供前端angular tree使用.
框架是使用EF6.0.可以针对返回的值使用Newtonsoft.Json.dll(百度搜一下)来对返回的值序列化为json字符串,如果对以下值那就是使用JsonConvert.SerializeObj ...
- [函数] Delphi FMX Windows 取得下载 Downloads 目录
在 Firemonkey 提供了一个跨平台的函数 TPath.GetDownloadsPath 来取得该平台的下载目录,但是非常奇怪的是,在 Windows 平台下,取得的下载目录确是: C:\Use ...
- Lock、ReentrantLock、synchronized、ReentrantReadWriteLock使用
先来看一段代码,实现如下打印效果: 1 2 A 3 4 B 5 6 C 7 8 D 9 10 E 11 12 F 13 14 G 15 16 H 17 18 I 19 20 J 21 22 K 23 ...
- entityframework学习笔记--003-使用model first
首先,我个人觉得这(model first 即模型优先)是一个鸡肋似的功能.当赞扬着他的强大的功能的同时,你也会觉得这个功能好像是不是不怎么需要,也很少使用. 1.右键你的项目,选择"添加& ...
- Atitit. null错误的设计 使用Optional来处理null
Atitit. null错误的设计 使用Optional来处理null 然后,我们再看看null还会引入什么问题. 看看下面这个代码: String address = person.getCount ...
- apache反向代理
正向代理是客户端发送请求给代理服务器,代理服务器将请求发给实际处理的服务器 反向代理是客户端发送请求给服务器(实际上是个代理服务器),服务器将请求发给实际处理的服务器 情景 在一台服务器上开了apac ...