使用C语言和DX库编写东方风格的STG射击游戏--------第一章--------创建基本界面以及可以移动的角色
这个是这章需要的文件,本章代码下载(建议下载后对照查看,记得配置好dx库以及素材文件)
各文件定义请查看
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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");为库函数,将出错信息输出到控制台
运行程序,如无意外将得到如下图所示的程序