wpf Animation colision detection - c#

hi i want to write a animation where car drivin on a road and waits untill train will pass and then goes again,but i cant find anything on the internet about it , i also want to cars drive in a "row" but now they driving through each other through.
Is it even possible ?
namespace Symulator_ruchu
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
Random r = new Random();
IEnumerable<PathFigure> colle;
DispatcherTimer dispatcherTimer = new DispatcherTimer();
DispatcherTimer train = new DispatcherTimer();
public MainWindow()
{
InitializeComponent();
dispatcherTimer.Tick += new EventHandler(dispTimer_tick);
dispatcherTimer.Interval = new TimeSpan(0,0,1);
dispatcherTimer.Start();
train.Tick += new EventHandler(train_tick);
train.Interval = new TimeSpan(0, 0, 10);
train.Start();
}
private void train_tick(object sender, EventArgs e)
{
Path car = new Path
{
Name = "AnimatedMatrixTrain",
Fill = Train.Fill,
Data = new RectangleGeometry
{
Rect = new Rect(0, 0, 55, 270)
},
LayoutTransform = new RotateTransform
{
Angle = 90
},
RenderTransform = new MatrixTransform
{
Matrix = new Matrix
{
OffsetX = 100,
OffsetY = 100
}
}
};
MatrixAnimationUsingPath maup = new MatrixAnimationUsingPath
{
Duration = TimeSpan.FromSeconds(r.Next(5, 10)),
DoesRotateWithTangent = true,
AutoReverse = false,
PathGeometry = new PathGeometry
{
Figures = PathFigureCollection.Parse("M 745,900 L 745,0")
}
};
Storyboard.SetTarget(maup, car);
Storyboard.SetTargetProperty(maup, new PropertyPath("(UIElement.RenderTransform).(MatrixTransform.Matrix)"));
Storyboard storyboard = new Storyboard();
storyboard.Children.Add(maup);
//Canvas.SetTop(car, r.Next(1, 500));
//Canvas.SetLeft(car, r.Next(1, 500));
storyboard.Begin(car);
Canv.Children.Add(car);
}
private void dispTimer_tick(object sender, EventArgs e)
{
Path car = new Path
{
Name = "AnimatedMatrixCar",
Fill = Car.Fill,
Data = new RectangleGeometry
{
Rect = new Rect(0,0,60,30)
},
LayoutTransform = new RotateTransform
{
Angle = 180
},
RenderTransform = new MatrixTransform
{
Matrix = new Matrix
{
OffsetX = 100,
OffsetY = 100
}
}
};
MatrixAnimationUsingPath maup = new MatrixAnimationUsingPath
{
Duration = TimeSpan.FromSeconds(r.Next(5,10)),
DoesRotateWithTangent = true,
AutoReverse = false,
PathGeometry = new PathGeometry
{
Figures = PathFigureCollection.Parse("m 10,286 h 800 c 130,10 190, 200 -105, 180 h -450 c -160,10 -200,250 -35,290 H 1200")
}
};
Storyboard.SetTarget(maup, car);
Storyboard.SetTargetProperty(maup, new PropertyPath("(UIElement.RenderTransform).(MatrixTransform.Matrix)"));
Storyboard storyboard = new Storyboard();
storyboard.Children.Add(maup);
//Canvas.SetTop(car, r.Next(1, 500));
//Canvas.SetLeft(car, r.Next(1, 500));
storyboard.Begin(car);
Canv.Children.Add(car);
}
}
Here is how wpf window look like:
enter image description here

I don't think you can use collision detection in an animation. You'd have to write your own code moved the car pixel by pixel. You could then use a distance calculation between some calculated edge point of your rectangle and anything else.
That's all possible but you'd be calculating angle of rotation yourself. Fair bit of fiddly work and it might not even be so smooth once you're finished.
I'd go with storyboard and animations.
Some trial and error will be necessary for this in order for the train to pass just after a car stops.
Use a storyboard and at least two matrix animations within that.
Each animation can have a begin time and duration. The first animation should have no begin time, you want that to start straight away.
You might want one of the easout easing functions so it slows down as it nears the crossing.
The second animation should have a begin time which makes it start up again after the train has passed. This time with an ease in easing function so it accelerates up to speed.
You will need to split your path geometry into two parts. Up to the crossing and then from the crossing to end of road. You could use inkscape or manually find where your crossing is using the points in the geometry.
You will apply this to your first car.
Off it goes.
Use async await to introduce a delay. Then repeat using your storyboard with the second car. It will of course do the same as the first one but start a bit later, giving a gap.
There is a bit of a complication though. Maybe you want your second car to stop behind the first.
That means you need two different geometries with the second ending earlier.
Not sure if you have your geometries.
I would use inkscape to draw the path. It's free. You could import your base picture, add a layer and draw a vectorin the new layer. That has line start and and nodes and curve handle nodes. You can drag the nodes and add more. There's a bit of a learning curve but it'll be fairly easy to do your neat line. Then select your line and save as xaml. You'll get a file with a path in it, and your geometry. Extra nodes for a second and third car stop position.
Are your cars looking ok with the matrix animation? I wrote a facing converter to rotate moving (infantry or cavalry) columns so they face the direction they are moving in.

