在拥有scope的武器的xml中,我们必须定义下面的标签(Tag)
<accessories> ... </accessories>
在上述的标签中,最重要的是下面这个子标签
<accessory name = "LAWScope">
<attach helper = "scope_term" layer = "">
<detach />
</accessory>
这个子标签定义了LAWScope(用作火箭筒上的瞄准镜)的位置信息,属性helper是个火箭筒的模型上的位置标记,通过这个标记,LAWScope可以跟火箭筒很好的组合成一个整体。
这个标记在标签<geometry>中可以看到,下面的<geometry>会讲述这个地方。
--
在游戏中,有scope的武器可以通过相应的键控制进入瞄准镜瞄准(注意这里后面的瞄准是动词)状态,在XML中,有相应的标签用来提供可配置的数据,该标签为
<zoommode name="Scope" type="Scope">
<zoom>
<param name="zoom_in_time" value=5>
<param name="zoom_out_time" value=0.2>
<param name="scope_offset" value="1, 1, 1">
</zoom>
<scope>
<param name="scope" value="scope">
</scope>
</zoommode>
上面标签的param参数中, zoom_in_time定义了开镜是镜头推进的速度,这个值越大,那么看到的镜头到位的动画就越慢(调试某些功能的时候可以用)。相反,Zoom_out_time定义了镜头收回的速度。
Scope_offset是一个很重要的值,它定义了在开镜后,最后游戏镜头要到达的最终的相对位置,这个相对位置是相对于武器模型的世界位置的。
在武器的XML中,标签<geometry>用来指定武器在各种状态下用到的模型,这里的状态指第一人称、第三人称模式。下面是一个例子:
<geometry>
<firstperson name="Objects/Weapons/Binoculars/binoculars_fp.chr"/>
<thirdperson name="Objects/Weapons/Binoculars/binoculars_tp.cgf"/>
</geometry>
上述的<firstperson>、<thirdperson>属性,分别对应于第一人称、第三人称下面的使用模型。这里必须指出的是,在第一人称下的模型跟第三人称下看到的一般是不一样的。这样做的是为了突出武器在第一人称下的效果。
<geometry>
<boneAttachment>
<attachment target="firstperson" name="scope_term" bone="scope_term" />
</boneAttachment>
</geometry>
这个<boneAttachment>中 name="scope_term"会把我们上面提到的<accessory>中的"scope_term"链接起来,这样在第一人称下面,accessory就能通过<accessory>中的helper跟该武器绑定。
--
在游戏中,开镜后的效果可以分成几段来讲,
首先,中心的圆框和十字准心,这个是通过HUD来实现,也就是2D的画面;
然后,我们能看到的火箭筒的圆筒,就是把相机放到火箭筒的scope的一端,往前看的效果。如果要看清楚这个过程,可以把上面讲过的zoom_in_time修改成大一点的数值,这样游戏镜头会有一个慢速推进的过程,我们就可以看到游戏镜头慢慢推向瞄准镜,最后到达我们最终看到的位置的整个过程。
最后的也是最复杂的部分,是瞄准的整个过程。这里做相应的讲述,
1,当我们拿了火箭筒在手上,然后按下鼠标右键。在CPlayerInput::OnAction()中,会得到"zoom"消息,OnAction()中会呼叫一定的函数,导致CWeapon::OnActionZoom()被调用。
CWeapon::OnActionZoom()中,会调用自己的CWeapon::StartZoom(),这里会判断该武器是否有Scope,有的话就会通过m_zm来调用m_zm的StartZoom()。
这里需要说明的是,m_zoom这里是一个CScope的实例,而CScope是一个CIronSight(额~,这里的意思是前者继承后者,如果你熟悉C++,你知道是一个意思)。
因为CScope并没有重载StartZoom()方法,因此CIronSight的StartZoom()方法被调用。
CIronSight::StartZoom(),开始就激活几个效果融合效果,然后调用EnterZoom(),这里要特别提到的是,送给EnterZoom()的参数中,有zoom_in_time。在整个引擎的初始化过程中,这个值就被相关的代码从XML读取兵放置到相关的变量中供读取。因此,在EnterZoom()中,主要的工作就在于把整个zoom过程的值都读取到位(当然有其他的工作需要做,但是我们这里只关心跟zoom in相关的)。
然后,在CScope::OnZoomStep()中,我们就可以看到每一帧对zoom过程的更新,这个关键值就是我们刚才提到的zoom_in_time,每一帧都会把这个值对比已经逝去的时间,来决定是否整个zoom过程是否结束。当然,每一帧镜头步进的方向,都是根据zoom_in_time和已经消逝的时间的比值,来乘以初始的方向值决定。这个方向值在上面的XML中有提到。