基本windows应用程序框架
主事件循环:
while(GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg); //虚拟加速键翻译器,输入工具
DispatchMessage(&msg); //调用WinProc()
}
主程序入口:定义窗口类→注册窗口→创建窗口→主事件循环;且每个Windows程序都有独立的事件句柄WinProc
一个实时事件循环:加入测试消息队列机制,PeekMessage(),使用PM_REMOVE
对应同一个窗口类的多个窗口的消息
第五章_ DirectX基础和COM
第六章_初次邂逅DirectDraw
第七章_高级DirectDraw和位图图形
IDIRECTDRAWSURFACE7::Blt()
IDIRECTDRAWSURFACE7::BltFast() 需要剪裁时用前者,不需要时用后者
基础裁剪知识(像素裁剪、位图裁剪),3D裁剪将会十分复杂
像素按视口裁剪
位图裁剪技巧
使用IDirectDrawClipper进行DirectDraw裁剪
步骤1,创建DirectDraw裁剪器对象,CreateClipper()
2, 创建Clipper序列 //最麻烦,需要填写RGNDATA结构
3,用IDIRECTDRAWCLIPPER::SetClipList
4,用IDIRECTDRAWSURFACE7::SetClipper
使用位图
载入.bmp文件 (位图头文件,位图信息段(有调色板的话),位图数据段)
载入8bit位图 SetEntries
载入16bit位图 (24bit转16bit)
载入24bit位图
离屏表面
创建的表面跟主表面是兼容的,具有一致的色深
在离屏表面上进行blitting
装载位图,创建表面,使用blitting
色彩键
源色彩键 DDCOLORKEY Object优先于background
目标色彩键,方法跟源色彩键相同SetColorKey,需要改变2个标志位
源叠加色彩键
目标叠加色彩键
如何更新DirectDraw调色板项
256色模式下的色彩旋转(Color Roation)
模拟水或液体的流动效果
使用RGB模式的技巧
1,利用手动色彩变换或查询表
2,采用新的DirectX彩色和Gamma补偿,实时地在主表面上执行色彩操作
手动色彩变换及查询表
透明·alpha混合·光照·暗化处理
DirectX新的色彩和Gamma控制接口
IDirectDrawColorControl可以控制高度,对比度,色调,饱和度,锐度和Gamma值
各种效果:如水下感觉,屏幕闪烁,灯光,黑暗
将GDI和DirectX联用
只需在DirectDraw中找到一个兼容DC
在独占模式下,Windows不能够用GDI在任何DirectDraw表面绘制
主DirectDraw对象
GetCaps获得HEL,HAL,用于获取任意表面能力
GetPixelFormat或GetSurfaceDesc结构DDSURFACEDESC2::ddpfPixelFormat
在窗口模式下使用DirectDraw
必须考虑使用者可能在任意分辨率和任意色彩深度模式下启动游戏
在窗口中绘制像素
1,主表面是整个屏幕,GetWindowRect()实际上获得的是整个窗口
2,不知道色深,GetPixelFormat()以决定色彩的深度
查找实际客户区
AdjustWindowRectEx 计算不同样式的窗口尺寸
剪裁DirectX窗口
裁剪只对blitter起作用
CreateClipper()
SetHWnd() 将裁剪器同窗口相关联
SetCClipper() 裁剪器同想要裁剪的表面相连
本章总结:
高彩模式,blitter,裁剪,彩色键,采样理论,窗口方式的DirectDraw
第八章_矢量光栅化及2D变换
绘制线条
问题1,计算机屏幕是一个由整数坐标表示的2D网格,如何显示浮点型坐标
Bresenham算法
解决实际问题:把像素以最接近实际直线的位置从点p1到点p2进行填充的这个过程成为光栅化。
1,计算斜率K
2,画点(x0,y0)
3, 在x方向上每前进1.0个单位,在y方向上就前进K个单位,把这两个值加到(x0,y0)上
基础2D图形裁剪知识
图像空间级(像素级)裁剪,对象空间级裁剪
两直线之交点
利用矩阵式求逆阵
裁剪直线
Cohen-Sntherland算法
判断线段跟矩形(剪裁区域)的情况
线框多边形
在游戏中,集中注意一件事,那就是速度!
为了画多边形,所要做的就是对顶点循环,并连接点与点
2D平面里的变换
平移
旋转(计算机中sin、cos采用弧度而不是角度)
坐标变换很像极坐标向笛卡尔坐标的转变
旋转时,逆时针θ为正,顺时针θ为负。在显示屏上,y轴是相反方向,正负也相反
实时程序中使用三角函数很糟糕,需要建立一个查询表,将算好的0-360度的sin、cos值保存在查询表内
关于精度,选择int还是float还是double
缩放,每个坐标乘以缩放因子
矩阵引论
基础的矩阵知识已经在《3D数学基础》内补完,这里学起来就异常轻松了。
使用矩阵进行各种变换(平移,缩放,旋转)
填充实心多边形
第一个约束条件,多边形必须为凸多边形
第二个约束条件,确定所要画的多边形到底有多复杂
绘制三角形和四边形
每个端点变成整数之前加0.5
四边形光栅化的一般情况
多边形的三角化
递归分割思想
通用凸N边形渲染算法
多边形碰撞检测
边界球/圆
对象具有一个平均半径,然后检测半径是否重叠(会有漏判)
开方函数sqrt会消耗大量CPU周期,想办法优化
1,只计算一次float差
2,泰勒级数展开
边界盒、边界箱
Find_Bounding_Box_Poly2D
点包含
测试一个点是否被包含在一个矩形内部
↓如何判断一个点是否被包含在任意凸多边形之内
半空间检测(Halfspace Test)需要运用到向量点积
深入定时和同步
基于Win32函数GetTickCount()
卷轴和摇镜头
页面卷轴Page Scrolling
均匀平铺显示引擎
采用基于tile的数据结构表示场景卷动
稀疏位图平铺显示引擎(适合太空射击游戏)
伪3D等轴测引擎
等轴测Isometric,即采用一定倾斜视角的游戏
方法一,基于单元,全2D
方法二,基于全屏,具有一些2D或3D的碰撞网络
方法三,采用全3D数学运算,使用一个固定的视角
采用工具画碰撞对象非常消耗时间,且对画面的任何变动都意味着返工
T3DLIB1函数库
2D引擎架构,可以先全屏再调整窗口大小到窗口程序
基本定义
可用宏
数据类型和结构
BOB(Billter Object Engine)
全局定义
DirectDraw接口
DDraw_Init
DDraw_Shutdown
DDraw_Attach_Clipper
DDraw_Create_Surface
DDraw_Flip
DDraw_Wait_For_Vsync
DDraw_Fill_Surface
DDraw_Lock_Surface
DDraw_UnLock_Surface
2D多边形函数
Draw_Triangle_2D
Draw_TriangleFP_2D
Draw_QuadFP_2D
Draw_Filled_Polygon2D
Translate_Polygon2D
Rotate_Polygon2D
Draw_Line
Draw_Pixel
Draw_Rectangle
Draw_HLine
Draw_VLine
Screen_Transitions
Draw_Text_GDI
数学和误差函数
Fast_Distance_2D //3.5% error
Fast_Distance_3D //11% error
Find_Bounding_Box_Poly2D
Open_Error_File
Close_Error_File
Write_Error
位图函数
Load_Bitmap_File
UnLoad_Bitmap_File
Create_Bitmap_File
Destroy_Bitmap
Load_Image_Bitmap
Flip_Bitmap
Scroll_Bitmap
Copy_Bitmap
调色板函数
Set_Palette_Entry
Get_Palette_Entry
Save_Palette_To_File
Load_Palette_From_File
Rotate_Colors
*Blink_Colors
实用工具函数
Get_Clock
Start_Clock
Wait_Clock
Collision_Test
Color_Scan //另一种碰撞检测法
BOB引擎
BOB基本上是由一个或多个DirectDraw表面(最大到64个)
BOB是由当前的DirectDraw裁剪器裁剪
Create_BOB
Destroy_BOB
Draw_BOB
Draw_Scaled_BOB
Load_Frame_BOB
Load_Animation_BOB
Set_Pos_BOB
Set_Vel_BOB
Set_Animation_BOB
Set_Anim_Speed
Animation_BOB
Move_BOB
Hide_BOB
Show_BOB
Collision_BOB //检测2个BOB重叠
本章总结:
光栅化、裁剪、直线绘制、矩阵、碰撞检测、定时、卷动、等轴测引擎、完整的位图&多边形库
第九章_DirectInput输入和力反馈
HEL(Hardware Emulation Layer) 硬件仿真层
HAL(Hardware Abstraction Layer)硬件抽象层
DirectInput组件
DirectInput8Create
DirectInputDevice8,从DirectInput8创建,和设备(...)通信的渠道
设置DirectInput步骤
1,通过DirectInput8Create创建DirectInput8接口
2,查询设备GUID
3,调用CreateDevice传递一个GUID
4,DirectInputDevice8::SetCooperativeLevel 设置协作等级
5,DirectInputDevice8::SetDataFormat 设置每个设备的数据格式
6,DirectInputDevice8::SetProperty 设置设备性能
7,DirectInputDevice8::Acquire 获得设备
8,(可选)DirectInputDevice8::Poll 轮询设备
9,DirectInputDirectDevice8::GetDeviceState 从设备获取数据
用DirectInput的好处就是能与设备驱动无关的方式操作任何输入设备
总是以创建顺序相反的顺序调用Release
数据采集模式
直接数据模式(默认)
缓存数据模式
创建主DirectInput对象
键盘
协作等级 DISCL_BACKGROUND | DISCL_NONEXCLUSIVE
复杂的数据结构格式,允许如何格式化从输入设备得来的数据
通用数据结构 SetDataFormat(&c_dfDIKeyboard)
GetDeviceState,要在每次游戏循环中读取键盘,时机:循环顶部,在任何处理开始之前
用完释放 Unacquire
捕捉鼠标
绝对模式(移动前后2个点)
相对模式(移动过程中点的连续)
使用游戏手柄(略)
输入消息化
所有的输入设备数据合并在一起,在根据这个结构做出决定
Merge_Input(合并后事件的数据,键盘数据指针,鼠标数据指针,手柄数据指针)
力反馈
输入系统 T3DLIB2
本章总结:
DirectInput、键盘、鼠标、游戏手柄、输入数据消息化、力反馈、完整T3DLIB2库
第十章_用DirectSound和DirectMusic演奏乐曲
DirectSound用于音效,跟单声道配合最好,立体声没有意义
DirectMusic用于音乐
一定使用长文件名!
初始化DirectSound
DirectSoundCreate
理解协作等级
可控制主声音缓冲的设定
不可控制主声音缓冲的设定
设定协作级别
lpds->SetCooperativeLevel
主声音缓冲与辅助声音缓冲
创建辅助声音缓冲
先创建DirectSoundBuffer描述性结构DSBUFFERDESC dsbd
WAVEFORMATEX pcmwf
lpds->CreateSoundBuffer(&dsbd, &lpdsbuffer, NULL)
若函数成功调用,则一个新的声音缓冲就建立了,并传给lpdsbuffer,该缓冲就是准备播放的
把数据写入辅助声音缓冲
辅助声音缓冲是循环的
锁Lock 缓存 lpdsbuffer->lock
写入数据,需长度
解锁Unlock lpdsbuffer->Unlock
释放 lpdsbuffer->Release
播放声音
播放缓冲区中的声音数据
lpdsbuffer->play(0,0,DSBPLAY_LOOPING)
停止播放
lpdsbuffer->Stop
控制音量
SetVolume 非增大或减小增幅,而是播放的衰减
配合宏 #define DSVOLUME_TO_DB(volume) ((DWORD)(-30*(100-volume)))
调整频率
SetFrequency 即改变音调
调整声道平衡
通过左右声道的调节(平移 Panning) 可做局部3D音效
SetPan(LONG Pan) 0代表中间位置
用DirectSound反馈信息
GetCaps 大部分音频信息
GetStatus 检查正在播放声音缓冲的状态
从HDD读取声音数据
DirectSound不支持声音文件的加载,需要自行编写
读取.wav文件
初始化DirectMusic
是一个完全COM化组件,需自己COM库来创建COM对象
因此每个应用程序仅仅需要DirectMusic
dmksctrl.h
dmusici.h
dmusicc.h
dmusicf.h
初始化COM
CoInitialize(NULL) 在任何直接COM调用之前写一次
创建一个演奏对象,即DirectMusic对象
调用完之后,dm_perf可以使用
Init() 如果需要同时使用DirectSound和DirectMusic则需把pDirectSound传入,否则传NULL
给演奏对象增加端口
dm_perf->addPort(NULL)
加载一个MIDI段
IDirectMusicLoader* dm_loader = NULL
加载MIDI文件
DirectMusic称数据块chunk为段segments
操作MIDI段
播放MIDI段
停止
检查状态
释放MIDI段
关闭DirectMusic
T3DLIB3库
对DirectSound&DirectMusic API的封装
本章总结:
初步了解DirectSound,DirectMusic;
了解制作(2D)游戏的每一件事情
第十一章_算法,数据结构,内存管理和多线程
数据结构
静态结构和数组
链表
树 (B树,二分查找树BST)
3D场景建模,以数百颗树表示空间中的各个房间
树结构构造二分空间解决渲染问题
算法分析
算法好>>汇编,优化器
算法分析技术(渐近分析Asymptotic Analysis),基于微积分
!调用函数比直接绘图用时多,考虑宏或者内联
递归 Recursion
函数不能溢出堆栈,且要有终止条件
优化理论
内存对齐
数学技巧
游戏编程的实质上是数学问题
位移 product = (n<<7)+(n<<9); //n*128+n*512=n*640
一个大float数组清零:memset((void*)float_array, 0,0 sizeof(float)*num_floats)
定点运算
循环体展开
查找表
汇编语言
多线程编程技术
SMP(对称多处理,Symmetrical Multiprocessing)利用多处理器分担工作量
多任务/抢先式操作系统(任何任务,进程,线程,都不能完全控制计算机)
线程的所有变量都在属于自己的堆栈中创建
结束线程
向该线程发送消息通知其结束(√)
使用内核级的调用强行结束该线程(×)
在一个封闭的循环中,等待一个变量,会给多任务内核带来繁重的负担并严重占用CPU
多线程和DirectX
本章总结:
数据结构,内存管理,递归,分析,定点数运算,多线程
第十二章_人工智能
人工智能初步
人工神经网络
遗传算法
模糊逻辑
3D游戏里的东西长得很真实,但行动起来却很傻
没有所谓的对错,只有是否有效
确定性AI算法
第一类AI —— 简单,可预知,可编程
跟踪算法
向量,比例缩放因子
反跟踪·闪避算法
模拟以及基本控制脚本编写
[指令,操作数]格式编码
条件逻辑处理的模式
建模行为状态系统
更多表现个性的行为
用软件对记忆和学习进行建模
AI由(状态机,条件逻辑,模式,随机数,概率分析)控制
计划树和决策树
编程语言对计划建模
寻路 pathfinding
试探路(Trial and Error)
轮廓跟踪(Control Tracing)看起来蠢,没有走最短路径
碰撞规避跟踪
路点寻路 通常被采用,可是会增加人工
寻找p1到p2路径,有很多算法可以做到。但没有一个是实时的
第十三章_基本物理建模
质量
时间,算法更多地与帧速率相关,而不是实际时间
位置,不规则物→质心
速率
加速度
力,力就是单位时间内动量的变化率
动量,无论什么物体突然停止,例撞上什么的时候,这个物体会承受所有的力
线性动量的物理性质:守恒与传递
模拟万有引力效果
模拟重力井 Gravity Well
摩擦力
μs 静态摩擦系数
μk 动态摩擦系数
摩擦力模型和重力模型很相似
斜面上的摩擦力
基本的特殊碰撞反应
弹性碰撞 动量,动能守恒
非弹性碰撞 不守恒
计算任意方向上的平面碰撞反应
矢量反射示例
线段的交点
简单运动学
正向运动学
方向运动学
粒子系统
一颗粒子的一般特征:位置,速度,颜色/动画,生命周期,重力,风力
一个粒子系统:1,粒子数据结构
2,处理每个粒子的粒子引擎
3,产生特定粒子初始条件的函数
水汽尾迹算法
模拟爆炸效果
基于帧的模拟与基于时间的模拟
第十四章_文字时代
第十五章_综合运用