2.4 走四方
人物虽然能移动了,可是只能在这个屋子里面也好像不是太好,从小我就是一个好动的孩子,所以我们游戏里面的主脚自然也不能是一个安静的人罗,我们要走出这片天地,到外面的世界去看看.
所以,我们要走四方,简单的说就是要能地图切换.我们就来解决地图切换的问题.在开始装载图片的小节里面,我们知道了如何装载图片,而且在那段程序里面我们加载了所有我们要用的图片资源,这里也包含不同的地图资源,所以,这里我们不用再加载一次了,我们可以直接进行地图切换了.
我们把地图切换写在刷新页面的函数里面.原理是,我们要在原图中设置一些坐标作为地图的切入点,一旦人物移动到我们提前设置好的位置,就把页面置换过去,换上新地图的指针.程序如下:
void refresh()
{
MakeRect(0,0,640,480);
lpDDSBuffer->BltFast(0,0,lpDDSOther,&r,NoKey);//始终显示buffer页面
man1.show();
if((man1.tx <= 330) && (man1.tx >= 310) && (man1.ty <= 460) && (man1.ty >= 430)) //到达这个坐标时进入城市
{
MakeRect(0,0,640,480);
lpDDSOther->BltFast(0,0,lpDDSOut,&r,NoKey);
lpDDSBuffer->Flip( NULL , DDFLIP_WAIT );
MakeRect(736,192);
lpDDSOther->BltFast(300,350,lpDDSSprite,&r,SrcKey);
MakeRect(736,480);
lpDDSOther->BltFast(370 ,150,lpDDSSprite,&r,SrcKey);
man1.tx=170;
man1.ty=50;
}
else if((man1.tx<=470) && (man1.tx>=450) && (man1.ty<=310) && (man1.ty>=290) ) //到达这个坐标时进入最后一个房间
{
MakeRect(0,0,640,480);
lpDDSOther->BltFast(0,0,lpDDSRoom,&r,NoKey);
lpDDSBuffer->Flip( NULL , DDFLIP_WAIT );
MakeRect(352,96);
lpDDSOther->BltFast(405 ,252,lpDDSSprite,&r,SrcKey);
man1.tx=100;
man1.ty=310;
}
else if((man1.tx<=70) && (man1.tx>=50) && (man1.ty<=450) && (man1.ty>=430) ) //到达这个坐标时进入游戏结束画面
{
MakeRect(0,0,639,479);
lpDDSOther->BltFast(0,0,lpDDSEnd,&r,NoKey);
lpDDSBuffer->Flip( NULL , DDFLIP_WAIT );
}
Flip();
}
完成上面的代码以后,我们的主脚就可以随心所欲的在这个我们为他创造的世界里面自由活动了.
2.5 我不想成为哑巴
除了走路以外,主脚总不能是个哑巴啊,至少我还没有看到过不能说话的游戏,哑巴怎么能完成我们交给他的人物嘛,而且,我们总要通过游戏向玩家传递一些信息嘛,所以说话或者说文字的输出那是一个必然的而且基础的功能.
下面我们来完成对话,还是先说原理吧:说白了,对话其实就是在Direct下输出文字,主脚和不同的NPC交互的输出文字,就形成了对话.
输出文字其实很简单, 为了向页面输出文字,我们首先要获得页面的HDC(设备描述句柄),然后调用Windows GDI 函数向页面输出文字。由于获得句柄后将不能使用DirectDraw函数改动页面,所以输出完文字后要立刻释放句柄。
HDC hdc;
if (lpDDSXXX->GetDC(&hdc) == DD_OK) //拿句柄
{
SetBkColor(hdc, RGB(0, 0, 255)); //设置文字背景色
SetTextColor(hdc, RGB(255, 255, 0)); //设置文字颜色
TextOut(hdc,100,400, text, strlen(text)); //句柄, 左上角X, 左上角Y,
//文字(char *), 文字长度
lpDDSXXX->ReleaseDC(hdc); //释放句柄
}
只要完成上面的功能就可以在页面输出文字了,在我的这个demo里面我把他封装在void man::say(char words[255])里面,于是只要调用这个函数就可以在页面输出文字.那么怎么和其他的NPC对话呢,那其实已经很简单了.我又写了个说话的函数,在里面进行的坐标的判断,通过不同的坐标达到和不同的NPC进行对话,不过这个办法并不科学,一般现在使用的方法是碰撞检测,由于碰撞检测又是一个很庞大的技术,所以这里不再累赘了,有兴趣的朋友可以找一些专业的游戏编程的书来看看.
下面我们罗列出部分,完整的程序你可以自己看我的demo.
void man::speak()
{
if ((man1.tx<=255)&&(man1.tx>=223)&&(man1.ty<=345)&&(man1.ty>=313))//当主脚在这个坐标触发消息的时候和这个NPC对话
{
switch(man1.i)
{
case 0: //通过case的递加来实现交互对话
MakeRect(672,320);
lpDDSOther->BltFast(50,400,lpDDSSprite,&r,SrcKey);
man1.say("小鸟:闷炮,你今天怎么米有去上课啊,外语老师又点名了呀.");
break;
case 1:
MakeRect(544,320);
lpDDSOther->BltFast(50,400,lpDDSSprite,&r,SrcKey);
man1.say("闷炮:去与不去都一样,反正他都是照着书念的,你去还不是没有听课啊");
break;
case 2:
MakeRect(672,320);
lpDDSOther->BltFast(50,400,lpDDSSprite,&r,SrcKey);
man1.say("小鸟:听说我们这个外语老师是个杀手哟,以前有很多兄弟都死在他手下的啊.");
break;
case 3:
MakeRect(544,320);
lpDDSOther->BltFast(50,400,lpDDSSprite,&r,SrcKey);
man1.say("闷炮:米有关系,考试要放的");
break;
case 4:
MakeRect(672,320);
lpDDSOther->BltFast(50,400,lpDDSSprite,&r,SrcKey);
man1.say("小鸟:不会哟,上学期就把老子杀了,靠!◎#¥%……×");
break;
case 5:
MakeRect(544,320);
lpDDSOther->BltFast(50,400,lpDDSSprite,&r,SrcKey);
man1.say("闷炮:那就是长相问题啦∶)");
break;
case 6: //每个NPC对话完以后要清空对话框,另外吧对话变量赋值为1,为了和其他的NPC对话的时候能从头开始
CleanDialog();
man1.i=0;
break;
}
}
一旦完成了对话,人物移动和地图切换,实际上就完成了一个demo需要的最最基本的要求,虽然一个游戏还包含很多东西,不过能这样已经可以做成一个有剧情的单线RPG了,呵呵,是不是觉得特有成就感啊,是啊,当时我能做的这种地步的时候也是觉得特别高兴,有点仙剑之父的意思(大言不惭,BS!).