1, 测试优先! 先确定需求和测试, 再考虑目标怎么开发. 故先搭建GM环境出来.
2,关于服务器的次序问题: 可以有一个公立机构专门负责提供所有相关的全局对象. 至于这些全局对象的出现,由于产生方式多种多样(例如是框架自动附带的,自已new的等), 则不必统一. 反正不用管怎么来的(那是公立机构内部负责的事), 使用者只管可以从公立机构获得即可.
3 技能就是new一个定时器对象挂载到玩家实例上去.
4 接下来实现各类定时器.
5 再接下来实现各种技能的定时器配置绑定.
6
new 和 factory 的关系:
方案1:new里面用factory指针把this加进去, delete同理.
方案2:factory提供create接口把new行为和绑定封装进行。
方案1, 弱关联,new什么新类型不用去修改factory的接口。
方案2, 为优化统一提供了空间。 因为全部的new都是内部的, 所以优化是可控制的。 例如说死了怪, 不直接进行delete,而是把它放进缓存区, 用时再拿出来赋值。 这样就避免了不断开辟和解放内存的问题。
7 一个不错的网址 http://www.ha97.com/3524.html
8 突然想到一个事, 能不能通过遗传算法的过程, 逆推个体的适应度.
9, 断线重连问题的一些想法:
(1),检测是网络波动造成的, 还是真断线造成的。 这个可以通过“UDP心跳”检测。 这个很成熟了, 不多说。
(2), 对于假掉线行为的, 或许可以这样。 由服务器端通过已记录的IP,主动发起链接,客户端做监听。
原因: 避开了玩家重连时, 对服务器的监听处理的压力。
10 对于网游角色类的设计:
个人认为或分类:
(1), 第一代: 弄一个无所不包的巨大的角色类, 然后加上一些特殊标志:例如英雄, 门, 商店等标识, 然后针对一些不同类会有的不同处理, 采用这些标志符进行区别处理。(VS的三国就是这样实现的)。
(2), 第二代: 弄一个通用角色基类, 然后派生不同的角色子类,例如:NPC类, Monster类, 玩家类。(QQ华夏就是这样做滴)。
(3), 第三代:
个人设计的, 不晓得市面上有没有人这么做了。 但是我觉得我的设计结合上了上面两种的优点, 而且更灵活, 更简洁, 所以是第三代设计:
服务系统不再承包角色类的设计和实现,系统只提供角色的ID。 角色的相关部件外包到应用层插件去实现。没有什么角色类的概念了, 角色对象的各种属性通过角色ID和各种应用层插件属性管理器, 动态组合在一起。
好处: 由于系统层不再承包角色类,而只负责角色ID(可能还会附带一些各插件沟通的但又无法归属于插件的共享数据), 所以逻辑更简洁优雅。角色的枝节属性“外包”出去, 扩展更灵活。
坏处: 局部处理更清晰, 但是总体处理则隐晦曲折了。 由于具体属性外包出去, 只留一个ID通用, 在使用时多了通过ID查询相关插件的成本(不过这个成本可以通过建立被动更新缓存解决 )。
11 技能代码:
void SpellEff(int level, GameUnitHandle Caster, GameUnitHandle Target, const Location* TargetLoc)
{
//技能响应声音特效:针对某听众,播放声音
PlaySoundTarget(Target->getEntity(),"liuxinghuxian",0.11);
if (!Target->CheckSpellBlock())
{
//技能响应画面特效
DestroyEntity(CreateEntityTarget(TheScene, "daqiao_liuxinghuxian", Target->getEntity(),"Bip01"));
//蓝伤害
Target->AddMana(-GetData(2));
//如果目标是英雄
if (Target->getWidgetType() == WT_HERO)
{
//技能提示
UIShowChatTips(TheUI, Target->getPlayer(), Caster->getName(), "流星忽现", HAA_ATTACK, "晕眩", "无法进行动作");
}
//技能伤害
UnitDamageUnit(Caster, Target, GetData(1), ATTACK_TYPE_SPELL, DAMAGE_TYPE_MAGIC);
if(!Target->IsDead())
{
//加角色状态
StunUnit(Target, GetData(3) * 1000);
}
}
}
12 在对STL的结构进行循环时,例如for( ..., map_XX.end() != it; ) , 要注意先移移动指定到下位,再处理当前指针的问题。 在处理问题是要注意, 如果处理功能是回调, 则本循环项不要再有任务何后绪处理理操作,如不是, 则全部在此项完成。 因为你不知道你的操作是否和回调操作冲突, 例如回调删除了当前项, 你后续处理又删了一次。
13 对于关联容器来说,如果某一个元素已经被删除,那么其对应的迭代器就失效了,不应该再被使用;否则会导致程序无定义的行为。
14 有不少代码的角色构造是通过pContext和len直接从数据库读出一段buf,然后通过memcpy的方样把buf挎到一个指针地址上,然后强制转换指针以使用。不好的地方在于,这里是初始化的, 不应和数据库的格式有何挂勾,在数据库和角色之间, 应另有一个转换层。
15
角色类的实现有两种方案:
(1),提供部件类。 部件以共同的基类指针保存在角色宿主的容器里, 宿主通过容器的相关标示(例如枚举)找到相应的部件指针,再通过强制转换以正确使用其功能。直接调用。
(2),提供消息机和监听类。 角色宿主提供一个消息机, 各部件以相应的监听者类挂载到角色有的消息机上。消息。
判决: 消息和直接调用的最大区别是, 消息是发起者和接收者是弱藕合的关系, 直接调用则是强藕合。宿主是可以没必要理解部件是什么东西啊, 一切让部件去自治即可, 但实际情况,有很多需求需要对各部件进行一系统协作式的有序操作, 如果是直接调用, 则外部模块对部件可以进行“外科手术式”的操作, 有利于复用并快速动态组合相关功能,并且过程可控局部化。 如果一切都用监听者去做, 则复用性下降,同时过程繁杂且不可控。 所以, 当需组织多个部件进行组合功能时, 用直接调用这种了解各模块的用途会方便很多。综上所述, 角色类将采用部件类的作法。
#pragma once
struct IUnit{};
template< class _ID_TYPE >
class IUnitPart
{
public:
typedef _ID_TYPE ID_TYPE;
IUnitPart( IUnit* _p_master ):m_p_master(_p_master){}
virtual ~IUnitPart(){ m_p_master = NULL; }
//取得本身生物
IUnit* get_master(){ return m_p_master; }
//初始化
virtual bool init( void* _p_par ) = 0;
//反初始化
virtual void uninit() = 0;
//取得部件类型
virtual long get_part_type() = 0;
//更新客户端
virtual void update_client( ID_TYPE _uid ) = 0;
//冻结本部件
virtual void freeze() = 0;
//解冻本部件
virtual void unfreeze() = 0;
protected:
IUnit* m_p_master;
};
struct Unit_Part
{
enum SIGN
{
SKILL_PREPARE = 1,
};
};
16
在释放操作上, 宜定义两种方式:
1, Delete, 用于删除资源。
2, Release,用于删除关联(与资源的关联)。
以windows为例,获取和解放CD有两种方式:GetDC和ReleaseDC, CreateDC和DeleteDC. 从windows的功能来看, delete是用于删除资源。 release是用于删除关联的(与资源的关联), 例如获得系统CD,得用getDC,因为它没法对系统层的东西做create和delete操作的。
17
李开复:【领导力】真正的领导力不是看你多有激情、魄力,而是看你是否有多元、均衡的能力。九种最重要的领导力:1.愿景比管控更重要;2.信念比指标更重要;3.人才比战略更重要;4.团队比个人更重要;5.授权比命令更重要;6.平等比权威更重要;7.均衡比魄力更重要;8.理智比激情更重要;9.真诚比体面更重要
18
刚刚看一篇文, 说得有意思。 当时数学界在推理和计算上很有限, 因为只有0才可以匆略不计。 所以牛顿和那个什么来的,大胆的发挥创造性思想, 推出无穷小的概念。从而突破问题细节,搞出了微积分。
印证了一句话: 上帝说要有光, 于是便有了光。
19
消息机采用了职责链和命令模式.
20
求两个数的最大公约数.
大, 小, 余
大, 小, 余
....
大, 小, 0
return 小.
//最大公约数
int get_gcd( int _x, int _y )
{
struct gct
{
//辗转相除法
int operator()( int _x, int _y, int _l)
{
if( 0 == _l) return _y;
else return gct()(_y, _l, _y%_l);
}
};
int max_v = (_x > _y) ? _x : _y;
int min_v = (_x < _y) ? _x : _y;
return gct()(max_v, min_v, max_v%min_v);
}
//最小公倍数
int get_lcm( int _x, int _y )
{
return (_x*_y)/get_gcd(_x, _y);
}
21, 消息机其实是观察者模式和职责任链模式的结合. 观察者模是被观察者通过一个轻量级的触发让观察者来处理被观察者.