原文地址:
那么,看起来已经有点像样了呢。
把自机的射击功能和碰撞检测加上的话,大部分的架构就完成了。
自机的射击实现方式也是和基本的敌机射击的实现是差不多的。
制作一个保存子弹信息的结构,把种类,速度,角度等等保存进去就行了。
这些数值设置好了之后,计算部分就可以轻松的算出轨道和碰撞信息了。
那么,我们先和往常一样,准备好变量和结构体。
——————————————————————————————————————————————————————————————
---- 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 这两个数,是子弹大小的尺寸。。。
如果, 子弹的坐标在,相对画面移动的速度+ 子弹图像尺寸的一半,这里的话,我们知道他上一帧也在画面外,
所以,这个子弹就可以消除了。
这样的处理,就是为了处理那样的情况,所以才这么写。
运行结果:
本人CSDN博客目录: