童晶老师的游戏开发课程作业--飞机大战的实现

此作业的要求参见[https://edu.cnblogs.com/campus/nenu/2020Fall/homework/11577]

作业要求

  1. 课程网址 [https://www.icourse163.org/course/HHU-1206797807]
  2. 项目名称及分值
游戏名称 满分分值 功能点提示
飞机大战 50 移动飞机、发射子弹、敌机移动、消灭敌机、被敌机撞击、存档读档
  1. 作业提交要求
    除代码及git以外,要求 WBS、PSP,要求使用博客报告完成的功能和截图,讲解
    关键技术和代码片断。其中WBS要求包括不限于每个子任务的工时估算时间和实
    际耗时,精确到分钟。子任务可以包括分析、设计、代码、测试、调试、文档,
    鼓励精确到二级子任务如功能点等。

项目git地址
https://github.com/ZigHello/learngit/tree/master/%E9%A3%9E%E6%9C%BA%E5%A4%A7%E6%88%98

项目PSP

类型 任务 开始时间 结束时间 中断时间(分钟) delta时间(分钟)
分析 技术原型、函数设计 12.07 8:07 12.07 9:23 0 76
编程 实现英雄机能按键移动 12.07 9:51 12.07 10:16 0 25
编程 实现子弹的移动 12.07 10:20 12.07 11:03 0 43
编程 实现敌机的移动 12.07 11:03 11.29 11:26 0 23
编程 实现子弹击中敌机 12.07 11:30 11.29 12:18 0 48
编程 实现得分的变化 12.08 14:00 12.08 14:14 0 14
编程 实现多发子弹 12.08 14:14 12.08 15:38 0 84
编程 实现多个敌机 12.08 15:40 12.08 16:54 0 74
编程 英雄机与敌机碰撞 12.08 18:14 12.08 19:23 0 69
博客 技术文档说明 12.08 20:30 12.08 22:11 0 101
总耗时 0 559min
项目WBS
任务类型 估计时间 实际用时
---- ---- ----
技术原型、函数设计 45min 76min
消息循环 25min 15min
获取按键消息 30min 25min
对象移动 90min 56min
随机数生成 10min 20min
碰撞检测 90min 117min
边界控制 30min 67min
关键技术
  • 功能:移动飞机、发射子弹、敌机移动、消灭敌机、被敌机撞击
  • 对象分析:
  1. 我机:绘制->按键控制移动->被敌机击中,游戏结束
  2. 子弹:绘制->按键控制子弹发射->子弹上移
  3. 敌机:绘制->敌机下移->子弹击中,敌机消失
  • 技术原型:
  1. 界面绘制
  2. 获取按键消息
  3. 对象移动
  4. 随机数生成
  5. 碰撞检测
  6. 边界控制
  • 函数设计:
    绘图函数: show()
    功能:游戏界面定义为一个二维数组,定义数组值为0时,绘制空格;数组值为1时,绘制我机;数组为2时,绘制子弹;数组为3时,绘制敌机。
    数据初始化函数:dataInit()
    功能:游戏开始,初始化我机、敌机位置。
    获取用户的按键消息函数:getUserInput()
    功能:获取用户的按键消息,改变我机的坐标位置及控制子弹是否发射。
    子弹上移函数:updateBullet()
    功能:子弹上移,改变子弹坐标。子弹超出边界,坐标置零。
    敌机下移函数:updateEnemy()
    功能:敌机下移,改变敌机坐标。敌机超出边界,分数--。
    碰撞函数:hitEnemy()
    功能:如果子弹击中敌机,分数++。原始敌机消失,子弹消失,同时生成新的敌机。
    如果敌机与我机相撞,游戏结束。
    游戏退出函数:gameOver()
    功能:退出游戏。
    采用二维数组的方式绘制界面,规定0画空格,1画我机,2画子弹,3画敌机
void show()   //界面显示
{
    gotoxy(0, 0);  //重绘
    int i, j;
    for (i = 0; i < High; i++)
    {
        for (j = 0; j < Width; j++)
        {
            if (flag == 1)
                break;
            else if (game[i][j] == 1)  //绘制飞机
                printf("*");  
            else if (game[i][j] == 2)  //绘制子弹
                printf("|");  //输出子弹
            else if (game[i][j] == 3)    //绘制敌机
                printf("@");
            else if ((j == Width - 1) || (i == High - 1) || (j == 0) || (i == 0)) //绘制边界 
                printf("-");
            else
                printf(" ");  //输出空格
        }
        printf("\n");
    }
    
    printf("得分:%d",score);
};

通过kbhit()函数获取按键消息,从而控制英雄级的移动及子弹的发射状况。

void getUserInput() // 与用户输入有关的更新
{
    char input;
    if(_kbhit()) //当按键时
    {
        input = _getch();
        if ((input == 'a') && position_y > 1)
        {
            game[position_x][position_y] = 0;
            position_y--;
            game[position_x][position_y] = 1;
        }
        if ((input == 'd') && position_y < Width - 2)
        {
            game[position_x][position_y] = 0;
            position_y++;
            game[position_x][position_y] = 1;
        }
        if ((input == 'w') && position_x > 1)
        {
            game[position_x][position_y] = 0;
            position_x--;  
            game[position_x][position_y] = 1;
        }
        if ((input == 's') && position_x < High - 2)
        {
            game[position_x][position_y] = 0;
            position_x++;
            game[position_x][position_y] = 1;
        }
        if (input == ' ')
        {
            bullet_x = position_x - 1;
            game[bullet_x][x] = 2;
     
        }
    }
};

更新敌机及子弹的位置,需要先将子弹原始位置的数组值置为0,再改变子弹纵坐标位置后,数组值置为2。敌机位置的改变原理同子弹一致。

void updateBullet()   //更新子弹位置
{
    int i, j;
    for (i = 0; i < High - 1; i++)
    {
        for (j = 0; j < Width - 1; j++)
        {
            if (game[i][j] == 2)
            {
                game[i][j] = 0;
                if (i > 0)
                {
                    i--;
                    game[i][j] = 2;
                }
            }
        }
    }
};

子弹与敌机的碰撞检测做的较简单,循环遍历整个数组,如果当前位置的数组值为2,则表示此处为子弹,再判断该位置的坐标与敌机坐标是否相同,相同则表示击中敌机,分数加1。与此同时子弹与敌机均消失,然后生成新的敌机。下面给出的代码是多台敌机的碰撞检测情况。
同理,如果当前位置的数组值为1,表示英雄机在此处,判断敌机坐标是否与英雄机坐标相同,相同则游戏结束。

void hitEnemy() 
{
    int i, j, k;
    for (i = 0; i < High - 1; i++)
    {
        for (j = 0; j < Width - 1; j++)
        {
            if (game[i][j] == 2)     //子弹击中敌机
            {
                for (k = 0; k < EnemyNum; k++) 
                {
                    if ((i == enemy_x[k]) && (j == enemy_y[k]))
                    {
                        score++;            //击中加分
                        if (score % 5 == 0) //子弹变厉害
                            BulletWidth++;
                        game[enemy_x[k]][enemy_y[k]] = 0;
                        enemy_x[k] = rand()%2;      //产生新的敌机
                        enemy_y[k] = 2 + rand() % Width - 2;
                        game[enemy_x[k]][enemy_y[k]] = 3;
                        game[i][j] = 0;  //子弹消失
                        
                    }
                }
            }
            if (game[i][j] == 1)    //我机与敌机相撞
            {
                for (k = 0; k < EnemyNum; k++)
                {
                    if ((i == enemy_x[k]) && (j == enemy_y[k]))
                    {
                        printf("游戏结束!!!\n");    
                        flag = 1;
                    }
                }
            }
        }
    }
   
}

采用了while循环来重绘页面,为了控制页面的重绘光标的闪动,引入了HideCursor()函数来隐藏光标。

//隐藏光标函数
void HideCursor()
{
    CONSOLE_CURSOR_INFO cursor_info = { 1,0 };//第二个值为0表示隐藏光标
    SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursor_info);
}

最终效果

posted @ 2020-12-08 22:20  张宵  阅读(267)  评论(0编辑  收藏  举报