concentrate on c/c++ related technology

plan,refactor,daily-build, self-discipline,

  C++博客 :: 首页 :: 联系 :: 聚合  :: 管理
  37 Posts :: 1 Stories :: 12 Comments :: 0 Trackbacks

常用链接

留言簿(9)

我参与的团队

搜索

  •  

最新评论

阅读排行榜

评论排行榜

2016年5月10日 #

 

Nginx开发第三方模块实例

Ø 序言

Nginx是一个极具扩展性的服务器,这显著体现在对第三方模块的支持,开发者能够将自己开发的模块,按照nginx既有的规则,完美地融合进http框架中,以实现开发者定制功能的作用。

这篇文章主要用于结合如何开发一个简单的第三方模块,目标人群为想了解nginx开发第三方模块的同学,文章内容主要包括三个部分,如何将HTTP模块嵌入nginx和如何开发第三方模块以及一个例子。

Ø 如何将HTTP模块嵌入nginx

Nginx目前来说提供了二种方式,config文件+configure 脚本,手动方式,后面手动方式是更加复杂的,且容易出错,在常规的nginx开发中,基本上都是用config文件+configure脚本方式比较多。接下来分别介绍这两种方式。

 

1)      Config文件+configure脚本

Config文件

这个是指提供config文件,并且在文件里面给出三个配置项,就可以达到效果。这三个配置项是指:

A.      Ngx_addon_name就是自己要开发的这个模块名字。

B.        Nginx模块名:这有点像设置环境变量啥的,首先要知道自己开发啥模块,nginx对应的模块有,$HTTP_MODULES(常规的http模块), $HTTP_FILTER_MODULES(HTTP过滤模块)$HTTP_HEAD_FILTER_MODULES(HTTP 头部过滤模块) $CORE_MODULES(nginx的核心模块)$EVENT_MODULES(nginx的事件模块)等,然后在后面添加你所要添加的模块名字,以空格隔开,比如这次我们开发添加的模块:

HTTP_MODULES = “$HTTP_MODULES ngx_http_helloworld_module”

C.        NGX_ADDON_SRCS这个顾名思义,就是指定新添加文件的路径,不过这个都是相对路径,因为在configure的时候就指定了上层路径,比如--add-modules=PATH

比如我们这次开发要添加的源文件:

NGX_ADDON_SRCS = “$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_helloworld_module.c”

Configure脚本

这里需要用- -add-module=PATH将第三方模块的路径加入,

比如configure - -add-module=~/ngx_3rd_modules/

那我们能分析下这背后做了什么呢?我们从下面两个部分来展开说明

a)      Auto/modules

这个主要是说明将定制的第三方模块添加到生成的ngx_modules.c里面。

a)         指定模块下面的配置文件.

b)         生成模块信息

一、生成模块数组

根据需要开启的模块加载对应的模块,下面是开启http模块后的所需要的模块
 

二、生成ngx_modules.c文件

 

b)      Auto/make

显而易见,这个就是负责编译相关的模块。

1)         生成第三方源码

2)         生成链接代码,并将目标文件,库文件链接成二进制程序


2)      手动方式

分两步来做,第一,修改obj/ngx_modules.c, 在里面增加对应的第三方模块,第二,修改obj/Makefile,在里面增加第三方模块的编译,这种直接修改的方法不太可取,易出错,一般都是用上面的第二种方法。

Ø 开发第三方模块注意事项

首先,要确定针对那个模块进行开发,nginx的模块是有顺序性的,比如: HTTP_MODULES = “$HTTP_MODULES ngx_http_helloworld_module”

其次,因为nginx是异步非阻塞的,在编制代码时,一定要注意不能阻塞nginx进程.

Ø 示例

见附件/Files/jolleydtan/test.zip

 

 参考:

深入理解nginx. 

posted @ 2016-05-10 08:25 jolley 阅读(1826) | 评论 (2)编辑 收藏

2016年4月16日 #

游戏服务器框架设计

Ø  序言

人们在认识事物的时候,一般都是先从大致的骨架开始,然后再到具体的细节,金字塔原理中用的比较多的就是自上而下的分析方法,这个方法放在放之四海而皆准。那么回到我们游戏服务器开发上面,也是如此。那么如何设计和选择服务器架构以及有啥需要注意的呢? 这是本文章要解决的问题。

文章主要目标人群是,对服务器框架设计感兴趣,有从事过游戏框架设计的同学。

文章内容,介绍五大设计原则以及给出两个示例,最后做总结。

Ø  设计原则

设计原则其实也是在设计时需要考虑的因素,过度设计是加重工作量的元凶,设计本质就是为了解决问题而存在的,下面列出了5大比较典型的原则。

1.         业务逻辑开发

a)         比如游戏为了增加存储,你就需要考虑使用内存数据库还是弄个数据库网关服务器来处理。

b)         比如游戏为了管理游戏玩家账号,以及支持对平台账号的接入,那么就需要账号服务器。

c)         比如游戏为了管理游戏玩家订单和跟踪付费情况,可能就需要支付服务器,如果游戏类型是计时收费的话,那么可能会需要计时服务器。

2.         运营维护

a)         配置

这里牵涉到静态配置和动态配置的问题,假设现在有一台网关服务器和三台游戏逻辑服务器,静态配置的话,就是网关服务器这边写死只连接这三台服务器,然后让网关服务器主动去连接,动态配置的话,就是让这三台服务器知道这个网关服务器的地址,然后自己在启动的时候去连接。

b)         开启或者关闭顺序

这主要是看各个服务器上面负责什么功能以及服务器上面的相关功能,拿游戏登陆服务器,游戏逻辑服以及数据库网关服务器这三个服务器的架构来说,比如开启的时候,你尽可能地跟玩家登陆连接的顺序相反, 一般都是数据库网关服务器,然后才是游戏逻辑服,最后才是游戏登陆服务器,其实就是防止玩家过早地登陆进来,却发现数据还没有准备好。

关闭的顺序其实就是相反的,主要原则就是让数据尽可能地保存好,并且让玩家不再进来。

c)         动态增删改

增删改分为三部分:1)增加一台服务器,2)减少一台服务器,3)修改服务器信息,比如前面提到的静态配置,就是不太方便增加服务器,要增加一台服务器,需要更新网关服务器的配置表,然后让网关服务器重新连接到新的服务器,而动态配置的话,就非常方便,让新增的服务器发起到网关服务器就好了。无需更改配置。

