传奇3客户端分析(一:WinMain函数)
本系列文章为原创文章,本系列文章请在有一定编程基础下阅读,基础问题、语法问题将不做回答,如有转载,请注明出处。
最近爱上Silverlight,所以来分析下手上现有的传奇3客户端源码,看看他们是怎样处理的,嘿嘿。源码就是网上的那个C++的版本。废话不多说了。直接打开源码,找到WinMain(你懂的)。
g_xMainWnd.Create()//主窗体的创建。
ShowWindow()//显示窗体
g_xSound.InitMirSound()//声效初始化
g_xSpriteInfo.SetInfo()//精灵
CSprite g_xSpriteInfo;
先分析一下这个精灵里面的东东。
class CSprite
2 {
3 public:
4 EFFECTSPRINFO m_stEffectSpr[_MAX_EFFECT]; // 精灵的效果._MAX_EFFECT=33
5 EFFECTSPRINFO m_stMagicSpr[_MAX_MAGIC]; // 魔法的效果._MAX_MAGIC=52
6 EFFECTSPRINFO m_stExplosionSpr[_MAX_EXPLOSION]; // 爆炸效果._MAX_EXPLOSION=8
7
8 EFFECTSPRINFO m_stMonEffectSpr[_MAX_EFFECT]; // 怪物效果.
9 EFFECTSPRINFO m_stMonMagicSpr[_MAX_MAGIC]; // 怪物魔法效果.
10 EFFECTSPRINFO m_stMonExplosionSpr[_MAX_EXPLOSION]; // 怪物爆炸效果.
11
12
13 SPRFRMDEF m_stHeroSpr[_MAX_HERO_MTN]; // Hero狼 悼累橇饭烙 沥狼._MAX_HERO_MTN=33
14 SPRFRMDEF m_stMonSpr [_MAX_MON_MTN]; // Monster狼 悼累橇饭烙 沥狼._MAX_MON_MTN=10
15 SPRFRMDEF m_stNPCSpr [_MAX_MON_MTN]; // Monster狼 悼累橇饭烙 沥狼.
16
17 BYTE m_bWOrder[_MAX_HERO_REALFRAME]; //_MAX_HERO_REALFRAME=2640
18
19 public:
20 CSprite();
21 ~CSprite();
22
23 VOID InitSpriteInfo();
24 VOID DeleteSpriteInfo();
25
26 VOID SetInfo();
27
28 VOID SetSprDfn(LPSPRFRMDEF pstSprDfn, WORD wFstFrm, WORD wFrmCnt, WORD wDelay);
29
30 VOID SetEffectInfo(LPEFFECTSPRINFO pstEffect, DWORD dwFstFrm, DWORD dwEndFrm, WORD wDelay, WORD wImgIdx, WORD wEffectIdx,
31 BYTE bSLightRadius, BYTE bLLightRadius,
32 BYTE bSLightRColor, BYTE bSLightGColor, BYTE bSLightBColor,
33 BYTE bLLightRColor, BYTE bLLightGColor, BYTE bLLightBColor,
34 BYTE bMagicRColor = 255, BYTE bMagicGColor = 255, BYTE bMagicBColor = 255,
35 BYTE bBlendType = _BLEND_LIGHTINV, BYTE bOpa = 0, BYTE bSwingCnt = 0);
36
37 LPEFFECTSPRINFO GetEffectInfo(WORD wEffectNum);
38 LPEFFECTSPRINFO GetExplosionInfo(WORD wEffectNum);
39 LPEFFECTSPRINFO GetMagicInfo(WORD wEffectNum);
40
41 VOID SetMonFrameInfo(WORD wMonNum);
42
43 BOOL SetWeaponOrder(CHAR* szFileName);
44 };
代码
{
WORD wFstFrm;
WORD wFrmCnt;
WORD wDelay;
}SPRFRMDEF, *LPSPRFRMDEF;
typedef struct tagEFFECTSPRINFO
{
DWORD dwFstFrm;
DWORD dwEndFrm;
WORD wDelay;
WORD wImgIdx;
WORD wEffectIdx;
BYTE bLightRadius[2];
BYTE bLightColor [2][3];
BYTE bMagicColor [3];
BYTE bBlendType;
BYTE bOpa;
BYTE bSwingCnt;
}EFFECTSPRINFO, *LPEFFECTSPRINFO;
先来看看构造函数CSprite(),里面是调用了初始化函数InitSpriteInfo(),初始化变量并分配内存,在C#中是不需要这样做的。
代码
2 {
3 ZeroMemory(m_stHeroSpr, sizeof(SPRFRMDEF)*_MAX_HERO_MTN);
4 ZeroMemory(m_stMonSpr, sizeof(SPRFRMDEF)*_MAX_MON_MTN);
5 ZeroMemory(m_stNPCSpr, sizeof(SPRFRMDEF)*_MAX_NPC_MTN);
6
7 ZeroMemory(m_stEffectSpr, sizeof(EFFECTSPRINFO)*_MAX_EFFECT);
8 ZeroMemory(m_stMagicSpr, sizeof(EFFECTSPRINFO)*_MAX_MAGIC);
9 ZeroMemory(m_stExplosionSpr,sizeof(EFFECTSPRINFO)*_MAX_EXPLOSION);
10 }
顺便把析构函数~CSprite()也看一下,调用函数DeleteSpriteInfo();这个函数里面调用的还是InitSpriteInfo();目前还不清楚为什么要这样,后面在分析。WinMain函数一开始就调用了g_xSpriteInfo.SetInfo(),那么我们来看看这个函数
SetInfo
2 {
3 SetWeaponOrder("weapon.ord");//读取客户端目录下的weapon.ord文件
4 //将SPRFRMDEF m_stHeroSpr[_MAX_HERO_MTN]每个都赋值,这是三十三个。
5 SetSprDfn(&m_stHeroSpr[0], 0, 4, 200);// _MT_STAND
6 //……节省代码中间的自己看源码去
7 SetSprDfn(&m_stHeroSpr[32], 2560, 3, 100);// _MT_HORSEHIT
8
9 //将SPRFRMDEF m_stMonSpr [_MAX_MON_MTN]每个都赋值,这里是九个。
10 SetSprDfn(&m_stMonSpr[0], 0, 4, 300);
11 //……省略
12 SetSprDfn(&m_stMonSpr[8], 640, 6, 150);
13
14 //将SPRFRMDEF m_stNPCSpr[_MAX_MON_MTN]每个都赋值,这里是三个。
15 SetSprDfn(&m_stNPCSpr[0], 0, 4, 300);
16 SetSprDfn(&m_stNPCSpr[1], 30, 10, 300);
17 SetSprDfn(&m_stNPCSpr[2], 60, 6, 300);
18
19 //将EFFECTSPRINFO m_stEffectSpr[_MAX_EFFECT]赋值_IMAGE_MAGIC=27
20 SetEffectInfo(&m_stEffectSpr[0], 230, 236, 100, _IMAGE_MAGIC, _SKILL_BANWOL, 3, 4, 100, 100, 100, 100, 100, 170);
21 //略
22 SetEffectInfo(&m_stEffectSpr[32], 830, 839, 100, _IMAGE_MAGIC, _SKILL_SHIELD, 3, 4, 100, 100, 100, 170, 100, 100);
23
24 //EFFECTSPRINFO m_stMagicSpr[_MAX_MAGIC]
25 SetEffectInfo(&m_stMagicSpr[0], 70, 88, 100, _IMAGE_MAGIC, _SKILL_AMYOUNSUL, 3, 4, 190, 220, 190, 190, 240, 190, 255, 255, 255, _BLEND_NORMAL);
26 //略
27 SetEffectInfo(&m_stMagicSpr[22], 110, 129, 100, _IMAGE_MAGIC, _SKILL_SPACEMOVE3, 3, 4, 100, 100, 100, 100, 100, 100); // 酒傍青过3.
28
29 //~~~ Monster Magic Frame Define. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
30 SetEffectInfo(&m_stMagicSpr[23], 0, 4, 100, _IMAGE_MONMAGIC, _MONMAGIC_KEPAL, 2, 3, 100, 100, 100, 150, 150, 150);
31 //略
32 SetEffectInfo(&m_stMagicSpr[51], 1770, 1790, 100, _IMAGE_MONMAGIC, _MONMAGIC_EXPLODE1, 2, 3, 100, 100, 50, 150, 150, 75);
33
34 //~~~ Explosion Frame Define. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
35 SetEffectInfo(&m_stExplosionSpr[0], 200, 220, 80, _IMAGE_MAGIC, _SKILL_HANGMAJINBUB, 4, 5, 200, 150, 60, 255, 170, 100, 255, 255, 255, _BLEND_LIGHTINV, 0, 1);// 亲付柳过.
36 SetEffectInfo(&m_stExplosionSpr[1], 170, 190, 80, _IMAGE_MAGIC, _SKILL_DEJIWONHO, 4, 5, 120, 170, 220, 160, 210, 255, 255, 255, 255, _BLEND_LIGHTINV, 0, 1);// 措瘤盔龋.
37 SetEffectInfo(&m_stExplosionSpr[2], 580, 590, 100, _IMAGE_MAGIC, _SKILL_FIREBALL, 2, 3, 120, 170, 220, 160, 210, 255); // 拳堪厘.
38 SetEffectInfo(&m_stExplosionSpr[3], 1140, 1150, 100, _IMAGE_MAGIC, _SKILL_FIRECHARM, 2, 3, 120, 170, 220, 160, 210, 255); // 气混拌.
39 SetEffectInfo(&m_stExplosionSpr[4], 1800, 1810, 100, _IMAGE_MAGIC, _SKILL_FIREBALL2, 2, 3, 120, 170, 220, 160, 210, 255); // 陛碍拳堪厘.
40 SetEffectInfo(&m_stExplosionSpr[5], 820, 830, 100, _IMAGE_MAGIC, _SKILL_BIGCLOAK, 4, 5, 200, 210, 190, 200, 150, 180); // 措篮脚.
41 //~~~ Monster Explosion Frame Define. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
42 SetEffectInfo(&m_stExplosionSpr[6], 100, 110, 100, _IMAGE_MONMAGIC, _MONMAGIC_ANTHEAL, 2, 3, 100, 100, 100, 150, 150, 150); // 规氢备喊篮 绝促.
43
44 SetEffectInfo(&m_stExplosionSpr[7], 2360, 2379, 100, _IMAGE_MAGIC, _SKILL_SINSU, 3, 4, 150, 150, 150, 200, 150, 180, 255, 255, 255, _BLEND_NORMAL, 255); // 脚荐.
45 }
来看看SetSprDfn(LPSPRFRMDEF pstSprDfn, WORD wFstFrm, WORD wFrmCnt, WORD wDelay);这个就是设置精灵的重要属性之一。设置精灵首张图片的编号,动画数量,间隔。
在来看看SetEffectInfo()函数,其实就是对tagEFFECTSPRINFO各属性进行赋值
VOID SetEffectInfo(LPEFFECTSPRINFO pstEffect,
DWORD dwFstFrm,
DWORD dwEndFrm,
WORD wDelay,
WORD wImgIdx,
WORD wEffectIdx,
BYTE bSLightRadius,
BYTE bLLightRadius,
BYTE bSLightRColor,
BYTE bSLightGColor,
BYTE bSLightBColor,
BYTE bLLightRColor,
BYTE bMagicRColor = 255,
BYTE bMagicGColor = 255,
BYTE bMagicBColor = 255,
BYTE bBlendType = _BLEND_LIGHTINV,
BYTE bOpa = 0,
BYTE bSwingCnt = 0);
通过上术分析可以看出传奇3客户端在一开始就对精灵进行了初始化。
g_xChatEditBox.Create()//登录文本输入窗口,控件在这里就不分析了。
ShowWindow(g_xChatEditBox.GetSafehWnd(), SW_HIDE);//显示这个文件窗口。
srand((unsigned)time(NULL));//随机种子
//初始化Socket连接,失败程序退出
WSAData wsd;
if( WSAStartup( MAKEWORD(2, 2), &wsd ) != 0 )
return -1;
//登陆,人物选择,游戏过程部分
g_xClientSocket.m_pxDefProc = g_xMainWnd.m_pxDefProcess = &g_xLoginProc;
g_xLoginProc.Load();
g_bProcState = _LOGIN_PROC;
//主窗口更新窗口,显示窗口
UpdateWindow(g_xMainWnd.GetSafehWnd());
ShowWindow(g_xMainWnd.GetSafehWnd(), SW_SHOW);
//全局版本号,用于服务器端连接验证
g_nVersion = 20090403;
DWORD dwLastTime, dwTime, dwDelay;
dwLastTime = dwTime = dwDelay = 0;
//消息循环重绘主窗口
代码
{
if ( PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE) )
{
if ( 0 == GetMessage(&msg, NULL, 0, 0) )
return (int) msg.wParam;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
dwTime = timeGetTime();
dwDelay = dwTime - dwLastTime;
dwLastTime = dwTime;
if ( dwDelay!=0 && g_xMainWnd.m_bIsWindowActive && g_xMainWnd.m_bIsWindowReady )
{
switch ( g_bProcState )
{
case _LOGIN_PROC:
g_xLoginProc.RenderScene(dwDelay);
break;
case _CHAR_SEL_PROC:
g_xChrSelProc.RenderScene(dwDelay);
break;
case _GAME_PROC:
g_xGameProc.RenderScene(dwDelay);
break;
}
if ( FAILED(g_xMainWnd.Present()) )
{
g_xMainWnd.RestoreSurfaces();
}
}
}
}
到这里,通过对WinMain的函数进行分析后,发现,客户端是在不停的刷新进行重绘来实现动画。下节分析g_xLoginProc游戏登录画面进行分析。

浙公网安备 33010602011771号