Related

How can I change the animation speed?

This is the code for the animation:
private void Pass_GotFocus(object sender, RoutedEventArgs e)
{
DoubleAnimation doubleAnimation = new()
{
Duration = new(TimeSpan.FromMilliseconds(800)),
From = 0,
To = 200
};
ColorAnimation colorAnimation = new()
{
Duration = new(TimeSpan.FromMilliseconds(800)),
To = Color.FromRgb(135, 206, 250)
};
Storyboard sb = new() { Duration = new(TimeSpan.FromMilliseconds(800)) };
Storyboard.SetTarget(doubleAnimation, passwordbox_underline);
Storyboard.SetTargetProperty(doubleAnimation, new PropertyPath(Rectangle.WidthProperty));
Storyboard.SetTarget(colorAnimation, passwordbox_underline);
Storyboard.SetTargetProperty(colorAnimation, new PropertyPath("(0).(1)", Rectangle.FillProperty, SolidColorBrush.ColorProperty));
sb.Children.Add(doubleAnimation);
sb.Children.Add(colorAnimation);
sb.Begin(this);
}
So I have an animated rectangle. It goes from 0 with to 200 width for 1 second with the same speed. My question is how can i make it to start faster at the beginning and gradually slow it down until stop?
You can use an easing function to achieve this kind of behavior.
Easing functions allow you to apply custom mathematical formulas to your animations. For example, you may want an object to realistically bounce or behave as though it were on a spring. You could use Key-Frame or even From/To/By animations to approximate these effects but it would take a significant amount of work and the animation would be less accurate than using a mathematical formula.
For example, the exponential function (ease out) will slow down the animation towards the end.
DoubleAnimation doubleAnimation = new DoubleAnimation
{
Duration = TimeSpan.FromMilliseconds(800),
From = 0,
To = 200,
EasingFunction = new ExponentialEase { EasingMode = EasingMode.EaseOut, Exponent = 5}
};

How to create a Turning animation?

