アマゾンバナーリンク

ディスプレイ広告

スポンサーリンク

弾幕五重奏

本日はオリジナル弾幕五重奏を、やんちゃでかわいい感じをイメージして作ってみました。

以上の弾幕です!1つずつソースコードを解説していきます。

記事内広告

寂しがりのソロ

public class CSabisigarinosoro : CBossBulletFactory
{
public CSabisigarinosoro(MOVE_BOSS_POS move_boss_pos) : base(move_boss_pos)
{
SpelName = "寂しがりのソロ";
}
public override void Run(double x, double y)
{
int k, n, t = Cnt % 300, t2 = Cnt;
if (t == 0)
MoveBossPos(40, 30, FIELD_MAX_X - 40, 120, 60, 60);
if (t2 == 0)
{
SGP.CreateBullet(x: x, y: y, angle: PI / 2, speed: 4.0, graph_type: 0, color: 0, state:0, pi2or1: 1.0);
//se_flag[0] = 1;
}
for (int i = 0; i < SGP.Bullet.Count; i++)
{
int a_cnt = SGP.Bullet[i].Cnt;
int state = SGP.Bullet[i].State;
double bx = SGP.Bullet[i].X;
double by = SGP.Bullet[i].Y;
if (a_cnt == 80 && state == 0)
{
SGP.Bullet[i].Speed = 0;
}
switch (state)
{
case 0:
if (t == 120 || t == 270)
{
for (n = 0; n < 7; n++)
{
for (int j = 0; j < 6; j++)
{
SGP.CreateBullet(x: bx, y: by, angle: PI / 5 * j + PI, speed: 1 * n + 2, graph_type: 7, color: 0, state: -1, pi2or1: 1.0)
}
}
//se_flag[0] = 1;
}
break;
}
}
if (t == 180 || t == 210 || t == 240)
{
for (int j = 0; j < 4; j++)
{
for (int i = 0; i < 5; i++)
{
SGP.CreateBullet(x: x, y: y, angle: PI / 2 + PI / 2 / 5 * (i - 5 / 2), speed: j * 0.5 + 2.2, graph_type: 4, color: 0, state: -1, pi2o1.0);
}
}
//se_flag[0] = 1;
}
++Cnt;
}
}

アルゴリズムは簡単で、最初のカウント(14行目)で真下弾を発射して、80カウント後にストップし、アシストから横6方向縦7方向に弾幕を発射します。この時アシスト弾幕のstateとアシスト弾幕から発射したい弾幕のstateを同じにするのがポイントです。
それとは別にボス本体からも120カウントと210カウントと240カウントの時に横5縦4の弾幕を発射します。

愛しき2人のデュエット

この弾幕は二つのアシストが発射されて、その間にアシストから花の弾幕が発射されます。

public class CItosikiFutarinoDuet : CBossBulletFactory
{
public CItosikiFutarinoDuet(MOVE_BOSS_POS move_boss_pos) : base(move_boss_pos)
{
SpelName = "愛しき2人のデュエット";
}
public override void Run(double x, double y)
{
const int C_TIME = 60;
const int C_TIME2 = 200;
int t = Cnt % 300;
if (t % 16 == 0 && t > 200)
{
for (int i = 0; i < 11; i++)
{
SGP.CreateBullet(x: x, y: y, angle: PI / 10 * i, speed: 3.0, graph_type: 7, color: 0, state: 0, pi2or1: 1.0);
}
}
if (t == 0)
{
MoveBossPos(40, 30, FIELD_MAX_X - 40, 120, 60, 60);
// アシスト弾幕
for (int i = 0; i < 2; i++)
{
SGP.CreateBullet(x: x, y: y, angle: PI / 2 - PI / 12 + PI / 6 * i, speed: 5.0, graph_type: 0, color: 1, state: 1, pi2or1: 1.0);
}
//se_flag[0] = 1;
}
for (int i = 0; i < SGP.Bullet.Count; i++)
{
int state = SGP.Bullet[i].State;
int a_cnt = SGP.Bullet[i].Cnt;
double bx = SGP.Bullet[i].X;
double by = SGP.Bullet[i].Y;
if (state == 1 && a_cnt % 20 == 0 && 15 < a_cnt && a_cnt < 70)
{
for (int j = 0; j < 10; j++)
{
SGP.CreateBullet(x: bx, y: by, angle: PI2 / 10 * j, speed: 1.5, graph_type: 15, color: 0, state: 2, pi2or1: 1.0, kaiten: 1);
}
SGP.PlaySound(13);
} 
}
for (int i = 0; i < SGP.Bullet.Count; i++)
{
if (SGP.Bullet[i].State == 2)
{
int cnt = SGP.Bullet[i].Cnt;
//ボスの座標-10まできたら減速
if (cnt < C_TIME2 && SGP.Bullet[i].Y < y - 10)
{
SGP.Bullet[i].Speed = 0.5;
}
if (C_TIME == cnt)
{
SGP.Bullet[i].Color = 1;
SGP.Bullet[i].Angle = Math.Atan2(y - SGP.Bullet[i].Y, x - SGP.Bullet[i].X);
}
if (C_TIME2 == cnt)
{// || boss_shot.bullet[i].y < boss.y-20){
SGP.Bullet[i].Color = 2;
SGP.Bullet[i].Angle = SGP.GetPlayerAnglePI2(x, y);
SGP.Bullet[i].Speed = 5.0;
SGP.Bullet[i].State = -1;
SGP.PlaySound(13);
}
}
}
++Cnt;
}
}

この弾幕は26行目のアシスト弾幕を斜め左下と右下に1つずつ発射して、そのアシスト弾幕から花弁の弾幕を発射します。(38行目)そして59行目で花弾幕をボスの方へ角度を設定します。
その後C_TIME2 == cntが満たされたされた時には、64行目のGetPlayerAnglePI2でプレイヤーへのなす角度を取得しその方向へ花弾幕を移動させます。

騒がしのトリオ

public class CSawagasinoTrio : CBossBulletFactory
{
public CSawagasinoTrio(MOVE_BOSS_POS move_boss_pos) : base(move_boss_pos)
{
SpelName = "騒がしのトリオ";
}
public override void Run(double x, double y)
{
int t = Cnt;
if (t == 0)
{
for (int i = 0; i < 3; i++)
{
SGP.CreateBullet(x: x, y: y, angle: PI / 2 + PI / 2 / 2 * (i - 3 / 2), state: i, speed: 4.5, graph_type: 0, color: 0, pi2or1: 1.0);
}
//se_flag[0] = 1;
}
for (int i = 0; i < SGP.Bullet.Count; i++)
{
int a_cnt = SGP.Bullet[i].Cnt;
int state = SGP.Bullet[i].State;
double bx = SGP.Bullet[i].X;
double by = SGP.Bullet[i].Y;
if (a_cnt == 30 && state != -1)
{
SGP.Bullet[i].Speed = 0.0;
}
if (a_cnt % 2 == 0 && 30 < a_cnt && state != -1)
{
SGP.CreateBullet(x: bx, y: by, angle: a_cnt * 0.2, state: -1, speed: 3.0, graph_type: 4, color: 1, pi2or1: 1.0);
} 
}
++Cnt;
}
}

この弾幕はすごく単純でアシスト弾幕を14行目で3つ発射し30カウントで止まります。
そしてその位置から、回転させながら弾幕を発射させます。(31行目)

麗しのカルテット

public class CUruwasinoQuartet : CBossBulletFactory
{
public CUruwasinoQuartet(MOVE_BOSS_POS move_boss_pos) : base(move_boss_pos)
{
SpelName = "麗しのカルテット";
}
public override void Run(double x, double y)
{
int t = Cnt % 380, t2 = Cnt;
double bx, by;
if (t2 == 0)
{
//input_phy_pos(FMX / 2, FMY / 2, 50);
}
if (t2 == 50)
{
// アシスト弾幕
for (int i = 0; i < 4; i++)
{
SGP.CreateBullet(x: x, y: y, angle: PI / 4 + PI / 2 * i, speed: 4.5, graph_type: 0, color: 0, state: 2, pi2or1: 1.0);
}
//se_flag[0] = 1;
}
if (t == 80)
{
for (int j = 0; j < 2; j++)
{
for (int i = 0; i < 20; i++)
{
SGP.CreateBullet(x: x, y: y, angle: PI2 / 20 * i, speed: 0.6 * j + 1, graph_type: 3, color: 4, state: 3, pi2or1: 1.0);
}
}
//se_flag[0] = 1;
}
// アシスト弾幕から発射する弾幕
for (int i = 0; i < SGP.Bullet.Count; i++)
{
int a_cnt = SGP.Bullet[i].Cnt;
int state = SGP.Bullet[i].State;
bx = SGP.Bullet[i].X;
by = SGP.Bullet[i].Y;
if (a_cnt == 30 && state == 2)
{
SGP.Bullet[i].Speed = 0;
}
if (t % 80 == 0 && state == 2)
{
for(int k = 0; k < 2; ++k)
{
for(int j = 0; j < 16; ++j)
{
SGP.CreateBullet(x: bx, y: by, angle: PI2 / 16 * (j - 16 / 2), speed: 1.0, graph_type: 8, color: k, state: k, pi2or1: 1.0);
}
}
}
}
for (int i = 0; i < SGP.Bullet.Count; i++)
{
int state = SGP.Bullet[i].State;
switch (state)
{
case 0:
SGP.Bullet[i].Angle -= PI / 10 / 100;
break;
case 1:
SGP.Bullet[i].Angle += PI / 10 / 100;
break;
default:
break;
}
}
for (int i = 0; i < SGP.Bullet.Count; i++)
{
if (SGP.Bullet[i].State == 3)
{
int cnt = SGP.Bullet[i].Cnt;
bx = SGP.Bullet[i].X;
by = SGP.Bullet[i].Y;
if (cnt == 60)
{
SGP.Bullet[i].Angle = Math.Atan2(0 - SGP.Bullet[i].Y, FIELD_MAX_X / 2+40 - SGP.Bullet[i].X);
SGP.Bullet[i].Speed = 2.5;
SGP.PlaySound(13);
}
if (cnt == 120)
{
SGP.Bullet[i].Angle = SGP.GetPlayerAnglePI2(bx,by);
SGP.Bullet[i].Speed = 3.0;
SGP.Bullet[i].State = -1;
SGP.PlaySound(13);
}
}
}
++Cnt;
}
}

