4.3 封面物体位置信息设置
进入了1号剧情后,这时执行的剧情是任务提示标从左向右进入屏幕,提示标显示提示“请按下E键”。完成这两个任务涉及两方面的功能:任务标的移动、提示标文字设置和键盘按键状态检测。
任务标的移动可以看做是封面物体的移动,移动封面物体可以使用函数W3DSetFMModPos,函数原型如下所示。请注意本书后续章节中出现的位置、旋转和缩放信息的设置表示方法,都将采用如下定义形式。
函数定义 |
BOOL W3DSetFMModPos(DWORD dwModID, DWORD dwChangeMode, vec3 vTrans, vec4 vRot, vec3 vScl) |
功能描述 |
设置封面物体的位置信息。dwModID为封面物体序号ID。vTrans为位置参数,vRot为旋转参数,vScl为缩放参数。 dwChangeMode为设置位置的模式。 当为0时: 此封面物体的位置将立即被设置为vTrans所指定的位置(vTrans[0],vTrans[1],vTrans[2]分别指定x,y,z位置分量),此封面物体的旋转将由vRot指定(vRot[0],vRot[1],vRot[2],vRot[3]分别指定旋转的角度,旋转轴x分量,旋转轴y分量,旋转轴z分量),此封面物体的缩放将由vScl指定(vScl[0],vScl[1],vScl[2]分别指定x,y,z缩放分量)。 当为1时: vTrans为此封面物体的位置增量(最终位置为:当前位置x分量+vTrans[0],当前位置y分量+vTrans[1],当前位置z分量+vTrans[2]) vRot为此封面物体的旋转增量(最终旋转信息为:当前旋转角度+vRot[0],当前旋转轴x分量+vRot[1],当前旋转轴y分量+vRot[2],当前旋转轴z分量+vRot[3]) vScl为此封面物体的缩放增量(最终缩放为:当前缩放x分量+vScl[0],当前缩放y分量+vScl[1],当前缩放z分量+vScl[2]) |
返回值 |
函数执行成功为true,失败为false,调用W3DGetLastError了解更多错误信息 |
那么对于任务提示标从左向右进入屏幕,我们既可以使用dwChangeMode的0模式不断设置最终位置,也可以使用1模式仅仅给一个增量,让引擎自动累积最终位置从而实现移动。这里我们使用0模式即不断设置最终位置,此种方式也较好理解。首先在3dsmax中设置提示标所在初始位置(即提示标在屏幕最左侧的位置),然后设置我们希望提示标移动到屏幕中最终停止的位置,如下图所示,左边是初始位置在屏幕外,右侧为飞入屏幕内的位置。
图4.6 提示标飞入屏幕位置确定
记录下3dsmax中左侧和右侧的位置:左侧(-0.093,0.032,-0.11),右侧(-0.06,0.032,-0.11),在1号剧情中添加如下代码:
...
else if(dwStage == 1)
{
W3DSetFMModPos(1,
0,
vec3(-0.086,0.032,-0.11),//设置到屏幕外
vec4(0.0f,0.0f,0.0f,0.0f),//不旋转
vec3(1.0f,1.0f,1.0f));//正常缩放
dwStage = 2;
}
...
1号剧情使用0模式将提示标立即将提示标设置到了屏幕外、不旋转、正常缩放(注意当使用0模式时,如果不想改变缩放,必须设置缩放参数为(1.0,1.0,1.0),否则模型将扭曲或消失),随后立即进入2号剧情。
4.4 封面物体文字信息设置
在2号剧情中,我们需要将提示标中的文字改为“请按下E键”,可以使用函数W3DSetFMModWord完成,函数原型如下:
函数定义 |
BOOL W3DSetFMModWord(DWORD dwModID, BOOL bChangeWord, WCHAR* word, BOOL bChangeWordCol, float fWordR,float fWordG,float fWordB, BOOL bChangeWordTran, float fTranX,float fTranY,float fTranZ, BOOL bChangeWordRot, float fRotRa,float fRotX, float fRotY,float fRotZ, BOOL bChangeWordScale, float fSclX,float fSclY,float fSclZ) |
功能描述 |
设置封面物体的文字信息。dwModID为封面物体序号ID。 bChangeWord设置是否改变文字内容,设置为true则word有效。 word设置文字内容,unicode字符串形式。 bChangeWordCol设置是否改变文字颜色,设置为true则fWordR,fWordG,fWordB有效。 fWordR,fWordG,fWord设置文字的颜色红,绿,蓝分量,每一个分量取值范围为[0.0,1.0]。 bChangeWordTran设置是否改变文字的位置信息,fTranX、fTranY和fTranZ分别是x、y、z位置分量。 bChangeWordRot设置是否改变文字的旋转信息,fRotRa、fRotX、fRotY和fRotZ是旋转角度、旋转x轴分量、y轴分量、z轴分量。 bChangeWordScale设置是否改变文字的缩放信息,fSclX、fSclY和fSclZ是缩放x分量、y分量、z分量。 (文字位置、旋转、缩放信息含义见3.2节封面物体配置信息中相关描述) |
返回值 |
函数执行成功为true,失败为false,调用W3DGetLastError了解更多错误信息 |
添加2号剧情代码如下所示,首先设置文字内容为“请按下E键”同时将文字颜色设置为红色,位置不改变。代码最后进入3号剧情。
...
else if(dwStage == 2)
{
W3DSetFMModWord(1,
1,TEXT("请按下E键"),//改变文字内容
1,1.0f,0.0f,0.0f,//初始设置为红色
0,0,0,0,0,0,0,0,0,0,0,0,0);
dwStage = 3;
}
...
4.5 无阻塞延时方法
在进入3号剧情后,需要不断红白闪烁文字,同时文字缓慢飞入屏幕指定位置。闪烁文字需要间隔一个时间将文字颜色变换为红色和白色,如果间隔时间使用阻塞型函数,如sleep等函数,那么剧情线程将阻塞,无法执行飞入代码,因此我们需要无阻塞的延时方法。无阻塞的延时方法可以使用多种第三方库或自行编写,也可以使用引擎自带无阻塞延迟函数完成,函数原型如下:
函数定义 |
BOOL W3DEventDelay(BOOL bReset,DWORD dwIndex, DWORD dwTime) |
功能描述 |
无阻塞延时。dwIndex指定事件序号,引擎支持5000种事件的独立超时检查,因此可设置为0~4999。 dwTime设置此事件的超时时间(ms为单位)。 bReset重置此事件,那么将强制记录当前时间为开始时间。 |
返回值 |
当前时间超时则返回true,否则返回false |
当第一次调用此函数时,引擎将记录当前时间为此事件的开始时间并返回false。随后对此事件的函数调用将检测当前时间距离记录的上一次开始时间是否超过指定的超时时间,未超过则返回false,若超过返回true且记录当前时间为此事件的当前时间。当重置此事件后,将结束此事件的无阻塞延时内部事件记录并重置内部参数并返回true,即相当于清除了此事件的超时时间,下次对此事件的函数调用可以像第一次调用那样设置新的超时时间。
那么使用这样的无阻塞延迟函数,我们可以完成不阻塞其他代码的延时。在3号剧情中添加如下代码。代码中使用0号事件,延时100ms将颜色设置变量反转一次,然后调用W3DSetFMModWord只设置文字颜色。
...
else if(dwStage == 3)
{
static bool _ys=0;
if(W3DEventDelay(0,0,100))
{
_ys = !_ys;
}
if(_ys)
{
W3DSetFMModWord(1,
0,0,
1,1.0f,0.0f,0.0f,//设置为红色
0,0,0,0,0,0,0,0,0,0,0,0,0);
}
else
{
W3DSetFMModWord(1,
0,0,
1,1.0f,0.0f,0.0f,//设置为白色
0,0,0,0,0,0,0,0,0,0,0,0,0);
}
}
...
4.6 封面物体飞入动画实现
封面物体的文字闪烁开始后,我们让封面物体从屏幕外飞入屏幕内指定位置,即从左侧(-0.093,0.032,-0.11)移动到右侧(-0.06,0.032,-0.11)。在剧情3中继续添加代码如下所示:
...
//提示标慢慢进入屏幕指定位置
static float _cswz=-0.093f;
W3DSetFMModPos(1,
0,
vec3(_cswz,0.032,-0.11),
vec4(0.0f,0.0f,0.0f,0.0f),
vec3(1.0f,1.0f,1.0f));
//位置自增
_cswz+=0.0005f;
//到指定位置
if(_cswz >= -0.06f)
{
W3DSetFMModWord(1,
0,0,
1,1.0f,0.0f,0.0f,//设置为红色
0,0,0,0,0,0,0,0,0,0,0,0,0);
dwStage = 4;
}
...
代码不断调用W3DSetFMModPos设置提示标位置,读者可以修改参数实现不同速度的飞入效果,当到达指定位置后,将提示标文字颜色设置为红色,同时进入4号剧情。
4.7 场景物体移动开发方法
进入4号剧情后,等待用户按下’E’键,按钮消失,这时从地面下方升上来一个圆盘拖着玩家上升到一个高台,在上升过程中地面不断震动。
对按键的检测,可以使用函数W3DGetSingleKeyInfo完成(2.5.4节中描述了函数原型),在4号剧情中添加代码如下:
...
else if(dwStage == 4)
{
bool _eResult;
//获得E键的状态
W3DGetSingleKeyInfo('E',&_eResult);
//如果按下
if(_eResult)
{
//...
}
}
...
检测到按下E键后,让按钮消失。让按钮消失可以用两种方法实现:按钮模型不绘制和按钮模型隐藏。模型不绘制与隐藏有一定的区别:
按钮模型不绘制:引擎不会为此模型分配渲染和物理资源,系统开销最小。
按钮模型隐藏:引擎会为此模型分配物理和其他资源,只是最终不进行图像渲染,有一定系统资源开销。
设置一个场景物体或PT物体是否绘制可以使用函数W3DSetSceneModShow或W3DSetPTModShow,函数原型如下:
函数定义 |
BOOL W3DSetSceneModShow(DWORD dwModID,DWORD dwMode) |
功能描述 |
设置场景物体显示状态。dwModID指定场景物体序号ID。dwMode设置此物体的显示状态,true为绘制,false为不绘制。 |
返回值 |
函数执行成功为true,失败为false,调用W3DGetLastError了解更多错误信息 |
函数定义 |
BOOL W3DSetPTModShow(DWORD dwModID,DWORD dwMode) |
功能描述 |
设置PT物体显示状态。dwModID指定PT物体序号ID。dwMode设置此物体的显示状态,true为绘制,false为不绘制。 |
返回值 |
函数执行成功为true,失败为false,调用W3DGetLastError了解更多错误信息 |
设置一个场景物体或PT物体是否隐藏可以使用函数W3DSetSceneModHide或W3DSetPTModHide,函数原型如下:
函数定义 |
BOOL W3DSetSceneModHide(DWORD dwModID,DWORD dwMode) |
功能描述 |
设置场景物体隐藏状态。dwModID指定场景物体序号ID。dwMode设置此物体的隐藏状态,true为隐藏,false为不隐藏。 |
返回值 |
函数执行成功为true,失败为false,调用W3DGetLastError了解更多错误信息 |
函数定义 |
BOOL W3DSetPTModHide(DWORD dwModID,DWORD dwMode) |
功能描述 |
设置PT物体隐藏状态。dwModID指定PT物体序号ID。dwMode设置此物体的隐藏状态,true为隐藏,false为不隐藏。 |
返回值 |
函数执行成功为true,失败为false,调用W3DGetLastError了解更多错误信息 |
因为此按钮仅显示一个模型,不进行物理运算,因此我们不绘制此按钮模型。添加代码如下所示,按下E键后不绘制2号场景物体(即为按钮物体),完成后进行5号剧情。
...
//如果按下
if(_eResult)
{
W3DSetSceneModShow(2,0);
dwStage = 5;
}
...
在5号剧情中,开始将地面下方的圆盘升上来拖着玩家上升到一个高台,同时地面震动。一个物体托着或推着一个物体移动,一般可以采用动画或物理运算方法。
动画方法:实时计算两个物体的距离,当距离为接触时,一个物体跟着另一个物体移动,这种方法程序实现比较复杂,且移动灵活性低、效果不自然。
物理运算方法:将两个物体设置为刚性物体物体,一个物理物体对另一个物体物体的碰撞、挤压等作用所发生的形变、位置移动由物理引擎实时计算。这种方法对游戏开发者来说较为简单,且移动灵活性高、效果更好。
这里我们使用物理运算方法实现。玩家包络已经是动态物理物体,那么我们只需要将此圆盘模型也设置为物理物体即可,但设置为静态还是动态物理物体?由于在此游戏中,我们可以认为此圆台的托举是对于玩家是个不可抗力,即玩家的力量无法让圆台发生位置改变,那么我们可以将此圆台设置为一个静态物理模型。制作圆台与高台模型如下图所示:
图4.7 圆台高台在场景中的位置
圆台和高台模型需要分别抬起和支撑玩家物体模型,因此这两个模型都需要设置为物理模型,然而这两个模型并不是闭合多边形因此无法进行正确的物理运算(2.1.1节有说明),所以我们需要为这两个模型独立制作碰撞包络,图4.8中绿色和蓝色模型分别是圆台与高台的包络模型,这里我们仅仅简单地包裹住模型,并没有更细节的表面处理,如果需要更精准细腻的物理处理,需要制作更细节的包络模型,但也会带来更长的物理运算时间。
图4.8 为圆台高台制作简单包络模型
在[SceneMod1]中添加场景信息,加入这几个模型,添加的配置信息如下所示,添加了圆台模型(3号场景物体),圆台包络(4号场景物体),高台包含两个模型(5号和6号场景物体),高台包络(7号场景物体)。
...
//圆台模型
3mod_lv1=model\LearnW3D\Chapter1\yuantai.obj
3tex=model\LearnW3D\Chapter1\yuantai.bmp
3mtl=model\LearnW3D\Chapter1\yuantai.mtl
3GenShadow=0
//圆台包络
4mod_lv1=model\LearnW3D\Chapter1\yuantaiBL.obj
4tex=model\LearnW3D\Chapter1\BAOLUO.bmp
4mtl=model\LearnW3D\Chapter1\BAOLUO.mtl
4DisableLight=1
4HideMod=1
4GenShadow=0
4StaticPhyMod=1
//高台组件1模型
5mod_lv1=model\LearnW3D\Chapter1\gaotai1.obj
5tex=model\LearnW3D\Chapter1\gaotai1.bmp
5mtl=model\LearnW3D\Chapter1\gaotai1.mtl
5GenShadow=0
//高台组件2模型
6mod_lv1=model\LearnW3D\Chapter1\gaotai2.obj
6tex=model\LearnW3D\Chapter1\gaotai2.bmp
6mtl=model\LearnW3D\Chapter1\gaotai2.mtl
6GenShadow=0
//高台包络
7mod_lv1=model\LearnW3D\Chapter1\gaotaiBL.obj
7tex=model\LearnW3D\Chapter1\BAOLUO.bmp
7mtl=model\LearnW3D\Chapter1\BAOLUO.mtl
7DisableLight=1
7HideMod=1
7GenShadow=0
7StaticPhyMod=1
//总场景物体数量
num = 7
...
运行后检查场景配置是否正确,游戏画面截图如4.9所示:
图4.9 圆台高台添加后的游戏运行测试
学习资料下载:
通过网盘分享的文件:W3D引擎游戏开发学习资料
链接: https://pan.baidu.com/s/1Wrs6uWqwOr8Wk-ImNa8Fvg?pwd=1234 提取码: 1234
公众号:W3D引擎