原文地址:
敌机的碰撞检测以及加上了,这次我们来做自机的碰撞检测吧。
首先,在做具体的处理之前,有些准备工作要做。
要做子弹的碰撞检测,我们需要知道比如子弹的碰撞判定范围这些信息。
那么,我们就像下面这样做。
——————————————————————————————————————————————————————————————————
---- struct.h 里添加如下代码 ----
//子弹的信息
typedef struct{
int size_x,size_y,col_num;
double range;
}bullet_info_t;
---- GV.h 里添加如下代码 ----
GLOBAL bullet_info_t bullet_info[10];//子弹信息
---- load.cpp load函数里添加如下部分 ----
sound_se[3]=LoadSoundMem("../dat/se/char_death.wav");//自机死亡音效
ChangeVolumeSoundMem( 80, sound_se[3] ) ;
---- ini.cpp 里添加如下部分 ----
//把传过来的信息放入构造体的函数
void input_bullet_info(bullet_info_t *binfo,int size_x,int size_y,int col_num,double range){
binfo->size_x =size_x; binfo->size_y =size_y;
binfo->col_num=col_num; binfo->range =range;
}
---- ini.cpp first_ini()函数里添加如下部分 ----
//例子:0号子弹是76x76像素,有5种颜色,碰撞范围是17像素
input_bullet_info(&bullet_info[0],76, 76, 5,17.0);
input_bullet_info(&bullet_info[1],22, 22, 6, 4.0);
input_bullet_info(&bullet_info[2], 5,120,10, 2.5);
input_bullet_info(&bullet_info[3],19, 34, 5, 2.0);
input_bullet_info(&bullet_info[4],38, 38,10, 2.0);
input_bullet_info(&bullet_info[5],14, 16, 3, 3.5);
input_bullet_info(&bullet_info[6],14, 18, 3, 2.0);
input_bullet_info(&bullet_info[7],16, 16, 9, 2.5);
input_bullet_info(&bullet_info[8],12, 18,10, 1.5);
input_bullet_info(&bullet_info[9],13, 19, 3, 2.0);
——————————————————————————————————————————————————————————————————
first_init 函数里有子弹的信息,我们要花点时间,根据这些信息来制定合适大小的碰撞范围。
如果有人觉得这个范围不行,那么就自己试试,调整一下吧。
这个函数里,包含了子弹大小,颜色的种类,和碰撞范围等信息。
那么,准备工作做好了,现在来看自机的处理吧。
话说回来,之前已经做好了一个碰撞检测的模块了,这次也是做同样的判定就行了,比较简单。
基本上复制过来就行。
虽然存在几个几乎一样的函数感觉不大好,但在这里把它改成通用的函数的话,会不大好理解。
函数的通用化以后再讲吧,这里先复制过来稍微改一下下就行了。
基本上敌机和自机的碰撞检测是一样的。
——————————————————————————————————————————————————————————
---- out.cpp 的改动 ----
#include "../include/GV.h"
#define ENEMY_RANGE_MAX 4
#define CSHOT_RANGE_MAX 2
#define CRANGE 2.0
//敌机的碰撞检测范围
int enemy_range[ENEMY_RANGE_MAX]={16,30,16,50};
//自机子弹的碰撞检测范围
int cshot_range[CSHOT_RANGE_MAX]={6,};
//检测敌机是否和自机子弹发生碰撞
int out_judge_cshot(int i,int s){
int j;
if(cshot[i].cnt>0){//对子弹轨道的每一刻的状态都进行计算
double x=cshot[i].x-enemy[s].x;//敌机和自机子弹的距离
double y=cshot[i].y-enemy[s].y;
//防止溢出
if(cshot[i].knd>=CSHOT_RANGE_MAX || enemy[s].knd>=ENEMY_RANGE_MAX)
printfDx("out_judge_cshot OVERFLOW");
//敌机的碰撞检测范围和自机子弹的碰撞检测范围加起来
double r=cshot_range[cshot[i].knd]+enemy_range[enemy[s].knd];
//如果需要计算其中的过程
if(cshot[i].spd>r){
//储存一帧前的位置
double pre_x=cshot[i].x+cos(cshot[i].angle+PI)*cshot[i].spd;
double pre_y=cshot[i].y+sin(cshot[i].angle+PI)*cshot[i].spd;
double px,py;
for(j=0;j<cshot[i].spd/r;j++){// 循环(前进距离/碰撞检测大小)次
px=pre_x-enemy[s].x;
py=pre_y-enemy[s].y;
if(px*px+py*py<r*r)
return 1;
pre_x+=cos(cshot[i].angle)*r;
pre_y+=sin(cshot[i].angle)*r;
}
}
if(x*x+y*y<r*r)//如果在碰撞范围内
return 1;//返回发生碰撞
}
return 0;
}
//判断自机和敌机子弹是否发生碰撞
int out_judge_enemyshot(int s,int n){
int j;
if(shot[s].bullet[n].cnt>0){//对子弹轨道的每一刻的状态都进行计算
double x=shot[s].bullet[n].x-ch.x;//敌机和自机子弹的距离
double y=shot[s].bullet[n].y-ch.y;
//防止溢出
if(shot[s].bullet[n].knd>=10)
printfDx("out_judge_enemyshot OVERFLOW\n");
//敌机子弹和自机的碰撞判定范围加起来
double r=bullet_info[shot[s].bullet[n].knd].range+CRANGE;
//如果需要计算其中的过程
if(shot[s].bullet[n].spd>r){
//保存上一帧的位置
double pre_x=shot[s].bullet[n].x+cos(shot[s].bullet[n].angle+PI)*shot[s].bullet[n].spd;
double pre_y=shot[s].bullet[n].y+sin(shot[s].bullet[n].angle+PI)*shot[s].bullet[n].spd;
double px,py;
for(j=0;j<shot[s].bullet[n].spd/r;j++){// 循环(前进距离/碰撞检测大小)次
px=pre_x-ch.x;
py=pre_y-ch.y;
if(px*px+py*py<r*r)
return 1;
pre_x+=cos(shot[s].bullet[n].angle)*r;
pre_y+=sin(shot[s].bullet[n].angle)*r;
}
}
if(x*x+y*y<r*r)//如果在碰撞范围内
return 1;//发生碰撞
}
return 0;
}
extern void enter_del_effect(int);
//判断敌机是否死亡
void enemy_death_judge(int s){
int i;
se_flag[8]=1;//敌机被击中的音效
if(enemy[s].hp<0){//敌机的HP如果小于0
enemy[s].flag=0;//敌机标记为消灭
se_flag[1]=1;//敌机 BIU 的音效
enter_del_effect(s);
for(i=0;i<SHOT_MAX;i++){//所有子弹数量循环
if(shot[i].flag!=0){//如果子弹正在显示
if(s==shot[i].num){//如果是这个敌机发射的子弹
shot[i].flag=2;//设置这个子弹的状态为不再继续
break;
}
}
}
}
}
//自机子弹和敌机的处理
void cshot_and_enemy(){
int i,s;
for(i=0;i<CSHOT_MAX;i++){//自机子弹的总数
if(cshot[i].flag>0){
for(s=0;s<ENEMY_MAX;s++){//敌人的总数
if(enemy[s].flag>0){
if(out_judge_cshot(i,s)){//自机子弹和敌机发生碰撞的话
cshot[i].flag=0;//把这个自机子弹标为消失
enemy[s].hp-=cshot[i].power;//根据子弹的威力扣掉敌机相应的HP值
enemy_death_judge(s);//判断敌机是否死亡
}
}
}
}
}
}
//敌机子弹和自机的处理
void enemyshot_and_ch(){
int s,n;
for(s=0;s<SHOT_MAX;s++){//敌机弹幕的总数
if(shot[s].flag>0){//如果弹幕正在显示
for(n=0;n<SHOT_BULLET_MAX;n++){//总子弹数量
if(shot[s].bullet[n].flag==1){//如果正在显示
if(out_judge_enemyshot(s,n)){//自机如果和那个子弹接触了
shot[s].bullet[n].flag=0;//清除这个子弹
/*决死的炸弹释放,在这里处理*/
if(ch.flag==0 && ch.mutekicnt==0){//如果在通常状态,没有处于无敌的情况下
ch.flag =2; //1:检查决死的炸弹 2:死亡动画浮上来
ch.cnt =0;
se_flag[3]=1;//BIU 的音效
return;
}
}
}
}
}
}
}
//碰撞判定的主函数
void out_main(){
cshot_and_enemy();
enemyshot_and_ch();
}
______________________________________________________________________________________________________
enemyshot_and_ch 是敌机的子弹和自机的碰撞判定处理函数,这里出现了一个ch.flag=2的状态呢。
被击中后,玩家会进入两个阶段的状态。
首先,被击中的瞬间,会进入“可以使用炸弹决死”的状态。 这个状态, 用 ch.flag = 1 来表示。
一定时间内没有按下炸弹按键的话,接下来就进入从画面底端往上浮的这个状态。
这个状态,用 ch.flag = 2 表示。
在画面中上浮的这个状态中,如果有按键输入的话,就会进入最初的状态。
另外,角色死后的一段时间,是处于无敌状态的。
是否处于无敌状态,由另一个变量表示。
ch.mutekicnt不等于0的时候处于无敌状态。这个时候不进行被子弹打中的处理。
另外,在 graph函数里绘制时,每两帧只绘制一帧,
这样就实现一闪一闪的效果,感觉就像无敌了一样。
无敌状态经过一段时间就会消失。
那么就让我们来把这些处理和改动来实现一下吧。
——————————————————————————————————————————————————————
---- char.cpp 的以下函数的改动 ----
void calc_ch(){
if(ch.cnt==0 && ch.flag==2){//这个瞬间死了的话
ch.x=FIELD_MAX_X/2;//设置坐标
ch.y=FIELD_MAX_Y+30;
ch.mutekicnt++;//设置无敌状态
}
if(ch.flag==2){//死后重生上浮状态中
unsigned int push=CheckStatePad(configpad.left)+CheckStatePad(configpad.right)
+CheckStatePad(configpad.up)+CheckStatePad(configpad.down);
ch.y-=1.5;//角色向上移动
//一秒钟以上,或者上移一定距离,或者有键按下的话
if(ch.cnt>60 || (ch.y<FIELD_MAX_Y-20 && push)){
ch.cnt=0;
ch.flag=0;//角色的状态恢复原状
}
}
if(ch.mutekicnt>0){//无敌的计数不等于0的话
ch.mutekicnt++;
if(ch.mutekicnt>120)//2秒以上的话
ch.mutekicnt=0;//重置为0
}
ch.cnt++;//角色的计数器自增
ch.img=(ch.cnt%24)/6;//计算选择当期的角色图像
}
---- graph.cpp 的以下函数的改动 ----
//绘制自机
void graph_ch(){
if(ch.mutekicnt%2==0)
DrawRotaGraphF(ch.x+FIELD_X,ch.y+FIELD_Y,1.0f,0.0f,img_ch[0][ch.img],TRUE);
}
——————————————————————————————————————————————————————
运行结果:
注: 由于制作时的帧率问题,以上的动画中没有很好的表现出角色的闪烁效果。
这个动画和实际运行的效果是不一样的。
请自己将代码编译运行,确认实际的运行效果。
(PS:上一篇文章翻译都是一年前的了,这半年多没更新了,一个字:懒。
要说工作忙也算不上,只是伤心了。项目忙了一段时间,然后测试了一段时间,然后,结果还是不理想,后面干脆砍掉重做。
唉,一直不抱希望,对这做出来效果烂的不行的项目。。新的一年,工资也没怎么涨,就这么混着耗下去。。。。唉。。。)
本人CSDN博客目录: