Logo Search packages:      
Sourcecode: val-and-rick version File versions  Download package

enemy.d

/*
 * $Id: enemy.d,v 1.2 2005/03/14 13:37:40 kenta Exp $
 *
 * Copyright 2005 Kenta Cho. Some rights reserved.
 */
module abagames.vr.enemy;

private import std.math;
private import opengl;
private import bulletml;
private import abagames.util.vector;
private import abagames.util.actor;
private import abagames.util.rand;
private import abagames.util.math;
private import abagames.util.sdl.texture;
private import abagames.vr.shape;
private import abagames.vr.field;
private import abagames.vr.bulletactor;
private import abagames.vr.bulletactorpool;
private import abagames.vr.bullettarget;
private import abagames.vr.bulletimpl;
private import abagames.vr.barrage;
private import abagames.vr.ship;
private import abagames.vr.stagemanager;
private import abagames.vr.screen;
private import abagames.vr.particle;
private import abagames.vr.shot;
private import abagames.vr.crystal;
private import abagames.vr.explosion;
private import abagames.vr.soundmanager;

/**
 * Enemy ships.
 */
00035 public class Enemy: Actor {
 private:
  static Rand rand;
  Field field;
  Screen screen;
  BulletActorPool bullets;
  Ship ship;
  ParticlePool particles;
  CrystalPool crystals;
  ExplosionPool explosions;
  EnemySpec spec;
  EnemyState _state;
  bool damaged;

  public static this() {
    rand = new Rand;
  }

  public static void setRandSeed(long seed) {
    rand.setSeed(seed);
  }

  public override void init(Object[] args) {
    field = cast(Field) args[0];
    screen = cast(Screen) args[1];
    bullets = cast(BulletActorPool) args[2];
    ship = cast(Ship) args[3];
    particles = cast(ParticlePool) args[4];
    crystals = cast(CrystalPool) args[5];
    explosions = cast(ExplosionPool) args[6];
    _state = new EnemyState;
  }

  public void set(EnemySpec spec) {
    this.spec = spec;
    damaged = false;
    exists = true;
  }

  public override void move() {
    if (!spec.move(state)) {
      remove();
      return;
    }
    if (spec.type == EnemySpec.EnemyType.GROUND && ship.checkEnemyHit(spec, state)) {
      remove();
      Explosion ep = explosions.getInstance();
      if (ep)
        ep.set(state.pos, 0, 0);
      return;
    }
    BulletActor.totalBulletsSpeed += 0.14f;
    damaged = false;
  }

  public void checkShotHit(Vector p, Collidable shape, Shot shot = null) {
    if (shot && (!ship.airMode && spec.type == EnemySpec.EnemyType.BLOCK))
      return;
    float ox = fabs(_state.pos.x - p.x), oy = fabs(_state.pos.y - p.y);
    if (spec.checkCollision(ox, oy, shape)) {
      if (shot)
        state.shield -= shot.damage;
      else
        state.shield -= 99999;
      if (state.shield <= 0) {
        destroyed(shot);
      } else {
        damaged = true;
      }
      if (shot)
        shot.remove();
    }
  }

  public void destroyed(Shot shot = null) {
    float hasCrystal = false;
    spec.destroyed(state, shot, explosions, particles);
    if (!ship.airMode) {
      Crystal cs = crystals.getInstance();
      if (cs)
        cs.set(state.pos);
      if (cast(EB1Spec) spec) {
        bullets.changeToCrystals();
        hasCrystal = true;
      }
    }
    if (hasCrystal)
      SoundManager.playSe("large_dest.wav");
    else
      SoundManager.playSe("zako_dest.wav");
    remove();
  }

  public void remove() {
    spec.remove(_state);
    exists = false;
  }

  public override void draw() {
    spec.draw(_state);
  }

  public EnemyState state() {
    return _state;
  }
}

public class EnemyPool: ActorPool!(Enemy) {
 private:

  public this(int n, Object[] args) {
    super(n, args);
  }

