记录时间:2009年11月24日
早期的技能系统设计在实现过程中首先发现了子弹模块的设计问题。
从技能系统的实现角度来看,子弹应该只是技能执行的一种扩展,本身不应该单独存在。否则加大了技能系统的制作难度,让逻辑变得分散。
当初考虑的原则是基于状态机。根据技能的表现,认为技能执行可以看成人物的一种行为状态。人物在技能执行时会中断掉其普通行为状态,在执行完技能后会回到普通行为状态。
这种设计的考虑是根据游戏内技能的表现来决定的,如果要求游戏中可以一边跑一边发技能,则前面的设计假设都不成立了。
如果将技能本身考虑为人物行为状态的一种延伸,则子弹的存在会影响这种设计的一致性。因为人物不可能要在执行完技能后等待子弹碰撞或者爆炸后才能回到普通行为状态。
因此一开始的设计将子弹作为一种独立的逻辑实体,技能只负责发射子弹,然后人物回到普通行为状态。子弹实体创建后独立的移动和更新,与发射者脱离关系。
这种设计从逻辑上看是合理的的,可以将一个技能的逻辑根据状态机的特性分拆,但在实际制作时发现由于逻辑分散,会导致实际制作人员思维混乱,并且难以发现BUG。设计需要简化。
换个角度来看待技能和子弹。实际上技能是分为近程和远程的,子弹只是远程技能的一种特性。技能要起作用,必然要有一个关键时间点,在该时间点上,技能可以产生伤害,附近Buff等。
近程技能的时间点是在技能执行的时间段内的,远程技能的时间点是在技能执行的时间段外的,因此如果将技能的效果提取成一种独立的操作,不依赖于某个技能或者子弹来执行,则可以通过
对时间的不同描述将近程和远程统一起来。
当然这种设计本身是有缺陷的,如果按照上面的设计,则子弹就变得和近程技能一样,是无法躲闪的。丧失掉了远程技能的设计多样性。
第一次设计的优化是从实现层面考虑的,考虑到子弹本身的逻辑对于每个远程技能来说没有太多的公用性,取消掉了子弹的单独脚本。子弹逻辑被整合到了技能脚本中。但子弹本身的设计并未被废除掉,在逻辑上子弹实体仍然与技能独立,远程技能的逻辑成为生成子弹,然后结束,此后子弹单独存在并更新。
例如一个远程技能被如下脚本实现:
--技能 阳关三叠
Skill_22100701 =
{
StageCount = 1,
Stage_0 =
{
KeyCount = 2,
Key_0 =
{
Time = 0.58;
Name = "attack"
};
stage_start = function(object,skillID)
SI:FaceToTarget(object,TARGET_LOCKED);
SI:PlayTargetAnimation(object,TARGET_ME,"阳关三叠");
SI:SetTargetMoveSpeed(object,TARGET_ME,0);
return RE_SKILL_SCRIPT_NORMAL;
end;
stage_update = function(object,time,skillID)
if(time > 0.8) then
return RE_SKILL_SCRIPT_END;
else
return RE_SKILL_SCRIPT_NORMAL;
end;
end;
stage_timer_callback = function(object,keyname,skillID)
if(keyname == "attack") then
SI:ShotBulletToTarget(object,TARGET_LOCKED,skillID,0,1,DT_HAND_L);
end;
end;
};
BulletCount = 1;
Bullet_0 =
{
bullet_explosive = function(object,bullet,touchedActorID,skillID)
SI:AttachSkillState(object,touchedActorID,32100701,10,0,0,0,0,0);
end;
}
};
这次设计优化只是减小了资源(脚本,表格)文件之间的关联性,并没有简化技能的实现逻辑,技能和子弹的设计仍然缺乏高度的一致性。