d)         服务器管理

服务器的管理主要在服务器的在线离线状态的管理,中心服务器(用来管理其它服务器)必须实时知道所管理服务器的状态,比如网关服务器必须要实时知道游戏逻辑服的状态,这样才好更新到登陆服务器上面,更改服务器状态。基本上在众多同级服务器上面基本上都会有个中心服务器。

3.         性能效率

这需要权衡利弊和性能优劣,比如在ARPG游戏逻辑服务器里面大量的消耗在AI上面,那么就要考虑给弄个线程还是进程,这同样适用于聊天功能,有一些聊天功能,或许可以选择使用UDP来作为网络层通讯方式。是否将功能模块设计成单独进程,这需要权衡,虽然可能在运营中会部署内网,相互之间是通过发消息的,类似于共享内存,但是还是会产生一些消耗的。

 

4.         负载均衡

这里包括两个部分,硬件负载均衡,和软件负载均衡。硬件负载均衡主要是指路由器。软件负载均衡主要有几种软件,nginx/lvs/haproxy/dns, 负载均衡的策略,可以参考nginx 的负载均衡,主要有round-robin, least-connected, 以及ip-hash等。

一般来说,游戏中大都是二级负载,首先是在登陆这边负载一次,然后再在进入游戏逻辑服那边负载一次,这样就够了。

5.         安全性

这里说下网关服务器,其它地方也叫前置服务器,front-end servers,,这个有几个好处:1)隐藏游戏逻辑服的连接信息. 2) 统筹游戏逻辑服的负载信息。

Ø  服务器框架示例

1)         无中心服务器架构

2)         有中心服务器架构

Ø  结论

服务器框架设计更像一门艺术,需要在解决问题的同时,又需要注意平衡得失。

 




posted @ 2016-04-16 17:33 jolley 阅读(1232) | 评论 (0)编辑 收藏

2016年4月2日 #

实现这个有这三种办法:
1)随机排序,按照顺序先后取出M个数字。
 IntVec shuffle(IntVec& vec)
133 {
134 int size = vec.size();
135 IntVec::iterator first = vec.begin();
136 IntVec::iterator last = vec.end();
137 for(IntVec::iterator i = first + 1; i != last; ++i)
138 {
139 std::iter_swap(i, first + rand()%((i - first)+ 1));
140 }
141 return vec;
142 }
这个呢,不会影响源数组,这个
2)取M次,每次做个事情就是随机出一个数,添加到目标数组里面,然后从源数组中删除。。
143
144 IntVec shuffle(IntVec& vec, int count)
145 {
146     IntVec desVec;
147     for(int i = 0; i < count;i++)
148     {
149         int random = rand()%vec.size();
150         desVec.push_back(vec[random]);
151         vec.erase(remove(vec.begin(),vec.end(),vec[random]),vec.end());
152     }  
153     return desVec;
154 }
这个呢,会影响源数组。
3)取M次,借助一个辅助数组记录哪个数据被取过,随机出一个数,添加到目标数组里面,然后将这个值添加到辅助数组里面.
 IntVec shuffle2(IntVec& vec, int count)
158 {
159     IntVec desVec;
160     IntVec flagVec;
161     for(int j = 0; j < count; j++)
162     {
163         flagVec.push_back(0);
164     }
165     for(int i = 0; i < count;i++)
166     {
167
168         int random = rand()%vec.size();
169         if (flagVec[random] == 0)
170         {
171             desVec.push_back(vec[random]);
172             flagVec[random] = 1;
173         }
174         else
175         {
176             i--;// 如果已经取过了,这次不算.
177         }
178
179     }
180     return desVec;
181 }
posted @ 2016-04-02 11:51 jolley 阅读(1245) | 评论 (0)编辑 收藏

2016年3月23日 #

这个是改良版的二分查找树,是通过阅读nebula device意外获得,这边先记下来。。
typedef vector<int> IntVec;
 16 int binarysearch(const IntVec& vec, int element)
 17 {
 18     int num = vec.size();
 19     int begin = 0;
 20     int end = num - 1;
 21     int half;
 22     int mid;
 23     int count = 0;
 24     printf("binarysearch--- vec count=%d, element=%d\n",num, element);
 25     while(begin <= end)
 26     {
 27         count++;
 28         if((half = num / 2))
 29         {
 30             if (element == vec[begin])
 31             {
 32                 printf("count=%d\n", count);
 33                 return begin;
 34             }
 35             if (element == vec[end])
 36             {
 37                 printf("count=%d\n", count);
 38                 return end;
 39             }
 40             mid = begin + ((num & 1)? half : (half - 1));
 41             printf("vec[%d]=%d\n",mid, vec[mid]);
 42
 43             if(element < vec[mid])
 44             {
 45                 end = mid - 1;
 46                 num = (num & 1)? half: half - 1;
 47                 printf("element < vec[mid]-- end, num\n", end, num);
 48             }
 49             else if (element > vec[mid])
 50             {
 51                 begin = mid + 1;
 52                 num = half;
 53                 printf("element < vec[mid]-- end, num\n",end, num);
 54             }
 55             else
 56             {
 57                 printf("count=%d\n", count);
 58                 return mid;
 59             }
 60         }
 61         else if(num)
 62         {
 63             if (element != vec[begin])
 64             {
 65                 return -1;
 66             }
 67             else
 68             {
 69                 return begin;
 70             }
 71         }
 72         else
 73         {
 74             break;
 75         }
 76     }
 77     return -1;
 78 }
posted @ 2016-03-23 22:16 jolley 阅读(145) | 评论 (0)编辑 收藏

2016年3月11日 #

现在nginx的版本已经到了1.9.12,不过在1.9.0的时候,就开始了对TCP代理服务器的支持。
之前也有一些早期的做法,比如就有写了nginx_tcp_module模块的https://github.com/yaoweibin/nginx_tcp_proxy_module,
以及nginx_stream_lua模块的
https://github.com/openresty/stream-lua-nginx-module
本来就想着用这两个的,后来发现已经有支持了,就先来试试看看这个了。
默认的话,nginx是没有开启对tcp的支持的.如果要支持的话,需要用--with-stream去指定。
我这边只要需要三个IP,一个是nginx进程所在的机器,我这边用192.168.1.4表示,
另外两台就是TCP上游业务服务器,我们分别用192.168.1.5和192.168.1.21来表示,
基于这样的考虑是因为nginx充当tcp代理服务器后,自身也会占用一个端口。
并且从目前来说,貌似一个nginx进程也就只能listen一个端口。
我用的版本是nginx 1.9.9.
我在/usr/local/nginx/conf下面新建了nginx_stream_tcp.conf作为本次的测试。
worker_processes auto;
  2 error_log /usr/local/nginx/logs/error.log info;
  3 events {
  4     worker_connections  1024;
  5 }
  6
  7 stream {
  8     upstream loadbalance {
  9 # Specifies a load balancing method for a server group where client-server mapping is based on the hashed key value
 10         hash $remote_addr consistent;
 11 # sets the weight of the server, by default, 1.
 12         server 192.168.1.21:8001 weight=5;
 13 # by default, the parameter is set to 10 seconds.
 14         server 192.168.1.5:9001  max_fails=3 fail_timeout=30s;
 15
 16 
 17     }
 18
 19 server {
 20 # listen 8001.
 21         listen 8001;
 22 # Defines a timeout for establishing a connection with a proxied server.
 23         proxy_connect_timeout 1s;
 24 # Sets the timeout between two successive read or write operations on client or proxied server connections
 25         proxy_timeout 3s;
 26 # Sets the address of a proxied server
 27         proxy_pass loadbalance;
 28     }
 29
 30 }
这个大部分是官网支持的,所以其实我也没有修改太多,就设置了几个IP和端口。
在编译好nginx后,可以用/usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx_stream_tcp.conf
就可以起来了,可以通过netstat -tlnp查看是否起来,大致显示这样的:
tcp        0      0 0.0.0.0:8001            0.0.0.0:*               LISTEN      7744/nginx_stream_t
当然也可以通过telnet来查看。
接下来,写个简单的cs程序来验证下吧.

server端:
if __name__ == '__main__':
 import socket
 import commands
 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
 sock.bind(('192.168.1.21', 8001))
 sock.listen(5)
 while True:
  connection,address = sock.accept()
  print "connected by",address
  while 1:

    buf = connection.recv(1024)
    if buf != "" :
     print "connection buffer", buf
     connection.sendall(buf)
 connection.close()

client端:
if __name__ == '__main__': 
    import socket
    HOST='192.168.1.4'
    PORT=8001
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
    sock.connect((HOST, PORT))
    while 1:
        cmd = raw_input("please input cmd:")
        sock.sendall(cmd)
        data = sock.recv(1024)
        print data
    sock.close()

在client向192.168.1.4发起一个TCP连接时,接下来192.168.1.4会连接到192.168.1.21,
192.168.1.21的server端会显示, connected by ('192.168.1.4',58559)
后面的端口应该是随机的临时端口。
其实它的确起到了转发作用,这个nginx进程相当于一个通用网关,如果有两个client向nginx进程发起连接,一旦nginx那边调度到同一个上游TCP服务器,那么只需要从NGINX进程建立一个TCP连接到上游TCP服务器即可。
之前我自己设计网关的时候,不是依赖于用户的,而是通过静态配置来建立连接的,比如上游逻辑服务器跟网关有连接,那都是在启动服务器的时候,就建立起来了。
这样有个好处就是可以省事,不过也可以采用这种方式,有玩家连接进某个上游TCP服务器才让网关跟这个TCP服务器建立连接,否则无需处理。因为不少时候还是会有不少服务器处于空闲的.

posted @ 2016-03-11 08:44 jolley 阅读(810) | 评论 (0)编辑 收藏

2011年6月8日 #

