C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[5]: 【C#,VisualStudio2019】フェードアウト処理


(過去ログ 172 を表示中)

[トピック内 6 記事 (1 - 6 表示)]  << 0 >>

■99248 / inTopicNo.1)  【C#,VisualStudio2019】フェードアウト処理
  
□投稿者/ エルデの王 (1回)-(2022/02/26(Sat) 17:33:18)

分類:[.NET 全般] 

2022/02/26(Sat) 17:34:21 編集(投稿者)
お世話になっています。
環境はC#,VisualStudio2019,WPFです。

一秒間に60回実行するタイマーを使用し、
4秒かけてクライアント領域を塗りつぶすフェードアウト処理を実装したのですが、
塗りつぶす速度が速すぎます。
以下のソースに問題点があるか、ご指導頂けたらと思います。

private void MainWindow1_ContentRendered(object sender, EventArgs e)
{
                // タイマー60FPSで始動
                DispatcherTimer timer = new DispatcherTimer(DispatcherPriority.Background);
                timer.Interval = TimeSpan.FromSeconds(1/60);
                timer.Tick += (x, s) => { TimerActionTest(); };
                this.Closing += (x, s) => { timer.Stop(); };
                timer.Start();

                this.FadeOut = true;
}

private void TimerActionTest()
{
    // 一秒間に60回実行される

	// FadeOutFlagはフィールド
    if (FadeOut == true
        || FadeOutFlag == true)
    {
        FadeOutFlag = true;

		// 要素があれば塗りつぶし。無ければ要素追加
        if (fade.Children.Count == 1)
        {
            var rec = fade.Children[fade.Children.Count - 1] as System.Windows.Shapes.Rectangle;
            
            // 塗りつぶし要素の大きさがクライアント領域より小さい、
            // かつカウンター(一秒間に60個貯まる)が60で割って余りが0の時
            if (rec.Height < this.sizeClientWinHeight
                && FadeOutNumber % 60 == 0)
            {
                rec.Height += this.sizeClientWinHeight / 4;
            }

            if (rec.Height >= this.sizeClientWinHeight)
            {
                FadeOut = false;
                FadeOutFlag = false;
                FadeOutNumber = 0;
            }
        }
        else
        {
        	// 要素追加
            fade.IsHitTestVisible = true;
            var rect = new System.Windows.Shapes.Rectangle();
            rect.Width = this.sizeClientWinWidth;
            rect.Height = 0;
            rect.Name = "recFadeOut";
            rect.Fill = System.Windows.Media.Brushes.Black;
            fade.Children.Add(rect);
            Canvas.SetZIndex(fade, 100);
        }

		// カウンター(一秒間に60回実行されるので、一秒間に60個貯まる)
        FadeOutNumber += 1;
        return;
    }
}

引用返信 編集キー/
■99249 / inTopicNo.2)  Re[1]: 【C#,VisualStudio2019】フェードアウト処理
□投稿者/ Hongliang (1217回)-(2022/02/26(Sat) 18:05:43)
> timer.Interval = TimeSpan.FromSeconds(1/60);
とりあえずここだけですが。
C#は整数同士の演算の結果は整数です。1/60だと端数切捨ての0になってしまいます。
1.0とか、1dとか、(double)1とか、少なくともどちらか片方を浮動小数点数型であることを明示すると、結果も浮動小数点数になります。
引用返信 編集キー/
■99250 / inTopicNo.3)  Re[2]: 【C#,VisualStudio2019】フェードアウト処理
□投稿者/ エルデの王 (2回)-(2022/02/26(Sat) 18:18:42)
No99249 (Hongliang さん) に返信
>> timer.Interval = TimeSpan.FromSeconds(1/60);
> とりあえずここだけですが。
> C#は整数同士の演算の結果は整数です。1/60だと端数切捨ての0になってしまいます。
> 1.0とか、1dとか、(double)1とか、少なくともどちらか片方を浮動小数点数型であることを明示すると、結果も浮動小数点数になります。

