【四圣龙神录的编程教室】第12章、来制作大量敌人的行动模式吧

原文地址:

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


上一篇里,一个敌人的移动操作的函数已经做好了。现在我们来做更多的敌人移动吧。

我们来做一个有0-10 的11种行动模式的操作函数吧。

另外,这里写了一个叫做rang的函数。这个函数读取一个参数n,返回从 -n 到 n 的随机 double类型的数。

下面代码很长,但都是很简单的函数的重复。

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

//--enemy_act_pattern.cpp 的改动--

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

//根据传进的参数,返回-ang~ang的随机角度数
double rang(double ang){
    return ( -ang + ang*2 * GetRand(10000)/10000.0 );
}

//移动模式0
//下落一段,停滞一会,然后上升
void enemy_pattern0(int i){
    int t=enemy[i].cnt;
    if(t==0)
        enemy[i].vy=3;//下落
    if(t==40)
        enemy[i].vy=0;//停止
    if(t==40+enemy[i].wait)//停止时间结束
        enemy[i].vy=-3;//往上移动
}

//移动模式1
//下落一段,停滞一会,然后往左下方移动
void enemy_pattern1(int i){
    int t=enemy[i].cnt;
    if(t==0)
        enemy[i].vy=3;//下落
    if(t==40)
        enemy[i].vy=0;//停止
    if(t==40+enemy[i].wait){//停止时间结束
        enemy[i].vx=-1;//往左
        enemy[i].vy=2;//往下移动
        enemy[i].muki=0;//设置朝向为左
    }
}

//移动模式2
//下落一段,停滞一会,然后往右下方移动
void enemy_pattern2(int i){
    int t=enemy[i].cnt;
    if(t==0)
        enemy[i].vy=3;//下落
    if(t==40)
        enemy[i].vy=0;//停止
    if(t==40+enemy[i].wait){//停止时间结束
        enemy[i].vx=1;//往右
        enemy[i].vy=2;//往下移动
        enemy[i].muki=2;//设置朝向为右
    }
}

//移动模式3
//快速的下落,并往左移动
void enemy_pattern3(int i){
    int t=enemy[i].cnt;
    if(t==0)
        enemy[i].vy=5;//下落
    if(t==30){//途中设置朝向为左
        enemy[i].muki=0;
    }
    if(t<100){
        enemy[i].vx-=5/100.0;//向左加速
        enemy[i].vy-=5/100.0;//减速
    }
}

//移动模式4
//快速下落,并向右移动
void enemy_pattern4(int i){
    int t=enemy[i].cnt;
    if(t==0)
        enemy[i].vy=5;//下落
    if(t==30){//途中设置朝向为右
        enemy[i].muki=2;
    }
    if(t<100){
        enemy[i].vx+=5/100.0;//向右加速
        enemy[i].vy-=5/100.0;//减速
    }
}

//移动模式5
//斜向左下
void enemy_pattern5(int i){
    int t=enemy[i].cnt;
    if(t==0){
        enemy[i].vx-=1;
        enemy[i].vy=2;
        enemy[i].muki=0;
    }
}

//移动模式6
//斜向右下
void enemy_pattern6(int i){
    int t=enemy[i].cnt;
    if(t==0){
        enemy[i].vx+=1;
        enemy[i].vy=2;
        enemy[i].muki=2;
    }
}

//移动模式7
//停滞一会,然后就往左上移动
void enemy_pattern7(int i){
    int t=enemy[i].cnt;
    if(t==enemy[i].wait){//停止时间结束
        enemy[i].vx=-0.7;//往左
        enemy[i].vy=-0.3;//往上移动
        enemy[i].muki=0;//设置朝向为左
    }
}

//移动模式8
//停滞一会,然后就往右上移动
void enemy_pattern8(int i){
    int t=enemy[i].cnt;
    if(t==enemy[i].wait){//停止时间结束
        enemy[i].vx=+0.7;//往右
        enemy[i].vy=-0.3;//往上移动
        enemy[i].muki=2;//设置朝向为右
    }
}

//移动模式9
//停滞一会,然后就往上移动
void enemy_pattern9(int i){
    int t=enemy[i].cnt;
    if(t==enemy[i].wait)//停止时间结束
        enemy[i].vy=-1;//往上移动
}