21行目のCreateBulletでアシスト弾幕を生成し、30カウントになったら止めます。
4つのアシストの位置から32方向に細かい弾幕を発射します。

それとは別に32行目にボスの位置から20方向に弾幕を発射してます。60カウントになったらフィールドの上まで移動し、120カウントになったら、プレイヤー目指して弾幕が富んできます。

幻聴のクインテット

public class CGentyounoQuintet : CBossBulletFactory
{
public CGentyounoQuintet(MOVE_BOSS_POS move_boss_pos) : base(move_boss_pos)
{
SpelName = "幻聴のクインテット";
}
public override void Run(double x, double y)
{
int t = Cnt % 830, t2 = Cnt;
if (t == 0)
{
//input_phy_pos(FMX / 2, FMY / 2 - 20, 50);
}
if (t == 60 || t == 230 || t == 400 || t == 520)
{
int color = DX.GetRand(9);
for (int i = 0; i < 20; i++)
{
SGP.CreateBullet(x: x, y: y, speed: 3.0,
angle: SGP.GetPlayerAnglePI2(x, y) + PI2 / 20 * (i - 10),
graph_type: 7, color: color, state: 0, pi2or1: 1.0);
}
//se_flag[0] = 1;
}
if (t2 == 50)
{
for (int i = 0; i < 5; i++)
{
SGP.CreateBullet(x: x, y: y, speed: 4.0,
angle: PI2 / 5 * i - PI / 2,
graph_type: 0, color: 0, state: 1, pi2or1: 1.0);
}
//se_flag[0] = 1;
}
for (int i = 0; i < SGP.Bullet.Count; i++)
{
int a_cnt = SGP.Bullet[i].Cnt;
int state = SGP.Bullet[i].State;
double bx = SGP.Bullet[i].X;
double by = SGP.Bullet[i].Y;
if (t == 80 && state == 1)
{
SGP.Bullet[i].Speed = 0.0;
}
if (state == 1)
{
//螺旋ショット
if (90 < t && t < 200 && t % 8 == 0)
{
SGP.CreateBullet(x: bx, y: by, speed: 3.0,
angle: PI2 / 100 * t,
graph_type: 1, color: 0, state: -1, pi2or1: 1.0);
//se_flag[0] = 1;
}
//螺旋ショット
if (260 < t && t < 370 && t % 8 == 0)
{
SGP.CreateBullet(x: bx, y: by, speed: 3.0,
angle: -PI2 / 100 * t,
graph_type: 1, color: 2, state: -1, pi2or1: 1.0);
//se_flag[0] = 1;
}
//全方向ショット
if (t == 400)
{
for (int j = 0; j < 20; j++)
{
SGP.CreateBullet(x: bx, y: by, speed: 3.0, angle: PI2 / 20 * (j - 10), graph_type: 7, c: 4, state: -1, pi2or1: 1.0);
}
//se_flag[0] = 1;
}
//6方向途中で自機に向かう
if (t == 460)
{
for (int j = 0; j < 6; j++)
{
SGP.CreateBullet(x: bx, y: by, speed: 2.0,
angle: PI2 / 6 * (j - 3),
graph_type: 3, color: 2, state: 2, pi2or1: 1.0);
}
//se_flag[0] = 1;
}
//螺旋ショット
if (600 < t && t < 800 && t % 6 == 0)
{
SGP.CreateBullet(x: bx, y: by, speed: 3.0,
angle: PI2 / 100 * t,
graph_type: 1, color: 1, state: -1, pi2or1: 1.0);
//se_flag[0] = 1;
}
}
if(state == 2 && a_cnt == 30)
{
SGP.Bullet[i].Angle = SGP.GetPlayerAnglePI2(bx, by);
SGP.PlaySound(13);
}
}
++Cnt;
}
}

まず20~22行目までのCreateBulletはボスが20方向に弾幕を放ちます。
31~33行目はアシスト弾幕を発射します。この時にstateに1を渡してアシスト弾幕であることをわかるようにしてます。

そしてアシスト弾幕から発射される弾幕は79~100行目までに定義されてます。
螺旋ショット→逆方向螺旋ショット→全方向ショット→6方向の刃弾幕(途中で自機狙い)→螺旋ショット

といった感じになります。まだまだボスの弾幕は作るのでこの講座は続きます。