Defold set animation and cursor in a single run - lua

Lets assume I have some input function which decides which direction to run. The atlas file being referenced to the game object has 8 (isometric) walk animations (same frame count, one animation per 1/8 rotation). Thus, if the rotation changes I want to set another animation but with its cursor at the same time (For the user the object should only rotate without starting the animation again)
I tried to do the following in the on_input function
self.cursor = go.get("#sprite", "cursor")
msg.post('#sprite','play_animation',{id = hash('run_5')})
go.set("#sprite", "cursor", cursor)
which is obviously not working because msg.post is async thus line 3 runs after 2 is being executed. How to get this done properly?

You can find some solutions here: at defold-forum.I can't write comments, so I had to write here.

Related

Swift/IOS: SCNNode appeared to return to its original position after SCNAction is finished, but its actual position was changed by SCNAction

I am very new to Swift and IOS development so this could be a simple question, but I struggle to find the answer on the internet.
I was trying to animate a static DAE model by running a SCNAction on one of its nodes. However, after the SCNAction was completed (and the node was moved), the node position will appear to go back to its original position immediately (same position when the static DAE model was loaded). But when I print the node's position, I noticed that the node's position was actually changed because of the SCNAction. And when I ran the SCNAction again on the same node, the node will go back to the end position resulted from the last SCNAction and start the SCNAction from there. I wonder why there's such mismatch between the node's actual position and the position appeared in the scene.
Another interesting thing was when I put SCNActions in sequence ([action1, action2]), the node will not return to its original position between actions. But if SCNAction.wait was added in between ([action1, SCNAction.wait, action2]), the node will return to its original position during the wait, and will start action2 again from action1's end position.
I am trying to maintain the positions of all nodes at the end of SCNActions. Is there any way to prevent it from going back to the original position?
Not sure if the question is clear enough. Any thoughts and ideas are appreciated.
Have you verified that the node does not come with an animation from the Collada file? Animations and actions are evaluated one after the other. The actions may override the effect of the animation, until they are done (or paused).
Unlike actions, animations don't write in the model tree (node.position) but only in the presentation tree (node.presentationNode.position).

How to get the current animation step from a CAKeyframeAnimation

I'm currently creating a small button with two different states. Every state is represented by two CAShapeLayers and the transition between the states is animated with a series of CAKeyframeAnimations/CABasicAnimations, which all change the path property of the shape layers. My question is how do I animate to a state starting from a current animation (i.e. button is pressed while animating).
Normally, I would ask the presentation layer for the current property value and use an additive animation (as perfectly described here), but since this is a multi-step animation I would have to figure out which step I am currently animating and then chain the appropriate animation to reverse to the previous state. But that is rather tricky (I wanted to have all the animation be removeOnCompletion=false and query the time offset of the animations to figure out which animation is currently active and how far).
Unfortunately, setting the layer speed to 0.0 and just animating the timeOffset back and forth doesn't work either, since I have secondary animations which behave differently in the opposite direction.
Using a custom layer property for the shape layers seems cumbersome, but I could match a progress property more easily to the current animation step.
So after some trial and error I come up with the following "solution": I use a CADisplayLink to get a time update for every frame and by subtracting the current timestamp from the timestamp when the animation started, I can figure out the elapsed animation time, thus the progress (by dividing through animationDuration). That way I can start the reverse animation with an offset. Internally, I calculate the next frame from the keyframe animation and adjust the keyTimes for the new duration.
You can see an implementation of this here

Flip Animation Using Core Animation Showing Reversed Contents

Here is the result that I get:
If I set the doubleSided property of layer 4 as No, the whole layer disappears. I know that already. But then, how can I show yet with correct content orientation?
Do the animation in two parts. At the halfway point, when the layer is side-on to the camera so you can’t see it, flip the layer the other way around and move the anchor point to the other side, and swap out the contents of the layer if you need to.
Unfortunately, I don’t have any sample code, because the last time I did this was on iOS 4, and the pile of hacks view-based animations that I was using don’t appear to work on layers any more. You could post your own code and accept your own answer if you want.

Menu from the Contre Jour app

I'm trying to do a menu like the one that "Contre Jour" game has, with 3 elements spinning in a circle when user drags left and right. I'm using CALayers with CATransforms to position them in a 3d spinning wheel (no problem so far).
I need a way (maybe with NSTimers?) to calculate in-between values, because CoreAnimation just interpolates values, but if you NSLog them, it's just gonna show the start and the end, or just the end. I need all the in-between values, I need to snap the wheel movement when I release the finger (touches ends)in one position (there are 3 elements, each one shoud be at 120 degrees.
My guess and am quite sure I'm correct is that they are using a game engine such as Unity3D or Cocos2D or any other of the many to manage their sprites, animations, textures, physics and basically everything. Trying to replicate it outside of game engine will most likely result in crummy performance and a lot of hair pulling. I would suggest looking into a dedicated game engine and give it a shot there.
I am not sure I understand exactly what Contre Jour does with the spinners, anyway, I think that a reasonable approach for your case is using a UIPanGestureRecognizers to update the status of your spinning wheels according to the panning.
Now, it is not clear what you do to animate the spinning wheel (if you could provide some code, this would help understanding exactly what you are trying to do), but the idea would be this: instead of specifying an animation ending point far away from the starting point (and letting Core Animation do all the handling for you, even when the dragging has stopped), you would only modify the status of the spinning wheel in small increments.
If your only issue is stopping the animation when the dragging stops, you could try calling removeAnimationForKey on your layer to halt a specific animation.
Look into CADisplayLink. This works very much like an NSTimer, except its refresh rate is tied to that of the display, so your animations will be smoother than if you were to use timers. This will allow you to calculate all the in-between values and update your control.
I'm not clear what you are asking, but I do have one insight for you: To get the in-between values of an in-flight animation, query the layer's presentationLayer property. the property that's being animated will have a value that's a close approximation of it's on-screen appearance at the moment you fetch the value.

Why isn't Quartz double buffering my drawInContext()?

I am rendering a simple line drawing (a line with some text in the middle) in a CALayer subclass via drawInContext(). I update this layer as the user is performing a gesture by calling setNeedsDisplay on it. The effect that I am seeing is what I might expect if there were no double buffering going on... i.e. I see parts of new rendering overlapping parts of old rendering. When I stop updating (complete the gesture) the system "catches up" and I always see the correct final result, but during the updates I see inconsistent results... This effect is not subtle and sometimes it is extreme... e.g. if I keep updating fast enough I can keep stale parts of the drawing on the screen for seconds while the new parts are drawing ahead...
I don't understand this at all. If Quartz is doing buffering then it seems that it is not blitting the result to the screen in its entirety or it is miscalculating the affected area.
Things I've tried:
1) I am disabling implicit animations and doing all of the drawing within a CATransaction
2) I am not making a mistake in my drawing... It's literally just two lines with some text in between... there is no way that I'm rendering the intermediate artifacts.
3) I have tried limiting the rate of updates by skipping most of them... but even at the lower rate I see artifacts until I stop updating and let the system catch up.
4) BTW, this happens identically in the simulator and on the device (iPad).
Is it necessary for me to draw into an offscreen buffer myself and copy it to the screen in its entirety? I thought that I had read that Quartz does this for me.
Update:
As usual, after hours of banging my head against the wall I find the (partial) answer 5 minutes after posting the question. I realized that I was using a CATiledLayer in order to get my layer re-rendered on zoom. If I switch it back to a regular CALayer the glitches go away. So I guess what I am seeing artifacts of the separate tiles rendering. Now I am trying to figure out how to deal with this...
So, it turns out that I had three problems:
1) CATiledLayer explicitly fades in new tile content with a default time of 0.25 seconds... This was causing havoc with my drawing. I overrode this in my CATiledLayer subclass:
+ (CFTimeInterval)fadeDuration {
NSLog(#"got fade duration");
return 0;
}
2) I also had to adjust the maximum tile size up (I set it to 1024x1024 though I don't know what size it is actually using).
3) I was making adjustments to my layer's frame periodically during the updates and that seemed to cause additional problems for the tiled layer. I am making changes to stop that.
With all of those changes the performance seems acceptable now.

Resources