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

一个好的接口是尽可能让更多实用的方法进行整理封装,要记住的是不常用的方法和类最好不好封装到接口中,因为那样会造成本身的困惑。基础模块中并没有太多封装,甚至连一个类的封装也没有,而是一些很常用的工具方法,而这些工具方法在整个客户端的设计中是必须的,所以才进入了基础模块。那么,就让我们看看客户端基础的一些方法都有哪些吧。

CODE

文件util.h

/**
 * PAP Engine ( -- )
 * $Id util.h
 * @link -- for the canonical source repository
 * @copyright Copyright (c) 2013-2014 viticm( [email protected] )
 * @license
 * @user viticm<[email protected]/[email protected]>
 * @date 2014-3-18 15:33:08
 * @uses vengine base util functions
 */
#ifndef VENGINE_BASE_UTIL_H_
#define VENGINE_BASE_UTIL_H_

#include "vengine/config.h"
#include "vengine/math/base.h"

#define PI (3.1415926535)
#define FLOATMIN (1.0E-9)

namespace vengine_base {

namespace util {

VENGINE_API void savelog(const char* format , ...);

//将字符串按照关键字分割
VENGINE_API int32_t convertstring_tovector(const char* str,
                                           std::vector<STRING>& save,
                                           const char* key = "\\/",
                                           bool one_ofkey = true,
                                           bool ignoreempty = true);

//取得两点间的距离
VENGINE_API float getdistance(
    const vengine_math::base::twofloat_vector_t& position1,
    const vengine_math::base::twofloat_vector_t& position2);
VENGINE_API float getdistance(
    const vengine_math::base::threefloat_vector_t& position1,
    const vengine_math::base::threefloat_vector_t& position2);

//取得两点间的距离平方
VENGINE_API float get_squaredistance(
    const vengine_math::base::twofloat_vector_t& position1,
    const vengine_math::base::twofloat_vector_t& position2);

VENGINE_API float get_squaredistance(
    const vengine_math::base::threefloat_vector_t& position1,
    const vengine_math::base::threefloat_vector_t& position2);

template<class T, class U, class V>
  inline void clamp(T &v, const U &min, const V &max) {
  v = (v < min) ? min : v;
  v = (v > max) ? max : v;
}

//求两个向量的点积
inline float get_dotproduct(
    const vengine_math::base::twofloat_vector_t& vector1,
    const vengine_math::base::twofloat_vector_t& vector2) {
  return vector1.x * vector2.x + vector1.y * vector2.y;
}

/*
|
|  取得从Pos1到Pos2的矢量相对于Y轴的旋转角度, 以z轴为0度
|
|              ->x
|                  o pos1
|          |       ||       z  v       |  |                  |    |                  |      |                  |        o pos2
|
|  Return [0 ~ 2pi)
*/

VENGINE_API float get_Yangle(
    const vengine_math::base::twofloat_vector_t& position1,
    const vengine_math::base::twofloat_vector_t& position2);

/*
|
|  取得从Pos1与Pos2之间的中心点
|
|             ->x
|                    o pos2
|          |       /
|       z  v      o <- This point!
|               /
|              o
|             pos1
|
*/
VENGINE_API vengine_math::base::threefloat_vector_t getcenter(
    const vengine_math::base::threefloat_vector_t& position1,
    const vengine_math::base::threefloat_vector_t& position2);

/*
|
|  取得v1相对于从Pos1与Pos2之间直线的镜像点
|
|             ->x
|                       o pos2
|        |  v1        /
|     z  v    \     /
|                \/
|               /  |              o      \
|             pos1      v2  <- This point!
|
*/
VENGINE_API vengine_math::base::twofloat_vector_t getreflect(
    const vengine_math::base::twofloat_vector_t& position1,
    const vengine_math::base::twofloat_vector_t& position2,
    const vengine_math::base::twofloat_vector_t& vector1);

//从内存中读取一行文本(相当于fgets)
VENGINE_API const char* getline_frommemory(char* buffer,
                                           int32_t size,
                                           const char* memory,
                                           const char* deadend);

VENGINE_API bool sheckstring_valid(const char* str);

/*
|  使目标点根据方向轴旋转,返回旋转后的坐标。
|
|  position    要旋转的目标点坐标
|  axis  以原点为起点的矢量方向轴
|  angle  旋转的角度
|
|  注:axis会被单位化,变以原点为起始点的矢量方向。如果想根据任意轴做旋转,
|    需要先将目标点做相应的平移,调用该函数旋转后,再平移回去即可。
|
*/
VENGINE_API vengine_math::base::threefloat_vector_t rotateangle(
    const vengine_math::base::threefloat_vector_t& position,
    const vengine_math::base::threefloat_vector_t& axis,
    float angle);

/*
|  hermite曲线差值算法。曲线被划分为150段,返回所需段数的2D坐标位置
|
|  x1,y1,x2,y2      曲线端点,最好数值限制在1000以内,否侧运算时会超出运算范围
|  xr1,yr1,xr2,yr2    曲线两参考向量, 最好限制在1000以内
|  currentiter      当前段数,值限定在150以内。
*/
//win32 POINT
POINT hermitecurve(int32_t x1,
                   int32_t y1,
                   int32_t x2,
                   int32_t y2,
                   int32_t xr1,
                   int32_t yr1,
                   int32_t xr2,
                   int32_t yr2,
                   int32_t currentiter);

//同 hermitecurve
POINT beziercurve(int32_t x1,
                  int32_t y1,
                  int32_t x2,
                  int32_t y2,
                  int32_t xr1,
                  int32_t yr1,
                  int32_t xr2,
                  int32_t yr2,
                  int32_t currentiter);

}; //namespace util

}; //namespace vengine_base

