mooc游戏设计基础(自学)10

mooc自学网址:
https://www.icourse163.org/learn/CUC-1450328379?tid=1450742649#/learn/content?type=detail&id=1216695336&sm=1(源自中国传媒大学韩红雷老师的课程和他出版的书籍《《游戏开发程序设计基础》》)

第十章

   本次要做的是对前一个坦克大战进行改进,主要采用的是引入外部文件的机制,包括属性修改文件、地图文件、图片文件等等。引入能进行属性修改的INI文件能使参数设置放在外部,而不用在程序中进行修改;地图文件则是用矩阵形式建立地图,1表示障碍物而0表示空地;图片文件能使游戏更加美观,包括背景、障碍物、敌人坦克、玩家坦克以及炮弹发射分别的四个方向。

在这里插入图片描述
(1)先在原tank的程序文件夹中创建一个“resources”文件夹,并在其中添加参数修改文件(格式为INI)、地图文件(格式为txt)以及各种位图文件(格式为bmp):
在这里插入图片描述在这里插入图片描述
(2)在原来代码的基础上进行修改,主要是加了障碍物和外部文件的使用,下面只对有做修改的部分进行说明:

enum Dir{UP,DOWN,LEFT,RIGHT,NONE};     //增加一个静止的方向变量,因为障碍物实体始终处于静止状态
typedef struct{
    int x,y;
    int v;
    int s;
    int b;
    int p;
    int e;
    HBITMAP a[4];           //将原来的颜色属性改成图片属性,每个实体都存有四个视角的图片
};
HBITMAP tank[4],tank2[4],tank3[4],bulletPic[4],grass,background;      //用于存放每一个位图          
#define MAX_GRASS 64              //表示场景中最多障碍物的数量
int nGrass                        //先定义障碍物的数量为0,方便后期修改
Entity grasses[MAX_GRASS];        //创建障碍物数组
void ResetPlayer()                          //重置玩家信息中将原来的颜色设置改成图片
{
    memcpy(player.a,tank1,4*sizeof*(Dir));  //外部文件tank1保存给player.a使用,包括四个方向    
}  
void ReadIni()            //将INI属性文件的相关值读入程序变量中,使用的函数是GetPrivateProfileInt,其参数是(所读区域,读取项,输入变量,文件路径)
{
   timeStep = GetPrivateProfileInt(L"Global", L"timeStep", timeStep, L"Resources\\Init.ini");
    sz = GetPrivateProfileInt(L"Enemy", L"size", sz, L"Resources\\Init.ini");
    velf = GetPrivateProfileInt(L"Enemy", L"velf", velf, L"Resources\\Init.ini");
    vels = GetPrivateProfileInt(L"Enemy", L"vels", vels, L"Resources\\Init.ini");
    enemyFirePer = GetPrivateProfileInt(L"Enemy", L"firePer", enemyFirePer, L"Resources\\Init,ini");
    enemyDir = GetPrivateProfileInt(L"Enemy", L"dirPer", enemyDir, L"resources\\Init.ini");
    nLife = GetPrivateProfileInt(L"Player", L"nLife", nLife, L"Resources\\Init.ini");
    szb = GetPrivateProfileInt(L"Bullet", L"size", szb, L"Resources\\Init.ini");
    velb = GetPrivateProfileInt(L"Bullet", L"vel", velb, L"Resources\\Init.ini");
}
void InitMap()
{
    FILE*f;
    fopen_s(&f,"Resouces\\Map.txt","r");          //打开TXT文件
    if(f==NULL)
        return;
    char line[MAX_GRASS];                         //用于临时存放每行读到的信息
    int nLine=0;                                  //代表当前读取到第几行
    while(!feof(f)){                              //如果没有达到文件结尾
        fgets(line,MAX_GRASS,f);                  //读取一整行到line中
        for(int i=0;line[i]!='\0';i++){          //对一行中的每个字符进行读取,当出现1的时候,表示此处有障碍物,将此处的坐标进行记录并赋予相关的属性值
            if(line[i]=='1'){                     
                if(nGrass>MAX_GRASS)
                    break;
                grass[nGrass].s=sz;
                grass[nGrass].b=0;
                grass[nGrass].e=0;
                grass[nGrass].dir=NONE;
                grass[nGrass].v=0;
                grass[nGrass].a[0]=grass[nGrass].a[1]=grass[nGrass].a[2]=grass[nGrass].a[3]=grass; //草地的四个方向视图都一致
                grass[nGrass].x=sz/2+sz*i;                   //记录此处的坐标值
                grass[nGrass].y=sz/2+sz*nLine;
                grass[nGrass].p=0;
                nGrass++;                                   //障碍物序号
            }
        }
        nLine++;                                           //进入下一行
    }
    fclose(f);                                            //关闭文件
}
void Init()       //初始化中增加文件读取,LoadImage进行外部文件读取,LoadBitmap进行内部资源文件导入
{

    ReadIni();           //先读取外部文件
    tank1[0] = (HBITMAP)LoadImage(NULL, L"Resources\\TankBlue.bmp", IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_DEFAULTSIZE | LR_LOADFROMFILE);   //(实例句柄,路径,图片类型,图片宽和高,以何种方式加载文件)
    tank2[0] = (HBITMAP)LoadImage(NULL, L"Resources\\TankYellow.bmp", IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_DEFAULTSIZE | LR_LOADFROMFILE);
    tank3[0] = (HBITMAP)LoadImage(NULL, L"Resources\\TankLarge.bmp", IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_DEFAULTSIZE | LR_LOADFROMFILE);
    bulletPic[0] = (HBITMAP)LoadImage(NULL, L"Resources\\bullet.bmp", IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_DEFAULTSIZE | LR_LOADFROMFILE);
    tank1[1] = (HBITMAP)LoadImage(NULL, L"Resources\\TankBlue1.bmp", IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_DEFAULTSIZE | LR_LOADFROMFILE);
    tank2[1] = (HBITMAP)LoadImage(NULL, L"Resources\\TankYellow1.bmp", IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_DEFAULTSIZE | LR_LOADFROMFILE);
    tank3[1] = (HBITMAP)LoadImage(NULL, L"Resources\\TankLarge1.bmp", IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_DEFAULTSIZE | LR_LOADFROMFILE);
    bulletPic[1] = (HBITMAP)LoadImage(NULL, L"Resources\\bullet1.bmp", IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_DEFAULTSIZE | LR_LOADFROMFILE);
    tank1[2] = (HBITMAP)LoadImage(NULL, L"Resources\\TankBlue2.bmp", IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_DEFAULTSIZE | LR_LOADFROMFILE);
    tank2[2] = (HBITMAP)LoadImage(NULL, L"Resources\\TankYellow2.bmp", IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_DEFAULTSIZE | LR_LOADFROMFILE);
    tank3[2] = (HBITMAP)LoadImage(NULL, L"Resources\\TankLarge2.bmp", IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_DEFAULTSIZE | LR_LOADFROMFILE);
    bulletPic[2] = (HBITMAP)LoadImage(NULL, L"Resources\\bullet2.bmp", IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_DEFAULTSIZE | LR_LOADFROMFILE);
    tank1[3] = (HBITMAP)LoadImage(NULL, L"Resources\\TankBlue3.bmp", IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_DEFAULTSIZE | LR_LOADFROMFILE);
    tank2[3] = (HBITMAP)LoadImage(NULL, L"Resources\\TankYellow3.bmp", IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_DEFAULTSIZE | LR_LOADFROMFILE);
    tank3[3] = (HBITMAP)LoadImage(NULL, L"Resources\\TankLarge3.bmp", IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_DEFAULTSIZE | LR_LOADFROMFILE);
    bulletPic[3] = (HBITMAP)LoadImage(NULL, L"Resources\\bullet3.bmp", IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_DEFAULTSIZE | LR_LOADFROMFILE);
    background = (HBITMAP)LoadImage(NULL, L"Resources\\Back.bmp", IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_DEFAULTSIZE | LR_LOADFROMFILE);
    grass = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_GRASS));     //内部资源文件导入




    for (nEnemy = 0;nEnemy < MAX_ENEMY;nEnemy++)       
    {
        enemys[nEnemy].s = sz;           
        enemys[nEnemy].b = 0;            
        enemys[nEnemy].e = 1;           
        enemys[nEnemy].dir = Dir(UP + rand() % 4);            
        enemys[nEnemy].v = rand() % 2 == 0 ? velf : vels;    
        //enemys[nEnemy].c = enemys[nEnemy].v == velf ? RGB(0, 122, 122) : RGB(0, 60, 30); 
        enemys[nEnemy].v == velf ? memcpy(enemys[nEnemy].a, tank3, 4 * sizeof(Dir)) :     memcpy(enemys[nEnemy].a, tank2, 4 * sizeof(Dir));  //根据快速或慢速进行图片拷贝
        
        enemys[nEnemy].x = (rand() % 3) * (wndWidth - sz) / 2 + sz / 2;  
        enemys[nEnemy].y = sz;      
        enemys[nEnemy].p = 0;       
    }
    ResetPlayer();
    InitMap();
}
void Fire(const Entity* ent)      //射击中将原来的炮弹颜色改为图片形式
{
    memcpy((pBullets+nB)->a,bulletPic,sizeof(Dir));        //将外部文件进行拷贝
}
 for (int i = 0;i < nEnemy;i++) {                 //判断敌人坦克和游戏边界发生碰撞
        ent = enemys + i;
        if (!WallCollider(ent)) {
            int cg = 0;
            for (int j = 0;j < nGrass;j++) {              //判断敌人和障碍物是否发生碰撞
                if (IsCollider(ent, grasses + j)) {
                    cg = 1;
                    Move(ent, -ts);
                    break;
                }
            }

            if (rand() % enemyDir == 0|| cg)
                ent->dir = Dir((ent->dir + 1 + rand() % 3) % 4);    //碰撞后改变方向
        }
    }

    for (int i = 0;i < nGrass;i++) {                   //对玩家和障碍物发生碰撞进行检测
        ent = grasses + i;
        if (IsCollider(ent, &player)) {
            switch (player.dir) {
            case UP:
                player.y = ent->y + ent->s;           //进行回撤并处于停止
                break;
            case DOWN:
                player.y = ent->y - ent->s;
                break;
            case LEFT:
                player.x = ent->x + ent->s;
                break;
            case RIGHT:
                player.x = ent->x - ent->s;
                break;
            }
            player.p = 1; 
            break;
        }
    }
