⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 enemy.java

📁 手机ACT游戏全代码(包括代码和jar和jad)
💻 JAVA
字号:


import javax.microedition.lcdui.Graphics;

public class Enemy {
       /**
        * 构建一个敌人需要初始化的基本数据
        * @param GE GameEngine游戏主轴
        * @param enemyData short[] 敌人的初始化数据
        */
       public Enemy(Engine GE, short[] enemyData)
       {
              engine = GE;
              objectIndex = (byte) enemyData[0]; //此敌人在动画数组中的索引
              x = enemyData[1]; //初始化敌人的位置(相对地图的x坐标)
              y = (short) (enemyData[2]); //初始化敌人的位置(相对地图的y坐标)
              startX = x; //记录敌人的初始位置
              startY = y;
              bround = enemyData[3]; //敌人的巡逻范围
              xSpeed = (byte) enemyData[4]; //敌人x方向的移动速度
              ySpeed = (byte) enemyData[5]; //敌人y方向的移动速度
              isLeft = enemyData[6] == 0; //敌人的初始化方向
              setStatus(STATE_RUN); //敌人的初始化状态
              isDead = false; //初始敌人设置为未死亡状态
              upStep = 0; //每帧向上移动的像素为0(即y方向无位移)
              HP = 100; //敌人的初始生命值
              getSize();
       }

       final static byte STATE_STAND = 0; //敌人的站立状态
       final static byte STATE_RUN = 1; //行走状态
       final static byte STATE_CHASE = 2; //追击主角状态
       final static byte STATE_ATTACK = 3; //攻击
       final static byte STATE_INJURE = 4; //受伤
       final static byte STATE_DEAD = 5; //死亡
       final static byte STATE_END = 6; //怪物结束

       protected Engine engine;
       protected short HP; //敌人的生命
       protected short x; //敌人的位置(相对地图的x坐标)
       protected short y; //敌人的位置(相对地图的y坐标)
       protected short w; //敌人的宽度(用来矩形碰撞处理)
       protected short h; //敌人的宽度
       protected short bround; //敌人的巡逻范围
       protected boolean isLeft; //敌人的方向
       protected byte upStep; //0表示y方向没有移动,> 0向下移动 ,< 0向上移动
       protected byte xSpeed; //敌人的x方向的移动速度
       protected byte ySpeed; //敌人的y方向的移动速度
       protected boolean isDead; //敌人是否死亡(是否存在)
       protected byte curStatus; //敌人的状态标记量
       protected short startX; //记录敌人的初始位置
       protected short startY;
       protected short px; //敌人的可碰撞区域(px,py,pw,ph构成的矩形)的起始X方向的坐标
       protected short py; //敌人的可碰撞区域(px,py,pw,ph构成的矩形)的起始Y方向的坐标
       protected short pw; //敌人的可碰撞区域(px,py,pw,ph构成的矩形)的宽度
       protected short ph; //敌人的可碰撞区域(px,py,pw,ph构成的矩形)的高度
       protected byte objectIndex; //此敌人在动画数组中的索引
       private byte actionIndex; //敌人的动作(站立、移动、攻击、追击的一种)
       private byte frameIndex; //敌人的帧
       private byte aniIndex; //切换帧变化的中间变量