  public void checkShotHit(Vector pos, Collidable shape, Shot shot = null) {
    foreach (Enemy e; actor)
      if (e.exists)
        e.checkShotHit(pos, shape, shot);
  }

  /*public int getNum() {
    int num = 0;
    foreach (Enemy e; actor)
      if (e.exists)
        num++;
    return num;
  }*/

  public void destroy() {
    foreach (Enemy e; actor)
      if (e.exists)
        e.destroyed();
  }
}

/**
 * Bits moving around a ground enemy.
 */
00173 public class EnemyBit {
 private:
  static const int MAX_NUM = 16;
  static BitmapShape shape;
  EnemyBitSpec spec;
  float radius;
  float radiusAmpCnt;
  float deg;
  float rollAmpCnt;
  float swingAmpCnt;
  float swingAmpDeg;
  float swingFixDeg;
  float distDeg;
  float distAmpCnt;
  float alignAmpCnt;
  int cnt;
  Vector pos;
  BulletActor[MAX_NUM] topBullet;
  Vector[MAX_NUM] bitPos;

  public static void init() {
    shape = new BitmapShape(BitmapShape.purser, 1);
  }

  public static void close() {
    shape.close();
  }

  public this() {
    pos = new Vector;
    foreach (inout Vector bp; bitPos)
      bp = new Vector;
  }

  public void set(BulletActorPool bullets, Ship ship,
                  EnemyBitSpec spec, int xReverse = 1, int yReverse = 1, float sfd = PI) {
    this.spec = spec;
    radius = spec.radiusBase;
    radiusAmpCnt = 0;
    deg = 0;
    rollAmpCnt = swingAmpCnt = swingAmpDeg = alignAmpCnt = 0;
    distDeg = distAmpCnt = 0;
    swingFixDeg = sfd;
    for (int i = 0; i < spec.num; i++) {
      topBullet[i] = bullets.addTopBullet(spec.barrage, 0, 0, 0, 0,
                                          xReverse, yReverse, spec.barrageSpeed,
                                          ship,
                                          1, spec.barragePostWait,
                                          1);
      if (topBullet[i])
        topBullet[i].unsetAimTop();
    }
    cnt = 0;
  }

  public void move(Vector p, Ship ship) {
    pos.x = p.x;
    pos.y = p.y;
    if (spec.radiusAmp > 0) {
      radiusAmpCnt += spec.radiusAmpVel;
      float av = sin(radiusAmpCnt);
      radius = spec.radiusBase + spec.radiusAmp * av;
    }
    if (spec.moveType == EnemyBitSpec.MoveType.ROLL) {
      if (spec.rollAmp != 0) {
        rollAmpCnt += spec.rollAmpVel;
        float av = sin(rollAmpCnt);
        deg += spec.rollDegVel + spec.rollAmp * av;
      } else {
        deg += spec.rollDegVel;
      }
    } else {
      swingAmpCnt += spec.swingAmpVel;
      if (cos(swingAmpCnt) > 0) {
        swingAmpDeg += spec.swingDegVel;
      } else {
        swingAmpDeg -= spec.swingDegVel;
      }
      if (spec.moveType == EnemyBitSpec.MoveType.SWING_AIM) {
        float od = atan2(ship.pos.x - pos.x, ship.pos.y - pos.y) + swingAmpDeg - deg;
        Math.normalizeDeg(od);
        deg += od * 0.1f;
      } else {
        float od = swingFixDeg + swingAmpDeg - deg;
        Math.normalizeDeg(od);
        deg += od * 0.1f;
      }
    }
    float d, ad, md;
    calcAlignDeg(d, ad, md);
    for (int i = 0; i < spec.num; i++) {
      d += md;
      if (!topBullet[i])
        continue;
      float bx = pos.x + sin(d) * radius;
      float by = pos.y + cos(d) * radius * (1 - spec.distRatio);
      topBullet[i].bullet.pos.x = bx;
      topBullet[i].bullet.pos.y = by;
      topBullet[i].bullet.deg = d;
      bitPos[i].x = bx;
      bitPos[i].y = by;
      if ((cnt % 30) == 0)
        topBullet[i].increasePostWait();
    }
    cnt++;
  }

  private void calcAlignDeg(out float d, out float ad, out float md) {
    alignAmpCnt += spec.alignAmpVel;
    ad = spec.alignDeg * (1 + sin(alignAmpCnt) * spec.alignAmp);
    if (spec.num > 1)
      md = ad / (spec.num - 1);
    else
      md = 0;
    d = deg - md - ad / 2;
  }

  public void draw() {
    for (int i = 0; i < spec.num; i++) {
      if (!topBullet[i])
        continue;
      glPushMatrix();
      Screen.glTranslate(bitPos[i]);
      shape.draw();
      glPopMatrix();
    }
  }

  public void remove() {
    for (int i = 0; i < spec.num; i++) {
      if (topBullet[i]) {
        topBullet[i].removeForced();
        topBullet[i] = null;
      }
    }
  }

  public void destroyed(ExplosionPool explosions, ParticlePool particles, Rand rand) {
    float d, ad, md;
    calcAlignDeg(d, ad, md);
    for (int i = 0; i < spec.num; i++) {
      d += md;
      if (topBullet[i]) {
        Explosion ep = explosions.getInstance();
        if (ep)
          ep.set(bitPos[i], 0, 0);
        float vx = sin(d) * 0.6f;
        float vy = cos(d) * 0.6f;
        for (int j = 0; j < 12; j++) {
          Particle pt = particles.getInstanceForced();
          pt.set(bitPos[i], vx + rand.nextSignedFloat(0.15f), vy + rand.nextSignedFloat(0.15f),
                 rand.nextFloat(0.5f) + 0.5f, 1, 0.2f, 32 + rand.nextInt(48));
        }
      }
    }
  }
}

