第十章 来显示敌人吧
既然是要做的是STG,那真想快点开始制作弹幕啊。
但是,在构造弹幕数据之前,我们必须先构造好敌人的数据,所以我们先来搞好敌人的构造吧。
首先我们先写好敌人数据的结构体。
–在struct.h中进行以下追加–
//和敌人相关的结构体
typedef struct{
//flag、计数器、移动模式、方向、敌人的种类、HP最大值、掉落道具、图像
int flag,cnt,pattern,muki,knd,hp,hp_max,item_n[6],img;
//坐标、速度x分量、速度y分量、速度、角度
double x,y,vx,vy,sp,ang;
//弹幕开始时间、弹幕的种类、弹的种类、颜色、状态、待机时间、停止时间
int bltime,blknd,blknd2,col,state,wtime,wait;
}enemy_t;
这是什么情况!
虽然一大堆变量杂七杂八地混在一起,不过没有必要全部记住。
flag就是flag、cnt就是计数器、pattern就是敌人移动的模式,现在我们用自我表意的名字命名了它们,当我们想要知道这个变量是用来做什么的时候,就看着它们的名字就了解了。
因为敌人肯定拥有许多不同的信息,因此虽然变量一下子变得很多很多,但是这并不复杂。
事先定义好游戏中用于表示计数器的stage_count,还有用于保存敌人图像句柄的img_enemy。
在define里面我们把画面上同时显示的最大敌人数使用ENEMY_MAX定义为30.
–在GV.h中进行以下追加–
GLOBAL int stage_count;
GLOBAL int img_enemy[3][9];//敌人的图像每种9张 X3种敌人
GLOBAL enemy_t enemy[ENEMY_MAX];
–在define.h中进行以下追加–
//同时表示的最大敌人数
#define ENEMY_MAX 30
–在load.cpp中进行以下追加–
LoadDivGraph( "../dat/img/enemy/0.png" , 9 , 3 , 3 , 32 , 32 , img_enemy[0] );
初始化函数分为两种类型:1、游戏启动之后只进行一次的初始化;2、每次新游戏开始时进行的初始化。
根据下面的例子来说,config的出事设定在新游戏开始的时候没有必要进行。
–ini.cpp变更–
#include "../include/GV.h"
//最开始的初始化
void first_ini(){
configpad.down=0;
configpad.left=1;
configpad.right=2;
configpad.up=3;
configpad.bom=4;
configpad.shot=5;
configpad.slow=11;
configpad.start=13;
configpad.change=6;
}
//新游戏的初始化
void ini(){
stage_count=1;
memset(&ch,0,sizeof(ch_t));//自机数据的初始化
ch.x=FIELD_MAX_X/2;
ch.y=FIELD_MAX_Y*3/4;
memset(enemy,0,sizeof(enemy_t)*ENEMY_MAX);//敌人数据的初始化
}
作为敌人数据处理中相当重要的流程,当游戏计数器在到达某一点的时候,开始登陆敌人的数据(enemy_enter)。
当敌人的数据被登录之后,就将处理交给控制函数,这个函数控制了敌人的行动,而这些敌人按照登录了的移动模式移动。
当敌人跑到画面外面的时候,就把登陆flag取消掉(enemy_act)。
整个流程大概就是这样。
在下面的例子中,尝试着让游戏计数器在100的时候登录编号为0的敌人,使其先往下移动然后又往上移动。
–enemy.cpp变更–
#include "../include/GV.h"
//使用敌人的移动模式0来控制敌人的移动
void enemy_pattern0(int i){
if(enemy[i].cnt<60){
enemy[i].y+=2.0;
}
if(enemy[i].cnt>60+240){
enemy[i].y-=2.0;
}
}
//登陆敌人的数据
void enemy_enter(){
if(stage_count==100){//在新游戏开始后计数器变为100的时候登录
enemy[0].cnt =0;
enemy[0].muki =1;
enemy[0].flag =1;
enemy[0].bltime =150;
enemy[0].hp =1000;
enemy[0].hp_max =enemy[0].hp;
enemy[0].pattern=0;
enemy[0].x =FIELD_MAX_X/2;
enemy[0].y =-20;
}
}
//控制敌人的行动
void enemy_act(){
int i;
for(i=0;i<ENEMY_MAX;i++){
if(enemy[i].flag==1){//如果敌人的flag为有效
enemy_pattern0(i);
enemy[i].cnt++;
enemy[i].img=enemy[i].muki*3+(enemy[i].cnt%18)/6;
//如果敌人跑到外面去了就把他们销毁
if(enemy[i].x<-50 || FIELD_MAX_X+50<enemy[i].x || enemy[i].y<-50 || FIELD_MAX_Y+50<enemy[i].y)
enemy[i].flag=0;
}
}
}
//敌人处理main
void enemy_main(){
enemy_enter();
enemy_act();
}
在绘制处理中只需要绘制增加了的敌人数据。
搜索目前已经登录了的敌人数据,然后对其进行绘制。
–graph.cpp变更–
#include "../include/GV.h"
void graph_enemy(){
int i;
for(i=0;i<ENEMY_MAX;i++){
if(enemy[i].flag==1){
DrawRotaGraphF(enemy[i].x+FIELD_X,enemy[i].y+FIELD_Y,1.0f,0.0f,img_enemy[0][enemy[i].img],TRUE);
}
}
}
void graph_ch(){
DrawRotaGraphF(ch.x+FIELD_X,ch.y+FIELD_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);
}
void graph_main(){
graph_enemy();
graph_ch();
graph_board();
}
main函数中变更了红字部分。
–main.cpp变更–
#define GLOBAL_INSTANCE
#include "../include/GV.h"
//循环必须进行的三大处理
int ProcessLoop(){
if(ProcessMessage()!=0)return -1;//如果过程处理错误返回-1
if(ClearDrawScreen()!=0)return -1;//如果画面清空处理错误返回-1
GetHitKeyStateAll_2();//执行当前的输入处理
GetHitPadStateAll(); //执行当前手柄输入处理
return 0;
}
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow){
ChangeWindowMode(TRUE);//窗口模式
if(DxLib_Init() == -1 || SetDrawScreen( DX_SCREEN_BACK )!=0) return -1;//初始化和里表面化
while(ProcessLoop()==0){//主循环
switch(func_state){
case 0://只在游戏启动时处理
load(); //载入数据
first_ini();//最开始的初始化
/*** 修改请注意 ***/
func_state=99;
break;
case 99://STG开始前进行的初始化
ini();
func_state=100;
break;
/*** 修改请注意 ***/
case 100://通常处理
calc_ch(); //角色计算
ch_move(); //控制角色移动
/*** 修改请注意 ***/
enemy_main();//敌人处理main
/*** 修改请注意 ***/
graph_main();//绘制main
/*** 修改请注意 ***/
stage_count++;
/*** 修改请注意 ***/
break;
default:
printfDx("错误的func_state\n");
break;
}
if(CheckStateKey(KEY_INPUT_ESCAPE)==1)break;//如果按下ESC键跳出循环
ScreenFlip();//里外画面翻转
}
DxLib_End();//DX Library终止处理
return 0;
}
现在将本次追加的函数进行登录。
–在function.h 中进行以下处理–
GLOBAL void enemy_main();
GLOBAL void ini();
运行结果