       /**
        * 敌人的逻辑
        * 包括敌人的AI实现、敌人的碰撞及多种攻击方式
        */
       protected final void move()
       {

              switch (curStatus)
              {
                     case STATE_STAND:
                        playAni(STATE_RUN,0);
                            break;
                     case STATE_RUN:
                            playAni(-1,0);
//                            actionIndex = 1;
                            if(x > startX +bround||
                               x < startX - bround){
                                   isLeft = x > startX;
                            }

                            /*这里注意区分isDead 与主角死亡状态的区别:isDead = true 表示主角已经从屏幕内显示。
                                    主角处于死亡状态则表示主角已经死亡,但是还是存在的。显示部分需要显示主角死亡的动画。
                                    此状态下敌人的攻击、追击逻辑不执行。但是主角逻辑依然执行*/
                            if(!engine.role.isDead&&//主角没有死亡
                               engine.role.curStatus != Role.STATE_DEAD&&//且主角不是死亡状态
                               engine.role.curStatus != Role.STATE_END&&//且主角不是结束状态
                               engine.role.x < startX + bround&&//主角在敌人的视野内,敌人开始追击
                               engine.role.x > startX - bround&&
                               Math.abs(engine.role.y - y) < h){
                                   setStatus(STATE_CHASE);
                            }
                            else{
                                   enemyMoveStep(4);
                            }
                            break;
                     case STATE_CHASE:
                            playAni(-1,0);

                            isLeft = x > engine.role.x;//追击状态下 敌人面向主角

                            if(engine.role.x > startX +2*bround||
                               engine.role.x < startX - 2*bround){//超出追击范围 返回巡逻状态(行走状态),预设定主角的追击范围为巡逻范围的2倍(可随意设定)
                                   setStatus(STATE_RUN);
                            }
                            else if(isLeft == (x > engine.role.x )&&//方向面向主角
                                    Math.abs(engine.role.x - x ) <= engine.role.w /2 + w/2){//且敌人与主角的位置间隔小于0时(这里主角的x是主角中心点的x)
                                   setStatus(STATE_ATTACK);
                            }
                            else{
                                   enemyMoveStep(6);
                            }
                            break;
                     case STATE_ATTACK:
                            if(engine.role.curStatus == Role.STATE_INJURE||
                               engine.role.curStatus == Role.STATE_DEAD||
                               engine.role.curStatus == Role.STATE_END||
                               engine.role.isDead){
                                   setStatus(STATE_STAND);
                            }
                            else
                            if(frameIndex == 3){//这里选取此怪物的攻击帧为第三帧
                                   getAttackSize(2);//2表示攻击状态对应的动画数据为2。也就时动画数据中第二维对应输入的参数
                                   if (Tools.hit(px, py, pw, ph, engine.role.x-(engine.role.w>>1), engine.role.y-engine.role.h, engine.role.w, engine.role.h))
                                   {

                                          engine.role.setStatus(Role.STATE_INJURE);
                                   }
                            }
                            playAni(STATE_CHASE,1);
                            break;
                     case STATE_INJURE:
                            playAni(STATE_CHASE,1);
                            break;
                     case STATE_DEAD:
                            playAni(STATE_END,1);
                            break;
                     case STATE_END:
                            isDead = true;
                            break;
              }

       }

       /**
        * 根据敌人的类型、动作、帧来显示此敌人的动画
        * @param g Graphics
        */
       protected final void drawEnemy(Graphics g)
       {
              if(curStatus < actionArray.length)
                     actionIndex = actionArray[curStatus];
              Tools.drawNpcItemData(g, objectIndex, actionIndex, frameIndex, x, y, isLeft);
       }

       /**
        * 切换敌人的状态,目标状态的动作索引
        * @param nextState int 目标状态(需要切换至此状态)
        * @param nextaActionIndex int 目标状态的动作索引
        */
       protected final void setStatus(int nextState)
       {
              if (curStatus == STATE_DEAD)
              { //已经死亡状态只能切换为结束状态
                     if(nextState != STATE_END)
                            return;
              }

              switch (nextState)
              {
                     case STATE_INJURE:
                            HP -= 5;
                            if (HP <= 0)
                            {
                                   curStatus = STATE_DEAD;
                                   aniIndex = 0; //改变状态后需要初始化下一状态的帧索引

                                   frameIndex = 0;
                                   return;
                            }
                            break;
              }
              aniIndex = 0; //改变状态后需要初始化下一状态的帧索引
              frameIndex = 0;
              curStatus = (byte) nextState;
       }

