【四圣龙神录的编程教室】第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座標スピード発射時間弾幕種類弾の色体力弾種類待機時間アイテム123456
/cntpatternkndxyspbltimeblkndcolhpblknd2waititem_n     
10000180-2001500010001200-1-1-1-1-1
18010200-2001500010001200-1-1-1-1-1
26020180-2001500010001200-1-1-1-1-1
34030200-2001500010001200-1-1-1-1-1
42040180-2001500010001200-1-1-1-1-1
50050200-2001500010001200-1-1-1-1-1
58060180-2001500010001200-1-1-1-1-1
6607020015001500010001200-1-1-1-1-1
7408018015001500010001200-1-1-1-1-1
8209020015001500010001200-1-1-1-1-1
900100180-2001500010003600-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


以下是对提供的参考资料的总结,按照要求结构化多个要点分条输出: 4G/5G无线网络优化与网规案例分析: NSA站点下终端掉4G问题:部分用户反馈NSA终端频繁掉4G,主要因终端主动发起SCGfail导致。分析显示,在信号较好的环境下,终端可能因节能、过热保护等原因主动释放连接。解决方案建议终端侧进行分析处理,尝试关闭节电开关等。 RSSI算法识别天馈遮挡:通过计算RSSI平均值及差值识别天馈遮挡,差值大于3dB则认定有遮挡。不同设备分组规则不同,如64T和32T。此方法可有效帮助现场人员识别因环境变化引起的网络问题。 5G 160M组网小区CA不生效:某5G站点开启100M+60M CA功能后,测试发现UE无法正常使用CA功能。问题原因在于CA频点集标识配置错误,修正后测试正常。 5G网络优化与策略: CCE映射方式优化:针对诺基亚站点覆盖农村区域,通过优化CCE资源映射方式(交织、非交织),提升RRC连接建立成功率和无线接通率。非交织方式相比交织方式有显著提升。 5G AAU两扇区组网:与三扇区组网相比,AAU两扇区组网在RSRP、SINR、下载速率和上传速率上表现不同,需根据具体场景选择适合的组网方式。 5G语音解决方案:包括沿用4G语音解决方案、EPS Fallback方案和VoNR方案。不同方案适用于不同的5G组网策略,如NSA和SA,并影响语音连续性和网络覆盖。 4G网络优化与资源利用: 4G室分设备利旧:面对4G网络投资压减与资源需求矛盾,提出利旧多维度调优策略,包括资源整合、统筹调配既有资源,以满足新增需求和提质增效。 宏站RRU设备1托N射灯:针对5G深度覆盖需求,研究使用宏站AAU结合1托N射灯方案,快速便捷地开通5G站点,提升深度覆盖能力。 基站与流程管理: 爱立信LTE基站邻区添加流程:未提供具体内容,但通常涉及邻区规划、参数配置、测试验证等步骤,以确保基站间顺畅切换和覆盖连续性。 网络规划与策略: 新高铁跨海大桥覆盖方案试点:虽未提供详细内容,但可推测涉及高铁跨海大桥区域的4G/5G网络覆盖规划,需考虑信号穿透、移动性管理、网络容量等因素。 总结: 提供的参考资料涵盖了4G/5G无线网络优化、网规案例分析、网络优化策略、资源利用、基站管理等多个方面。 通过具体案例分析,展示了无线网络优化中的常见问题及解决方案,如NSA终端掉4G、RSSI识别天馈遮挡、CA不生效等。 强调了5G网络优化与策略的重要性,包括CCE映射方式优化、5G语音解决方案、AAU扇区组网选择等。 提出了4G网络优化与资源利用的策略,如室分设备利旧、宏站RRU设备1托N射灯等。 基站与流程管理方面,提到了爱立信LTE基站邻区添加流程,但未给出具体细节。 新高铁跨海大桥覆盖方案试点展示了特殊场景下的网络规划需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值