【四圣龙神录的编程教室】第17章、让自机可以发射子弹吧

原文地址:

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


那么,看起来已经有点像样了呢。

把自机的射击功能和碰撞检测加上的话,大部分的架构就完成了。

自机的射击实现方式也是和基本的敌机射击的实现是差不多的。

制作一个保存子弹信息的结构,把种类,速度,角度等等保存进去就行了。

这些数值设置好了之后,计算部分就可以轻松的算出轨道和碰撞信息了。

那么,我们先和往常一样,准备好变量和结构体。

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

---- struct.h 里加入下面红色部分----

//自机的子弹相关的构造体(红色的)
typedef struct{
        int flag,power,cnt,knd;//标志,火力,计数,种类
        double x,y,angle,spd;//坐标,角度,速度
}cshot_t;

//自机相关的构造体
typedef struct{
        int flag;               //フラグ
        int cnt;                //カウンタ
        int power;              //パワー
        int point;              //ポイント
        int score;              //スコア
        int num;                //残機数
        int mutekicnt;  //無敵状態とカウント
        int shot_mode;  //ショットモード
        int money;              //お金
        int img;
        int slow;               //スローかどうか
        double x,y;             //座標
        int shot_cnt;           //射击的计数(红色)
}ch_t;


---- define.h 里加入下面语句 ----

//自机发射子弹的最大数目
#define CSHOT_MAX 200


---- GV.h 里加入下面语句 ----

GLOBAL int img_cshot[2];        //自机子弹所用的图像
GLOBAL cshot_t cshot[CSHOT_MAX];//自机子弹注册用的变量


---- load.cpp 的 load()函数里添加下面语句 ----

img_cshot[0]=LoadGraph("../dat/img/char/bl_00.png");
img_cshot[1]=LoadGraph("../dat/img/char/bl_01.png");

sound_se[2]=LoadSoundMem("../dat/se/cshot.wav");


---- ini.cpp 的 ini函数里添加下面语句 ----

memset(cshot,0,sizeof(cshot_t)*CSHOT_MAX);
ch.power=500;


---- function.h 里添加下面的语句 ----

GLOBAL void cshot_main();


---- graph.cpp 里添加下面的语句 ----

void graph_cshot(){
        for(int i=0;i<CSHOT_MAX;i++){
                if(cshot[i].flag>0){
                        DrawRotaGraphF(cshot[i].x+FIELD_X,cshot[i].y+FIELD_Y,1,0,
                                       img_cshot[cshot[i].knd],TRUE);
                }
        }
}


---- graph.cpp 的 graph_main函数改为 ----

void graph_main(){
        graph_enemy();
        graph_cshot();
        graph_ch();
        graph_bullet();
        graph_board();
}


---- main.cpp 的main函数的switch部分改成下面这样 ----

            case 100://通常的处理
                calc_ch();    //自机的处理
                ch_move();    //自机的移动处理
                cshot_main();//自机射击的主函数
                enemy_main();//敌机处理的主函数
                shot_main();//射击的主函数
                graph_main();//绘制的主函数
                stage_count++;
                break;

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

最后,自机子弹的登陆是必不可少的。

当自机的火力是200以下的话就是两发,以上的话就是4发子弹。

4发子弹的位置,就像下面看起来这样。


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

int cshot0pos_x[4]={-10, 10,-30, 30};
int cshot0pos_y[4]={-30,-30,-10,-10};

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

第一发在(-10,-30) 的位置,第二发在(10,-30)的位置,第三发在(-30,-10)的位置……就像这样。

这次和之前的一样,准备了子弹登陆的保存的位置,子弹登陆的时候在

int search_cshot()

方法里,找一个空的位置,来存放登陆的子弹。

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

---- cshot.cpp 改动 ----


#include "../include/GV.h"

int cshot0num[2]  ={2,4};
int cshot0pos_x[4]={-10, 10,-30, 30};
int cshot0pos_y[4]={-30,-30,-10,-10};