#endif //VENGINE_BASE_UTIL_H_

总结

这里没有太多复杂的方法应用,仅仅是一个记录日志的接口和一些常用的数学算法的封装,对于一个客户端(3D类型)来说这些方法基本上都是需要用到的。在这里还是强调那一点,就是必须用到的方法才加入基本模块,如果不是类的封装一般就封装在工具集合中,有些朋友更喜欢将工具集合叫做方法工厂(functions factory)。无论怎样命名,你要清楚的知道你要在什么地方会用到,以及它自身的作用范围。好了,基础模块的方法也没有什么特别需要去说明的,至于数学算法大家可以上网上去搜集资料了解一下,在这里我就不具体解释其实现的过程了。下节将为大家讲述math(数学)模块,其实天龙八部/武侠世界参考了比较好的ogre的设计,我们下节可以看到它怎样去扩展一些数学相关的数据类型的。

时间: 2024-10-10 02:25:22

MMORPG大型游戏设计与开发(客户端架构 part2 of vegine)的相关文章

MMORPG大型游戏设计与开发(UI SYSTEM SHOW)

接下来一段时间,这些文件可能不再更新,期间我会学习和掌握一些前端知识.虽然我非常欣赏剑侠网络版叁和九阴真经的画面,但是那是一个庞大的游戏引擎,一般人是无法窥伺的,除非你是天才而且要拥有机器毫无中断的毅力.我也很羡慕国外诸如刺客信条系列.古墓丽影系列,因为在画面和操作方面都做到了世界级水平,这也正是我想研究其实现原理的原因之一.况且那些大型游戏,在中端机器上运行的都比较流畅,也是我很想弄明白的.至于虚幻引擎,这是给那些大型公司,诸如腾讯拿去折腾的,个人根本用不起,那么只能选择开源了.UI我选择了C

MMORPG大型游戏设计与开发(客户端架构)

首先为所有等待的朋友说一声歉意,实在让大家等的太久.客户端的设计本来就是一个大的工程,而且工作的关系,也没有太多时间在这方面做研究.不过在私下有空的时间,我还是继续着这方面的研究,很遗憾没有用期望的ogre+cegui最新的版本作为开发,这方面原因是新的版本资料实在不多,对于没有什么经验的人来说实在是一大难事,所以最终选择了同天龙八部/武侠世界版本接近的源码作为开发.好了,废话不多说,今天好介绍的是客户端的基本构架,天龙八部/武侠世界的设计模式. CLIENT 功能实现 本次功能实现了vengi

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

