日志:
3 月 10 日 开始………………………………………………………
3 月 25 日 发现地图移动的两个错误,并进行修正:
a) 移动的碰撞只用了左上角,忘记了要用四个角
b) 跨越地图的玩家移动被重复计算,为此在VM中发现预先循环将所有跨越地图的玩家放新地图,接下来的两次循环才进行移动
3 月 26 日 完成地图消息的消息处理,其中对地图相关消息进行了重新定义
3 月 27 日 开始客户端的地图移动,并尝试用STL改造代码
3 月 28 日 完成客户端的地图移动,由于对STL理解不够,只在少部分使用了STL函数
3 月 29 日 完善客户端地图相关消息处理和发送
3 月 30 日 完成客户端地图功能
3 月 31 日 加入将地图服务器涉及的消息重新分成两类:地图移动消息和地图事件消息
地图服务器初始化地图信息
4 月 1 日 登陆时地图服务器初始化玩家信息
4 月 2 日 玩家改变地图时读出将区域中新的地图,并将新增地图中的邻居信息入通过MsgOtherIn传入给他,同时将玩家信息传给他的邻居们
4 月 3 日 根据统一后的消息加入了补给的计算
4 月 4 日 加入VM的定时器,重载mapSocket的OnRead函数
4 月 5 日 加入数据临界区
4 月 6 日 停电
4 月 7 日 上午开会,下午将全局函数整合进其他类,没有成功
4 月 8 日 加入MapManager类,将mapList和player的相互操作作为其成员函数,使CMapListSession和CMapPlayerSession完全独立。
4 月 9 日 在MsgLog中加入地图服务器相关消息,开始调试
4 月 10 日 将继续调试地图服务器,同时将客户端改成九张地图
4 月 11 日 将继续调试地图服务器
4 月 12 日 在认真考虑客户端与服务器的同步,进行修改
4 月 13 日 地图编辑器的打开文件和保存文件的方法
4 月 14 日 停电
4 月 15 日 上午开会,下午加入针对IN_BUILDING玩家的处理
4 月 16 日 完善开题报告,在移动过程中添加、删除精灵
4 月 17 日 完善地图服务器文档
4月18--20日服务器协同调试,不过经常被各种事情打断
只发现以下错误:
1、 在testlogin中登录第二个玩家,mapserver便退出
原因:在onread中多了一个对singal的判断,以致线程在玩家1时没有退出临界区
当收到玩家2的消息,进入临界区中会出错
2、 消息会发生重叠,可能是Edit的显示问题
3、 有时调试出错退出,下一次调试会出错,直到再下一次再正确
4、 第一个玩家登陆时,消息正确,但后面的玩家消息错误越来越多
原因:makemsg()中用于产生消息的buf太小了
5、直接运行exe,当两个玩家登陆时,第一玩家收不到otherIn消息,而第二个却收到两条;于是mapserver调试运行,消息却正确
原因:在检查中
4 月 21 日 解决了地图编辑器的保存问题
4 月 22 日 发现上述问题5是因为Edit的buf太小,以致消息发送正常,只是显示异常
开始测试定时运行地图状态机,处理玩家移动
4 月 23 日
1、上述问题又出现,在从黄良毅更新了新的MsgLog后才正常,看来buf太小只是一方面原因,另一方面是消息的追加方式。
2、Socket的OnRead线程在处理完msgBuf中所有的消息后才返回。如在处理某一消息处理时就到了状态机运行的间隔时间,只能处理完该消息才将控制权交给状态机,当然状态机会有所延迟。原来的OnRead没有体现这些,而是默认消息处理不会超过间隔时间, 为此进行了修改。
4 月 24 日
发现错误:
1、当两个玩家登陆之后,玩家1和2都无法开始移动
原因:测试时玩家登陆都是在默认坐标,将会互相阻挡,进港或出建筑物也会有问题。
修改:根据玩家的移动方向不同选择踫撞点。另外为了测试方便,在些临时文件保存玩家的登陆坐标,测试时玩家从中读出登陆时坐标。
2、当移动起点和终点相同时,在计算移动参数会出现除零错误,加入判断避免错误
4 月 25 日
测试进入建筑物,选择交易所,玩家进入交易所,逻辑服务器发回交易所和玩家自身的货物信息。
测试出建筑物,但是从gameserver收到msgQuitRequest后的处理未发消息给mapServer。
测试补给,将地图和玩家属性改成海上,补给会定时改变,好像没什么问题。
在客户端加入MapMoveMsg和MapEventMsg消息的处理
4 月 26 日
1、测试跨越地图移动,从地图1移动至地图2,
发现错误:当玩家准备跨越至地图2时会出现访问异常。
原因:在预先跨越地图(PreBlock)在遍历玩家list时发现有人跨越就将其删除,即在遍历容器时将修改容器,使容器失效。
修改:将所有跨越者保存在临时表中,在遍历结束后一并删除。
2、对服务器地图信息类和地图玩家信息类重新命名,分别为CMapInfo和CMapPlayer
4 月 27 日
1、 测试进港,从海上地图2移动至港口,经逻辑服务器确认,进入地市地图1。不过逻辑服务器的进港确认处理还未加入,只好以后再测
2、 测试出港,从地市地图1移动至码头,客户端发出港请求,逻辑服务器确认后,进入海上地图2。
改正了码头、港口的触发点错误、逻辑服务器对补给和水手判断的错误,可以按以下过程出港。
玩家进入码头,逻辑服务器发回补给价格
玩家发出港请求,逻辑服务器将请求通知地图服务器,地图服务器发回海上地图的信息
3、 将msgMoveBegin, msgPutOff, msgPutIn等消息实体是发送给地图或逻辑服务器,其msgHead.userID就是要处理的玩家playerID,于是把原定义重复中的playerID都去掉了
4 月 28 日 (上午开会)
对mapserver的代码进行整理,改了TestLogin的菜单
重新测试出建筑物,gameserver收到msgQuitRequest后,发msgQuitConfirm消息给mapServer。mapServer再发返回城市消息给客户端。
4 月 29 日 (上午开会)
重新确定了进港和进建筑物的消息,在地图服务器、客户端重新进行处理
重新测试进港,gameserver收到msgPutInRequest后,发msgPutInConfirm消息给客户端。客户端模拟发msgMapInfoRequest,地图服务器返回msgDisplaceMap
4 月 30 日
1、在TradeAge加入了状态机,结果一运行就退出
原因:MapServer和TradeAge 都使用编号为1的定时器,引起冲突
修改:TradeAge 改用编号为2的定时器
2、玩家登陆时TradeAge异常退出,调试时在访问玩家属性提示访问冲突
原因: TradeAge在OnMapInit中先添加登陆的玩家,再初始化玩家当前区域的地图。
在初始化当前地图时有一个清空地图中玩家的操作,把登陆的玩家也误删了
修改:初始化当前地图时只清空其他的玩家
3、玩家移动之后,重新SetSprite()提示访问冲突?????????????
原因:在WinMain的系统消息循环中有Display()定时刷新时会用到sprite,引起冲突
修改:在WinMain的系统消息循环中注释掉Display()
4、为了使客户端MapPlayer中的便于计算0.1秒, 客户端的MapPlayer不用地图服务器的,暂时从地图服务器进行修改,以后应该把两边的共同部分抽象成基类,分别根据需要派生。目前的移动同步正常
5、测试进出交易所,结果正常
6、测试进港,玩家登陆地图2(海上地图),移动进入港口,再进入地市1(在地图1)。
第一次运行玩家登陆成功,直到地图服务器发DisplaceMap到客户端,客户端初始化玩家新区域的地图,提示“变量id致使stack破坏”,id好像是指定义的一个临时数组char id[10];
调试又没问题。而以后每次运行时,地图服务器发出MapInitConfirm,登陆服务器转发了,但是TradeAge的消息中无法添加,甚至不响应,可能stack破坏有关。只有在重启或注销之后才能正常运行一次
5 月 1 日
1、 加入玩家移动到鼠标点击处,运行却无法移动
原因:鼠标点击坐标是相对于镜头左上角的偏移,忘记将其转成全局坐标
2、 客户端能自主移动进入港口并消失,在消息框却没有加移动验证、进港等消息
原因:可能是客户端状态机的间隔0.1秒太小了(5 月3日又改回0.1秒,运行正常,可见不是间隔的问题,另有原因)
修改:将客户端状态机的间隔改成0.2秒,相应的地图服务器的改成1秒
3、 客户端接收到DisplaceMap便不响应,调试时异常断点在list的empty()
原因:客户端的各种list初始化时忘记Clear()
4、收到DisplaceMap便不响应,调试时在mapPlayer的getState()提示访问冲突
原因:一开始从playerList获得迭代器指针,在调用一个函数时容器被修改了,以致迭代器指针也失效,再使用就会提示访问冲突
修改:在容器修改后重新获得迭代器指针
5 月 2 日
1、 想在OnMapInitConfirm()中将获得的一个玩家信息的内存释放,提示在dbgheap中出现未处理异常:用户断点
原因:该内存在静态消息buf,不是动态的。
2、 客户端能自主移动进入港口并消失,在消息框却没有加移动验证、进港等消息,如昨天一样
原因:不明,但重启后调试又正常
3、 客户端接收到DisplaceMap便不响应,调试时异常断点在list的end()
原因:客户端的在初始化新地图已经旧地图全部删除了,在后来的一个操作却试图获得旧地图的指针
修改:调整了初始化新地图各项操作的顺序
4、切换至新地图后却没有显示Sprite
原因: 新地图playerList在添加与玩家是出错
修改:
5、出现在地市地图中时忘记重新SetCamera
6、切换地图之后在码头门口,一移动又不响应,程序还是不稳定
5 月 3 日 继续通过进入港口、在城市中移动,出港来测试
1、 玩家进入港口后出现在码头门口,但是无法移动
原因:GetGlobalByCompare在转换方法不对,修改。
2、 移动时在y方向经常到不了鼠标点击的终点
原因:移动时只以x坐标判断是否到终点,改成以x和y一起判断
3、移动至终点后不停止
原因: 上一步修改后判断到终点的函数有问题
4、 鼠标点击的终点后,要走的移动路径贴近地图左、上边缘时,无法移动
原因:地图的InMap()少了=,将左上边缘的认为不在地图中
5、在城市中移动,进入码头隐藏精灵, 点“出建筑物”菜单又显示精灵,正常
6、将地图服务器的状态周期改回0.5秒,客户端为0.1
地图服务器移动验证改成每10个周期一次,但是发现这样玩家走的是折线
原因:因为计算用乘100除100来近似两位精度的浮点计算,当玩家要走的移动路径斜率较小或较大时,方向1上有偏移(方向1或2指x 或y方向),方向2的偏移会近似成0。当前一方向移动移动至与终点时,才重设偏移,这下又方向2上有偏移,方向1的为0.
以后改进
5 月 4 日
1、跨越地图的算法目前局限在一个区域中移动,以后再实现类似环球航行的绕地球一圈的算法
2、在Cscene中加入成员函数AddSprite()用于加入一个精灵指针
在CMap中加入id,用于以后改进跨越地图算法
3、跨越地图时提示在CMapPlayer的GetMapID()访问冲突,退出
原因:跨越时的算法有错。
4、玩家移动到地图边界时静止等待服务器确认跨越,确认后又开始运动,但是跨越后精灵会消失,要用鼠标点击一下窗体精灵才会出现
原因:跨越后忘记设置精灵和镜头的坐标
5、跨越时,切换地图后跳跃较大。虽然将在服务器确认后玩家状态设为运行,但似乎并没开始运动,于是每次MoveCheck或是MoveOver消息到来后都跳跃一下
原因:不明
6、跨越地图不等待服务器确认,但是镜头与移动方向反向移动
原因:跨越后忘记设置精灵和镜头的坐标有错
7、加入玩家退出游戏的消息处理,但是在保存信息时ini.WriteInt("global", "x", global.x)之类的语句时MapServer中会不响应,而ini会出现重复的键值和键名。
5 月 5 日
1、玩家1从TradeAge中登陆,之后玩家1从TestLog中登陆,在玩家1中可以看见玩家1。如果玩家2退出,其精灵也消失。如果玩家1退出,玩家2收到消息。
2、进入建筑物时玩家就不能再移动
3、从地图服务器和客户端的地图移动所需玩家信息中提取出了公共类CMapPlayer
派生出CServerMapPlayer和CClientMapPlayer。客户端地图移动所需玩家信息从图服务器传来,先转成CMapPlayer,再转成CClientMapPlayer。
5 月 6 日 整理文档
5 月 7 日 -15日回家
5 月 16 日 整理文档
5 月 17 日 上午去找老师没找到,
下午更改了玩家移动的时间间隔和速度等参数,
晚上为解决客户端无法显示其他玩家的移动,调试MapServer,发现要地图中添加新的玩家的方法有错,改正即可
5 月 18 日
1、 手动修改城市1触发点,每个建筑物门口有四个触发图元
2、 在互联网上进行连接在,登陆远程服务器成功。
3、 当玩家跨越地图后,和原地图中的玩家互相看不见
原因:在跨越地图时只是重设了当前玩家精灵的偏移,没有重设其他的
修改:重设区域内所有的精灵
3、在地图中加入阻挡,但是没有起作用,也许地图文件中未编辑阻挡关系
4、用加了阻挡关系的地图,似乎阻挡的太多了,无法靠近建筑物,
而且进入建筑物更加容易消失。
5 月 19 日 写论文
5 月 20 日
1、 客户端进入建筑物由地图服务器确认解决了消失问题
2、 在海上地图4的的港口进入城市后,又出海,被显示在海上地图2的的港口
修改:逻辑服务器进行了修改
3、 在删除精灵指针的同时释放内存
在海上和城市中使用不同的精灵:
服务器收到MapInfoRequest时重新设置精灵类型,以便于广播给区域其他玩家
客户端收到DisplaceMap时重新设置精灵类型,产生新的精灵
但是只是在登陆时可以从船只变成人物,以后再进出港一直是人物,无法重新设置精灵类型, 而且精灵背景为黑
原因:调试时很奇怪,玩家的状态总是与实际相反,而且只要一做pCurrent->f()
pSprite的属性值就混乱。
不理会以上,又可能是因为原有的精灵未释放,在显示两个精灵时精灵背景也会是黑的
5 月 21 日
1、客户端在每次运行状态机、切换地图、跨越地图后都用CMapManager::SetCamera()重新设置镜头和精灵坐标
2、客户端在InitNewMap()删除原有玩家前先释放其精灵内存
3、地图服务器和客户端在改变精灵类型时同时改变踫撞点
4、出港是时玩家精灵是在OnDisplaceMap()中改变,可是这段单步调试时并不按语句执行,而且监视值有错(以前也碰到很多次这的情况,执行exe时没错,可能编译器有问题),甚至于无法单步执行至出港改变精灵类型的那一句。
其他客户端也需要显示这个玩家出港后的精灵,不同的是其他客户端在OnOtherIn()中从地图服务器获得这个玩家的信息,并产生精灵。虽然OnOtherIn()单步调试时并不按语句执行,但恰好可以在获得的信息看到玩家精灵类型值是2(正确值应为3)。
1) 追踪至地图服务器在OnMapInfoRequest中GetShipType=0, 精灵类型=ShipType+2=2
2) 追踪至SeverMapPlayer的Init()中有ship[0].Init(),而Tship.Init()的定义在gameserver
3) 追踪至gameserver的Tship.Init()中
int type = ini.ReadInt(ca, "船只类型");
identifier.ID = type;
this->baseInfo = g_ship.GetBaseShip(type);执行后baseInfo.type.ID仍为0,为加了一句 baseInfo.type.ID = type; , 问题解决
5 月 22 日
1、 重新编辑了城市地图使玩家的移动更加流畅
2、 修改了地图编辑器显示地图的一些错误之后,在海洋地图边界加了了阻挡用于测试
5 月 23 日 -28日改论文
5 月 29 日 软件水平考试
5 月 30 日 论文,下午修改了对地图移动的触发点的判断,当玩家的中心进入触发点时才触发事件
5 月 31 日
1、上午服务器的第0.5秒周期的移动偏移用0.1秒内偏移的5倍表示,而不是直接算0.5秒内偏移,使服务器和客户端的移动尽量一致。但是效果不明显,移动结束还是会被往前拉一些
2、客户端改成每0.5秒验证一次玩家的移动,这使服务器和客户端的移动尽量一致。但是为了使显示流畅,每0.1秒改变一下精灵的位置,并不改变玩家坐标。当至0.5秒验证玩家的移动时,如果移动阻挡将被拉回。移动有些不流畅。
3、下午原来状态机遍历每张地图的玩家列表,验证玩家的移动,由于玩家可能跨越地图,于是玩家的移动可能被计算两次,当初为了避免加了个预先跨越。
现在状态机遍历玩家列表,不用预先跨越,简化了程序,跨越地图不需服务器确认。
6 月 1 日 客户端在状态机在判断是否到0。5秒时出错,计数器从0到5,算成了0.6秒,以致移动不流畅。将计数器改成从1到5。以前的服务器的移动和补给验证存在同样的问题也纠正了。
6 月 2 日 白天停电,
1、 晚上发现第一个玩家进入建筑物后,第二个玩家进入城市时在其客户端仍然显示第一个玩家,未隐藏。
原因:第二个玩家客户端收到第一个玩家OtheIn消息时,产生精灵时未判断其处于建筑物中而将其隐藏。
2、 改人物相互阻挡的算法
将玩家重叠定义为:玩家A的精灵中心坐标处于玩家B的精灵区域中。由于玩家精灵的大小一样,其实玩家B的精灵中心坐标处于玩家A的精灵区域中。
人物相互阻挡并不要求十分精确,有时会出现玩家重叠的情况。
多个玩家从建筑物中出来,均被显示在门口是,会重叠
多个玩家同时移向同,均被显示在门口是,会重叠
为此,将人物相互阻挡的算法改为:玩家A移动时
1如果玩家A和B在尝试移动前已经互相重叠,A尝试移动后不改变玩家的相对方向,而且A将远离B,则不阻挡,否则阻挡
2如果玩家A和B在尝试移动未互相重叠,A尝试移动后玩家B的中心不处于A移动扫过的区域中,则不阻挡,否则阻挡
改后,多个玩家从建筑物中出来可以移动,移动速度较快时也不出现穿过对方的现象
6 月 3 日
下午和黄良毅一起修改了CInitSet
晚由于客户端CSuperScene基本上只在mapManager中使用,于是将封装在CMapManager中。
将set目录下的精灵ini文件中的[up]fsp=*改成[up]fps=*
6 月 10 日
上午加入补给用完和水手死光后,玩家回到城市,完善了补给和水手同步
晚上加入一张海上地图,使之成为一个区域
注意:
1、 有些消息(OtherMove、OtherIn、OtherOut)是用于发送给其他玩家的,但由于在广播消息时没有考虑这一点,而是把消息发送给当前区域所有在地图中的人(建筑物中的玩家认为不在地图中),这样也会发送给自己。客户端收到自己的消息不进行处理,其他人的才处理。
2、 地图服务器通过OtherIn消息广播自己的进入之前,要把玩家的地图设为新地图。而客户端收到之后,要重新设置移动玩家的MoveOffset。
3、 地图服务器的ChangeMap已经没用到了,客户端的ChangeMap也只在OnAcrossMap中用一下,好像作用不大了
还有客户端的InitNewMap只是在登陆和进出港切换地图时用一下,InitNewAdjMap只是OnAcrossMap中与ChangeMap配合使用