public class EnemyBitSpec {
 public:
  static enum MoveType {
    ROLL, SWING_FIX, SWING_AIM,
  };
  int num;
  float alignDeg;
  float alignAmp;
  float alignAmpVel;
  float radiusBase;
  float radiusAmp;
  float radiusAmpVel;
  int moveType;
  float rollDegVel;
  float rollAmp;
  float rollAmpVel;
  float swingDegVel;
  float swingAmpVel;
  float distRatio;
  //float distDegBase;
  //float distAmpVel;
  ParserParam[] barrage;
  int barragePostWait;
  float barrageSpeed;

  public this() {
    num = 1;
    alignDeg = PI * 2;
    alignAmp = alignAmpVel = 0;
    radiusBase = 1;
    radiusAmp = radiusAmpVel = 0;
    moveType = MoveType.SWING_FIX;
    rollDegVel = rollAmp = rollAmpVel = 0;
    swingDegVel = swingAmpVel = 0;
    distRatio = 0;
    //distDegBase = distAmpVel = 0;
  }

  public void setAlignAmp(float a, float v) {
    alignAmp = a;
    alignAmpVel = v;
  }

  public void setRadiusAmp(float a, float v) {
    radiusAmp = a;
    radiusAmpVel = v;
  }

  public void setRoll(float dv, float a, float v) {
    moveType = MoveType.ROLL;
    rollDegVel = dv;
    rollAmp = a;
    rollAmpVel = v;
  }

  public void setSwing(float dv, float a, bool aim = false) {
    if (aim)
      moveType = MoveType.SWING_AIM;
    else
      moveType = MoveType.SWING_FIX;
    swingDegVel = dv;
    swingAmpVel = a;
  }
}

public class EnemyState {
 public:
  static enum AppearanceType {
    TOP, SIDE, TOP_LEFT, TOP_RIGHT,
  };
  static const int ENEMY_BIT_MAX = 4;
  int appType;
  int animIdx, animIdxInc, animCnt;
  Vector pos;
  Vector ppos; // Position at a previous frame.
  int shield;
  BulletActor topBullet;
  float deg, speed;
  int state;
  int cnt;
  Vector vel;
  EnemyBit[ENEMY_BIT_MAX] enemyBit;
  int enemyBitNum;
  int blockX, blockY;