//返回自机子弹可以存放的位置编号
int search_cshot(){
        for(int i=0;i<CSHOT_MAX;i++){
                if(cshot[i].flag==0)
                        return i;
        }
        return -1;
}

//普通子弹登陆
void ch0_shot_pattern(){
        int k;
        for(int i=0;i<cshot0num[ch.power<200?0:1];i++){
                if((k=search_cshot())!=-1){
                        cshot[k].flag=1;
                        cshot[k].cnt=0;
                        cshot[k].angle=-PI/2;
                        cshot[k].spd=20;
                        cshot[k].x=ch.x+cshot0pos_x[i];
                        cshot[k].y=ch.y+cshot0pos_y[i];
                        cshot[k].power=23;
                        cshot[k].knd=0;
                }
        }
        se_flag[2]=1;//发射音效
}

//低速子弹登陆
void ch1_shot_pattern(){
        int k;
        for(int i=0;i<cshot0num[ch.power<200?0:1];i++){
                if((k=search_cshot())!=-1){
                        cshot[k].flag=1;
                        cshot[k].cnt=0;
                        cshot[k].angle=-PI/2;
                        cshot[k].spd=20;
                        cshot[k].x=ch.x+cshot0pos_x[i]/3;//低速的话,位置往中间靠
                        cshot[k].y=ch.y+cshot0pos_y[i]/2;
                        cshot[k].power=23;
                        cshot[k].knd=0;
                }
        }
        se_flag[2]=1;
}

//子弹登陆部分
void enter_shot(){
        //子弹发射按键按下的话
        if(CheckStatePad(configpad.shot)>0){
                ch.shot_cnt++;
                if(ch.shot_cnt%3==0){//每3帧内一次
                        if(CheckStatePad(configpad.slow)>0)//如果是低速的话
                                ch1_shot_pattern();
                        else
                                ch0_shot_pattern();
                }
        }
        else
                ch.shot_cnt=0;
}

//子弹的移动计算
void calc_cshot(){
        for(int i=0;i<CSHOT_MAX;i++){
                if(cshot[i].flag==1){
                        int dranx=cshot[i].spd+11/2,drany=cshot[i].spd+55/2;
                        cshot[i].x+=cos(cshot[i].angle)*cshot[i].spd;
                        cshot[i].y+=sin(cshot[i].angle)*cshot[i].spd;
                        cshot[i].cnt++;
                        if(cshot[i].x<-dranx || cshot[i].x>FIELD_MAX_X+dranx ||
                                cshot[i].y<-drany || cshot[i].y>FIELD_MAX_Y+drany)//已经在画面外的话
                                cshot[i].flag=0;
                }
        }
}

//自机子弹相关的函数
void cshot_main(){
        calc_cshot();//子弹的轨道计算
        enter_shot();//子弹登陆
}

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

calc_cshot() 会对子弹在画面外做判定,为什么用

int dranx=cshot[i].spd+11/2,drany=cshot[i].spd+55/2;

这样来判定,这里补充说明一下。下一章会讲碰撞检测,

预先对那个做一些了解是有必要的,下一章不会讲这段代码了,所以我们先在这里讲了吧。

子弹只靠勾股定理来检测是否碰撞是不够的。

比如说,子弹的速度是200,子弹的判定大小是10,那么有190的范围是不会碰到的。

也就是说,必须要根据子弹的轨迹来计算是否会产生碰撞。

当子弹在画面外的时候,子弹就被消除了,最后的轨迹就计算不出来了。

也就是说,当上一帧子弹在画面外,这一帧子弹还是在画面外的话,才可以被消除。

此外,11 和 55 这两个数,是子弹大小的尺寸。。。

如果, 子弹的坐标在,相对画面移动的速度+ 子弹图像尺寸的一半,这里的话,我们知道他上一帧也在画面外,

所以,这个子弹就可以消除了。

这样的处理,就是为了处理那样的情况,所以才这么写。

运行结果:

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


本人CSDN博客目录:

http://blog.csdn.net/tidus5



展开阅读全文
©️2020 CSDN 皮肤主题: 大白 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值