I want to make a turning animation to show the vehicle turning in Junction. Also, I want to do it with c#(code behind) because my vehicles are dynamically added.
Solution tried:
I tried to use TranslateTransform and RotateTransform but I could only create sharp turn animation. I want to create a smooth turn animation.
Current Output:
Sample Code
//Code to add car
private void Click1_Click(object sender, RoutedEventArgs e)
{
var myCar = new Image()
{
Source = new BitmapImage(new Uri("ms-appx:///Assets/RedCar.png")),
Width = 140,
Height = 65,
HorizontalAlignment = HorizontalAlignment.Left,
VerticalAlignment = VerticalAlignment.Top,
RenderTransform = new TranslateTransform()
{
X = 0,
Y = actualHeight / 2 - 145
}
};
VehicleGrid.Children.Add(myCar);
}
//Code to create forward animation
private void MoreForward(UIElement element)
{
Storyboard storyboard = new Storyboard();
DoubleAnimation doubleAnimation = new DoubleAnimation()
{
Duration = new Duration(new TimeSpan(0, 0, 3)),
To = LeftRoad.ActualWidth - 140
};
Storyboard.SetTarget(doubleAnimation, element.RenderTransform);
Storyboard.SetTargetProperty(doubleAnimation, "X");
storyboard.Children.Add(doubleAnimation);
storyboard.Begin();
}
Full Code
You can see my full code in Github: TrafficManagementSystem
There's an interesting post that details how to create a layout path where your object can move along with.
But in a simple scenario like yours, you basically just want a curved motion like what's described in this Android's Material Design Guideline. Yeah... Android's, as we don't have native curved motion API support just yet (the Windows UI team did mention that they are looking to support this in the future though).
However, it's not too difficult to create your own curved motion. In fact, many have used this trick on the web already - apply the opposite speed of an easing on each axis. Also in your case, you will want the curve of the easing to be sharp in order to produce a nice turning animation.
For example, for a car coming from left to right and then doing a left turn, you can apply a QuinticEase with EaseIn mode on x-axis and one with EaseOut on y-axis. To turn the vehicle, just apply another rotation animation to it but with a short delay and lesser duration to ensure the turning only happens at the crossroad.
By slightly modifying my answer in this question, you can achieve what I described above with the following code
The AnimateTransform helper method
public static void AnimateTransform(this UIElement target, string propertyToAnimate, Orientation? orientation, double? from, double to, int duration = 3000, int startTime = 0, EasingFunctionBase easing = null)
{
if (easing == null)
{
easing = new ExponentialEase();
}
var transform = target.RenderTransform as CompositeTransform;
if (transform == null)
{
transform = new CompositeTransform();
target.RenderTransform = transform;
}
target.RenderTransformOrigin = new Point(0.5, 0.5);
var db = new DoubleAnimation
{
To = to,
From = from,
EasingFunction = easing,
Duration = TimeSpan.FromMilliseconds(duration)
};
Storyboard.SetTarget(db, target);
var axis = string.Empty;
if (orientation.HasValue)
{
axis = orientation.Value == Orientation.Horizontal ? "X" : "Y";
}
Storyboard.SetTargetProperty(db, $"(UIElement.RenderTransform).(CompositeTransform.{propertyToAnimate}{axis})");
var sb = new Storyboard
{
BeginTime = TimeSpan.FromMilliseconds(startTime)
};
sb.Children.Add(db);
sb.Begin();
}
Create the turning animations
MyCar.AnimateTransform("Translate", Orientation.Horizontal, null, -600, duration: 3000, easing: new QuinticEase
{
EasingMode = EasingMode.EaseIn
});
MyCar.AnimateTransform("Translate", Orientation.Vertical, null, -600, duration: 3000, easing: new QuinticEase
{
EasingMode = EasingMode.EaseOut
});
MyCar.AnimateTransform("Rotation", null, null, -90, duration: 2000, startTime: 500);
Result in motion
Alternatively, you can replace the traditional Storyboard animation with the new Composition API, which provides fully customizable easing functions (see below), but the idea is the same.
public static CubicBezierEasingFunction EaseOutExpo(this Compositor compositor) =>
compositor.CreateCubicBezierEasingFunction(new Vector2(0.14f, 1f), new Vector2(0.34f, 1f));
Hope this helps!

Programmatic Move Animation in Windows Phone 8

I am working to create a Move Animation in windows. I want to move and object from one location to the other. Basically what I am trying to do is to FLIP the selected rectangle and then randomly swap the positions of two Rectangle objects the movement should be shown as an animation.
I have tried and achieved FLIP animation. But now if there are 4 rectangles in a grid, random two rectangles should exchange their positions followed by a move animation. I tried to use the below code. But it is not working.
It just creates a Rectangle in the center of the screen and nothing else.
1) Created a new project
2) Added the below code to the MainPage.xaml.cs file.
public partial class MainPage : PhoneApplicationPage
{
// Constructor
public MainPage()
{
InitializeComponent();
Loaded += Create_And_Run_Animation;
// Sample code to localize the ApplicationBar
//BuildLocalizedApplicationBar();
}
private void Create_And_Run_Animation(object sender, EventArgs e)
{
// Create a red rectangle that will be the target
// of the animation.
Rectangle myRectangle = new Rectangle();
myRectangle.Width = 200;
myRectangle.Height = 200;
Color myColor = Color.FromArgb(255, 255, 0, 0);
SolidColorBrush myBrush = new SolidColorBrush();
myBrush.Color = myColor;
myRectangle.Fill = myBrush;
// Add the rectangle to the tree.
ContentPanel.Children.Add(myRectangle);
// Create a duration of 2 seconds.
Duration duration = new Duration(TimeSpan.FromSeconds(2));
// Create two DoubleAnimations and set their properties.
DoubleAnimation myDoubleAnimation1 = new DoubleAnimation();
DoubleAnimation myDoubleAnimation2 = new DoubleAnimation();
myDoubleAnimation1.Duration = duration;
myDoubleAnimation2.Duration = duration;
Storyboard sb = new Storyboard();
sb.Duration = duration;
sb.Children.Add(myDoubleAnimation1);
sb.Children.Add(myDoubleAnimation2);
Storyboard.SetTarget(myDoubleAnimation1, myRectangle);
Storyboard.SetTarget(myDoubleAnimation2, myRectangle);
// Set the attached properties of Canvas.Left and Canvas.Top
// to be the target properties of the two respective DoubleAnimations.
Storyboard.SetTargetProperty(myDoubleAnimation1, new PropertyPath("(Canvas.Left)"));
Storyboard.SetTargetProperty(myDoubleAnimation2, new PropertyPath("(Canvas.Top)"));
myDoubleAnimation1.To = 200;
myDoubleAnimation2.To = 200;
// Make the Storyboard a resource.
ContentPanel.Resources.Add("unique_id", sb);
// Begin the animation.
sb.Begin();
}
}
I haven't added anything in the xaml file. that is just as it is. Is there anything that i need to add to the xaml file for the animation to run properly. ?
Please Help
Better late than never ;-).
Just got the problem myself, you need to add
myDoubleAnimation1.EnableDependentAnimation = true;
myDoubleAnimation2.EnableDependentAnimation = true;
to your code to force WinRT to do execute animation - otherwise it deems your animation to be not worthy due to possible performance issues ... sigh.
Source: https://msdn.microsoft.com/en-us/library/windows/apps/windows.ui.xaml.media.animation.doubleanimation.enabledependentanimation.aspx