 private:
  static const float MINIMUM_APP_DIST = 3;

  public this() {
    animIdx = animCnt = 0;
    animIdxInc = 1;
    pos = new Vector;
    ppos = new Vector;
    vel = new Vector;
    foreach (inout EnemyBit eb; enemyBit)
      eb = new EnemyBit;
  }

  public bool setAppearancePos(Field field, Ship ship, Rand rand,
                               int appType = AppearanceType.TOP) {
    this.appType = appType;
    bool validPos = false;
    for (int i = 0 ; i < 8 ; i++) {
      switch (appType) {
      case AppearanceType.TOP:
      case AppearanceType.TOP_LEFT:
      case AppearanceType.TOP_RIGHT:
        switch (appType) {
        case AppearanceType.TOP:
          pos.x = rand.nextSignedFloat(field.size.x);
          break;
        case AppearanceType.TOP_LEFT:
          pos.x = -rand.nextFloat(field.size.x);
          break;
        case AppearanceType.TOP_RIGHT:
          pos.x = rand.nextFloat(field.size.x);
          break;
        }
        pos.y = field.outerSize.y * 0.99f;
        deg = PI + rand.nextSignedFloat(0.5f);
        break;
      case AppearanceType.SIDE:
        if (rand.nextInt(2) == 0) {
          pos.x = -field.outerSize.x * 0.99f;
          deg = PI / 2;
        } else {
          pos.x = field.outerSize.x * 0.99f;
          deg = -PI / 2;
        }
        pos.y = rand.nextFloat(field.size.y);
        break;
      }
      //if (field.getBlock(pos) < 0 && ship.pos.dist(pos) >= MINIMUM_APP_DIST) {
      if (field.getBlock(pos) < 0) {
        validPos = true;
        break;
      }
    }
    return validPos;
  }
}

/**
 * Base class for a specification of an enemy.
 */
