2012年11月27日火曜日

自由落下のアニメーション

物体の自由落下をシミュレートします。 空気抵抗は考えません。
1ピクセルを1mにしています。
Task.Factory.StartNew で 非同期処理」の方法で、別スレッドで0.1秒ごとに物体の位置を計算し、通知用の Location クラスのY座標を更新すると、バインドしているEllipseのCanvas.Leftプロパティの値が更新されてアニメーションします。
落下距離が300mを超えると停止します。
Stopwatch クラスの ElapsedMilliseconds プロパティで経過時間をミリ秒で取得します。
重力加速度9.8m/s^2としたときの落下距離はつぎのようになります。

double y = 4.9 * (経過時間ミリ秒/ 1000.0) * (経過時間ミリ秒 / 1000.0);




MainWindow.xaml

<Window x:Class="AnimationTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Height="390" Width="225">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <DockPanel Grid.Row="0">
            <TextBlock>経過時間(ミリ秒):</TextBlock>
            <TextBlock Name="millisecondsTextBlock" Text="{Binding Path=Milliseconds}"/>
        </DockPanel>
        <DockPanel Grid.Row="1">
            <TextBlock>落下距離(メートル):</TextBlock>
            <TextBlock Name="heightTextBlock" Text="{Binding Path=Y}"/>
        </DockPanel>
        <Canvas Grid.Row="2">
            <Ellipse Canvas.Left="100" Canvas.Top="{Binding Path=Y}"
                 Height="10" Width="10" Fill="WhiteSmoke" Stroke="Black" />
        </Canvas>
    </Grid>
</Window>


MainWindow.xaml.cs

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

namespace AnimationTest
{
    public partial class MainWindow Window
    {
        private Location location = new Location();
        private Task task;

        public MainWindow()
        {
            InitializeComponent();
            this.DataContext = this.location;
            task = Task.Factory.StartNew(obj => ComputeLocation((Location)obj), this.location);
        }

        private void ComputeLocation(Location location)
        {
            Stopwatch sw = new Stopwatch();
            sw.Start();
            while (true)
            {
                Thread.Sleep(100);
                long milliseconds = sw.ElapsedMilliseconds;
                location.Milliseconds = milliseconds;
                double y = 4.9 * (milliseconds / 1000.0) * (milliseconds / 1000.0);
                location.Y = y;
                if (location.Y > 300)
                {
                    break;
                }
            }
        }
    }
}

Location.cs

using System;
using System.ComponentModel;

namespace AnimationTest
{
    public class Location INotifyPropertyChanged
    {
        private long milliseconds;
        public long Milliseconds
        {
            get { return this.milliseconds; }
            set
            {
                if (value != this.milliseconds)
                {
                    this.milliseconds = value;
                    NotifyPropertyChanged("Milliseconds");
                }
            }
        }

        private double y;
        public double Y
        {
            get { return this.y; }
            set
            {
                if (value != this.y)
                {
                    this.y = value;
                    NotifyPropertyChanged("Y");
                }
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private void NotifyPropertyChanged(string info)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(thisnew PropertyChangedEventArgs(info));
            }
        }
    }
}

0 件のコメント:

コメントを投稿