void DrawEntity(HDC hdc, const Entity* ent)       //坦克绘制也采用图片形式而不是颜色
{
    HDC hdcMem = CreateCompatibleDC(hdc);                   //建立一个兼容的后备缓存
    HBITMAP bmp = ent->a[int(ent->dir) % 4];                //再建立一个用于保存四个方向的位图
    HBITMAP hbmOld = (HBITMAP)SelectObject(hdcMem, bmp);    //将对应方向的位图进行选择
    BITMAP bm;
    GetObject(bmp, sizeof(bm), &bm);                        //获取bmp位图信息并存放到bm中
    SetStretchBltMode(hdc, STRETCH_HALFTONE);               //设置和选择位图形式
    TransparentBlt(hdc, ent->x - ent->s / 2, ent->y - ent->s / 2, ent->s, ent->s, hdcMem, 0, 0, bm.bmWidth, bm.bmHeight, RGB(255, 255, 255)); //支持透明度的位图
    SelectObject(hdcMem, hbmOld);   //善后处理
    DeleteDC(hdcMem);
}
void DrawScene(HDC hdc)         //绘制游戏场景中的背景由新加入图片导入的形式,后续的文字效果不变
{
    HDC hdcMem = CreateCompatibleDC(hdc);                                 //新建后备缓存
    HBITMAP hbmOld = (HBITMAP)SelectObject(hdcMem, background);           //把background这个外部文件载入到hdcmem后备缓存中
    BITMAP bm;
    GetObject(background, sizeof(bm), &bm);                               //获取缓存信息
    SetStretchBltMode(hdc, STRETCH_HALFTONE);                             //选择模式
    BitBlt(hdc, 0, 0, wndWidth, wndHeight, hdcMem, 0, 0, SRCCOPY);        //完全拷贝,不含透明信息
    SelectObject(hdcMem, hbmOld);
    DeleteDC(hdcMem);
}
 SetWindowLong(hWnd, GWL_STYLE, WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU);      //最后设置不允许玩家随意更改窗口大小 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值