00476 public class EnemySpec {
 public:
  static const float MINIMUM_FIRE_DIST = 7;
  static enum EnemyType {
    GROUND, BLOCK, AIR,
  };
  static enum AnimationType {
    NONE, SEQUENCE, BACKANDFORTH, MANUAL,
  };
  ParserParam[] barrage;
 protected:
  static const int ANIMATION_INDEX_NUM = 3;
  static const float SKY_SCROLL_RATIO = 0.1f;
  static Rand rand;
  BulletActorPool bullets;
  Field field;
  Ship ship;
  int shield;
  BitmapShape[] shape;
  int type;
  int animType, animInterval;
  int animIndexStep;
  BitmapShape shadowShape;
  int shadowIdx;
  int barragePrevWait;
  int barragePostWait;
  float barrageSpeed;

  static this() {
    rand = new Rand;
  }

  public static void setRandSeed(long seed) {
    rand.setSeed(seed);
  }

  public this(BulletActorPool bullets, Field field, Ship ship,
              int type,
              Texture tex, int bitmapIdx, int animIndexStep, int animType, int animInterval,
              int shadowIdx = -1) {
    this.bullets = bullets;
    this.field = field;
    this.ship = ship;
    this.type = type;
    int ain = ANIMATION_INDEX_NUM;
    if (animType == AnimationType.NONE)
      ain = 1;
    for (int i = 0; i < ain; i++) {
      BitmapShape bs = new BitmapShape(tex, bitmapIdx + i * animIndexStep);
      shape ~= bs;
    }
    this.animType = animType;
    this.animInterval = animInterval;
    shield = 1;
    if (shadowIdx >= 0) {
      this.shadowIdx = shadowIdx;
      shadowShape = new BitmapShape(tex, shadowIdx);
    } else {
      shadowShape = null;
    }
    barragePostWait = -1;
  }

  public void setState(Ship ship, EnemyState es) {
    es.shield = shield;
    es.enemyBitNum = 0;
    if (barragePostWait >= 0) {
      barragePrevWait = rand.nextInt(barragePostWait);
      es.topBullet = bullets.addTopBullet(barrage, es.pos.x, es.pos.y, 0, 0,
                                          rand.nextInt(2) * 2 - 1, 1, barrageSpeed,
                                          ship,
                                          barragePrevWait + 1, barragePostWait);
    } else {
      es.topBullet = null;
    }
  }

  public bool move(EnemyState es) {
    es.ppos.x = es.pos.x;
    es.ppos.y = es.pos.y;
    if (animType != AnimationType.NONE && animType != AnimationType.MANUAL) {
      es.animCnt--;
      if (es.animCnt <= 0) {
        es.animCnt = animInterval;
        es.animIdx += es.animIdxInc;
        if (es.animIdx >= ANIMATION_INDEX_NUM) {
          if (animType == AnimationType.SEQUENCE) {
            es.animIdx = 0;
          } else {
            es.animIdxInc *= -1;
            es.animIdx += es.animIdxInc * 2;
          }
        } else if (es.animIdx < 0) {
          es.animIdxInc *= -1;
          es.animIdx += es.animIdxInc * 2;
        }
      }
    }
    if (es.topBullet) {
      es.topBullet.bullet.pos.x = es.pos.x;
      es.topBullet.bullet.pos.y = es.pos.y;
      if (ship.pos.dist(es.pos) < MINIMUM_FIRE_DIST || !field.checkInField(es.pos))
        es.topBullet.isActive = false;
      else
        es.topBullet.isActive = true;
    }
    for (int i = 0; i < es.enemyBitNum; i++)
      es.enemyBit[i].move(es.pos, ship);
    return true;
  }

  public void draw(EnemyState es) {
    glPushMatrix();
    Screen.glTranslate(es.pos);
    if (!ship.airMode && type == EnemyType.GROUND) {
      glPushMatrix();
      glTranslatef(0.3f, -0.2f, 0);
      shape[es.animIdx].drawAlpha();
      glPopMatrix();
    }
    shape[es.animIdx].draw();
    if (shadowShape) {
      glPushMatrix();
      glTranslatef(1, 0, 0);
      shadowShape.draw();
      glPopMatrix();
    }
    glPopMatrix();
    for (int i = 0; i < es.enemyBitNum; i++)
      es.enemyBit[i].draw();
  }

  public void remove(EnemyState es) {
    if (es.topBullet) {
      es.topBullet.removeForced();
      es.topBullet = null;
    }
    for (int i = 0; i < es.enemyBitNum; i++)
      es.enemyBit[i].remove();
  }

  public bool checkCollision(float x, float y, Collidable c) {
    return shape[0].checkCollision(x, y, c);
  }

  public void destroyed(EnemyState es, Shot shot, ExplosionPool explosions, ParticlePool particles) {
    Explosion ep = explosions.getInstance();
    if (ep) {
      if (shot) {
        float d = shot.deg;
        ep.set(es.pos, Shot.SPEED * sin(d) * 0.3f, Shot.SPEED * cos(d) * 0.3f);
      } else {
        ep.set(es.pos, 0, 0);
      }
    }
    float vx = 0, vy = 0;
    if (shot) {
      float d = shot.deg;
      vx = Shot.SPEED * sin(d) * 0.7f;
      vy = Shot.SPEED * cos(d) * 0.7f;
    }
    for (int i = 0; i < 16 + rand.nextInt(8); i++) {
      Particle pt = particles.getInstanceForced();
      pt.set(es.pos, vx + rand.nextSignedFloat(0.5f), vy + rand.nextSignedFloat(0.5f),
             1, rand.nextFloat(0.5f) + 0.5f, 0.2f, 16 + rand.nextInt(16));
    }
  }

  public void setBarrageInterval(int i) {
    barragePostWait = i;
  }

  public void setBarrageSpeed(float s) {
    barrageSpeed = s;
  }
}

public class EG1Spec: EnemySpec {
 public:
  static enum MoveState {
    STAYING, MOVING,
  };
 private:
  float accel, maxSpeed, staySpeed;
  int moveDuration, stayDuration;