       /**
        * 获得攻击帧的攻击区域
        * @param tempActionIndex int
        */
       protected final void getAttackSize(int tempActionIndex)
       {
              int tempFrameIndex = 0;
//根据游戏类型获得游戏的攻击帧
              switch (objectIndex)
              {
                     case 1: //索引为1的怪物的攻击帧
                            tempFrameIndex = 3;//怪物的攻击帧为第三帧
                            break;
                     default: //其他怪物的攻击帧
                            tempFrameIndex = 0; //默认为第0帧
                            break;
              }
//以下部分获得攻击帧
              try
              {
                     /*根据动画数据我们定义数据npcItemDataSize 来保存所有动画数据中的每帧的宽、高以及X、Y方向最小偏移,存贮格式为:
                             第一维:表示对象的索引(即objectIndex表示某个对象,与动画数据的对象索引对应,所以此维的长度与npcItemData长度相同)。
                             第二维:表示此对象的动作的索引。
                             第三维:所有帧的x方向的最大偏移,Y方向的最大偏移,宽度、高度。如果是很多帧则下4为分别为第二帧的x方向的最大偏移,Y方向的最大偏移,宽度、高度。依此类推。
                      */
                     pw = Data.npcItemDataSize[objectIndex][tempActionIndex][tempFrameIndex * 4 + 2];
                     //从存贮动画数据的每帧的宽、高以及X、Y方向最小偏移的数组中获得,数据npcItemDataSize的或者后面讲述。
                     ph = Data.npcItemDataSize[objectIndex][tempActionIndex][tempFrameIndex * 4 + 3];

                     px = (short) (x +
                                   Data.npcItemDataSize[objectIndex][tempActionIndex][tempFrameIndex * 4 + 0]);
                     py = (short) (y +
                                   Data.npcItemDataSize[objectIndex][tempActionIndex][tempFrameIndex * 4 + 1]);
              }
              catch (Exception ex)
              {
              }
       }

       /**
        * 获得敌人当前帧的宽度、高度
        *与getAttackSize(int tempActionIndex)区别在于,此方法为此敌人通常情况下的宽度、高度,而方法getAttackSize(int tempActionIndex)获得的则是攻击时才使用到的攻击碰撞区域
        */
       protected final void getSize()
       {
              w = Data.npcItemDataSize[objectIndex][0][0 * 4 + 2]; //从保存每帧动画的尺寸的数组中获得当前帧的宽度、高度
              h = Data.npcItemDataSize[objectIndex][0][0 * 4 + 3];
       }

       /**
        * nextState > 0 切换状态
        * nextState  = -1 循环播放
        * nextState < -1 停留在最后一帧
        * @param nextState byte
        * 同主角类里的改变帧的部分
        */
       private final void playAni(int nextState, int nextaActionIndex)
       {
              /*当达到最后一帧时*/
              if (aniIndex >= Data.frameItemIndex[objectIndex][actionIndex].length)
              {
                     if (nextState >= 0)
                     {
                            aniIndex = 0; //初始化下状态下的中间索引
                            frameIndex = Data.frameItemIndex[objectIndex][actionIndex][aniIndex]; //初始化下状态下的帧索引
                            setStatus(nextState); //切换至目标状态
                            return;
                     }
                     else if (nextState == -1)
                     { //当动画帧显示到此状态下的最后一帧时,输入参数为-1则表示需要无限循环播放此状态下的动画。初始化为第一帧。
                            aniIndex = 0;
                     }
                     else
                     { //否则为显示最后一帧直至切换状态为止
                            return;
                     }
              }
              frameIndex = Data.frameItemIndex[objectIndex][actionIndex][aniIndex]; //获得现在需要显示的实际帧
              aniIndex++;
       }

       /**
        * 敌人的每步移动
        * @param step int
        */
       void enemyMoveStep(int step){
              if(isLeft){
                     if(Map.isFall(x - step,y) ||
                        !Map.isRun(x - step,y-(h>>1))){
                            isLeft = !isLeft;
                            setStatus(STATE_RUN);
                     }
                     else
                            x -= step;
              }
              else
              {
                     if (Map.isFall(x + step, y + 2) ||
                         !Map.isRun(x + step, y - (h >> 1)))
                     {
                            isLeft = !isLeft;
                            setStatus(STATE_RUN);
                     }
                     else
                            x += step;

              }
       }
       //这里定义了每个怪物的动作索引,对应每个怪物的6种状态
       byte[] actionArray = new byte[6];
       void setActionIndex(byte[] data){
              System.arraycopy(data,0,actionArray,0,actionArray.length);
       }

}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -