【四圣龙神录的编程教室】第21章、给自机加上碰撞检测和无敌效果吧

原文地址:

http://dixq.net/rp/21.html


敌机的碰撞检测以及加上了,这次我们来做自机的碰撞检测吧。

首先,在做具体的处理之前,有些准备工作要做。

要做子弹的碰撞检测,我们需要知道比如子弹的碰撞判定范围这些信息。

那么,我们就像下面这样做。

——————————————————————————————————————————————————————————————————

---- 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);
}
——————————————————————————————————————————————————————

运行结果:

http://dixq.net/rp/swf/21.swf


注: 由于制作时的帧率问题,以上的动画中没有很好的表现出角色的闪烁效果。

这个动画和实际运行的效果是不一样的。

请自己将代码编译运行,确认实际的运行效果。



(PS:上一篇文章翻译都是一年前的了,这半年多没更新了,一个字:懒。

要说工作忙也算不上,只是伤心了。项目忙了一段时间,然后测试了一段时间,然后,结果还是不理想,后面干脆砍掉重做。

唉,一直不抱希望,对这做出来效果烂的不行的项目。。新的一年,工资也没怎么涨,就这么混着耗下去。。。。唉。。。)



本人CSDN博客目录:

http://blog.csdn.net/tidus5


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值