  public this(BulletActorPool bullets, Field field, Ship ship) {
    super(bullets, field, ship, EnemyType.GROUND, 
          BitmapShape.enemies, 1, 4, AnimationType.BACKANDFORTH, 20);
  }

  public void setParam(float ac, float ms, float ss, int md, int sd) {
    accel = ac;
    maxSpeed = ms;
    staySpeed = ss;
    moveDuration = md;
    stayDuration = sd;
  }

  public bool setFirstState(EnemyState es, int appType) {
    if (!es.setAppearancePos(field, ship, rand, appType))
      return false;
    es.speed = 0;
    es.state = MoveState.MOVING;
    es.cnt = moveDuration;
    super.setState(ship, es);
    return true;
  }

  public bool move(EnemyState es) {
    super.move(es);
    es.pos.x += sin(es.deg) * es.speed;
    es.pos.y += cos(es.deg) * es.speed;
    if (!ship.airMode || ship.toAir || ship.toGround)
      es.pos.y -= field.lastScrollY;
    else
      es.pos.y -= field.lastScrollY * SKY_SCROLL_RATIO;
    if  (es.pos.y <= -field.outerSize.y)
      return false;
    if ((!ship.airMode && field.getBlock(es.pos) >= 0) || !field.checkInOuterField(es.pos)) {
      es.deg += PI;
      es.pos.x += sin(es.deg) * es.speed * 2;
      es.pos.y += cos(es.deg) * es.speed * 2;
    }
    switch (es.state) {
    case MoveState.MOVING:
      es.speed += (maxSpeed - es.speed) * accel;
      es.cnt--;
      if (es.cnt <= 0) {
        es.cnt = stayDuration;
        es.state = MoveState.STAYING;
      }
      break;
    case MoveState.STAYING:
      es.speed += (staySpeed - es.speed) * accel;
      es.cnt--;
      if (es.cnt <= 0) {
        es.deg = rand.nextFloat(PI * 2);
        es.cnt = moveDuration;
        es.state = MoveState.MOVING;
      }
      break;
    }
    return true;
  }
}

public class EG2Spec: EnemySpec {
 private:
  float speed, turnDeg;

  public this(BulletActorPool bullets, Field field, Ship ship) {
    super(bullets, field, ship, EnemyType.GROUND,
          BitmapShape.enemies, 3, 4, AnimationType.SEQUENCE, 10);
  }

  public void setParam(float sp, float td) {
    speed = sp;
    turnDeg = td;
  }

  public bool setFirstState(EnemyState es) {
    if (!es.setAppearancePos(field, ship, rand))
      return false;
    super.setState(ship, es);
    return true;
  }

  public bool move(EnemyState es) {
    super.move(es);
    es.pos.x += sin(es.deg) * speed;
    es.pos.y += cos(es.deg) * speed;
    if (!ship.airMode || ship.toAir || ship.toGround)
      es.pos.y -= field.lastScrollY;
    else
      es.pos.y -= field.lastScrollY * SKY_SCROLL_RATIO;
    if  (es.pos.y <= -field.outerSize.y)
      return false;
    if ((!ship.airMode && field.getBlock(es.pos) >= 0) || !field.checkInOuterField(es.pos)) {
      es.deg += PI;
      es.pos.x += sin(es.deg) * speed * 2;
      es.pos.y += cos(es.deg) * speed * 2;
    }
    float ad = atan2(ship.pos.x - es.pos.x, ship.pos.y - es.pos.y);
    float od = ad - es.deg;
    Math.normalizeDeg(od);
    if (od <= turnDeg && od >= -turnDeg)
      es.deg = ad;
    else if (od < 0)
      es.deg -= turnDeg;
    else
      es.deg += turnDeg;
    Math.normalizeDeg(es.deg);
    return true;
  }
}

public class EB1Spec: EnemySpec {
 public:
  EnemyBitSpec[EnemyState.ENEMY_BIT_MAX] bitSpec;
  int bitNum;

