So I have 2 Image's I want the first Image to move towards the other Image I have both X,Y coordinates, how should this be done if I want it moving pixel by pixel towards the target Image?
Bare in mind, I'm using Windows-Universal I've tried DoubleAnimation but my knowledge in that stuff is really bad, I don't know where to start. The Image would sometimes have to move diagonally (across) rather than moving right then up.
How should I do this?
This is what I have so far:
private void MoveToTarget_Start()
{
moveToTimer = new DispatcherTimer();
moveToTimer.Tick += MoveToTarget_Tick;
moveToTimer.Interval = new TimeSpan(0, 0, 0, 0, 1);
moveToTimer.Start();
}
void MoveToTarget_Tick(object sender, object e)
{
}
First, you need to know how many pixels you need to move. For that, we can try to retrieve the absolute position of each element and compare them (there may be a more straightforward way, I just don't know how):
private Point GetAbsolutePosition(UIElement element)
{
var ttv = element.TransformToVisual(Window.Current.Content);
return ttv.TransformPoint(new Point(0, 0));
}
(taken from this answer)
From there, we retrieve the point of each element and compute the difference:
var position1 = GetAbsolutePosition(Image1);
var position2 = GetAbsolutePosition(Image2);
var offsetX = position2.X - position1.X;
var offsetY = position2.Y - position1.Y;
Now, we now of how many pixels we'll have to move on each axis. We add the TranslateTransform for the element (it may be better to do that beforehand directly from the XAML):
var translateTransform = new TranslateTransform();
image1.RenderTransform = translateTransform;
Finally, we create the animations, and target the TranslateTransform. Then we group them in a Storyboard, and start it:
var animationX = new DoubleAnimation()
{
From = 0,
To = offsetX,
Duration = TimeSpan.FromSeconds(2)
};
var animationY = new DoubleAnimation()
{
From = 0,
To = offsetY,
Duration = TimeSpan.FromSeconds(2)
};
Storyboard.SetTarget(animationX, translateTransform);
Storyboard.SetTargetProperty(animationX, "X");
Storyboard.SetTarget(animationY, translateTransform);
Storyboard.SetTargetProperty(animationY, "Y");
var storyboard = new Storyboard();
storyboard.Children.Add(animationX);
storyboard.Children.Add(animationY);
storyboard.Begin();
To be honest the best idea is to use DoubleAnimation and Storyboard classes.
I would set background as Canvas then You can animate it throught Canvas.SetLeft and Canvas.SetTop properties.
First You should create DoubleAnimationC class
DoubleAnimation da = new DoubleAnimation()
{
SpeedRatio = 3.0,
AutoReverse = false,
From = 0
To = 100
BeginTime = TimeSpan.FromSeconds(x),
};
Storyboard.SetTarget((Timeline)doubleAnimation, YOUR IMAGE);
Storyboard.SetTargetProperty(doubleAnimation, new PropertyPath("(Canvas.Top)"));
Of course change those properties as You like and now we must create StoryBoard class which will contains our animation
Storyboard sb = new Storyboard();
sb.Children.Add(da);
sb.Start();
Hope it helps!
Related
I am trying to animate the location of a MapIcon in the UWP version of Bing Maps. I am having problems specifying the PropertyPath for the Latitude component (a double value) of the GeoPoint used as the center value for the icon:
MapIcon mapIcon1 = new MapIcon();
mapIcon1.Location = myMap.Center;
mapIcon1.NormalizedAnchorPoint = new Point(0.5, 1.0);
mapIcon1.Title = "My Friend";
mapIcon1.Image = mapIconStreamReference;
mapIcon1.ZIndex = 0;
myMap.MapElements.Add(mapIcon1);
double centerLatitude = myMap.Center.Position.Latitude;
double centerLongitude = myMap.Center.Position.Longitude;
Storyboard storyboard = new Storyboard();
DoubleAnimation animation = new DoubleAnimation();
animation.From = centerLatitude;
animation.To = centerLatitude + 100f;
animation.Duration = new Duration(new TimeSpan(0, 0, 0, 5));
animation.EnableDependentAnimation = true;
storyboard.Children.Add(animation);
//Storyboard.SetTargetProperty(animation, "(MapIcon.Location)(Geopoint.Position)(BasicGeoposition.Latitude)");
//Storyboard.SetTargetProperty(animation, "(MapIcon.Location)(MapControl.Center)(Geopoint.Position)(BasicGeoposition.Latitude)");
//Storyboard.SetTargetProperty(animation, "(MapIcon.Location)(BasicGeoposition.Latitude)");
//Storyboard.SetTargetProperty(animation, "(MapIcon.Location.Latitude)");
Storyboard.SetTarget(storyboard, mapIcon1);
storyboard.Begin();
None of the commented out statements work; they all result in the "Cannot resolve TargetProperty on specified object" error. I was particularly hopeful for the first attempt "(MapIcon.Location)(Geopoint.Position)(BasicGeoposition.Latitude)", but no luck.
(I am able to animate the Color attribute of a MapIcon successfully.)
Storyboard.SetTargetProperty targets the dependency property where the animation applies. So, what you want to apply animation to 'Latitude'is impossible.
You would have to make it by yourself. For example, using the DispatcherTimer.
I've been trying out the new Windows.UI.Composition APIs lately and when using the color bloom animation, I've been trying to run four of them simultaneously from each side of the screen. I've been able to make all four of them run at a click of a button but the last transition I've started always takes over the display in the end for example:
This is what happens:
But what should happen is that all the colors should fill the screen at the same time. How would I be able to do that?
This is the code I used to start the animations:
private void surroundBloomButton_Click(object sender, RoutedEventArgs e)
{
//all of these headers are actually textblocks I've placed on the sides of the grid.
var header = topFlower;
var headerPosition = topFlower.TransformToVisual(UICanvas).TransformPoint(new Windows.Foundation.Point(0d, 0d));
var header2 = rightFlower;
var header2Position = rightFlower.TransformToVisual(UICanvas).TransformPoint(new Windows.Foundation.Point(0d, 0d));
var header3 = bottomFlower;
var header3Position = bottomFlower.TransformToVisual(UICanvas).TransformPoint(new Windows.Foundation.Point(0d, 0d));
var header4 = leftFlower;
var header4Position = leftFlower.TransformToVisual(UICanvas).TransformPoint(new Windows.Foundation.Point(0d, 0d));
//Uses values of the textBlock size
var initialBounds = new Windows.Foundation.Rect()
{
Width = header.RenderSize.Width,
Height = header.RenderSize.Height,
X = headerPosition.X,
Y = headerPosition.Y
};
var finalBounds = Window.Current.Bounds; // maps to the bounds of the current window
//The code is super easy to understand if you set a break point here and
//check to see what happens step by step ;)
surroundButtonTransition.Start((Windows.UI.Color.FromArgb(255, 255, 0, 0)), // the color for the circlular bloom
initialBounds, // the initial size and position
finalBounds); // the area to fill over the animation duration
// Add item to queue of transitions
initialBounds = new Rect()
{
Width = header2.RenderSize.Width,
Height = header2.RenderSize.Height,
X = header2Position.X,
Y = header2Position.Y
};
surroundButtonTransition.Start((Windows.UI.Color.FromArgb(255, 255, 150, 0)), // the color for the circlular bloom
initialBounds, // the initial size and position
finalBounds); // the area to fill over the animation duration
initialBounds = new Rect()
{
Width = header3.RenderSize.Width,
Height = header3.RenderSize.Height,
X = header3Position.X,
Y = header3Position.Y
};
surroundButtonTransition.Start((Windows.UI.Color.FromArgb(255, 0, 255, 0)), // the color for the circlular bloom
initialBounds, // the initial size and position
finalBounds); // the area to fill over the animation duration
initialBounds = new Rect()
{
Width = header4.RenderSize.Width,
Height = header4.RenderSize.Height,
X = header4Position.X,
Y = header4Position.Y
};
surroundButtonTransition.Start((Windows.UI.Color.FromArgb(255, 0, 0, 255)), // the color for the circlular bloom
initialBounds, // the initial size and position
finalBounds); // the area to fill over the animation duration
}
private void SurroundButtonTransition_ColorBloomTransitionCompleted(object sender, EventArgs e)
{
//Changes colour of background to "White Smoke " when
//the animations have finished.
UICanvas.Background = new SolidColorBrush(Windows.UI.Colors.WhiteSmoke);
}
As you said, you are trying out the new Windows.UI.Composition APIs lately and when using the color bloom animation.
Since you had not post your code about the surroundButtonTransition that I use the ColorBloomTransitionHelper from the GitHub. It uses the ContainerVisual.Children.InsertAtTop method to insert a new visual at the top of the visual collection.
Also there is no method to add new visual at the same zindex as other visual in ContainerVisual.Children. Please check the method in VisualCollection class.
If you want all the colors should fill the screen at the same time, you should be able to change the alpha value of your color.
For example:
surroundButtonTransition.Start((Windows.UI.Color.FromArgb(100, 255, 0, 0)), initialBounds, finalBounds);
surroundButtonTransition.Start((Windows.UI.Color.FromArgb(100, 255, 150, 0)), initialBounds, finalBounds);
surroundButtonTransition.Start((Windows.UI.Color.FromArgb(100, 0, 255, 0)), initialBounds, finalBounds);
surroundButtonTransition.Start((Windows.UI.Color.FromArgb(100, 0, 0, 255)), initialBounds, finalBounds);
I want to make an animation that involves translating a circle _fixedCircle on x-axis from starting point (5,0) to end point (200,0) and then from (200,0) to (5,0) In a forever loop but not following a path, but "jumping", in other words, immediate translation from point to point.
To animate this circle doing a linear interpolation there is this:
Storyboard sb = new Storyboard();
DoubleAnimation anim = new DoubleAnimation();
sb.Children.Add(anim);
Storyboard.SetTarget(anim, _fixedCircle);
Storyboard.SetTargetProperty(anim, new PropertyPath("(Canvas.Left)"));
anim.From = 5;
anim.To = 200;
anim.RepeatBehavior = RepeatBehavior.Forever;
anim.AutoReverse = true;
MYCANVAS.Resources.Add("CIRCLE_ID", sb);
Duration duration = new Duration(TimeSpan.FromSeconds(2));
anim.Duration = duration;
anim.Begin();
But how to create "jumping" effect?
Try using a DoubleAnimationUsingKeyFrames, adding a DiscreteDoubleKeyFrame for each jump you want, e.g. (calculation of jump values has a lot of room for improvement ;)):
DoubleAnimationUsingKeyFrames anim = new DoubleAnimationUsingKeyFrames();
int maxNrOfJumps = 10;
for (int jump = 0; jump < maxNrOfJumps; jump++) {
double value = ((200 - 5) / maxNrOfJumps) * jump;
anim.KeyFrames.Add(new DiscreteDoubleKeyFrame(value, KeyTime.FromPercent(jump / (double)maxNrOfJumps)));
}
Discrete key frames like DiscreteDoubleKeyFrame create sudden "jumps" between values (no Interpolation). In other words, the animated property does not change until the key frame's key time is reached at which point the animated property goes suddenly to the target value.
https://msdn.microsoft.com/en-us/library/system.windows.media.animation.discretedoublekeyframe%28v=vs.110%29.aspx
Edit:
Running it can be done without a Storyboard, this is how I tested it:
_fixedCircle.BeginAnimation(Canvas.LeftProperty, anim);
Edit2:
You'd still need to set these properties to keep the animation running:
anim.RepeatBehavior = RepeatBehavior.Forever;
anim.AutoReverse = true;
Also, don't forget to set the Duration...
immediate translation from point to point
Are you looking for a kind of instant teleportation from the first point to the last one ?
If so :
Storyboard sb = new Storyboard();
DoubleAnimation anim = new DoubleAnimation();
sb.Children.Add(anim);
Storyboard.SetTarget(anim, _fixedCircle);
Storyboard.SetTargetProperty(anim, new PropertyPath("(Canvas.Left)"));
anim.From = 5;
anim.To = 200;
// anim.RepeatBehavior = RepeatBehavior.Forever; // nope
anim.AutoReverse = false; // well
MYCANVAS.Resources.Add("CIRCLE_ID", sb);
Duration duration = new Duration(TimeSpan.FromSeconds(0)); // here we go
anim.Duration = duration;
anim.Begin();
Why not use skipToFill property?
just add it to your storyboard.
There was some similar threads, but I didn't find solution of my problem. It's my first post here.
Here's the thing:
Viewport3D viewPort3D;
GeometryModel3D geometryModel = new GeometryModel3D();
Transform3DGroup transform3DGroup = new Transform3DGroup();
...
// Rotation
RotateTransform3D rotateTransform3D = new RotateTransform3D();
AxisAngleRotation3D axisAngleRotation3d = new AxisAngleRotation3D();
axisAngleRotation3d.Axis = new Vector3D(0, 1, 0);
axisAngleRotation3d.Angle = angle;
rotateTransform3D.Rotation = axisAngleRotation3d;
transform3DGroup.Children.Add(rotateTransform3D);
// Translation
TranslateTransform3D translateTransform3D = new TranslateTransform3D();
translateTransform3D.OffsetX = offsetX;
transform3DGroup.Children.Add(translateTransform3D);
// Adding transforms
geometryModel.Transform = transform3DGroup;
Model3DGroup model3DGroup = new Model3DGroup();
model3DGroup.Children.Add( image.getGeometryModel3D() );
modelVisual3D.Content = model3DGroup;
viewPort3D.Children.Add( modelVisual3D );
And now I want to make translation using storyboard (because later I want to add also rotating to that storyboard):
Storyboard s = new Storyboard();
Transform3DGroup transform3DGroup = model3DGroup.Children.ElementAt(current).Transform as Transform3DGroup;
for (int j = 0; j < transform3DGroup.Children.Count; ++j)
{
if (transform3DGroup.Children.ElementAt(j) is TranslateTransform3D)
{
TranslateTransform3D translation = transform3DGroup.Children.ElementAt(j) as TranslateTransform3D;
DoubleAnimation doubleAnimation = new DoubleAnimation();
doubleAnimation.From = 0;
doubleAnimation.To = 2;
doubleAnimation.Duration = new Duration(TimeSpan.FromSeconds(1));
doubleAnimation.AutoReverse = true;
doubleAnimation.RepeatBehavior = RepeatBehavior.Forever;
s.Children.Add(doubleAnimation);
s.Duration = new Duration(TimeSpan.FromSeconds(1));
Storyboard.SetTarget(doubleAnimation, model3DGroup.Children.ElementAt(current));
Storyboard.SetTargetProperty(doubleAnimation, new PropertyPath("(Model3D.Transform).(Transform3DGroup.Children)[1].(TranslateTransform3D.OffsetX)"));
s.Begin(); // Exception during the execution.
}
}
Exception in the last line:
'[Unknown]' property value in the path
'(Model3D.Transform).(Transform3DGroup.Children)[1].(TranslateTransform3D.OffsetX)'
points to immutable instance of
'System.Windows.Media.Media3D.TranslateTransform3D'.
I took PropertyPath similar to the path generated in blend 4.
Thank you for any help.
I think because translate tranform 3d is an immutable instance it has to be indicated that it should be mutable while rendering / translation is taking place.
I guess
We can supply x:Name to that immutable TranslateTransform3D object, to make it mutable.
Bind to its property than to animate it.
E.g. in your case
NameScope.SetNameScope(this, new NameScope());
this.RegisterName("AxisRotation", MyAxisRotation3DObject.Rotation);
this.RegisterName("TranslateTransformation", MyTranslation3DObject);
This way we give names to Axis Rotation 3D and Translate Transform 3D objects and then in double animations refer them as Storyboard.SetTargetName(.., "AxisRotation") and Storyboard.SetTargetName(.., "TranslateTransformation") and access their direct properties such as Storyboard.SetTargetProperty(.., new PropertyPath("Angle")) and Storyboard.SetTargetProperty(.., new PropertyPath("OffsetX")) resp.
Your error states that TranslateTransform3D is immutable, what means, it cannot be changed. And you're trying to animate one of its properties, hence got the error.
I want to animate the rectangle x position from my code behind (as the x position is only determined at the run time).
I have got the following code:
KeySpline easeOut = new KeySpline(0, 1, 0.3, 1);
Storyboard sb = new Storyboard();
DoubleAnimationUsingKeyFrames da1 = new DoubleAnimationUsingKeyFrames();
SplineDoubleKeyFrame keyFrame1 = new SplineDoubleKeyFrame();
GeneralTransform generalTransform = rect4.TransformToVisual(this);
Point point = generalTransform.Transform(new Point());
keyFrame1.Value = point.X;
keyFrame1.KeySpline = easeOut;
da1.KeyFrames.Add(keyFrame1);
sb.Children.Add(da1);
Storyboard.SetTarget(da1, rect);
Storyboard.SetTargetProperty(da1, new PropertyPath("What is the path?"));
sb.Begin();
The thing I don't know is what to put for the PropertyPath?!
If you placed it on the Canvas use this
Storyboard.SetTargetProperty(da1, new PropertyPath("(Canvas.Left)"));
I would place the code in the Xaml in Window.Resorces, give it a name x:Name="da1" and ten just simply call it in code
sb.Begin();