• 使用C语言和DX库编写东方风格的STG射击游戏第一章创建基本界面以及可以移动的角色


    这个是这章需要的文件,本章代码下载(建议下载后对照查看,记得配置好dx库以及素材文件)

    各文件定义请查看

    View Code
    define.h : 定义常量
    function.h : 函数的声明
    GV.h : 全局变量的声明
    sturct.h : 结构体的定义
    
    char.cpp : 角色属性函数,例如移动
    graph.cpp : 界面载入
    ini.cpp : 初始化
    key.cpp : 按键定义
    load.cpp : 读入数据资源
    mian.cpp : 程序主循环

     首先由main.cpp开始看吧,main.cpp的代码如下

     1 #define GLOBAL_INSTANCE 
     2 #include "../include/GV.h"
     3 
     4 //每次更新都必须的函数
     5 int ProcessLoop(){
     6     if(ProcessMessage()!=0)        //处理系统消息
     7         return -1;        
     8     if(ClearDrawScreen()!=0)        //清理画面
     9         return -1;        
    10     GetHitKeyStateAll_2();        //获取键盘输入
    11     GetHitPadStateAll();         //获取手柄输入
    12     return 0;
    13 }
    14 
    15 int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow){
    16     ChangeWindowMode(TRUE);        //设置为窗口模式
    17     if(DxLib_Init() == -1 || SetDrawScreen( DX_SCREEN_BACK )!=0) 
    18         return -1;        //初始化dx库与设置背画面
    19 
    20     //游戏主循环
    21     while(ProcessLoop()==0){
    22 
    23         switch(func_state){
    24         case 0:
    25             load();         //载入数据
    26             first_ini();        //初始化数据
    27             func_state=100;
    28             break;
    29         case 100:
    30             calc_ch();   ///角色动画变化
    31             ch_move();
    32             graph_main();        //把图像数据等画到背画面上
    33             break;
    34         default:
    35             printfDx("未知的func_state\n");
    36             break;
    37         }
    38         //按esc键则退出程序
    39         if(CheckStateKey(KEY_INPUT_ESCAPE)==1)
    40             break;
    41         ScreenFlip();        //把在背画面设置好的画到表画面,也就是显示到显示屏上
    42     }
    43 
    44     DxLib_End();        //终止程序
    45     return 0;
    46 }

    从第一行开始看,查看gv.h可以发现

    #ifdef GLOBAL_INSTANCE
    #define GLOBAL
    #else
    #define GLOBAL extern 
    #endif

    也就是说,如果文件包含了gv.h,就不用把gv.h里面的数据声明为extern了.

    接下来跳到15行开始,这里是跟MFC框架相似的主函数入口winmain

    其中ChangeWindowMode,DxLib_Init,SetDrawScreen为库函数,作用看注释,DxLib_Init与DxLib_End相对应

    背画面可以看成是一个舞台的的后台,演员要在后台里面化好妆,准备好才出到前台来表演

    ProcessLoop里的函数为每次(每一帧)更新都必须要调用的函数

    例如从系统消息队列里面获取消息,清理上一帧的数据,获取键盘按键状态等

    这里可以到key.cpp里看GetHitKeyStateAll_2和GetHitPadStateAll的实现

    unsigned int stateKey[256];        //键盘按键次数
    
    int GetHitKeyStateAll_2(){
        char GetHitKeyStateAll_Key[256];        //键盘按键状态,被按下的为1
        GetHitKeyStateAll( GetHitKeyStateAll_Key );
        for(int i=0;i<256;i++){
            if(GetHitKeyStateAll_Key[i]==1) 
                stateKey[i]++;
            else                            
                stateKey[i]=0;
        }
        return 0;
    }

    GetHitKeyStateAll为DX库函数,作用为获取键盘256个键值的状态,被按下的键被标识为1,存储在GetHitKeyStateAll_Key[256]里

    按键连发次数被保存在stateKey[256]数组里,连发结束则设置为0

    GetHitPadStateAll的原理同上,pad_t pad;被定义在sturct.h里面

    //添加手柄控制
    typedef struct{
        int key[PAD_MAX];
    }pad_t;
    
    //手柄按键的标识
    typedef struct{
        int left,up,right,down,shot,bom,slow,start,change;
    }configpad_t;

    其中(在key.cpp可查看)函数input_pad_or_key()为处理键盘与手柄同时按下同一功能键的情况,返回次数较多的一方

    回到main.cpp里,主循环func_state恒被初始化为0,所以函数必定被执行load与first_ini函数(分别被定义在load.cpp和ini.cpp里)

    关于load方法中的LoadDivGraph( "../dat/img/char/0.png" , 12 , 4 , 3 , 73 , 73 , img_ch[0] ) ;

    0.png为以下这个,img_ch[0](在gv.h中定义)为一个二维数组的其中一维

    其作用为将0.png分成12张图,横4张,纵3张,每张73x73大小,存储在img_ch[0]这个数组里面

    first_ini为初始化角色最初出现的位置以及手柄按键

    往下来到main.cpp的case100中,(calc_ch不明白的话暂时不要管,只知道其作用即可)

    //角色动作图像变换以连成动画效果
    void calc_ch(){
        ch.cnt++;
        ch.img=(ch.cnt%24)/6;
    
    }
    
    //指定角色的移动
    void ch_move(){
        int i,sayu_flag=0,joge_flag=0;
        double x,y,mx,my,naname=1;
    
        //左右下上四方向的速度
        double move_x[4]={-4.0,4.0,0,0},move_y[4]={0,0,4.0,-4.0};
    
        //手柄四方向的按键状态
        int inputpad[4];
        inputpad[0]=CheckStatePad(configpad.left); inputpad[1]=CheckStatePad(configpad.right);
        inputpad[2]=CheckStatePad(configpad.down); inputpad[3]=CheckStatePad(configpad.up);
    
        //角色向左或者向右时的图像变化
        if(CheckStatePad(configpad.left)>0)
            ch.img+=4*2;        //向左移动的角色图像
        else if(CheckStatePad(configpad.right)>0)
            ch.img+=4*1;        //向右移动的角色图像
    
        //45度斜向移动的话就稍作减速
        for(i=0;i<2;i++)        //检测左右按键的输入
            if(inputpad[i]>0)    //检测到输入的话
                sayu_flag=1;    //将标识设置为1
        for(i=2;i<4;i++)        //检测上下按键的输入,原理同上
            if(inputpad[i]>0)    
                joge_flag=1;
        if(sayu_flag==1 && joge_flag==1)    //如果两个标识都为1的话,也就是斜向行走的话
            naname=sqrt(2.0);    //稍作减速设置,naname在下面用上
    
        //检测是否有输入从而令角色的移动
        for(int i=0;i<4;i++){        //4个方向检测
            if(inputpad[i]>0){        //有输入的话
                x=ch.x , y=ch.y;        //存储角色座标
                mx=move_x[i];   my=move_y[i];        //赋予移动距离
                //减速移动
                if(CheckStatePad(configpad.slow)>0){        
                    mx=move_x[i]/3; my=move_y[i]/3;    //将移动速度设置为原来的3份1
                }
                x+=mx/naname , y+=my/naname;        //角色原座标加上移动的距离
                //防止角色超出边界
                if(!(x<10 || x>FIELD_MAX_X-10 || y<5 || y>FIELD_MAX_Y-5)){
                    ch.x=x , ch.y=y;
                }
            }
        }
    }

    graph_main中的两个函数

    //角色描绘
    void graph_ch(){
        DrawRotaGraphF(ch.x,ch.y,1.0f,0.0f,img_ch[0][ch.img],TRUE);
    }
    
    //界面描绘
    void graph_board(){
        DrawGraph(  0,  0,img_board[10],FALSE);
        DrawGraph(  0, 16,img_board[11],FALSE);
        DrawGraph(  0,464,img_board[12],FALSE);
        DrawGraph(416,  0,img_board[20],FALSE);
    }

    DrawRotaGraphF(x座标,y座标,图像缩放的大小,图像的角度,图像数据,是否透明)

    DrawGraph(x座标,y座标,图像数据,是否透明)

    最后的printfDx("未知的func_state\n");为库函数,将出错信息输出到控制台

     运行程序,如无意外将得到如下图所示的程序

     



     

  • 相关阅读:
    Linux下Nginx服务Rewrite和Proxy_Pass
    nginx配置中proxy_redirect的作用(转)
    nginx location rewrite常用详解
    Nginx URL重写(rewrite)配置及信息详解
    Selenium上传文件
    Selenium测试Ajax应用程序中的主要问题
    Selenium得到当前页面的URL
    Selenium高亮页面对象
    Selenium简单测试页面加载速度的性能(Page loading performance)
    Selenium Page object Pattern usage
  • 原文地址:https://www.cnblogs.com/tomboy/p/2588837.html
Copyright © 2020-2023  润新知