  public this(BulletActorPool bullets, Field field, Ship ship) {
    super(bullets, field, ship, EnemyType.BLOCK,
          BitmapShape.ground, 12, 2, AnimationType.BACKANDFORTH, 30, 18);
    foreach (inout EnemyBitSpec bs; bitSpec)
      bs = new EnemyBitSpec;
  }

  public void setFirstState(EnemyState es, float x, float y, int bx, int by) {
    es.pos.x = x;
    es.pos.y = y;
    es.blockX = bx;
    es.blockY = by;
    super.setState(ship, es);
    es.enemyBitNum = bitNum;
    for (int i = 0; i < bitNum ; i++) {
      int xr = 1, yr = 1;
      if (bitSpec[i].moveType == EnemyBitSpec.MoveType.ROLL && rand.nextInt(5) == 0)
        yr = -1;
      if (rand.nextInt(4) == 0)
        xr = -1;
      es.enemyBit[i].set(bullets, ship, bitSpec[i],
                         xr, yr, PI + (x / field.size.x) * PI / 4);
    }
  }

  public bool move(EnemyState es) {
    super.move(es);
    es.pos.y -= field.lastScrollY;
    if  (es.pos.y <= -field.outerSize.y)
      return false;
    return true;
  }

  public void destroyed(EnemyState es, Shot shot, ExplosionPool explosions, ParticlePool particles) {
    Explosion ep = explosions.getInstance();
    if (ep)
      ep.set(es.pos, 0, 0, 30, 3);
    for (int i = 0; i < bitNum ; i++)
      es.enemyBit[i].destroyed(explosions, particles, rand);
    field.setRuin(es.blockX, es.blockY);
  }
}

public class EA1Spec: EnemySpec {
 private:
  static enum MoveState {
    APPROACHING, SEPARATION,
  };
  float vxBase, vyBase;

  public this(BulletActorPool bullets, Field field, Ship ship) {
    super(bullets, field, ship, EnemyType.AIR,
          BitmapShape.enemies, 0, 4, AnimationType.MANUAL, 0);
  }

  public void setParam(float vxb, float vyb) {
    vxBase = vxb;
    vyBase = vyb;
  }

  public bool setFirstState(Ship ship, EnemyState es) {
    int appType;
    if (ship.pos.x < 0) {
      appType = EnemyState.AppearanceType.TOP_RIGHT;
      es.vel.x = -vxBase * (1 + rand.nextSignedFloat(0.3f));
    } else {
      appType = EnemyState.AppearanceType.TOP_LEFT;
      es.vel.x = vxBase * (1 + rand.nextSignedFloat(0.3f));
    }
    if (!es.setAppearancePos(field, ship, rand, appType))
      return false;
    es.vel.y = -vyBase * (1 + rand.nextSignedFloat(0.2f));
    es.state = MoveState.APPROACHING;
    super.setState(ship, es);
    return true;
  }

  public bool move(EnemyState es) {
    super.move(es);
    es.pos.x += es.vel.x;
    es.pos.y += es.vel.y;
    if (!ship.airMode || ship.toAir || ship.toGround)
      es.pos.y -= field.lastScrollY;
    else
      es.pos.y -= field.lastScrollY * SKY_SCROLL_RATIO;
    if  (!field.checkInOuterField(es.pos))
      return false;
    switch (es.state) {
    case MoveState.APPROACHING:
      if (fabs(es.pos.x - ship.pos.x) < 4.4f) {
        es.state = MoveState.SEPARATION;
        if (es.appType == EnemyState.AppearanceType.TOP_RIGHT)
          es.animIdx = 2;
        else
          es.animIdx = 1;
      }
      break;
    case MoveState.SEPARATION:
      if (es.appType == EnemyState.AppearanceType.TOP_RIGHT)
        es.vel.x += (vxBase * 3 - es.vel.x) * 0.03f;
      else
        es.vel.x += (-vxBase * 3 - es.vel.x) * 0.03f;
      break;
    }
    return true;
  }
}


Generated by  Doxygen 1.6.0   Back to index