//移动模式10
//往下移动,然后转来转去的向上移动
void enemy_pattern10(int i){
    int t=enemy[i].cnt;
    if(t==0) enemy[i].vy=4;//下落
    if(t==40)enemy[i].vy=0;//停止
    if(t>=40){
        if(t%60==0){
            int r=cos(enemy[i].ang)< 0 ? 0 : 1;
            enemy[i].sp=6+rang(2);
            enemy[i].ang=rang(PI/4)+PI*r;
            enemy[i].muki=2-2*r;
        }
        enemy[i].sp*=0.95;
    }
    if(t>=40+enemy[i].wait){
        enemy[i].vy-=0.05;
    }
}

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

总之,我们来看看我们写的这个函数会做出什么样的动作吧。

在Excel 里按照下面进行改动。直接下载来代替也是可以的。


/カウンタ 移動パターン 敵の種類 x座標 y座標 スピード 発射時間 弾幕種類 弾の色 体力 弾種類 待機時間 アイテム1 2 3 4 5 6
/cnt pattern knd x y sp bltime blknd col hp blknd2 wait item_n          
100 0 0 180 -20 0 150 0 0 100 0 120 0 -1 -1 -1 -1 -1
180 1 0 200 -20 0 150 0 0 100 0 120 0 -1 -1 -1 -1 -1
260 2 0 180 -20 0 150 0 0 100 0 120 0 -1 -1 -1 -1 -1
340 3 0 200 -20 0 150 0 0 100 0 120 0 -1 -1 -1 -1 -1
420 4 0 180 -20 0 150 0 0 100 0 120 0 -1 -1 -1 -1 -1
500 5 0 200 -20 0 150 0 0 100 0 120 0 -1 -1 -1 -1 -1
580 6 0 180 -20 0 150 0 0 100 0 120 0 -1 -1 -1 -1 -1
660 7 0 200 150 0 150 0 0 100 0 120 0 -1 -1 -1 -1 -1
740 8 0 180 150 0 150 0 0 100 0 120 0 -1 -1 -1 -1 -1
820 9 0 200 150 0 150 0 0 100 0 120 0 -1 -1 -1 -1 -1
900 10 0 180 -20 0 150 0 0 100 0 360 0 -1 -1 -1 -1 -1


Excel文件的下载


这里,敌人的行动模式存在enemy[i].pattern 数据里面,要根据存在这里的0-10 的这样的值,

自动调用 函数enemy_pattern0 ~ 函数 enemy_pattern10 ,这要怎么做呢?

这里就要使用叫做函数指针的东西了。