struct A
{
 int a;// 装备
 int b;// 角色数据
 char c;
};
void main( void )
{
 //printf("hello world!");
 char buffer[] = "This is a test of the memset function";

 A aStruct;
 // 发现数据相同。
 memset(&aStruct,'*',sizeof(aStruct));
 printf( "Before: %s\n", buffer );
 memset( buffer, '*', 4 );
 printf( "After:  %s\n", buffer );
 if (buffer[2] == '*')
 {
  printf("hello,world\n");
 }
 // 判断这个是否要保存。
 if (aStruct.a == 0x2a2a2a2a)
 {
  // 发送给DBSERVER.
  printf("hello char\n");
 }
 if (aStruct.c == 0x2a)
 {

 }
 getchar();

posted @ 2011-06-08 20:30 jolley 阅读(293) | 评论 (0)编辑 收藏

2009年4月10日 #

gamma系数就是灰度系数,改变gamma系数的值就是相当于改变色阶(图象亮度强弱的指数标准),gamma值越少,图象越亮.
调试d3d,将控制面板中D3DDebugging打开,进行调试,在选择调试信息输出等级的时候,可以选择more来获得更加多得详细信息。
http://nexe.gamedev.net/directKnowledge/default.asp?p=Debugging
Direct3D9: (INFO) :MemFini!
Direct3D9: (WARN) :Memory still allocated!  Alloc count = 152
Direct3D9: (WARN) :Current Process (pid) = 00000fb8
Direct3D9: (WARN) :Memory Address: 00c95988 lAllocID=1 dwSize=000047f8, (pid=00000fb8)
这里是检测出内存泄露了.
一般是内存信息什么的没有releasing和deleting掉.
之前遇到的一个问题lock is not supported when multi-sampling is enabled是因为shader debugging打开了,之后关闭了,就没有事情了。
刚才编译hlsl的时候,发现了x3025错误,后来的dx版本要使用D3DXSHADER_ENABLE_BACKWARDS_COMPATIABLITY|D3DXSHADER_DEBUG才能编译,特别是2008年的dx版本。

 DX默认的是D3DFILL_SOLID,如果出现D3DFILL_WIREFRAME的情况一定要设置回去。
CD3DArcBall:允许你将用户的输入解释为旋转或者平移.我们所要做的是将鼠标消息传递给这个类,并且将视图矩阵设为类的旋转或者平移矩阵就可以了.
点乘: a.b = ||a|| *||b|| * cosA, 一般用来判断为0,那么表明正交,>0,方向基本相同,<0,方向基本相反.使用点乘来计算投影.
给定两向量v,n,将其分解为v平和v垂,分别平行于和垂直于n,并且满足 v = v平+v垂,一般成平行分量v平为v在n 上的投影.
V平 = n * ||V平|| / ||n||.
cosA = ||V平||/||V|| cosA||V|| = ||V平||
V平= n*n*v/( ||n||*||n||).
叉乘得到的向量垂直于原来的两个向量.
a *b指向该平面的正上方,垂直于a和b.
||a*b|| = ||a|| * ||b|| * sinA.
||a*b|| 也等于以a和b为两边的平行四边形的面积.
如果a,b平行或任意一个为0,则a*b = 0,叉乘对零向量的解释是它平行于任意其他向量,点乘的解释是和任意其他向量垂直.
任意对角矩阵D,都有D转置矩阵= D,包括单位矩阵.
DirectX使用的行向量.
v = xp+yq+zr,向量v就表示成p,q,r的线性变换了,向量p,q,r称做基向量.这里基向量是笛卡尔坐标系
变换物体相当于以相反的量变换描述这个物体的坐标系.
2d里面是这样设置的:
逆时针旋转经常(不是必须)被认为是正方向,顺时针方向是负方向.
绕x轴旋转:
[ 1 0 0        
0 cosA sinA
0 -sinA cosA]
绕y轴旋转:
[cosA 0 -sinA
0  1 0
sinA 0 cosA]
绕z轴旋转:
[ cosA sinA 0
-sinA cosA 0
0 0 1]
绕轴n旋转角度A,那么获得的矩阵是:
[nx*nx*(1-cosA)+cosA     nx*ny*(1-cosA)-nz * sinA  nx*nz*(1-cosA) + ny*sinA
nx * ny *(1-cosA) - nz *sinA ny*ny*(1-cosA)+cosA  ny*nz*(1-cosA) - nx* sinA
nx * nz *(1-cosA)+ny * sinA ny * nz *(1-cosA) + nx* sinA nz*nz*(1-cosA)+cosA]
缩放:通过基向量构造矩阵,得到以单位向量n为缩放方向,k为因子的缩放矩阵:
s(n,k) = [ p]     [ 1 + (k-1)nx2  (k-1)nxny   (k-1)nxnz]
                    =
             [ q]     [ (k -1)nxny   1+(k-1)ny2   (k-1)nxnz]
             [ r]     [(k-1)nxnz  (k-1)nzny   1+(k-1)nz2]

投影意味着降维操作,有一种投影方法是在某个方向上用零做缩放因子,这种情况下,所有点都被拉平至垂直的轴(2D)或平面(3D),这种类型的投影称做正交投影,或者平行投影,因为从原来的点到投影点的直线相互平行.
n垂直于投影直线,而不是平行,3D中,向垂直于n的平面投影的矩阵如公式:
p(N) =   [1-nx2 -nxny -nxnz]
              [-nxny 1-ny2 -nynz]
              [-nxnz -nzny 1-nz2]
镜像: 将物体沿直线(2D中)或平面(3D中)翻折.
P(n) = [ 1-2nx2 -2nxny -2nxnz]
          [-2nxny 1-2ny2 -2nynz]
          [-2nxnz -2nzny 1-2nz2]
Hxy的意义是x,y坐标被坐标z改变
Hxy(s,t) = [1 0 0]
                [0 1 0]
                [s  t 1 ]

Hxz(s,t) = [ 1 0 0]
                [s  1 t]
                [0 0 1]

Hyz(s,t) = [1 s t]
                [0 1 0]
                [0 0 1] 

M物体->像机 = M物体->世界M世界->像机
P->像机 = P物体 M物体->像机
线形变换: 如果满足下式,那么映射f(a)就是线性的:
f(a+b) = f(a) + f(b)
以及F(ka) = kf(a).
仿射变换: 线性变换后接着平移,因此仿射变换的集合是线性变换的超集.任何线性变换都是仿射变换,但不是所有仿射变换都是线性变换.
如果存在一个逆变换可以"撤消"原变换,那么该变换是可逆的.
如果变换前后两向量夹角的大小和方向都不改变,该变换是等角.只有平移,旋转和均匀缩放是等角变换.
等角变换将会保持比例不变.
平移,旋转和镜像是仅有的正交变换.长度,角度,面积,和体积都保持不变.
刚体变换只改变物体的位置和方向,不包括形状,所有长度,角度,面积和体积都不变.平移和旋转是仅有的刚体变换,镜像并不被认为是刚体变换.
假设矩阵M有r行,c列,记法Mij表示从M中除去第i行和第j列后剩下的矩阵.显然,该矩阵有r-1行,c-1列,矩阵Mij称为M的余子式.
posted @ 2009-04-10 16:56 jolley 阅读(386) | 评论 (0)编辑 收藏

2009年3月30日 #

这几天安装这个sql server 2000,花掉了很多时间,希望以后安装的时候,尽量避免出现这些情况,其它的错误情况就不说明了,现在只说明我遇到的问题的解决办法:将原来的安装目录删除掉,将c:\program files\Microsoft SQL Server下面的80目录给删除掉,将注册表里面的HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server以及HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSSQLServer里面的键值信息删除掉。我机器上面并没有HKEY_LOCAL_USER\SOFTWARE\Microsoft\Microsoft SQL Server这个目录的。
application verifier 的信息可以从这里获得:http://technet.microsoft.com/en-us/library/bb457063.aspx
application verifier主要用来检测指针引起的内存错误.在程序运行期间进行跟踪内存使用情况.
application verifier的log信息包括错误所在的调用堆栈,并且要注意及时地清除上次的错误记录,我之前遇到的问题是,我用application verifier检测到某个错误,而之后再用这个exedebug启动的时候,就报错,后来在application verifier里面清除了记录才可以正常运行.
posted @ 2009-03-30 08:46 jolley 阅读(446) | 评论 (0)编辑 收藏

2009年2月17日 #

computer display = a single graphics adapter + a display monitor.
graphics adapter contains the hardware needed store and display images on a monitor or other display device.
all of these adapters stored a representation of the displayed image in a bank of dual-ported memeory called a frame buffer.
the system uses one of the ports to read and write images into the frame buffer.the second port is used by the video scan out circuitry of the adapter to create a signal for the monitor.Direct3D only supports VGA compatible adapters.

Frame                               Color Lookup
Buffer                               Table


2D Pixel                           D/A
Engine                              Converter

Host CPU                        CRT Monitor

Direct3D abstractions include :device, swap chains, surfaces, and resource .

an application enumerates the devices available on each adapter, examining their capablities and supported display modes to find an acceptable device.
device is the object that expose the rendering operations of the hardware. its properties control the rendering behavior or provide information about rendering, while the device's methods are used to perform the rendering itself.

devices always contain at least one swap chain and a collection of resources used for rendering.
resources are application specific data stored in or near the device hardware for use during rendering Direct3D provides resources for scene geometry(vertices and indices) and appearance(images, textures, and volumes).

a surface is a resource containing a rectangular collection of pixel data such as color, alpha, depth/stencil or texture information.
a swap chain contains one or more back buffer surfaces where scenes are rendered and presented for display on the monitor, is a collection of back buffers.

a device's render target is the back buffer surface, with an optional depth/stencil surface, in which rendering will occur.

while all back buffers are valid render targets, not all render targets are back buffers.
it is also possible to have a texture as a render target allowing dynamic rendering effects.

to obtain a device object, Direct3D provides an object for device enumeration and creation. all other objects are created through the device. an application first obtains the runtime interface, then selects and creates a device from those available, and using the device creates the necessary resources for rendering.

most COM methods return HRESULT to indicate success or failure.
in windowed mode: the results of graphic rendering are presented for display insidei the client area of a window on the desktop.
Direct3D cooperates with GDI to make the results of rendering visible, using a ::StretchBlt operation to present a back buffer in the window's client region
in exclusive mode: Direct3D communicates directly with the display driver avoiding GDI. when an exclusive mode application is running, no other applications have access to display hardware and no GDI is visible on the screen.

HAL(hardware abstraction layer): has hardware acceleration of graphics rendering, making it fastest device type.

reference device: useful for debugging, when developing software applications that target new features not yet common in hardware, the reference device maybe your obly choice for generating an image with those Direct3D features.

the null reference device: does nothing and all rendering will result in a black screen.useful for manipulating resources on a machine that provides no hardware or software  implementation of the runtime.

the pluggable software device: RegisterSoftwareDevice method,

each resource has Type, Pool, Format, and Usage attributes, each of these attributes of a resource are specified at the time the resource is created and remain constant for the lifetime of the resource object.
type attributes describes the kind of resource and is defined by D3DRESOURCETYPE.
pool attribute of a resource describes how it is managed by the Direct3D runtime and is defined by the D3DPOOL enumeration.
resources in the default pool exist only in device memory.
resources in the managed pool exist in system memory and will be copied into the device's memory by the runtime when needed.
resource in the system memory pool exist only in system memory
resource in the scratch pool reside only in system memory and are not bound  by format constraints of the device
when a device is lost, all resources in the default pool are lost and should be released and recreated by the application when the device is regained.
Format attribute of a resource describes the layout of the resources's data in memory and is defined by the D3DFORMAT enumeration.

all resources have a format, but most of the format enumerants define the memory layout for pixel data.
D3DFMT_D24S8: D:depth buffer, S:stencil buffer.

Usage attribute describes how the application will be use the resource and is defined by a collection of flag bits. static reources are typically loaded with data once and used repeatedly without change, while dynamic resources are repeatedly modified bu the application.
a direct3D application starts by obtaining the IDirect3D9 COM interface pointer by calling Direct3DCreate9.
GetAdapterCount is to determine the number of adapters in the system. each adapter provides a number of video display modes. each display mode contains a screen dimention, refresh rate and pixel format and is described by D3DDISPLAYMODE structure.
the back buffer surface format of a device must be compatible with the display mode's format. CheckDeviceFormat method can be used to discover compatible formats.
GetAdapterModeCount: the number of display modes.
EnumAdapterModes: the display mode information.
GetAdapterDisplayMode: the display mode currently in use by the adapter.
two display modes can have the same width, height and format values but different values for the RefreshRates.
the CheckDeviceType method tells us if a particular combination of display format and back buffer format are valid for a device of a given type operating in windowed or exclusive mode.
with a valid device type, we can check the device's capabilities for rendering required by our application with GetDeviceCaps.

we can validate all the resources required by our application with the CheckDeviceFormat, checkDeviceFormat should be used to validate all the format of all resources used by the application: back buffer surfaces, depth/stencil surfaces, texture surfaces, and volume texture formats. if the application requires a depth buffer for viaiblitiy determination, it should use CheckDepthStencilMatch to find a depth buffer that can be used with its render target formats in a given display mode.
CheckDeviceMultiSampleType: check multisampling needs.
GetAdapterIdentifier: allows an application to identify a specific brand of adapter from a specific vendor.
D3DCREATE_ADAPTERGROUP_DEVICE: allows an application to drive both video outputs through a single device interface, allowing resources to be shaed for both outputs.
Direct3D uses single precision floating point computations. if an application requires higher precision from FPU.there are two choices, either the application can ensure that the FPU is in single precision mode when calling into Direct3D, or ir can request that the device preserve the application's FPU precision before Direct3D performs any floating -point operations and restore the precision before returning to the application.
D3DCREATE_SOFTWARE_VERTEXPROCESSING: select software vertex processing, which is always available from the runtime.the runtime used an efficient implementation of software vertex processing that is optimized for the CPU.
D3DCREATE_MIXED_VEVERTEXPROCESSING: select a combination of software and hardware vertex processing selected by SetSoftwareVertexProcessing mixed vertex processing is incompatible with a pure device and will fail if both are requested together.

D3DPRESENTFLAG_DEVICECLIP: restricts the results of a present operation to the client area of the device window in windowed mode.
D3DPRESENTFLAG_DISCARDDEPTHSTENCIL: instructs the runtime to discard the contents of the depth stencil surface after a call to Present, or when a new depth stencil surface is set on the device.
D3DPRESENTFLAG_LOCKABLEBACKBUFFER: requests a default swap chain with back buffer surfaces that can be directly accessed by the application.
in windowed mode: hDeviceWindow specifies the window whose client area will be used for presentation in windowed operation  if hDeviceWindow is zero, then the focus window willbe used for presentation.
in exclusive mode, hDeviceWindow specifies the top-level window used by the application

D3DPRESENT_RATE_DEFAULT: instructs the runtime to choose a suitable refresh rate in exclusive mode, and uses the current refresh rate in windowed mode.
an application may wish to create a full-screen display on a specific monitor.
GetAdapterMonitor: return an HMONITOR handle for an adapter, once you have the handle to the device 's montior, u can determine what part of the virtual desktop is covered by the monitor.

a scene is a collection of three dimensional objects that are projected onto the render target surface from the viewpoint of a syntheitic camera
each object in a scene is described by a collection of geometric primitives, such as points, lines, and triangles, with the device's action methods. 
the pipeline converts geometric descriptions into pixels on the render target surface through the process of rasterization. graphic primitives are rendered in the order in which they are described to the devices similar to the way a CPU executes binary instructions sequentially through memory.
the entire graphics pipeline is controlled through the properties of the device.
the properites are manipulated through the Get/Set methods of the device.
every device has a distinct set of capabilities. Direct3D specifies an abstract machine interface, but does not provide a software emulation for a feature not provided directly by the hardware's driver.
 a device provides specific information on its capabilities to allow an application to adapt to the capabilities of the device.
much of the behavior of the graphics pipeline is controlled by render states.
groups of device properties, including render states, can be cached and set as a group with state blocks.
the device object represents the rendering pipeline, we get images from the pipeline by supplying it with scene data and instructing it to render scenes into images.
scene data consists of geometric data defining shapes in space and data defining the appearance of the shapes.
we can break the pipeline up into large sections consisting of vertex data assembly, vertex processing, promitive assembly and rasterization, pixel processing, the frame buffer,a dn video scan out.

vertex data assembly section gathers together vertex components from a collection of data streams to assemble a compute vertex and its associated data.
vertex processing performs computations on each vertex such as the transformation and lighting of vertices.the processed vertex data is then assembled into graphic primitives and rasterized into a stream of pixels.
pixel processing performs a computations on each rasterized pixel to determine the final color of the pixel that will be written into the frame buffer.
frame buffer performs a read/modify/write operations combining processed pixels from the rasterizer with the existing pixels in the render ttarget.
video scan out reads the pixels out of the frame buffer for conversion into video signals displayed by the monitor.

scenes are rendered to the render target selected on the device. if the render target is part of a swap chain, the render target can be made viaible on the device through presentation.
the render target may not be part of a swap chain if the render target is a texture resource.
you present renderings for display through a swap chain as the last thing you do when rendering a scene.
a swap chain consists of one or more back color buffers into which images are rendered. a device is always associated with at least one swap chain and in windowed mode additional swap chains can be created to obtain multiple presentable surfaces.
the philosophy of the Direct3D object is to expose the capabilities of the hardware to the application programmer and let the application adapt to the hardware.
GetDeviceCaps: return the capabilities of an actual device, while GetDeviceCaps method on the Direct3D object returns the generic capabilities of a device.
IUnknown 
      IDirect3DVolume9
      IDirect3DResource9
           IDirect3DIndexBuffer9
           IDirect3DVertexBuffer9
           IDirect3DSurface9
           IDirect3DBaseTexture9
               IDirect3DTexture9
               IDirect3DCubeTexture9
               IDirect3DVolumeTexture9
resource objects are used as containers for the scene data rendered by the device such as primitive vertices, indices intto vertex arrays, surface textures and volumes. 
two and three dimensional textures expose their contents as collections of sutfaces and volumes, respectively. the back buffer, depth/stencil buffer and render target properties of the device are also exposed as surfaces.
volume objects do not inherit from IDirect3DResoutce9 and therefore do not participate in the resource management exposed by this interface.
managed resources are assigned an unsigned integer priority, with higher priority taking precedence so that resources with a lower priority are discarded from device memory first.
non-managed resources always return a priority of zero. within the same priority, Direct3D uses a least-recently used strategy to discard old resoucrs in preference to newly created resources.
when the application attempts to use more resources than the card can hold while rendering a scene, Direct3D switches to a most-recently used first strategy for discarding memory.
resources in D3DPOOL_DEFAULT are not managed and are never discarded from device memory by the resource manager.
if u need to allocate new resources in the default pool after managed resources have been loaded, you should evict all managed resources before allocating new resources in the default pool.
resources in pool D3DPOOL_SYSTEMMEM are never located in device memory, so that they do not participate in resource management.
GetAvailableTextureMem: obtain an estimate of the available texture memory.
the GetDevice method returns the device with which this resource is associated. resources cannot be shared across devices.
GetPrivateData/SetPrivateData: allow an application to associate its own arbitrary chunks of data with any Direct3D erouces.
each distinct item of private data is identified by a GUID. all private data associated with a resource is freed when the associated resource itself is freed.
methods and functions in Direct3D that create COM objects, such as CreateDevice, add a reference to the object for the caller before they return the interface pointer, the application must release these objects when they are no longer needed to avoid a memory leak.
Device queries allow you to obtain information from the driver layer of the device, the two main uses for driver queries are for obtaining rendering statistics and event notifications from the device.
D3DQUERYTYPE enumeration gives the possible kinds of queries: vertex cache description queries, resource manager statistics queries, vertex statistics queries, event queries, occlusion queries, timestamp queries, time queries and cache utilization queries.
a query exists in one of three state: signaled, building, or issued.
Issue: used by the application to signal a state transition on the query.
the device driver can also change the state of a query when it has returned the data requested by the query.
the query will report the results for primitives issued between the begining of the query and the end of the query.
occlusion queries return the number of pixels that passed the depth test for primitives rendered between the begin and end of the query.
the resource manager statistics query returns a D3DDEVINFO_RESOURCEMANAGER structure, which contains an array of D3DRESOURCESTATS structure, one for each resource type.
the vertex cache is a memory cache close to the GPU that avoids access to vertex memory for a small number of recently used vertices.
PIX: is a performance measurement tool for DirectX applications. the remaining query types return data for performance measurements with tools like PIX.
the device object's properties control the behavior of the rendering pipeline while its methods supply data for the pipeline to render.

state blocks are COM objects that provide a way for your application to cache a group of device properties for later use.
each state block is associated with a device, returned by the GetDevice method.once  a state block has been created, the state block can be applied to the device by calling apply on the state block, calling capture on an existing state block captures the current values of the device properties into the state block.
there are two ways to create a state block object and fill it with specific device property values.
the first way: call CreateStateBlock with D3DSTATEBLOCKTYPE value identifying the kind of state you  want recorded in the block.
the second way of obtaining a state block object is to call BeginStateBlock, set device properties and then call EndStateBlock.
when EndStateBlock is called, each device property marked for capture is recorded into the state block. if a device property is set multiple times between BeginStateBlock and EndStateBlock, only the last value set in the property is captureed into the state block.
release the state block COM object when you are finished with a state block.
a pure device has a performance advantage because the runtime and driver do not have to keep a copy of the non-queryable state for the application.
scenes contain one or more objects that are positioned relative to each other and to the virtual camera that views the scene. such objects are called "models", and contain data that define their shape and apperance. the shape of a model is described by a collection of a simple geometric shapes, called graphic primitives.
when we draw a three dimensional scene, we need to solve the problem of visibility: objects in the foreground should occlude objects in the background. Two- dimensional applications use a painter's algorithm to determine visibility. Direct3D can use depth/stencil surfaces to resolve visibility.

using either a flexible vertex format or a vertex shader declaration, Direct3D describes colors, textures corrdinates,vertex blending weights and arbitrary shader data at each vertex.the vertex data is supplied to the device through a collection of streams, each associated with a vertex buffer.
the streams can be driven through a level of indirection with an index buffer.the streams can be driven though a level of indirection with an index buffer.
the scene is described to the device one primitive at a time. each primitive  is rasterized into a collection of pixels written to the render target property of the device.
All Direct3D rendering is done within a scene. each successive frame draws the models at successive moments in time, as in cel animation used for cartoons.
frame rates of greater than 15 fps can be preceived as "real-time", the z-buffer algorithm solution to the visibility problem works at each pixels on the render target instead of on models, as models are rasterized, each pixel that is associated with z value is used to determine which pixel is cloest to the camera.the closer pixels are stored into the render target, while pixels farther away are discarded. the depth/stencil buffer holds each pixel's depth from the camera. to use the Z-buffer for resolving visibility, set RS_Z Enable to D3DZB_TRUE, RS_Z Write Enable to TRUE, and RS_Z Func to D3DCMP_LESS.

if the D3DPRASTERCAPS_ZBUFFERLESSHSR bit of D3DCAPS9:RasterCaps is set, it indicates the device has an alternative visivility algorithm for hidden surface removal that doesn't use a Z-buffer. how visibility is determined is hardware dependent and application transparent. 

all back buffers on swap chains are valid render targets, but render targets are not restricted to back buffer surfaces, when the device is created or reset, the render target is back buffer zero of the device's default swap chain. when present is called on the device, the render target  advances to the next back buffer so that after present returns, render target is back buffer zero again.

setting the render target to a surface other than a back buffer surface allows the device to render directly into an imanage surface instead of rendering into a swap chain's back buffer and using stretchrect to obtain the results of the rendering, which could stall the pipeline.

D3DPT_POINTLIST draws a collection of points,
D3DPT_LINELIST draws a squence of possibly disjoint line segments.
posted @ 2009-02-17 15:49 jolley 阅读(662) | 评论 (0)编辑 收藏

2009年1月31日 #

 // 接受密聊对方名称,将焦点设置到聊天输入框中,并且将光标设置为第一个位置
 // 参数1:密聊用户名,参数2:频道信息
 static bool ChangeChannelAndSetFocus(char* username,Channel channel);
这段代码看起来是没有事情的,但是在接口设置上面存在不好的做法,如果是私密频道的话,是有用username做私聊对象的,如果是非私聊频道的话,就没有这个私聊对象了.但是如果要调用这个接口的话,还得给个这样的值.
比如这样的用法:->ChangeChannelAndSetFocus("",public_channel),
其实如果稍微改变一下接口设置的话,就好了.
 static bool ChangeChannelAndSetFocus(Channel channelchar* username = "");
这样使用默认参数就好了.
之前的调用就可以这样使用了.
:->ChangeChannelAndSetFocus(public_channel),看起来舒服多了.哎感觉编程功底还有待加强,这么简单的问题,拿出来想想,还有这么多学问呢.

这几天写了一段函数代码,后来被一个家伙调用了,他直接在我的函数里面修改,这样造成了原来我函数里面的逻辑出现错误,现在想来,如果以后是这样的情况,就不能允许他在我的函数里面修改我的逻辑和相关调用,但是要留出接口给它调用,至于具体的操作,要我自己允许才能添加,当然我可以帮他看看原来他添加的代码,但是这样也就没有什么意义了.这种合作性的工作尤其要讲究这些,不然很麻烦的.


突然想起来要记录点什么,调试引擎的时候,可以采用这样的方式,打开上层逻辑的工程,然后将引擎相关的代码拖拽到上层逻辑所在的工程里面去,然后在这个代码里面可以设置相关断点,以前总不知道怎么找上层逻辑与底层引擎的入口,最近终于知道了.呵呵.通过这样的方法,就可以在上层逻辑做某些操作,然后关联这些逻辑相关的引擎代码.

今天一直在被单态困扰着,事情是这样的:大厅和战斗场景里面都有两个类似的chatroom,并且他们各自使用的协议是不一样的.现在想把他合并起来做成类似singleton的东西. 之前就遇到一个问题,大厅和战斗场景不能在相互之间发送信息,后来我的处理方法是将战斗场景里面添加大厅里面的响应事件,这样的话,在大厅里面发送私聊信息到战斗场景里面,就可以接受到了,但是后来发现在战斗场景里面发送信息到大厅里面,却接受不到,并且这个时候,在大厅和战斗场景里面已经存在很多冗余代码了,这样的处理让我感觉很不爽,我在想有没有其它办法,后来请教了老大,老大帮忙解释了一下,后来,在协议处理方式上面修改了一下,才可以的。chatroom在不同的时候发送不同的协议就好了,并且在接受的时候分开大厅和战斗场景处理就好了,这样还是用了接受、和发送这两段废代码。对于singleton的了解还是不够好。 

之前遇到的问题,是聊天发送消息并不立即显示在本地,而要先将信息转到服务端,服务端进行查询,如果能够找到这个私聊对象,那么就返回给信息,否则就显示说该用户不存在,在战斗场景里面向大厅的某个玩家发送私聊信息以后,退出战斗场景以后,发现大厅里面还显示着在战斗场景里面发送的聊天信息。这样即使我按照常规思路去把网络接受端的相关代码注释掉也不能达到消除大厅里面的聊天信息的目的,感觉很郁闷。后来查看私聊信息方面的代码,发现没有将信息有效地拦截,私聊信息在本地上面还可以被显示,没有经过网络方面的验证就直接发送过来了。在私聊信息方面做一些处理并且在退出战斗场景的时候做一些信息删除处理,这样就可以达到目的了。
因为玩家对象位置数据是从服务器那边发送过来的,玩家从服务器获得数据需要一段时间,所以需要加入一个插值,来将现在的位置过渡到下一个的位置.这里可以采用多种插值方法.

今天写了代码去改写强制动作的处理,结果发现很多处是有问题的,其中原因是没有将原来的代码作用看仔细造成了,感到羞愧呢,

另外在编写交互性比较强的代码时,一定要考虑自己的代码可能带来的影响。

更新某个文件比较麻烦的话,那么可以先采用原始文件删除,并且重新全部更新的做法去做,而不是用更新某个字段的方法去做.

如果没有初始化声音设备成功的话,那么应该可以弹出提示信息框,并且将原始声音音量设置为0.

之前在修改一个bug(在人物控制面板打开以后,一直克隆object,造成了在引擎底层无法锁定vertexBuffer的问题),开始以为是内存泄露了,在打开控制面板10分钟以后,游戏就突然出错了,还一度想用一些辅助工具来查找内存的信息是否出错,后来发现在人物控制面板里面克隆了过多的人物object,而这些object却没有及时地删除,造成占用过多的资源,到最后连锁住vertex buffer也不行了.在分析这个问题上面的时候,我还是一个劲地挖底层而没有考虑太多的逻辑层面的东西,实在有点南辕北辙的味道.值得反省.

在输入的使用上面,一般的游戏都采用directInput,即使是U2,上次遇到的问题是,在一同事机器上面运行输入的时候就进入不了,但是在别人的机器上面却可以运行好好的,后来经常查访发现:1)用配置文件写入的,之后再绑定到某个特定键的快捷键都不能用,因为这些是读入内存以后,然后用add_binding来绑定到directInput设备上面的,2) 在游戏里面使用windows message的却可以正常使用.进入游戏的时候,你不能输入,而只能回车,按tab键以后,就可以在登陆界面输入,如果不能按tab键,则不能输入,进入游戏以后却可以按不是从配置文件里面读取的信息,比如技能,人物面板,仓库,以及地图等.
其中我个人建议是,尽量不要用directInput.1)首先是directInput依赖于机器,如果机器好的话,那么没事情,如果有事情的话,那么也很难解决,2)directInput里面采用了hook,来拦截消息,这样,还不如直接用windows message来的快?
http://www.gamedev.net/community/forums/topic.asp?topic_id=520366
详细的讨论见上面.

