I would like to modify a Timeline while it is running, for example in response to a mouse-click I want to change the target value of the animation. I have tried several methods to do this including (in a mouse clicked handler) :
Pausing the animation by calling pause() on the Timeline, clearing the KeyFrames ObservableList, adding a new KeyFrame and calling play() on the Timeline.
Creating a new KeyFrame with a Cue-name, adding the new frame to the Observable list and calling jumpTo(cueName) on the Timeline.
Some example code is:
String cueName = String.valueOf(System.currentTimeMillis());
KeyValue kv = new KeyValue(myObject.rotateProperty(), -90 + 180.0 * Math.random(), new CustomInterpolator());
KeyFrame kf = new KeyFrame(Duration.seconds(10), cueName, kv);
startupTimeline.getKeyFrames().add(kf);
startupTimeline.jumpTo(cueName);
startupTimeline.play();
Neither of these appear to work, the animation just stops.
Should I be able to modify the KeyFrame list of an existing Timeline or do I need to create a new Timeline if I want to change an animation while it is executing?
To the best of my knowledge, a Timeline can't be changed in that manner once it has started playing. The issue is that you might change the total cycle duration, which would confuse all the interpolation computations.
You probably need an AnimationTimer for this. AnimationTimer has an abstract handle(long timestamp) method which takes a time stamp (in nano-seconds), and is invoked every time the scene graph is rendered. So you can do something like:
AnimationTimer animation = new AnimationTimer() {
private long startTime = -1;
#Override
public void handle(long timestamp) {
if (startTime == -1) {
startTime = timestamp ;
}
long totalElapsedNanoseconds = timestamp - startTime ;
// update UI based on elapsed time...
}
}
The handle() method is invoked on the JavaFX Application Thread, so it is safe to update the UI, and to reference any variables that are only changed on the same thread.
Related
I am trying to achieve smooth animation using Xamarin SkiaSharp. The core issue is the the time between calling canvasView.InvalidateSurface(); and hitting the mathod OnCanvasViewPaintSurface to do the redraw can vary from 3 to 30 ms which gives a somewhat jerky appearance when you are moving an object across the screen. I have tried to mitigate this by adding a dead loop in the draw code, which helps some but is not a great solution. I do not understand why the time varies so much, and I do not see any way around this. You cannot put a sleep in the draw code. How do games achieve smooth animation? My code follows
async Task DoAnimationLoop()
{
while (DoAnimation)
{
AccumulatedTime = StopWatch1.ElapsedMilliseconds;
await Task.Delay(TimeSpan.FromMilliseconds(5));
if (AccumulatedTime > 50)
{
StopWatch1.Restart();
MoveItems();
SKCanvasView canvasView = Content as SKCanvasView;
TotalBounds = new Size(canvasView.Width,
canvasView.Height);
canvasView.InvalidateSurface();
}
}
}
private void OnCanvasViewPaintSurface(object sender,
SKPaintSurfaceEventArgs e)
{
AccumulatedTime = StopWatch1.ElapsedMilliseconds;
while (AccumulatedTime < 30)
{
AccumulatedTime = StopWatch1.ElapsedMilliseconds;
}
e.Surface.Canvas.Clear();
e.Surface.Canvas.DrawBitmap(Background, 0, 0);
foreach(Item item in AllItems)
{
e.Surface.Canvas.DrawBitmap(item.CurrentBitmap,
item.CurrentPositionX, item.CurrentPositionY);
}
}
For future readers:
From experience, I get the smoothest animations with SkiaSharp by creating SkiaSharp SKCanvasViews that have Bindable properties that can be incremented with Xamarin.Forms.Animate. Animate handles all the timing and sleeping code based on variables you configure it with. As you want a loop, you can set the repeat delegate to return true when calling Animate.Commit( ... repeat: () => true ...)
Here is a method example that animates a progress bar "filling" to 100 percent (without looping), by incrementing the ProgressBar's PercentageFilled Property. Note the timing settings you can configure: Refresh rate = 11ms (equates to "90 fps": 1000ms/90 = 11.11), timeToAnimate is the length of time the animation should take to complete in ms, and you can choose from several easing functions.
private void AnimateProgressBar()
{
double startPercentage = 0; //start at 0 percent
double endPercentage = 1; //fill to 100 percent (Forms.Animate will evenly increment
//between 0 and 1 , and in this case the ProgressBar's OnPaintSurface method knows how to draw based
//on the given decimal i.e. if PercentageFilled is .5 it will draw the bar to
//50 percent of its possible max length)
uint timeToAnimate = 1000;
Xamarin.Forms.Animation animation = new Animation(v => _ProgressBar.PercentageFilled = (float)v, startPercentage, endPercentage, easing: Easing.CubicOut);
animation.Commit(_ProgressBar, "FillPercentage", length: timeToAnimate, finished: (l, c) => animation = null, rate: 11);
}
When the PercentageFilled Property is changed it triggers InvalidateSurface by placing a call to InvalidateSurface() within the OnPropertyChanged method. To do this override OnPropertyChanged like so in your SKCanvasView derived class:
class ProgressBar: SKCanvasView
{
//...
public BindableProperty PercentageFilledProperty =
BindableProperty.Create(nameof(PercentageFilled), typeof(float), typeof(ProgressBar), 0f);
public float PercentageFilled
{
get { return (float)GetValue(PercentageFilledProperty ); }
set { SetValue(PercentageFilledProperty , value); }
}
protected override void OnPropertyChanged(string propertyName = null)
{
base.OnPropertyChanged(propertyName);
InvalidateSurface();
}
protected override void OnPaintSurface(SKPaintSurfaceEventArgs args)
{
//Draws progress bar based on the PercentageFilled filled property
}
//....
}
In the question's code it appears that a lot of items are being moved (MoveItems();) in sequence and this technique of drawing items one by one moving might be the cause of jitter? But MoveItems appears to be the place where you might want to use Forms.Animate that is you could Create a Forms.Animation with MoveItems() as the Callback. Look into the microsoft documentation for "Custom Animations in Xamarin.Forms" for more info on how to animate with callbacks.
Also check out "The basics to create custom Xamarin.Forms controls using SkiaSharp" by Konrad Müller on Medium which contains this helpful paragraph which might be useful to consider if you are making a game:
The basic SkiaSharp.Views.Forms provides two views you can use as a
base for your controls: SKCanvasView and SKGLView. The CanvasView uses
the CPU accelerated backend while the GLView uses OpenGL and therefore
the GPU. You might intuitively think that using the GPU for graphics
operations is always the better choice but in fact, OpenGL has a high
overhead when creating the GL context. The CanvasView simply allocates
the memory it needs and as long as enough CPU power is available, it
can render without problems. In theory, the CanvasView should be
better suited for less demanding renderings and GlView better for
complex renderings but the power of modern smartphones makes these
differences mostly unnoticable. I would recommend to simply stick to
the CanvasView and switch to the GlView if the rendering gets to
complex and you notice performance problems.
I'm trying to do a simple think: when a button is pressed i load a video using the processing video library, each button is associated with a different video, for example button 1 with video 1, button 2 with video 2, and so on. The code works but every time I call a video, also the same i have already load, rewriting the gloabal variable the consume of CPU grows, reaching the 40% after the thrid loading, after 7 video the consume of CPU is near the 100%. An extraction of the code:
import processing.video.*;
Movie movie;
void setup() {
size(1280, 720, P3D);
background(0);
}
void draw() {
//image(movie, 0, 0, width, height);
if (but1_1==1) {
println("video 1");
movie = new Movie(this, "1.mp4"));
movie.loop();
movie.volume(0);
}
if (but1_2==1) {
println("video 2");
movie = new Movie(this, "2.mp4"));
movie.loop();
movie.volume(0);
}
if (but1_3==1) {
println("video 3");
movie = new Movie(this, "3.mp4"));
movie.loop();
movie.volume(0);
}
}
As you can see, it should not be any reason in based on which the CPU consume grows: the instantiated object movie is always rewritten every time a new video (or the same) is loaded. Any suggestions?
You are loading the movies in loop, which means they don't stop. So the more buttons you press, the more videos are processed at the same time. On every button press, you should stop the movie-playing-process of the old movie first, before you start a new one.
I have created a Blender model that uses an armature with bone constraints to animate the model. After exporting the model as a .fbx file and passing it through fbx-conv, my animation is split up into several animations.
Each animation ends up with an ID similar to "MyObject|MyAnimation".
In other words, I need to run all of these sub-animations at once to run my full animation.
I tried several AnimationController methods. First I tried calling AnimationController.setAnimation() for each of the animations, which doesn't work because it cancels the current animation each time it is called.
The AnimationController.animate() method sounds like it is supposed to do what I want, but I just get the same result as with .setAnimation().
Here is the code I tried:
instance = new ModelInstance( myModel );
controller = new AnimationController( instance );
for( Animation animation : instance.animations ) {
controller.animate( animation.id, 0 );
}
Is this not how .animate() is intended to work?
Also, I am not entirely certain of how to correctly use the second argument, transitionTime. Could that be the problem?
As Xoppa pointed out, the LibGDX docs on 3D Animations and Skinning says the following:
"If you want to apply multiple animations to the same ModelInstance, you can use multiple AnimationControllers, as long as they don't interfere with each other (don't affect the same nodes)."
Example:
ModelInstance myInstance = new ModelInstance( myModel );
AnimationController controllerOne = new AnimationController( myInstance );
AnimationController controllerTwo = new AnimationController( myInstance );
controllerOne.setAnimation( "FirstAnimationId", -1 );
controllerTwo.setAnimation( "SecondAnimationId", -1 );
Then in your render loop, you will also need to call .update(delta) on all of your AnimationControllers:
controllerOne.update( Gdx.graphics.getDeltaTime() );
controllerTwo.update( Gdx.graphics.getDeltaTime() );
Everytime MediaPlayer.Play() is executed from the UI thread the UI freezes for a significant amount of time. I don't think you can do anything about the time it takes to start playing the SongCollection but at least the UI should stay responsive.
Running MediaPlayer.Play() from another thread obviously doesn't work.
The MediaPlayer is a component from the Xna Namespace. If you are using this feature in a game, you are most certain running a GameLoop to prevent this freeze from happening: GameLoop
If you use this component in an App, you can simulate this behavior your own
public MainPage()
{ InitializeComponent();
// Timer to simulate the XNA Game Studio game loop (Microphone is from XNA Game Studio)
DispatcherTimer dt = new DispatcherTimer();
dt.Interval = TimeSpan.FromMilliseconds(33);
dt.Tick += delegate { try { FrameworkDispatcher.Update(); } catch { } };
dt.Start();
}
(see complete sample on how to run a microphone outside a gameloop: msdn)
I'm learning to develop windows phone application. I started with a browser based app by following this tutorial - http://blogs.msdn.com/b/jaimer/archive/2011/02/04/back-button-press-when-using-webbrowser-control-in-wp7.aspx. I'm experimenting with http://m.facebook.com I can correctly use back button to go to the previous page and all that stuff but I'm not able to implement exit on double tap of back button.
I have seen many browsers app which exit after double tapping the back button. for example - Flipkart - http://www.windowsphone.com/en-us/store/app/flipkart/84fc03ea-210d-4e3e-88e0-de502a2434c5
There is no double tab event for back button. How can we achieve this?
You can create a global long that represents the last time the user pressed the back button.
Every time the back button is pressed, you can make your program subtract the number of elapsed ticks. If it has passed a short amount of ticks, you can make your program exit. If not, set the last tick variable once more.
You can get the current tick that represents the current time with System.DateTime.Ticks.
Simple code sample:
long LastExitAttemptTick = DateTime.Ticks;
private void BackButtonPressHandler(...)
{
long thisTick = DateTime.Ticks;
if (LastExitAttemptTick - thisTick < [specified amount])
throw new Exception("Exit Exception"); //You can use XNA, but this is a quick and dirty way of exiting
else
LastExitAttemptTick = DateTime.Ticks;
}
You can use a value of 10,000,000 ticks (1 second). MSDN says 10,000 ticks per millisecond, so 10,000 * 1000 = 10,000,000.
EDIT: Or as you said, you can also use DateTime.Now and use the seconds value instead. Either way works.
well this kind of logic could work for you
make a global variable
int Count=0
protected ovverride void OnBackKeyPress(CancelEventArgs e)
{
if(Count==0)
{
e.Canel=true;
Count++;
}
else if(Count==1)
{
Count=0;
//code for exiting
//may be App.Current.Terminate(); in wp8
//or in wp7
//if (NavigationService.CanGoBack)
//{
// while (NavigationService.RemoveBackEntry() != null)
// {
// NavigationService.RemoveBackEntry();
// }
//}
}
}
Hope this helps
To close the application on double click, you can use DispatcherTimer task to check whether a two clicks are within one second, if yes close the application else start timer and again check. The snippet for that as follows:
make a DispatcherTimer object as a class field like,
DispatcherTimer dt = new DispatcherTimer();
In your class's constructor specify the interval you want to check for double tap and also add event handler to perform some action when specified time has elapsed. You can do in a class's constructor,
dt.Interval = TimeSpan.FromSeconds(1.0);
dt.Tick += delegate(object s, EventArgs e)
{
dt.Stop();
};
Here what we're doing is we're specifying timespan of 1 second to check whether double tap occurs within that second. Tick event is for what we want to do when timer completes its 1 second. We're simply going to stop the timer.
Now navigate to back key event handler and here is my code to check double tap:
protected override void OnBackKeyPress(System.ComponentModel.CancelEventArgs e)
{
e.Cancel = true;
if (!dt.IsEnabled)
dt.Start();
else
new Microsoft.Xna.Framework.Game().Exit();
}
When for the first tap, timer is not started, it will go to if condition and will start the timer. If second tap occurs after 1 second, then the Tick event we wrote in constructor will fire and according to logic written there, the timer will stop.
Now assume the double tap occurs consequently within 1 second. For the 1st tap as usual it will start the timer, if immediately user presses back button again, then in its handler, it will check whether timer is running. As timer has not completed its 1 second interval, else condition will fired up and the application will close.
I used XNA library / shortcut to force close the application. To work with new Microsoft.Xna.Framework.Game().Exit(); method you should add a microsoft.xna.framework.game.dll in a reference.
Make TimeSpan interval as required.
Hope this helps. Thanks.
EDIT:
Sometimes XNA is not installed on windows 8. Here is a solution for that, so that you add above mentioned assembly reference in you project.
http://blogs.msdn.com/b/astebner/archive/2012/02/29/10274694.aspx
You have to download update which is around around 23MB.
To save time here's a Dropbox link to above assembly reference:
https://db.tt/RYTwv7cS
Yes there is no Double Tap event for back button. You have to write your own logic to exit application on Double Tap on device back key tap twice. Here is the solution this may be help you.
Create a Global variable and initialize with zero
Int TapCount =0;
Now Override OnBackKeyPress event with your own logic.
protected override void OnBackKeyPress(System.ComponentModel.CancelEventArgs e)
{
TapCount++;
if(TapCount==2)
{
if( windows phone 8 )
{
Application.Current.Terminate();
}
else
{
if (NavigationService.CanGoBack)
{
while (NavigationService.RemoveBackEntry() != null)
{
NavigationService.RemoveBackEntry();
}
}
}
}
else
e.Canel=true;
base.OnBackKeyPress(e);
}
It's very simple. I've implemented it like this:
First declare global variable:
int count;
Now initialize its value in OnNavigatedTo(NavigationEventArgs e) method:
count = 0;
Now at last add the below code to your cs file:
protected override void OnBackKeyPress(System.ComponentModel.CancelEventArgs e)
{
count++;
e.Cancel = true;
if(count == 2)
{ e.Cancel = false; base.OnBackKeyPress(e); }
}