两个月过去了,还有人关注超级玛丽的制作。正如郭老师所说,我很欣慰。我的代码中,注释很少。有的网友提醒我,没有注释的情况下,时间长了,自己也看不懂了。我认为代码的评价标准是:功能正确,扩展方便,结构清晰。为了感谢大家支持,我继续讲代码。现在我是公务员,工作很忙,讲解要慢一些。
今天开始讲逻辑层:struct ROLE
这个结构用来存储两种精灵:敌人(各种小怪)和子弹(攻击方式)。敌人包括两种蘑菇兵和两种火圈。子弹包括火球和旋风。游戏中,精灵的结构很简单:
struct ROLE
{
int x;//横坐标
int y;//纵坐标
int w;//图片宽度
int h;//图片高度
int id;//精灵id
int iframe;//图片当前帧
int iframemax;//图片最大帧数
//移动部分
int xleft;//水平运动的左界限
int xright;//水平运动的右界限
int movex;//水平运动的速度
//人物属性
int health;//精灵的生命值
int show; //精灵是否显示
};
游戏中的子弹处理非常简单,包括存储、生成、销毁。
子弹的存储:所有的子弹存储在一个数组中,如下:
struct ROLE FireArray[MAX_MAP_OBJECT];
其实,所有的动态元素都有从生成到销毁的过程。看一下子弹是怎样产生的。
首先,玩家按下z键:发出子弹,调用函数:
int GAMEMAP::KeyProc(int iKey)
case KEY_Z: //FIRE
if(iBeginFire)
break;
iTimeFire=0;
iBeginFire=1;
break;
这段代码的意思是:如果正在发子弹,代码结束。否则,设置iBeginFire为1,表示开始发子弹。
子弹是在哪里发出的呢?
思路:用一个函数不停地检测iBeginFire,如果它为1,则生成一个子弹。函数如下:
int GAMEMAP::CheckAni(int itimeclip)
发子弹的部分:
//发子弹
if(iBeginFire)
{
//发子弹的时间到了(连续两个子弹要间隔一定时间)
if(0 == iTimeFire )
{
//设置子弹属性: 可见, 动画起始帧:第0帧
FireArray[iFireNum].show=1;
FireArray[iFireNum].iframe = 0;
//子弹方向
//如果人物朝右
if(0==rmain.idirec)
{
//子弹向右
FireArray[iFireNum].movex=1;
}
else
{
//子弹向左
FireArray[iFireNum].movex=-1;
}
//区分攻击种类: 子弹,旋风
switch(iAttack)
{
//普通攻击: 子弹
case ATTACK_NORMAL:
//精灵ID: 子弹
FireArray[iFireNum].id=ID_ANI_FIRE;
//设置子弹坐标
FireArray[iFireNum].x=rmain.xpos;
FireArray[iFireNum].y=rmain.ypos;
//设置子弹宽高
FireArray[iFireNum].w=FIREW;
FireArray[iFireNum].h=FIREH;
//设置子弹速度: 方向向量乘以移动速度
FireArray[iFireNum].movex*=FIRE_SPEED;
break;
最后,移动数组的游标iFireNum.这个名字没起好, 应该写成cursor.游标表示当前往数组中存储元素的位置.
//移动数组游标
iFireNum=(iFireNum+1)%MAX_MAP_OBJECT;
至此, 游戏中已经生成了一个子弹. 由图像层,通过子弹的id,坐标在屏幕上绘制出来.
子弹已经显示在屏幕上, 接下来, 就是让它移动, 碰撞, 销毁. 且听下会分解.