跳ね返り係数は100%で、空気抵抗は考えません。
ボール本体のほかに、残像を2つ表示しています。1つは50ミリ秒まえの、もう1つは100ミリ秒前の残像です。
かつて熱中した アルカノイド というゲームを思い出します。
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="200" Width="300" SizeChanged="Window_SizeChanged">
<Canvas Grid.Row="2" Name="canvas1">
<Canvas.Resources>
<Style TargetType="Ellipse">
<Setter Property="Height" Value="10" />
<Setter Property="Width" Value="10"/>
<Setter Property="Stroke" Value="Black" />
<Setter Property="Fill" Value="WhiteSmoke" />
</Style>
</Canvas.Resources>
<Ellipse Name="ellipse1" Canvas.Left="{Binding Path=X}" Canvas.Top="{Binding Path=Y}" />
<Ellipse Name="ellipse2" Canvas.Left="{Binding Path=X}" Canvas.Top="{Binding Path=Y}" Opacity=".5"/>
<Ellipse Name="ellipse3" Canvas.Left="{Binding Path=X}" Canvas.Top="{Binding Path=Y}" Opacity=".2"/>
<Rectangle Name="bar1" Width="10" Height="4" Fill="Black" Canvas.Bottom="0" Canvas.Left="{Binding Path=X}"/>
</Canvas>
</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 location1 = new Location(0);
private Location location2 = new Location(50);
private Location location3 = new Location(100);
private Task task1;
private Task task2;
private Task task3;
private int rateY = 1200;
private int rateX = 1000;
private Stopwatch sw = new Stopwatch();
public MainWindow()
{
InitializeComponent();
this.ellipse1.DataContext = this.location1;
this.ellipse2.DataContext = this.location2;
this.ellipse3.DataContext = this.location3;
this.bar1.DataContext = this.location1;
}
private void ComputeLocation(Location location)
{
double rateY2 = rateY / Math.Sqrt(this.canvas1.ActualHeight) * 0.52;
int harfRateY = rateY / 2;
double rateX2 = rateX / this.canvas1.ActualWidth * 0.55;
int harfRateX = rateX / 2;
while (!location.IsCanceled)
{
Thread.Sleep(15);
long milliseconds = sw.ElapsedMilliseconds;
milliseconds = milliseconds - location.Delay;
if (milliseconds < 0)
{
milliseconds = 0;
}
long fractionY = milliseconds % rateY;
if (fractionY >= harfRateY)
{
fractionY = rateY - fractionY;
}
double sqrtY = fractionY / rateY2;
location.Y = (int)Math.Floor(sqrtY * sqrtY);
long fractionX = milliseconds % rateX;
if (fractionX >= harfRateX)
{
fractionX = rateX - fractionX;
}
location.X = (int)Math.Floor(fractionX / rateX2);
}
}
private void Window_SizeChanged(object sender, SizeChangedEventArgs e)
{
this.location1.IsCanceled = true;
this.location2.IsCanceled = true;
this.location3.IsCanceled = true;
if (this.task1 != null)
{
this.task1.Wait();
}
if (this.task2 != null)
{
this.task2.Wait();
}
if (this.task3 != null)
{
this.task3.Wait();
}
this.location1.IsCanceled = false;
this.location2.IsCanceled = false;
this.location3.IsCanceled = false;
sw.Restart();
this.task1 = Task.Factory.StartNew(obj => ComputeLocation((Location)obj), this.location1);
this.task2 = Task.Factory.StartNew(obj => ComputeLocation((Location)obj), this.location2);
this.task3 = Task.Factory.StartNew(obj => ComputeLocation((Location)obj), this.location3);
}
}
}
Location.cs
using System.ComponentModel;namespace AnimationTest
{
public class Location : INotifyPropertyChanged
{
public bool IsCanceled { set; get; }
private long delay;
public long Delay
{
get { return this.delay; }
}
private int x;
public int X
{
get { return this.x; }
set
{
if (value != this.x)
{
this.x = value;
NotifyPropertyChanged("X");
}
}
}
private int y;
public int Y
{
get { return this.y; }
set
{
if (value != this.y)
{
this.y = value;
NotifyPropertyChanged("Y");
}
}
}
public Location(long milliseconds)
{
this.delay = milliseconds;
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
}
}
0 件のコメント:
コメントを投稿