游戏之旅-我的编程感悟

时间:2022-12-28 12:11:37

搜索算法
1.地图寻路问题(A,A*,IDA*)
2.博弈问题(Alpha-Beta剪枝,SSS*,MemSSS*)

职能算法
1.遗传算法
2.模拟退火
3.禁忌搜索
4.人工神经网络


汇编优化:
能用整数,则尽量不用浮点数;
循环展开技术(比如100次降到50次):由于现代CPU具有分支预测技术,循环展开增加了代码量,更多占用CPU内部一级代码高速缓存的空间,循环展开远远不如原来有效。
局部变量在堆栈中,这样可以重复使用内存,当一块内存被反复读写,其数据就会存在CPU的内部一级缓存中,访问速度非常快。而零散的静态变量则没有这个优势。内存同CPU内部缓存的数据交换,往往成为程序的速度瓶颈。


除2的整数幂可以被优化成移位操作,但是我们并不主张把n/8写成n>>3,因为现代编译器会帮你做这件事。这里需要注意的是:如果你知道n肯定是个正数,而n又被声明成int时,写成(unsigned)n/8是有利于编译器帮你优化的。因为对于一个有符号的数字除以8并不完全等价于右移3位。
实际上,即使除数不是2的整数幂,编译器的优化依然会消除除法,变成一次乘法加一次移位操作。让编译器有优化余地的唯一前提就是,让除数是一个常数,除了直接写除数,也可以用const int来定义。
对于浮点运算,我们有更多的方法减少除法的运算次数(以下方法在特定条件下,使用一些技巧也同样适用于整数运算):
 对于整数除法,如果需要对一个数字反复做除法,则可以先算出其倒数,然后用乘法代替。如果 是常数除法,比如a/3.14倒不必写成a*(1.0/3/14),因为编译器通常会帮你完成这种优化。
 在某些情况下,可以用乘法消除掉除法运算,比如if(a>b/c)可以写成if(a*c>b).编译器之所以 不会帮你做这样的优化,是因为两者并非完全等价(如果c是负数,后者的要写成<;当然这个方法 用于整数的时候,要考虑a*c有溢出的可能)
 我们还可以想办法把多个除法合并起来。对于运算a/b+c/d,(a*d+c*b)/(b*d)会更快一些,这是 因为即使是算3次乘法也快过一次除法。

避免过大的循环


全局变量:在C中随处可见,而在C++中是会被尽量回避的,C++程序员更多的会把一类全局变量写成一个类并做成单件,先取得单件的指针,再使用单件的方法来访问这些数据。表面上看起来C++中的方法会多一次间接性,但是现代CPU,在对待数据时,把数据集中却有助于提高数据高速缓存的使用效率,并且之间访问全局变量会产生一个32位地址数据,处理速度比用一个this指针加一个短偏移量要低。


消失了的宏:宏在C语言中有极其重要的地位,而在C++中尽力回避。红在C语言的编程中主要有四大用途:定义函数,代码生成,内联代码和对编译流程做出选择。C++,定义常数通常用const。
其实在更多的情况下,我们选择一个内联函数返回一个常数值来取代直接定义一个全局的常数,这种灵活的方案被许多经验丰富的C++程序员采纳。因为C++对inline函数优化得很好,最终编译器会把它优化成一个常数,而没有函数调用的消耗。
inline函数在C++里应用非常广泛,配合template可以完成许多以前只有宏才能完成的事情。


判断一个C++程序是否由一个有经验的C++程序员写出来,最简单的方法之一就是看看代码中const的出现频率。
几乎所有的C++程序员在描述字符串常量的时候都会写const char*而不是C语言程序员喜欢的char*。
C++程序员总是把函数的参数尽可能写成const,表示这个函数不会修改它。同样成员变量也经常会被修饰成const,这样就只能在构造时构建它们。另外,为成员函数增加一个const修饰表达这个函数不会修改类的成员变量也使得成员变的优雅。

(成员函数的定义最后加上const,实际上是指出隐式传入的this指针是一个const指针。)

尽可能使用const使软件在设计阶段的思路更清晰,让编译器更加理解程序员的想法,以便在程序员不小心犯错误时及时指出。


+=比+加=更符合性能要求,因为它不需要临时构造出一个对象

 

为什么需要脚本?
(1)灵活性,需求会随着项目的进展时刻变化,我们必须随时改动游戏中的许多东西。
(2)减少和底层的耦合度
(3)增加代码复用性,如果我们把所有游戏逻辑有关的东西都放进了脚本中,那么脚本以下的模块实际上可以被很多游戏项目复用。
(4)降低开发门槛
(5)方便更新
(6)阻碍用户对游戏做逆向工程

应该用脚本做些什么?
(1)如果游戏的界面比较丰富,请一定为这个模块设置一个脚本驱动接口
(2)网络游戏的客户端网络包的处理应该使用脚本
(3)游戏的情节和游戏规则应该用脚本驱动
(4)游戏的配置应该写在脚本中