在调试逻辑没有发现什么错误提示的时候,试着去调试引擎,可能问题发生得更加深,不在逻辑层面上,而在引擎内部,这样就要直接调试引擎了.

在涉及到渲染方面的bug,尽量借用d3ddebugging来辅助查错.这样可以方便解决问题.

连接错误:IID_IDirectSound3DBuffer,其实加上dxguid.lib就好了。
纹理寻址模式包括:
wrap, border color, clamp,和mirror以及mirror once.
 pDrawPrimInternal->SetTexture(hTex);
之前遇到的一个问题是,显示玩家在小地图上面到地图边界了,还能重复绘制地图,给人的感觉好像是走不到边界,走地图好像是在卷轴里面一样。
后来才知道一般默认的纹理寻址模式是wrap方式。
 get_device()->SetSamplerState(0,D3DSAMP_BORDERCOLOR,0x00ffffff);
 get_device()->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_BORDER);
 get_device()->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_BORDER);

解决bug有时候不如重写
尽量让策划去管理逻辑,逻辑程序员尽量将重心放在具体技术问题上面,不懂的地方应该主动跟策划沟通,而不是自己想。
代码可以先模拟出来,然后再放到具体的环境里面测试,独立写个demo之后再去测试,这样往往会比较快捷和省事情。
学会模拟机器执行代码的次序,并且提高阅读代码的问题,之前的时候,我使劲去调试,每次调试只为了解决一个问题,但是事实上,如果从阅读代码开始的话,那么我可以省掉1天的时间。
学会调节编写代码时候的心情和心态,这样有助于进行高效编程,当心情不好的时候,一定要集中全部的注意力,并且将思路和流程作出图记载在纸上面,这样可以强迫自己全神贯注。

