2012年12月4日火曜日

DispatcherTimer で 飛び跳ねるボール

「飛び跳ねるボール」では、3つのボールの座標を、それぞれ別スレッドの非同期処理で計算していました。
ここでは、同じようなアニメーションを、DispatcherTimer を使って実現しています。
DispatcherTimer の Tick イベントの処理で直接 UIスレッドにアクセスできるので、「飛び跳ねるボール」で使ったような座標通知用のメッセージクラス(Location クラス)は必要ありません。

15ミリ秒ごとに処理される timer_Tickメソッドで、3つの円の中心座標、EllipseGeometry.Center を書き換えています。


MainWindow.xaml

<Window x:Class="BouncingBall.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Height="200" Width="300" 
        SizeChanged="Window_SizeChanged" Loaded="Window_Loaded">
    <Canvas Name="canvas1">
        <Canvas.Resources>
            <Style TargetType="Path">
                <Setter Property="Fill" Value="WhiteSmoke"/>
                <Setter Property="Stroke" Value="Black"/>
            </Style>
        </Canvas.Resources>
        <Path>
            <Path.Data>
                <EllipseGeometry x:Name="ellipse1" RadiusX="5" RadiusY="5" />
            </Path.Data>
        </Path>
        <Path Opacity=".5">
            <Path.Data>
                <EllipseGeometry x:Name="ellipse2" RadiusX="5" RadiusY="5" />
            </Path.Data>
        </Path>
        <Path Opacity=".2">
            <Path.Data>
                <EllipseGeometry x:Name="ellipse3" RadiusX="5" RadiusY="5" />
            </Path.Data>
        </Path>
    </Canvas>
</Window>

MainWindow.xaml.cs

using System;
using System.Diagnostics;
using System.Windows;
using System.Windows.Threading;

namespace BouncingBall
{
    public partial class MainWindow Window
    {
        private int rateY = 1200;
        private int rateX = 1000;
        private double rateY2;
        private int harfRateY;
        private double rateX2;
        private int harfRateX;
        private Stopwatch sw = new Stopwatch();

        public MainWindow()
        {
            InitializeComponent();
        }

        private void Window_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            rateY2 = rateY / Math.Sqrt(this.canvas1.ActualHeight) * 0.52;
            harfRateY = rateY / 2;
            rateX2 = rateX / this.canvas1.ActualWidth * 0.55;
            harfRateX = rateX / 2;

            sw.Restart();
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            DispatcherTimer timer = new DispatcherTimer();
            timer.Tick += timer_Tick;
            timer.Interval = new TimeSpan(0, 0, 0, 0, 15);
            timer.Start();
        }

        private void timer_Tick(object sender, EventArgs e)
        {
            if (!sw.IsRunning)
            {
                return;
            }

            long milliseconds = sw.ElapsedMilliseconds;
            this.ellipse1.Center = GetPoint(milliseconds);
            this.ellipse2.Center = GetPoint(milliseconds - 50);
            this.ellipse3.Center = GetPoint(milliseconds - 100);
        }

        private Point GetPoint(long milliseconds)
        {
            if (milliseconds < 0)
            {
                milliseconds = 0;
            }

            long fractionY = milliseconds % rateY;
            if (fractionY >= harfRateY)
            {
                fractionY = rateY - fractionY;
            }
            double sqrtY = fractionY / rateY2;
            double y = sqrtY * sqrtY;

            long fractionX = milliseconds % rateX;
            if (fractionX >= harfRateX)
            {
                fractionX = rateX - fractionX;
            }
            double x = fractionX / rateX2;

            return new Point(x, y);
        }
    }
}

0 件のコメント:

コメントを投稿