重写有些核心接口的时候,其实遇到了许多的问题,甚至一度的想过要放弃,但是最终还是坚持了下来.在客户端提供的这些接口中,可以清晰的看到客户端所依赖的各种模块的支持,以及各自之间的一些关联.下面只是介绍了vengine(微引擎)接口的基础模块框架,所谓的接口即对象设计中常见的Interface,为一个框架提供了清晰的规范支持. VEGINE FRAMEWORK 功能实现 该接口已全部实现,具体的实例只需要继承接口封装即可.上图只为简单的模块介绍,其实每个接口都有每个接口其特别的用处,这一点会在接下的

MMORPG大型游戏设计与开发(part1 of net)

网络模块的设计,是大型多人在线游戏中比较重要的一部分.我之所以将网络模块放到最前面,是因为许许多多的开发者面对这一块的时候充满了疑惑,而且也觉得很神秘和深奥.这些我们面对到的困难,其实是由于我们对这方面了解的不足以及太过陌生. 本次设计中参考到了天龙八部/武侠世界的网络模块的设计,进行了封装调整,而且天龙八部其实也参考了韩国经典网游的设计,所以在稳定这方面还是有一定的积累. 在前面的构架中,大家可以看到一次交互的大致流程图,玩家登陆.创建角色.删除角色.选择角色等都由登陆服务器(login)进行

MMORPG大型游戏设计与开发(服务器 游戏场景 地图和区域)

地图的数据以及区域的信息是场景的重要组成部分,这些数据同时存在客户端和服务器,而且都是由编辑器生成的.那么保存的文件数据结构是怎样的?一张3D的场景地图又是怎样处理这些数据的?同时告诉大家这里同样只是讲的理论与设计,理论和设计往往都很空洞,但是却很灵活,需要靠每个人怎么运用. 一些图片 区域和格子 从上面的截图可以看出游戏场景其实是由格子来区分的,不管是矩形的格子还是其他形状的格子也好,一张地图不可能只有一个点(即多点组成一张地图).在3D场景中似乎格子的位置总伴随着高度信息,所以让人感觉有些迷

MMORPG大型游戏设计与开发(part6 of net)

上一部分,讲述了一个服务器与服务器之间的通信实例,客户端其实原理大同小异.网络部分准备就暂时讲到这里,不过我们不妨再回头过来想想在这过程中有没有优化和改进的地方.这部分讲解的是以网络包代码作分析,实现自动生成其代码的功能. 网络包代码 /** * PAP Engine ( -- ) * $Id connect.h * @link -- for the canonical source repository * @copyright Copyright (c) 2013-2013 viticm(

MMORPG大型游戏设计与开发(规范)

一件事如果没有规范.章法,那么做这件事起来往往会遇到许多难题,特别是在多人协作的时候,没有到规范通常让每个人多多少少都面临着头疼的困难.举个例子,多个人要做一桌美味的饺子,有买材料.做面皮.弄肉(菜)馅等.如果没有分工,做面皮的人也可以去弄肉馅,买材料的人也可以由弄肉馅去,这样一来可能导致这一桌香喷喷的饺子做的极慢,而且很可能导致这几个人各怀意见.所以如果规定了谁去做某件事,则大家都无异议,效率上也就不言而喻了. 1.目录规范 不同的语言有着不同的目录结构设计,但是一定要记住:区分模块功能.目录

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

游戏世界中我们拥有许多对象,常见的就是角色自身以及怪物和NPC,我们可以见到怪物和NPC拥有许多的行为,比如说怪物常常见到敌对的玩家就会攻击一样,又如一些NPC来游戏世界中走来走去,又有些怪物和NPC有的时候还会发出一些奇怪的谈论.我们都知道物体是死的,没有生命的,程序其实就是一种物体,它本身是不会进行任何的操作的,比如场景中的角色我们不操作则傻站着一样.但是NPC和怪物似乎有自己的判断力,谁该打谁不该打,还会排队行走,这些不是有生命的才能实现的吗?这就是AI,全称为Actificial Int

MMORPG大型游戏设计与开发(part5 of net)

上一部分将服务器的具体代码的实现介绍给了大家,想必大家也了解到了服务器处理一次消息的复杂度.如果大家能够将各个过程掌握清楚,就会发觉其实整个逻辑与交互过程是比较清晰的.那么服务器与服务器之间的通讯,其实也就是相当于客户端与服务器的通讯又是如何实现的呢?本文将用一个实例来将这个过程展示给大家. CODE bool ServerManager::connectserver() { uint8_t step = 0; __ENTER_FUNCTION bool result = false; pap_