今天遇到的文件打开问题是文件名路径有空格造成的,值得指出的是对于文件打开报错,一般很难获得返回值信息,但是可以通过GetLastError或者@Err,以及hr等来获得一些错误返回值信息。

对字符串操作,尽量要检查是否有空格,如果字符串长度前面有空格的话,那么将被认为所提供的字符串是空的。要避免这种情况的发生。对于字符串匹配要注意部分匹配的情况,比如"Tex", "Text",这里如果只匹配前面三个字符的话,那么两者是相等的,之前就遇到一个这样的问题,就是texture的信息被text信息所覆盖了,导致控件找不到正确的texture而不能显示出来。 

今天遇到的问题是这样的,之前遇到的状态切换问题,是与状态切换无关,而与插值有关,在切换状态以后,收到一个插值位置,这样又给角色一个新的位置,给别人看的效果就是角色先落地了,之后又上升了,像坐电梯一样。不过从这里说明了一个问题:我在思考问题的时候,有欠周全的因素。

今天跟踪一个bug,在战斗的时候,出现卡死的情况,后来发现状态切换出现了问题,后来一直去查看战斗方面的状态,但是还没有发现什么结果,现在在想在战斗中的标志或者状态的时候应该设立一些标志集合,这样便于在某个时候检查一些状态的信息。现在很多的标志在游戏里面,局部的,全局的,标志在角色上面的,标志在物体上面的,这些都需要好好地管理。

全方面,多角度地思考问题,而不能将思维局限在某处.学会从大局或者小处去分析问题,大处不行的话,就小处,将相关的信息串起来.所有的信息应该是个串型或者链型的.之前在处理问题的时候,把思路限制在太小的范围内了.以至于花了很多时间才找到问题所在.

根据正常情况和非正常情况来获得数据比较,以确定正确的流程和结构。如果遇到错误的乱值,那么就看看正常的数值,然后根据这个比较来获得一些提示信息。

今天犯了错误,自己有最新版本,但是没有上传,结果vss上面的版本把自己的最新版本给覆盖了。

在发送消息的时候,有时候为了防止频繁发送消息,要加入一个cd时间,防止因为网络问题,服务端收到玩家连续的信息。

物理系统, v = v0 - gt. 玩家上跳的速度表示,而在下降,则是v = gt,按照自由落体运动来进行.并且速度是个向量,这样如果在X,Z轴上面有初速度的话,那么就可能出现抛物线的情况.



posted @ 2009-01-31 08:23 jolley 阅读(443) | 评论 (2)编辑 收藏