How to keep shape in ILCube

I want to plot some 3d surfaces with ILNumerics. I noticed that ILCube does not keep the shape of surface if I rotate it and it is because it tries to fit the cube in the ILPanel. If I use ILCamera, however, it will keep the shape but there is no cube around it. Here is an example,
private void ilPanel1_Load(object sender, EventArgs e)
{
var scene = new ILScene();
ILArray<float> A = ILSpecialData.torus(0.75f, 0.25f);
var sf = new ILSurface(A);
var pc = new ILPlotCube();
pc.TwoDMode = false;
scene.Add(pc);
pc.Add(sf);
sf.Colormap = Colormaps.Jet;
var cb = new ILColorbar();
cb.Location = new PointF(1, .1f);
sf.Children.Add(cb);
ilPanel1.Scene = scene;
}
and the result is
and for ILCamera
private void ilPanel1_Load(object sender, EventArgs e)
{
var scene = new ILScene();
ILArray<float> A = ILSpecialData.torus(0.75f, 0.25f);
var sf = new ILSurface(A);
var cam = scene.Camera;
cam.Add(sf);
sf.Colormap = Colormaps.Jet;
var cb = new ILColorbar();
cb.Location = new PointF(1, .1f);
sf.Children.Add(cb);
ilPanel1.Scene = scene;
}
and the result is
Is there any way to make the ILCube to keep the shape of the surface? Or add a cube around the surface to the ILCamera? Thanks.
Plot cubes currently do not support equal axis aspect ratios. But it is fairly simple to add this yourself.
For your example, the content of the plot cube (torus) is stretched along the Z axis, because the extend of the torus along Z is smaller than in X or Y direction. Hence, the plot cube chooses to stretch the content to give better details.
In order to show the torus without distortion, make sure the axis range of the plot cube equals in all directions:
pc.Limits.Set(new Vector3(-1,-1,-1), new Vector3(1,1,1));
See an interactive example here: http://ilnumerics.net/ilcc.php?ilc=i63fb4c
Drawback: you will have to adjust the Limits setting everytime the content of the plot cube is modified (ie. data is added / removed / altered).

WPF 3D - Apply a transformation, change the underlying object values

I've got a method that transforms a number of cylinders. If I run the method a second time it transforms the cylinders from their original position rather than their new position.
Is there anyway of 'applying' the transformation so that it changes the underlying values of the cylinders so that I can re-transform from the new values?
Can anyone assist?
Cheers,
Andy
void TransformCylinders(double angle)
{
var rotateTransform3D = new RotateTransform3D { CenterX = 0, CenterY = 0, CenterZ = 0 };
var axisAngleRotation3D = new AxisAngleRotation3D { Axis = new Vector3D(1, 1, 1), Angle = angle };
rotateTransform3D.Rotation = axisAngleRotation3D;
var myTransform3DGroup = new Transform3DGroup();
myTransform3DGroup.Children.Add(rotateTransform3D);
_cylinders.ForEach(x => x.Transform = myTransform3DGroup);
}
You are remaking the Transform3DGroup every time the method is called:
var myTransform3DGroup = new Transform3DGroup();
Transforms are essentially a stack of matrices that get multiplied together. You are clearing that stack every time you make a new group. You need to add consecutive transforms to the existing group rather than remake it.

Categories

Resources