(*enemy_pattern[ENEMY_PATTERN_MAX])(int) = { enemy_pattern0, enemy_pattern1, .....

像这样,把对应的函数的地址代入进去。

之后,把对应元素编号,用之前的 enemy[i].pattern 来指定,就可以调用处理了。

实际使用了函数指针来调用的函数,就是下面的红字部分(颜色我省了)。

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

//--enemy.cpp里添加如下代码--

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

#define ENEMY_PATTERN_MAX 11

extern void enemy_pattern0(int);extern void enemy_pattern1(int);extern void enemy_pattern2(int);
extern void enemy_pattern3(int);extern void enemy_pattern4(int);extern void enemy_pattern5(int);
extern void enemy_pattern6(int);extern void enemy_pattern7(int);extern void enemy_pattern8(int);
extern void enemy_pattern9(int);extern void enemy_pattern10(int);

void (*enemy_pattern[ENEMY_PATTERN_MAX])(int) = {
    enemy_pattern0,    enemy_pattern1,    enemy_pattern2,    enemy_pattern3,    enemy_pattern4,
    enemy_pattern5,    enemy_pattern6,    enemy_pattern7,    enemy_pattern8,    enemy_pattern9,
    enemy_pattern10,
};

//搜索空闲的敌机编号
int enemy_num_search(){
    for(int i=0;i<ENEMY_MAX;i++){//根据flag,寻找空闲的enemy
        if(enemy[i].flag==0){
            return i;//返回可以使用的编号
        }
    }
    return -1;//全部都被使用了的话,返回错误信息
}

//敌机数据的载入
void enemy_enter(){//敌机的行动数据载入和操作的函数
    int i,j,t;
    for(t=0;t<ENEMY_ORDER_MAX;t++){
        if(enemy_order[t].cnt==stage_count){//到了开始移动的时间
            if((i=enemy_num_search())!=-1){
                enemy[i].flag   =1;//标志
                enemy[i].cnt    =0;//计数
                enemy[i].pattern=enemy_order[t].pattern;//移动模式
                enemy[i].muki   =1;//方向
                enemy[i].knd    =enemy_order[t].knd;//敌机种类
                enemy[i].x      =enemy_order[t].x;//坐标
                enemy[i].y      =enemy_order[t].y;
                enemy[i].sp     =enemy_order[t].sp;//速度
                enemy[i].bltime =enemy_order[t].bltime;//子弹的发射时间
                enemy[i].blknd  =enemy_order[t].blknd;//弹幕的种类
                enemy[i].blknd2 =enemy_order[t].blknd2;//子弹的种类
                enemy[i].col    =enemy_order[t].col;//颜色
                enemy[i].wait   =enemy_order[t].wait;//停止时间
                enemy[i].hp     =enemy_order[t].hp;//体力
                enemy[i].hp_max =enemy[i].hp;//体力最大值
                enemy[i].vx     =0;//水平方向的分速度
                enemy[i].vy     =0;//竖直方向的分速度
                enemy[i].ang    =0;//角度
                for(j=0;j<6;j++)
                    enemy[i].item_n[j]=enemy_order[t].item_n[j];//掉落的道具
            }
        }
    }
}

//敌机的行动操作
void enemy_act(){
    int i;
    for(i=0;i<ENEMY_MAX;i++){
        if(enemy[i].flag==1){//这个敌机的标志设置为开启的话
            if(0<=enemy[i].pattern && enemy[i].pattern<ENEMY_PATTERN_MAX){
                enemy_pattern[enemy[i].pattern](i);                 //这行是红字。。。
                enemy[i].x+=cos(enemy[i].ang)*enemy[i].sp;
                enemy[i].y+=sin(enemy[i].ang)*enemy[i].sp;
                enemy[i].x+=enemy[i].vx;
                enemy[i].y+=enemy[i].vy;
                enemy[i].cnt++;
                enemy[i].img=enemy[i].muki*3+(enemy[i].cnt%18)/6;
                //敌机已经移动到画面之外的话进行消除
                if(enemy[i].x<-20 || FIELD_MAX_X+20<enemy[i].x || enemy[i].y<-20 || FIELD_MAX_Y+20<enemy[i].y)
                    enemy[i].flag=0;
            }
            else
                printfDx("enemy[i].pattern的%d值不正确。",enemy[i].pattern);
        }
    }
}

//敌机处理的main方法
void enemy_main(){
    enemy_enter();
    enemy_act();
}
——————————————————————————————————————————————————————————————————

为了后面的角度计算方便,这里先把圆周率给定义一下。

圆周率的 pi 和 2*pi 都会用到,这里预先把乘好的值也定义下来。

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

--define.h里添加如下代码--

//圆周率
#define PI 3.1415926535898
#define PI2 (PI*2)

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

运行结果

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

像运行结果里,有各种各样行动方式的敌人出现的话,就成功了。


(PS:最近玩剑灵,所以好久没更新了。唉,进了这DT的游戏公司,回去都12点了,再玩会剑灵,没别的时间了)

(2014-2-18 笔记,这篇结合上一篇的笔记,就很好懂了。这篇只是新增了几个敌机的移动模式而已。然后用指针数组,根据i 找到对应的模式函数。然后具体分析里面的模式,其实都比较好懂,在某个时间点改变x y 方向的速度什么的。然后就是最后一种模式,可以仔细看看。这里用的是角度和速度,来控制移动的。而enemy_act 函数里面,先是根据角度移动,然后是根据x y 速度分量移动。 所以两种移动方式都会有效的,会叠加起来。估计这里这样设计的好处,就是某些地方,适合极坐标的时候,就只用角度来进行移动,方便弹幕的绘制)


本人CSDN博客目录:

http://blog.csdn.net/tidus5


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

抵扣说明:

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

余额充值