回答ありがとうございます。
試したところ、塗りつぶし速度が速すぎから遅すぎへと変化しました……。
ロジックに問題がありそうです。
問題の一つをご指導頂きありがとうございました。
引用返信 編集キー/
■99257 / inTopicNo.4)  Re[3]: 【C#,VisualStudio2019】フェードアウト処理
□投稿者/ radian (17回)-(2022/02/28(Mon) 08:24:23)
2022/02/28(Mon) 08:48:31 編集(投稿者)

そもそもWindowsのタイマーってそんなに正確じゃないんで、指定した時間間隔で正確に呼び出されるのを期待しないほうがいいです。
タイマー処理に入ったらフェードアウト開始からの経過時間を計算して、そこからアニメーションの効果量を変えればいいんじゃないでしょうか。

WPFだったら、これも読んだ方がいいかも。
[方法: 要素またはブラシの不透明度をアニメーション化する - WPF .NET Framework | Microsoft Docs]
https://docs.microsoft.com/ja-jp/dotnet/desktop/wpf/graphics-multimedia/animation-overview?view=netframeworkdesktop-4.8
引用返信 編集キー/
■99259 / inTopicNo.5)  Re[4]: 【C#,VisualStudio2019】フェードアウト処理
□投稿者/ ぼーちゃん (34回)-(2022/02/28(Mon) 10:25:43)
TimerActionTest()の最初に

System.Diagnostics.Debug.WriteLine(DateTime.Now.ToString("HH:mm:ss.fff"));

などと入れて、出力を見てください。
16.6ms間隔では呼び出されておらず、32msとか、それ以上の時間が掛かっていると思います。
1tickに掛かる時間が1/60秒を達成できていないので遅いということだと思います。

DispatcherTimerはIntervalより短い間隔で実行されることは無いですが、
Interval時間が経過した瞬間に実行される保証はされていません。
https://docs.microsoft.com/ja-jp/dotnet/api/system.windows.threading.dispatchertimer.interval?view=windowsdesktop-6.0

以下は経験則的な話ですが、
VisualStudioからのデバッグ実行でなくビルドしたexeを直接実行すると設定に近い時間では動くと思います。
(IntervalはTimeSpan.FromMilliseconds(16)などと入れたほうが良いです)
ただし、実行環境によって結果は変わり安定はしません。

他の方がおっしゃられているように経過時間を計算して処理するか、
簡易的には60fpsにこだわらないならもっとレートを落とした方がよいと思います。
引用返信 編集キー/
■99317 / inTopicNo.6)  Re[5]: 【C#,VisualStudio2019】フェードアウト処理
□投稿者/ PATIO (28回)-(2022/03/11(Fri) 16:12:49)
No99259 (ぼーちゃん さん) に返信
> TimerActionTest()の最初に
>
> System.Diagnostics.Debug.WriteLine(DateTime.Now.ToString("HH:mm:ss.fff"));
>
> などと入れて、出力を見てください。
> 16.6ms間隔では呼び出されておらず、32msとか、それ以上の時間が掛かっていると思います。
> 1tickに掛かる時間が1/60秒を達成できていないので遅いということだと思います。
>
> DispatcherTimerはIntervalより短い間隔で実行されることは無いですが、
> Interval時間が経過した瞬間に実行される保証はされていません。
> https://docs.microsoft.com/ja-jp/dotnet/api/system.windows.threading.dispatchertimer.interval?view=windowsdesktop-6.0
>
> 以下は経験則的な話ですが、
> VisualStudioからのデバッグ実行でなくビルドしたexeを直接実行すると設定に近い時間では動くと思います。
> (IntervalはTimeSpan.FromMilliseconds(16)などと入れたほうが良いです)
> ただし、実行環境によって結果は変わり安定はしません。
>
> 他の方がおっしゃられているように経過時間を計算して処理するか、
> 簡易的には60fpsにこだわらないならもっとレートを落とした方がよいと思います。

順番的にはやりたい処理の1回にかかる時間を確認する所が最初なのではないかと思います。
画面の更新処理は重い処理なのでそもそも60fpsのタイミングで連続実行が出来るのかを確認しないと
前に進めないと思います。
画面の更新処理に時間が掛かりすぎているのであれば、
60fpsをあきらめるかもっと早く画面更新を行える方法を模索するかになると思います。
(いや、もう時間測定はやっていて、大丈夫という確信はあるというのであれば、聞き流してください)
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -