OSDN Git Service

演奏ステージを実装。
[strokestylet/CsWin10Desktop3.git] / StrokeStyleT / ステージ / 演奏 / 演奏ステージ.cs
1 using System;
2 using System.Collections.Generic;
3 using System.Diagnostics;
4 using System.Linq;
5 using FDK.メディア;
6 using FDK;      // for SystemStringExtensions
7
8 namespace SST.ステージ.演奏
9 {
10         class 演奏ステージ : ステージ
11         {
12                 public Dictionary<ヒット判定種別, int> ヒットした回数 { get; } = new Dictionary<ヒット判定種別, int>();
13                 public enum フェーズ
14                 {
15                         初期状態,
16                         演奏中,
17                         クリアor失敗,
18                         キャンセル,
19                 }
20                 public フェーズ 現在のフェーズ { get; protected set; } = フェーズ.初期状態;
21
22                 public 演奏ステージ()
23                 {
24                         #region " 子Activity の外部依存 Action を実装する。"
25                         //----------------
26                         this.スクロール譜面.ヒット判定文字列開始 = ( chipType, hitType ) => { this.ヒット判定文字列.表示開始( chipType, hitType ); };
27                         this.スクロール譜面.コンボリセット = () => { this.コンボ.COMBO値 = 0; };
28                         this.スクロール譜面.コンボ加算 = () => { this.コンボ.COMBO値++; };
29                         this.スクロール譜面.ヒット判定数加算 = ( hitType ) => { this.ヒットした回数[ hitType ]++; };
30                         this.スクロール譜面.背景動画再生開始 = () => { this.背景動画開始済み = true; };
31                         this.スクロール譜面.チップヒット = ( chip ) => {
32                                 this.回転羽.発火する( chip.チップ種別 );
33                                 this.ドラムサウンド.発声する( chip.チップ種別, chip.音量 * 0.25f );
34                         };
35                         this.スクロール譜面.ステージクリア = () => { this.現在のフェーズ = フェーズ.クリアor失敗; };
36                         //----------------
37                         #endregion
38                 }
39                 protected override void On活性化( デバイスリソース dr )
40                 {
41                         FDK.Log.Info( "演奏ステージを開始します。" );
42                         Debug.Assert( null != StrokeStyleT.演奏スコア, "[バグあり] 演奏スコアが null です。" );
43
44                         #region " ヒットした回数をすべてクリア。"
45                         //----------------
46                         this.ヒットした回数.Clear();
47                         foreach( var 判定 in typeof( ヒット判定種別 ).GetEnumValues() )
48                                 this.ヒットした回数[ (ヒット判定種別) 判定 ] = 0;
49                         //----------------
50                         #endregion
51                         #region " 選択ノードの持つ動画ファイルパスが有効なら背景動画とBGMを初期化する。"
52                         //----------------
53                         var 動画ファイルパス = ( (SST.曲.MusicNode) StrokeStyleT.曲ツリー管理.現在選択されているノード ).動画ファイルパス;
54                         if( 動画ファイルパス.Nullでも空でもない() )
55                         {
56                                 this.背景動画 = new 動画( 動画ファイルパス );
57                                 this.背景動画.活性化する( dr );
58                                 this.BGM = new FDK.メディア.サウンド.WASAPI排他.Sound();
59                                 this.BGM.ファイルから作成する( 動画ファイルパス );
60                                 StrokeStyleT.Wasapiデバイス.サウンドをミキサーに追加する( this.BGM ); // 作成に失敗した Sound を追加しても鳴らないだけなので、ノーチェックで大丈夫。
61                         }
62                         //----------------
63                         #endregion
64
65                         this.コンボ.活性化する( dr );
66                         this.レーンフレーム.活性化する( dr );
67                         this.スクロール譜面.活性化する( dr );
68                         this.ヒット判定文字列.活性化する( dr );
69                         this.回転羽.活性化する( dr );
70                         this.ドラムサウンド.活性化する( dr );
71                         this.ドラムセット.活性化する( dr );
72                         this.判定バー.活性化する( dr );
73                         this.ステージ台.活性化する( dr );
74                         this.FPS画像.活性化する( dr );
75
76                         this.演奏開始時刻sec = 0.0;
77                         this.現在進行描画中の譜面スクロール速度の倍率 = StrokeStyleT.ユーザ管理.現在選択されているユーザ.譜面スクロール速度の倍率;
78                         this.BGM再生開始済み = false;
79                         this.背景動画開始済み = false;
80                         this.レーンフレーム.左端位置dpx = 400f;
81                         this.レーンフレーム.高さdpx = dr.設計画面サイズdpx.Height;
82                         this.現在のフェーズ = フェーズ.演奏中;
83                         this.活性化した直後である = true;
84                 }
85                 protected override void On非活性化( デバイスリソース dr )
86                 {
87                         FDK.Log.Info( "演奏ステージを終了します。" );
88
89                         this.コンボ.非活性化する( dr );
90                         this.レーンフレーム.非活性化する( dr );
91                         this.スクロール譜面.非活性化する( dr );
92                         this.ヒット判定文字列.非活性化する( dr );
93                         this.回転羽.非活性化する( dr );
94                         this.ドラムサウンド.非活性化する( dr );
95                         this.ドラムセット.非活性化する( dr );
96                         this.判定バー.非活性化する( dr );
97                         this.ステージ台.非活性化する( dr );
98                         this.FPS画像.非活性化する( dr );
99
100                         // 背景動画がなければ null なので注意。
101                         this.背景動画?.非活性化する( dr );
102
103                         //this.BGMを解放する(); → ここではまだ解放しない。結果ステージが終わったときに解放する。
104                 }
105                 public override void 進行描画する( デバイスリソース dr )
106                 {
107                         // 進行描画。
108
109                         #region " 初めての進行描画。"
110                         //----------------
111                         if( this.活性化した直後である )
112                         {
113                                 this.演奏開始時刻sec = this.サウンドタイマ.現在のデバイス位置secを取得する( StrokeStyleT.Wasapiデバイス.AudioClock );
114                                 this.FPS = new FDK.カウンタ.FPS();
115                                 this.活性化した直後である = false;
116                         }
117                         //----------------
118                         #endregion
119
120                         double 演奏時刻sec = this.サウンドタイマ.現在のデバイス位置secを取得する( StrokeStyleT.Wasapiデバイス.AudioClock ) - this.演奏開始時刻sec;
121
122                         this.FPS.FPSをカウントする();
123                         this.FPS.VPSをカウントする();
124                         this.FPS画像.表示文字列 = $"VPS: {this.FPS.現在のVPS.ToString()}";
125
126                         #region " 譜面スクロール速度の追い付き進行。"
127                         //----------------
128                         if( this.現在進行描画中の譜面スクロール速度の倍率 < StrokeStyleT.ユーザ管理.現在選択されているユーザ.譜面スクロール速度の倍率 )
129                         {
130                                 // 時間間隔に関係なく進行描画ごとに倍率を変えてしまっているが、まあVPSなど60~120くらいやろうからよし。
131                                 this.現在進行描画中の譜面スクロール速度の倍率 =
132                                         Math.Min( this.現在進行描画中の譜面スクロール速度の倍率 + 0.05, StrokeStyleT.ユーザ管理.現在選択されているユーザ.譜面スクロール速度の倍率 );
133                         }
134                         else if( this.現在進行描画中の譜面スクロール速度の倍率 > StrokeStyleT.ユーザ管理.現在選択されているユーザ.譜面スクロール速度の倍率 )
135                         {
136                                 // 同上。
137                                 this.現在進行描画中の譜面スクロール速度の倍率 =
138                                         Math.Max( this.現在進行描画中の譜面スクロール速度の倍率 - 0.05, StrokeStyleT.ユーザ管理.現在選択されているユーザ.譜面スクロール速度の倍率 );
139                         }
140                         //----------------
141                         #endregion
142
143                         if( this.背景動画開始済み )
144                         {
145                                 // 背景動画チップがヒット済みなら、背景動画の進行描画を行う。
146                                 this.背景動画?.進行描画する( dr, new SharpDX.RectangleF( 0f, 0f, dr.設計画面サイズdpx.Width, dr.設計画面サイズdpx.Height ) );
147
148                                 // 背景動画が再生されているのにBGMがまだ再生されていないなら、再生を開始する。
149                                 if( false == this.BGM再生開始済み )
150                                 {
151                                         this.BGM?.再生を開始する();
152                                         this.BGM再生開始済み = true;
153                                 }
154                         }
155                         this.ステージ台.進行描画する( dr, 0.0f, 0.0f );
156                         this.レーンフレーム.進行描画する( dr );
157                         this.コンボ.進行描画する( dr );
158                         this.ヒット判定文字列.進行描画する( dr );
159                         this.スクロール譜面.小節線拍線を進行描画する( dr, 演奏時刻sec, this.現在進行描画中の譜面スクロール速度の倍率 );
160                         this.判定バー.進行描画する( dr, 597f, 座標.判定バーの中央Y座標dpx - 43f );
161                         this.ドラムセット.進行描画する( dr );
162                         this.スクロール譜面.チップを進行描画する( dr, 演奏時刻sec, this.現在進行描画中の譜面スクロール速度の倍率 );
163                         this.回転羽.進行描画する( dr );
164                         this.FPS画像.進行描画する( dr, 0f, 0f );
165
166                         // 入力。
167
168                         StrokeStyleT.すべての入力デバイスをポーリングする();
169
170                         // ESC 押下 → キャンセル
171                         if( StrokeStyleT.キーボード入力.キーが押された( SharpDX.DirectInput.Key.Escape ) )
172                         {
173                                 this.BGMを解放する();
174                                 this.現在のフェーズ = フェーズ.キャンセル;
175                         }
176                         // 上矢印押下 → 譜面スクロール速度の倍率を +0.5
177                         else if( StrokeStyleT.キーボード入力.キーが押された( SharpDX.DirectInput.Key.Up ) )
178                         {
179                                 StrokeStyleT.ユーザ管理.現在選択されているユーザ.譜面スクロール速度の倍率 =
180                                         Math.Min( StrokeStyleT.ユーザ管理.現在選択されているユーザ.譜面スクロール速度の倍率 + 0.5, 8.0 );    // 最大 8.0
181                         }
182                         // 下矢印押下 → 譜面スクロール速度の倍率を -0.5
183                         else if( StrokeStyleT.キーボード入力.キーが押された( SharpDX.DirectInput.Key.Down ) )
184                         {
185                                 StrokeStyleT.ユーザ管理.現在選択されているユーザ.譜面スクロール速度の倍率 =
186                                         Math.Max( StrokeStyleT.ユーザ管理.現在選択されているユーザ.譜面スクロール速度の倍率 - 0.5, 0.5 );    // 最小 0.5
187                         }
188                 }
189                 public void BGMを解放する()
190                 {
191                         if( null != this.BGM )  // 背景動画がなければ null である
192                         {
193                                 StrokeStyleT.Wasapiデバイス.サウンドをミキサーから削除する( this.BGM );
194                                 FDK.Utilities.解放する( ref this.BGM );
195                         }
196                 }
197
198                 protected bool 活性化した直後である = false;
199                 protected bool 背景動画開始済み = false;
200                 protected bool BGM再生開始済み = false;
201                 protected double 現在進行描画中の譜面スクロール速度の倍率 = 0.0;
202                 protected double 演奏開始時刻sec = 0.0;
203                 protected readonly FDK.メディア.サウンド.WASAPI排他.SoundTimer サウンドタイマ = new FDK.メディア.サウンド.WASAPI排他.SoundTimer();
204                 protected readonly SST.ステージ.演奏.コンボ コンボ = new コンボ();
205                 protected readonly SST.ステージ.演奏.レーンフレーム レーンフレーム = new レーンフレーム();
206                 protected readonly SST.ステージ.演奏.スクロール譜面 スクロール譜面 = new スクロール譜面();
207                 protected readonly SST.ステージ.演奏.ヒット判定文字列 ヒット判定文字列 = new ヒット判定文字列();
208                 protected readonly SST.ステージ.演奏.回転羽 回転羽 = new 回転羽( 32 );
209                 protected readonly SST.ステージ.演奏.ドラムサウンド ドラムサウンド = new ドラムサウンド();
210                 protected readonly SST.ステージ.汎用.ドラムセット ドラムセット = new 汎用.ドラムセット();
211                 protected readonly FDK.メディア.画像 ステージ台 = new 画像( @"$(Static)\images\ステージ台.png" );
212                 protected readonly FDK.メディア.画像 判定バー = new 画像( @"$(Static)\images\判定バー.png" );
213                 protected readonly FDK.メディア.文字列画像 FPS画像 = new 文字列画像();
214                 protected FDK.メディア.動画 背景動画 = null;
215                 protected FDK.メディア.サウンド.WASAPI排他.Sound BGM = null;
216                 protected FDK.カウンタ.FPS FPS = null;
217         }
218 }