MMORPG大型游戏设计与开发(服务器 游戏场景 事件)
今天第星期天,知识是永远是学习不完的,所以今天这部分算比较轻松,同时也希望大家会有一个好的周末。场景事件即场景的回调,和别的事件一样是在特定的条件下产生的,前面也介绍过场景的各种事件,今天详细的说一说这些事件的具体作用。
游戏截图
场景事件
一个完整的对象一般都拥有事件,至于什么是事件在这里就不多解释了。在场景中的事件在天龙/武侠世界中的事件包括场景初始化、场景定时器、场景退出、玩家进入场景、角色升级、角色死亡、角色重生、场景通知、任务接受检查、NPC对话默认事件、NPC事件列表事件。
1、场景初始化(scene init)
场景初始化事件,负责副本场景的数据维护、负责副本定时器的开启、负责城市入口的挂接、调用脚本初始化函数。
2、场景定时器(scene timer)
负责定时器数据的处理,一般会调用到脚本的相应函数。
3、场景退出(scene quit)
场景退出一般是清理数据的作用,首先调用脚本的场景退出函数,然后移除所有对象。移除的对象包括玩家、怪物、宠物、操作台、掉落包。
4、玩家进入(player enter)
一个玩家进入场景产生的事件,一般调用脚本函数处理该事件。
5、玩家升级(player level up)
玩家升级后的回调,试想一下玩家升级后会有哪些数据的改变?场景中有哪些数据需要更新?是不是这里的玩家升级事件也就包括了其他数据的改变?
6、玩家死亡(player death)
玩家死亡一般伴随着许多数据的改变,如常见的金钱掉落,物品掉落等等,还有玩家死亡可能会触发任务状态的改变,或一个剧情等等。
7、玩家复活(player relive)
玩家的复活事件,是不是玩家复活的时候常见的数据直接在逻辑中就实现了,还是要放到事件函数中?我们这里常说的事件函数一般都是指调用脚本,调用脚本其实为了能够频繁的改动数据。
8、玩家断线(player disconnect)
断线是一个痛苦的事情,特别是在我们玩的正开心的时候,但是怎么也比不过一些实在的数据处理的时候,如天龙八部中离线事件中把玩家交易的完全处理放到了这里。
9、场景通知(scene notify)
一开始一听这个事件的时候我也曾觉得很迷茫,但是看了具体代码的时候才知道在游戏中是为副本场景来服务的,只有当副本已经初始化完成才会收到该消息用来传送玩家到副本中。
10、任务接受检查事件(mission accept check)
要接受一个任务会有条件的,如人物等级的限制、所在场景、事件限制等等。
11、NPC默认对话框事件(npc default dialog)
如果是可以交互的NPC则会有对话框来表现这种交互,如果还有默认的操作则将默认操作的选项显示出来。
12、NPC默认事件列表(npc default event list)
默认事件列表是指NPC默认的一些事件,这些事件在经过该回调正确的检查之后才显示正确的选项。
算法(归并和基数排序)
1、归并排序
并排序算法实现复杂,因为二路归并算法需要的临时空间较大,所以常常用在外部序中。(其核心的思想为将两个或两个以上的元素有序序列合并为一个有序序列)
并算法是一种稳定的排序算法。
code.
#include <stdio.h>
#include <stdint.h>
#include <malloc.h>
#include <inttypes.h> /**
* 归并排序算法实现复杂,因为二路归并算法需要的临时空间较大,所以常常用在外部
* 排序中。(其核心的思想为将两个或两个以上的元素有序序列合并为一个有序序列)
* 归并算法是一种稳定的排序算法。
*/ //将source数组中的元素复制到dest数组中,其中,length为长度,first是目标数组的起始位置
void copyarray(int32_t source[], int32_t dest[], int32_t length, int32_t first);
//归并排序
void mergesort(int32_t array[], int32_t left, int32_t right);
//合并两个子序列中的元素
void merge(int32_t array[], int32_t left, int32_t right);
//数组打印
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[]);
printf("before sort: ");
displayarray(array, length);
mergesort(array, , length - );
printf("after sort: ");
displayarray(array, length);
return ;
} void copyarray(int32_t source[], int32_t dest[], int32_t length, int32_t first) {
int32_t i, j = first;
for (i = ; i < length; ++i) {
dest[j] = source[i];
++j;
}
} void mergesort(int32_t array[], int32_t left, int32_t right) {
int32_t i;
if (left < right) {
i = (left + right) / ;
mergesort(array, left, i);
mergesort(array, i + , right);
merge(array, left, right);
}
} void merge(int32_t array[], int32_t left, int32_t right) {
int32_t begin1, begin2, middle, k = , length;
int32_t *pointer = NULL;
begin1 = left;
middle = (left + right) / ;
begin2 = middle + ;
length = right - left + ;
pointer = (int32_t *)malloc(length * sizeof(int32_t));
if (NULL == pointer) return;
while (begin1 <= middle && begin2 <= right) {
if (array[begin1] < array[begin2]) {
pointer[k++] = array[begin1++];
} else {
pointer[k++] = array[begin2++];
}
}
while (begin1 <= middle) pointer[k++] = array[begin1++];
while (begin2 <= right) pointer[k++] = array[begin2++];
copyarray(pointer, array, length, left);
if (pointer != NULL) free(pointer);
pointer = NULL;
} void displayarray(int32_t array[], int32_t length) {
int32_t i;
for (i = ; i < length; ++i)
printf("%4d", array[i]);
printf("\n");
}
result.
2、基数排序(比较复杂)
数排序算法实现比较复杂,它是一种多关键字的排序算法,属于分类排序。因为基数序算法不需要过多比较,所以在数据较多的情况下,采用基数排序算法的效率要高于他的排序算法。
基数排序也是一种稳定的算法。
code.
#include <stdio.h>
#include <stdint.h>
#include <malloc.h>
#include <inttypes.h>
#include <math.h>
#include <string.h>
#include <stdlib.h> /**
* 基数排序算法实现比较复杂,它是一种多关键字的排序算法,属于分类排序。因为基数
* 排序算法不需要过多比较,所以在数据较多的情况下,采用基数排序算法的效率要高于
* 其他的排序算法。
*/ #define SIZEMAX 200 //待排序元素的最大个数
#define N 10 //待排序元素的实际个数
#define NUMBERKEY_MAX 6 //关键字项数的最大值
#define RADIX 10 //关键字基数,10表示十进制数字可以分为十组 typedef struct listcell_struct {
int32_t key[NUMBERKEY_MAX]; //关键字
int32_t next;
} listcell_t; //静态链表的节点,存放待排序的元素 typedef struct list_struct {
listcell_t data[SIZEMAX]; //存储元素,data[0]为头节点
int32_t keynumber; //每个元素的当前关键字个数
int32_t length; //静态链表的当前长度
} list_t; //静态链表,存放元素序列 typedef int32_t addr[RADIX]; //指针数组的类型,用来指向每个链表的第一个节点和最后一个节点 void displaylist(list_t L); //输出链表中的元素
void display_staticlist(list_t L); //以静态链表的形式输出元素
void initlist(list_t *list, int32_t dest[], int32_t length);
int32_t transchar(char _char); //将字符转换为数字
void distribute(listcell_t data[], int32_t i, addr f, addr r); //分配
void collect(listcell_t data[], addr f, addr r); //收集
void radixsort(list_t *L); int32_t main(int32_t argc, char *argv[]) {
int32_t array[N] = {, , , , , , , , , };
list_t L;
initlist(&L, array, N);
printf("need sort number is %d, key number is %d\n", L.length, L.keynumber);
printf("before sort static list: ");
display_staticlist(L);
printf("before sort list: \n");
displaylist(L);
radixsort(&L);
printf("after sort: \n");
displaylist(L);
return ;
} //按数组序号形式输出静态链表
void displaylist(list_t L) {
int32_t i, j;
printf("no key addr \n");
for (i = ; i <= L.length; ++i) {
printf("%2d ", i);
for (j = L.keynumber - ; j >= ; --j) {
printf("%c", L.data[i].key[j]);
}
printf(" %d\n", L.data[i].next);
}
} //按链表形式输出静态链表
void display_staticlist(list_t L) {
int32_t i = L.data[].next, j;
while (i) {
for (j = L.keynumber - ; j >= ; --j)
printf("%c", L.data[i].key[j]);
printf(" ");
i = L.data[i].next;
}
printf("\n");
} //初始化静态链表L
void initlist(list_t *L, int32_t array[], int32_t length) {
char _char1[NUMBERKEY_MAX] , _char2[NUMBERKEY_MAX];
int32_t i, j;
int32_t max = array[];
for (i = ; i < length; ++i) { //将最大的元素存入max
if (max < array[i]) max = array[i];
}
(*L).keynumber = (int32_t)(log10(max)) + ; //求字关键字的个数
(*L).length = length; //待排序个数
for (i = ; i <= length; ++i) {
//itoa(array[i - 1], _char1 , 10); //将整型转换为字符,并存入_char
sprintf(_char1, "%d", array[i - ]);
//如果_char的长度<max的位数,则在_char前补'0'
for (j = strlen(_char1); j < (*L).keynumber; ++j) {
strcpy(_char2, "");
strcat(_char2, _char1);
strcpy(_char1, _char2);
}
//将每个元素的个位数存入key,作为关键字
for (j = ; j < (*L).keynumber; ++j) {
(*L).data[i].key[j] = _char1[(*L).keynumber - - j];
}
}
for (i = ; i < (*L).length; ++i)
(*L).data[i].next = i + ;
(*L).data[(*L).length].next = ;
} int32_t transchar(char _char) {
return _char - '';
} //为data数组中的第i个关键字key[i]建立radix个子表,使同一子表中元素的key[i]相同
//f[0...radix - 1]和r[0...radix - 1]分别指向各个子表中第一个和最后一个元素
void distribute(listcell_t data[], int32_t i, addr f, addr r) {
int32_t j, p;
for (j = ; j < RADIX; ++j) f[j] = ; //初始化各个子表
for (p = data[].next; p; p = data[p].next) {
j = transchar(data[p].key[i]); //将关键字转换为数字
if (!f[j]) { //f[j]是空表,则f[j]指示第一个元素
f[j] = p;
} else {
data[r[j]].next = p;
}
r[j] = p; //将p所指的节点插入第j个子表中
}
} //收集,按key[i]将f[0...radix - 1]所指各子表依次连接成一个静态链表
void collect(listcell_t data[], addr f, addr r) {
int32_t i;
int32_t temp;
for (i = ; !f[i]; ++i); //找第一个非空子表,为求后续函数
data[].next = f[i];
temp = r[i]; //r[0].next 指向第一个非空子表中的第一个节点
while (i < RADIX - ) {
for (i = i + ; i < RADIX - && !f[i]; ++i); //查找下一个非空子表
if (f[i]) {
data[temp].next = f[i];
temp = r[i];
}
}
data[temp].next = ; //temp指向最后一个非空子表中的最后一个节点
} //基数排序,使得L成为按关键字非递减的静态链表,L.r[0]为头节点
void radixsort(list_t *L) {
int32_t i;
addr f, r;
//由低位到高位一次对各关键字进行分配和收集
for (i = ; i < (*L).keynumber; ++i) {
distribute((*L).data, i, f, r); //第i次分配
collect((*L).data, f, r); //第i次收集
printf("the %d times collect result: ", i + );
display_staticlist(*L);
}
}
result.
MMORPG大型游戏设计与开发(服务器 游戏场景 事件)的更多相关文章
- MMORPG大型游戏设计与开发(游戏服务器 游戏场景 概述 updated)
我们在玩游戏的时候,我们进入游戏后第一眼往往都是看到游戏世界中的场景,当然除了个别例外,因为那些游戏将游戏场景隐藏了起来,如文字游戏中的地点一样.既然我们接触了游戏世界的核心,那么作为核心的场景又包括 ...
- MMORPG大型游戏设计与开发(服务器 AI 概述)
游戏世界中我们拥有许多对象,常见的就是角色自身以及怪物和NPC,我们可以见到怪物和NPC拥有许多的行为,比如说怪物常常见到敌对的玩家就会攻击一样,又如一些NPC来游戏世界中走来走去,又有些怪物和NPC ...
- MMORPG大型游戏设计与开发(服务器 游戏场景 动态场景与副本)
场景的内容讲解到今天算是暂时划上一个句号了,接下来为大家讲解的是AI部分(大型AI),如果有兴趣的朋友不妨持续关注这些文章,大家一起学习和进步.动态场景和副本是场景中特殊的类型,副本在这里想必已经是无 ...
- MMORPG大型游戏设计与开发(服务器 游戏场景 核心详述)
核心这个词来的是多么的高深,可能我们也因为这个字眼望而却步,也就很难去掌握这部分的知识.之所以将核心放在最前面讲解,也可以看出它真的很重要,希望朋友们不会错过这个一直以来让大家不熟悉的知识,同我一起进 ...
- MMORPG大型游戏设计与开发(概述)updated
1.定义 MMORPG,是英文Massive(或Massively)Multiplayer Online Role-PlayingGame的缩写,即大型多人在线角色扮演游戏. 2.技术与知识 在这系列 ...
- MMORPG大型游戏设计与开发(客户端架构 part8 of vegine)
脚本模块是游戏设计中争论比较多的话题,那是因为作为脚本本身所带来的利弊.其实这都无关紧要,取舍是人必须学会的一项技能,如果你不会取舍那么就让趋势给你一个满意的答复.自从魔兽世界以及传奇(世界)问世以来 ...
- MMORPG大型游戏设计与开发(server 游戏场景 事件)
游戏截图 场景事件 一个完整的对象一般都拥有事件,至于什么是事件在这里就不多解释了. 在场景中的事件在天龙/武侠世界中的事件包含场景初始化.场景定时器.场景退出.玩家进入场景.角色升级.角色死亡.角色 ...
- MMORPG大型游戏设计与开发(服务器 游戏场景 地图和区域)
地图的数据以及区域的信息是场景的重要组成部分,这些数据同时存在客户端和服务器,而且都是由编辑器生成的.那么保存的文件数据结构是怎样的?一张3D的场景地图又是怎样处理这些数据的?同时告诉大家这里同样只是 ...
- MMORPG大型游戏设计与开发(服务器 游戏场景 多线程)
多线程在随着cpu发展应用的是越来越多,游戏场景因为其在服务器所占的数据量与逻辑复杂度的原因必须依赖于它.为什么场景要采用多线程?场景的线程是怎样的?场景的线程又是如何创建的?场景的线程又是怎样管理的 ...
随机推荐
- js补充小知识点(continue,break,ruturn)
1.continue,break,ruturn eg:1-100的和 $(function () { $("#hello").click(function () { var iNu ...
- 【C#公共帮助类】DateTimeHelper设置电脑本地时间,实际开发很需要
关于本文档的说明 本文档主要为了解决实际开发当中,服务器和客户端电脑时间不能相等的问题,纯干货,实际项目这种时间不同步的情况很多很多,时间不相等,到时候把本地的数据提交给服务器,服务器看实际上传时间和 ...
- 虚拟机安装ubuntu问题解决办法
vmware workstation 10安装ubuntu 13.10看不到下一步,如图所示 解决办法:如果不能调整安装程序的窗口大小,就按住Alt往上托窗口,应该就可以看到右下方的"下一步 ...
- 用Fiddler做为手机的上网代理
1. 首先需要知道你电脑的ip地址,这个略. 2. 打开手机,wifi那里,选择你的路由器,编辑或者设置,每个手机叫法不一样,点进去 到了里面,每个手机不一样,但是大致上,有一个[使用代理]的这么一个 ...
- JSTL中的fmt标签小例子
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding= ...
- php实现设计模式之 职责链模式
<?php /** * 职责链模式 * * 为解除请求的发送者和接收者之间的耦合,而使用多个对象都用机会处理这个请求,将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它 * 抽象 ...
- 更新整理本人所有博文中提供的代码与工具(C++,2013.11)
为了更方便地管理博文中涉及的各种代码与工具资源,现在把这些资源迁移到 Google Code 中,有兴趣者可前往下载. C++ 1.<通用高性能 Windows Socket 组件 HP-Soc ...
- java web学习总结(十) -------------------HttpServletRequest对象
一.HttpServletRequest介绍 HttpServletRequest对象代表客户端的请求,当客户端通过HTTP协议访问服务器时,HTTP请求头中的所有信息都封装在这个对象中,通过这个对象 ...
- IE9 IE8 ajax跨域问题的解决
项目中用到的跨域 ,在除IE9以下的浏览器上运行都是没有问题的,IE8 IE9中报错,error :no transport; 网上解决办法均是 在发起请求之前添加 jQuery.support.co ...
- Sharepoint学习笔记—习题系列--70-573习题解析 -(Q144-Q146)
Question 144You are developing a Feature that will be used in multiple languages.You need to ensure ...