zoukankan      html  css  js  c++  java
  • 童晶老师的游戏开发课程作业--飞机大战的实现

    此作业的要求参见[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("
    ");
        }
        
        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("游戏结束!!!
    ");    
                            flag = 1;
                        }
                    }
                }
            }
        }
       
    }
    

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

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

    最终效果

  • 相关阅读:
    优化网站设计(一):减少请求数
    ASP.NET MVC 计划任务(不使用外接程序,.net内部机制实现)
    ASP.NET MVC 母版页
    ASP.NET MVC 系统过滤器、自定义过滤器
    大流量网站的底层系统架构分析
    如何开发高性能低成本的网站之技术选择
    使用Sqlserver事务发布实现数据同步(sql2008)_Mssq l数据库教程
    xpath路径表达式
    减负!云端编译构建,这样让你的开发省时省力……
    SVN如何迁移到Git?
  • 原文地址:https://www.cnblogs.com/ZigHello/p/14105642.html
Copyright © 2011-2022 走看看