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