In Cocos2D, we use CCSequence to chain actions/animations and whatever in a sequence.
Like:
Move (animate) image from top left of screen to bottom right of screen over 5 seconds. (we just enter the start and end locations of the image, Cocos2D takes care of tweening the location over time)
Delay/wait the sequence 2.5 seconds
Move that image again to centre of screen while scaling it up to 1.5 size over 3 seconds.
Then have a block called on completion so that we can continue with some other code...
This way it's very easy to chain actions up with probably 4-6 lines of code. How do we do that in Unity? I am using Unity 4.6 and am so far only using 2D elements.
IEnumerator Sequence()
{
yield return Move();
yield return new WaitForSeconds(2.5f);
yield return MoveScaling;
yield return OnComplete();
}
...
StartCoroutine(Sequence());
This is more ore less what the code will look like. I let to you the implementation of the single subroutine. To get more info have a look at how Unity coroutine work (they are simply C#'s iterator blocks)
Related
In Windows World, a dedicated render thread would loop something similar to this:
void RenderThread()
{
while (!quit)
{
UpdateStates();
RenderToDirect3D();
// Can either present with no synchronisation,
// or synchronise after 1-4 vertical blanks.
// See docs for IDXGISwapChain::Present
PresentToSwapChain();
}
}
What is the equivalent in Cocoa with CAMetalLayer? All the examples deal with updates being done in the main thread, either using MTKView (with it's internal timer) or using CADisplayLink in the iOS examples.
I want to be in control of the whole render loop, rather than just receiving a callback at some non-specified interval (and ideally blocking for V-Sync if it's enabled).
At some level, you're going to be throttled by the availability of drawables. A CAMetalLayer has a fixed pool of drawables available, and calling nextDrawable will block the current thread until a drawable becomes available. This doesn't imply you have to call nextDrawable at the top of your render loop, though.
If you want to draw on your own schedule without getting blocked waiting on a drawable, render to an off-screen renderbuffer (i.e., a MTLTexture with dimensions matching your drawable size), and then blit from the most-recently-drawn texture to a drawable's texture and present on whatever cadence you prefer. This can be useful for getting frame timings, but every frame you draw and then don't display is wasted work. It also increases the risk of judder.
Your options are limited when it comes to getting callbacks that match the v-sync cadence. Your best is almost certainly a CVDisplayLink scheduled in the default and tracking run loop modes, though this has caveats.
You could use something like a counting semaphore in concert with a display link if you want to free-run without getting too far ahead.
If your application is able to maintain a real-time framerate, you'll normally be rendering a frame or two ahead of what's going on the glass, so you don't want to literally block on v-sync; you just want to inform the window server that you'd like presentation to match v-sync. On macOS, you do this by setting the layer's displaySyncEnabled to true (the default). Turning this off may cause tearing on certain displays.
At the point where you want to render to screen, you obtain the drawable from the layer by calling nextDrawable. You obtain the drawable's texture from its texture property. You use that texture to set up the render target (color attachment) of a MTLRenderPassDescriptor. For example:
id<CAMetalDrawable> drawable = layer.nextDrawable;
id<MTLTexture> texture = drawable.texture;
MTLRenderPassDescriptor *desc = [MTLRenderPassDescriptor renderPassDescriptor];
desc.colorAttachments[0].texture = texture;
From here, it's pretty similar to what you do in an MTKView's drawRect: method. You create a command buffer (if you don't already have one), create a render command encoder using the descriptor, encode drawing commands, end encoding, tell the command buffer to present the drawable (using a -presentDrawable:... method), and commit the command buffer. Whatever was drawn to the drawable's texture is what will end up on-screen when it's presented.
I agree with Warren that you probably don't really want to sync your loop with the display refresh. You want parallelism. You want the CPU to be working on the next frame while the GPU is rendering the most current frame (and the display is showing the last frame).
The fact that there's a limit on how many drawables may be in flight at once and that nextDrawable will block waiting for one will prevent your render loop from getting too far ahead. (You'll probably use some other synchronization before that, like for managing a small pool of buffers.) If you want only double-buffering and not triple-buffering, you can set the layer's maximumDrawableCount to 2 instead of its default value of 3.
This answer provides a nice way to make smooth animations in SciLab. I now have to write a simulation of a body attached to two strings (and therefore its movement regarding some additional forces).
The code in the link works well to render movement of a single point and, unfortunately, I didn't manage to make an animation of a point + two lines using this method. If someone is curious, I tried this code to do it:
frametime=(tk-t0)/Nt//defining the waitnig time
plot(Y(1,1),Y(2,1),"o")//plotting the point
plot([0;Y(1,1)],[0;Y(2,1)],style=1)
plot([D;Y(1,1)],[0;Y(2,1)],style=1)//plotting the two initial lines
h1_compound = gce();
h_point=h1_compound.children
h_point.mark_size = 20;
h_point.mark_background = 2;
h_line1=h_compound.children
h_line2=h_compound.children
//h_axes = gca();
//h_axes.data_bounds = [0,-1;10,1];
realtimeinit(frametime);
for i=1:Nt//my vectors have Nt points
realtime(i);//wait "frametime" seconds before drawing the new position
h_point.data=[Y(1,i),Y(2,i)];
h_line1.data=[[0;Y(1,i)],[0;Y(2,i)]]
h_line2.data=[[D;Y(1,i)],[0;Y(2,i)]]
end
The question is: is there any way to make an animation of three shapes without making axes blink (as it is with the window refreshment) or other wierd stuff?
Since you didn't create a MCVE I can't reproduce your exact problem. But you may try to add drawlater(); before, and drawnow(); after your data modification to see if it does help with blinking or not.
Or you may get much better looking result by saving your plots in every round with xs2gif and assemble the animation with another gifmaker progam (there are free online sites to do this, however with some limitations). If you need to present your result, you should do this step anyway.
I'm new to JavaFX and encountered a problem with the rotating animation while trying to write a Rubik's cube solving program.
I know JavaFX provides some classes for the animation ,but instead of using them, I wanted to try my own approach initially.
Following is the rough idea of my code :
for(90 times)
{
cube.setRotate(cube.getRotate() + 1);
try{Thread.sleep(100);}
catch{InterruptedException e) {Thread.currentThread().interrupt();}
}
By rotating the cube only one degree at a time and using time delay and loop appropriately, I expected to see something similar to rotating animation.
But the result I get is that the cube in the screen doesn't change with each setRotate() in the for loop, it only changes after the loop is over and therefore it changes 90 degrees at one time after 90*100 milliseconds.
I'm wondering if there is a method that can refresh the output in the screen each time using the setRotate() method.
Why do you want to avoid the mechanisms which are designed to make animations. Don't you think there is a reason that they exist?
With your code you are blocking the JavaFX application thread and the resulting behaviour is described in all documents dealing with this issue.
I'm attempting to implement window-flipping identical to that in iWork -
https://dl.dropbox.com/u/2338382/Window%20Flipping.mov
However, I can't quite seem to find a straightforward way of doing this. Some tutorials suggest sticking snapshot-images of both sides of the window in a bigger, transparent window and animate those. This might work, but seems a bit hacky, and the sample code is always bloated. Some tutorials suggest using private APIs, and since this app may be MAS-bound, I'd like to avoid that.
How should I go about implementing this? Does anyone have any hints?
NSWindow+Flipping
I've rewritten the ancient code linked below into NSWindow+Flipping. You can grab these source files from my misc. Cocoa collection on GitHub, PCSnippets.
You can achieve this using CoreGraphics framework. Take a look at this:
- (void) flipWithDuration: (float) duration forwards: (BOOL) forwards
{
CGSTransitionSpec spec;
CGSTransitionHandle transitionHandle;
CGSConnection cid = CGSDefaultConnection;
spec.type = CGSFlip;
spec.option = 0x80 | (forwards ? 2 : 1);
spec.wid = [self windowNumber];
spec.backColor = nil;
transitionHandle = -1;
CGSNewTransition (cid, &spec, &transitionHandle);
CGSInvokeTransition (cid, transitionHandle, duration);
[[NSRunLoop currentRunLoop] runUntilDate:
[NSDate dateWithTimeIntervalSinceNow: duration]];
CGSReleaseTransition (cid, transitionHandle);
}
You can download sample project: here. More info here.
UPDATE:
Take a look at this project. It's actually what You need.
About this project:
This category on NSWindow allows you to switch one window for
another, using the "flip" animation popularized by Dashboard widgets.
This was a nice excuse to learn something about CoreImage and how to
use it in Cocoa. The demo app shows how to use it. Scroll to the end
to see what's new in this version!
Basically, all you need to do is something like:
[someWindow flipToShowWindow:someOtherWindow forward:YES];
However, this code makes some assumptions: — someWindow (the initial
window) is already visible on-screen. — someOtherWindow (the final
window) is not already visible on-screen. — Both windows can be
resized to the same size, and aren't too large or complicated — the
latter conditions being less important the faster your CPU/video card
is. — The windows won't go away while the animation is running. — The
user won't try to click on the animated window or do something while
the animation is running.
The implementation is quite straightforward. I move the final to the
same position and size as the initial window. I then position a larger
transparent window so it covers that frame. I render both window
contents into CIImages, hide both windows, and start the animation.
Each frame of the animation renders a perspective-distorted image into
the transparent window. When the animation is done, I show the final
window. Some tricks are used to make this faster; the flipping window
is setup only once; the final window is hidden by setting its alpha to
0.0, not by ordering it out and later ordering it back in again, for instance.
The main bottleneck is the CoreImage filter, and the first frame
always takes much longer to render — 4 or 6 times what it takes for
the remaining frames. I suppose this time is spent with setup and
downloading to the video card. So I calculate the time this takes and
draw a second frame at a stage where the rotation begins to show. The
animation begins at this point, but, if those first two frames took
too long, I stretch the duration to make sure that at least 5 more
frames will get rendered. This will happen with slow hardware or large
windows. At the end, I don't render the last frame at all and swap the
final window in instead.
This is the first time I've ever posted in a forum, so thanks in advance for anyone who takes the time to read/answer this question.
What I'm trying to create is basically a flipping coin animation, which starts off turning very fast and then slows down to stop with a (randomly generated) side facing upwards after about 8 seconds.
I've done the animation of a complete flip, which lasts about half a second, and made it in to a movieclip... now I'm stuck!
Any ideas how I might go about doing this in actionscript3?
The fastest way around this would be to use some very basic actionscript. First, create 2 animations (One heads, one tails). Now, you only need a single frame for this and don't need to place the movieclips on the stage. Use the following or similar code:
var whichSide:int = 0;
var coin1:coinAnimation1 = new coinAnimation1();
var coin2:coinAnimation2 = new coinAnimation2();
whichSide = math.Round(math.Random(1));
if(whichSide == 1)
{
addChild(coin1);
}
else
{
addChild(coin2);
}
Just don't forget to right click the movieclip and export for actionscript, giving the movieclips the class of: coinAnimation1 and coinAnimation2.
Hope this helps.
I've accomplished such animation on ´Keyframes´ using the Tweener class. You can easily tween on the keyframe parameter with specific transition...
Basic example:
Tweener.addTween(myMovieClip, {_frame:10, time:2.5});
More information about Tweener here