Add State at runtime - unity3d

I want to create at animation controller for at object at run time and then add states within that controller.
For exmple, a state with animation for walking.
I have successfully create the state but I am unsure as to how to assign a motion clip to that state?
var rootStateMachine = controller.layers[0].stateMachine;
//add state
var stateA1 = rootStateMachine.AddState("stateA1");
I want to assign an animation clip to stateA1.

It stores in the AnimatorState.motion property.
stateA1.motion = your_animation_clip;

Related

How to get correct position of a gameobject thatis inside a vertical Layout group in unity?

I have a vertical layout group containing 3 game object
when I try to get the correct position of the child Objects from the vertical Layout group, it does not giving the correct output.
I tried
myPosition = this.gameObject.transform.localPosition;
myPosition = this.gameObject.transform.position;
myPosition = this.GetComponent<RectTransform>().position;
myPosition = this.GetComponent<RectTransform>().anchoredPosition;
Non gave the correct output. How to get this
You just need to fetch the position in Update or LateUpdate method, don't do that in Awake or Start.
void Update()
{
if(transform.hasChanged)
myPosition = ((RectTransform)transform).anchoredPosition;
}
https://docs.unity3d.com/Packages/com.unity.ugui#1.0/manual/UIAutoLayout.html
The rebuild will not happen immediately, but at the end of the current frame, just before rendering happens.
According to the documentation above, you cannot freely trigger layout rebuild, so this way is just based on the order of layout calculations: Call these 4 methods before fetching the position.
// VerticalLayoutGroup vlg;
vlg.CalculateLayoutInputHorizontal();
vlg.SetLayoutHorizontal();
vlg.CalculateLayoutInputVertical();
vlg.SetLayoutVertical();
myPosition = ((RectTransform)transform).anchoredPosition;

Q: How to play OneShotAnimations in reverse with new rive

I have an app where I have an animated check mark made in rive. It is a one shot animation and I want to play it and have it stay in the end of the animation once it's done and then also be able to reverse it when the user clicks on it again. I tried using a SimpleAnimation but I also wasn't able to achieve what I want but it did stay after the animation was done. I don't, however, know how to play an animation and then reverse it or play another animation.
The check mark looks something like this: https://cln.sh/MwLFNs
They are two separate animations but they are copy pasted but in reverse so I can use either one or both.
What I need is to have the animation play and then when the user clicks on the check, I want the animation to change to another one which would then play. How can I achieve this?
Thanks for the help!
you can use State machines, get the state and decide what to do when you want
// Getting state machine
void _onRiveInit(Artboard artboard) async {
final controller =
StateMachineController.fromArtboard(artboard, 'State Machine 1');
if (controller != null) {
artboard.addController(controller);
_lick = controller.findInput<bool>('Lick') as SMITrigger;
}
}
void _onHandlerStateMachine() => _lick?.value = !_lick!.value;
_onRiveInit is a function that is fired when the Rive file is being loading,
after you get the controller to the state machine to modify his state (This is important the name of the State Machine has to be the same of the animation State machine name)
and to modified the value of the trigger your must get the reference on this way
_lick = controller.findInput('Lick') as SMITrigger;
then you can use
void _onHandlerStateMachine() => _lick?.value = !_lick!.value;
to put or remove the animation on any time, also you can have more than one trigger.
If your need that your animation do something and after a time do something else you can use a debouncer function
_debouncer.run(() {
_onHandlerStateMachine()
});
**Remember update the view if are using state management
when the rive file is load
// Loads a Rive file
Future<void> _loadRiveFile() async {
final bytes = await rootBundle.load(riveFileName);
RiveFile rFile = RiveFile.import(bytes);
final artboard = rFile.mainArtboard;
_onRiveInit(artboard);
globalArtboard = artboard
..addController(
_animationController = SimpleAnimation('idle'),
);
}
Here I have and example of a Rive animation of Teddy, using Flutter with provider
https://github.com/alcampospalacios/flutter-rive-animations

How to trigger an entity's animation declared in .reality file?

In Reality Composer I created MyScene.rcproject, in MyScene I created a panel and its spin animation, the action sequence begins when its notification is posted from code.
When it's come to trigger the animation from MyScene.rcproject it works like I expect:
self.sceneAnchor = try MyScene.loadMyScene()
sceneAnchor.generateCollisionShapes(recursive: true)
sceneAnchor.notifications.spin.post()
But when I export MyScene.rcproject file to MyScene.reality and I implement it into another app project:
panelEntity = try? ModelEntity.load(named: "MyScene")
sceneAnchor.addChild(panelEntity)
I can't find any method to trigger the spin animation. Is it possible to trigger entity's animation, inside MyScene.reality file?
In RealityKit 2.0, if using .reality file instead of .rcproject, Notifications class is inaccessible.
public private(set) lazy var notifications = A.Scene.Notifications(root: self))

Adding Animation to Inputfield and save the transform

I wanted to add a simple search animation to my input field in my unity UI.
This is my InputField and the idea is, when I select it, it should expand slowly, and when I deselect it, it should shrink back to its normal form.
This is the rect Transform Component of this inputfield. I added to the input field and Event Trigger Component and an Animator. I created two Animations called SearchAnimation and DeselectAnimation and added them to my AnimationController called 'SearchController'.
This is how I designed my SearchController:
I set the Transitions between the defaultState and SearchAnimation to be listening to the SelectBool and DeselectBool (the name already describes its purpose).
Then I added the following script to my input Field so that those two booleans will be set accordingly to the event trigger:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class OnClickScript : MonoBehaviour {
Animator anim;
void Start()
{
anim = GetComponent<Animator>();
}
public void OnSelect()
{
anim.SetBool("SelectBool", true);
anim.SetBool("DeselectBool", false);
GetComponent<RectTransform>().sizeDelta = new Vector2(450, 50);
GetComponent<RectTransform>().localPosition.Set(-275, 0, 0);
}
public void OnDeselect()
{
anim.SetBool("DeselectBool", true);
anim.SetBool("SelectBool", false);
GetComponent<RectTransform>().sizeDelta = new Vector2(200, 50);
GetComponent<RectTransform>().localPosition.Set(-130, 0, 0);
}
}
But after the animation is played the inputfield is set back to its inital size and location. How do I fix this?
Easy way:
Create one more clips. The clip is made of only one key which is the Size Delta of the SelectedState. Then make this clip the animation clip of the state.
I put my test project here.
With above approach, once you want to change the size of default state and selected state, you will have to change all four animation clips manually.
Hard way
Using AnimationClip.SetCurve to create animation from the script. With this approach, you can create more maintainable animations. But it's not easy to create complex animations with scripts.
Suggestions:
Using Pivot:
In the script, you are changing local position to prevent the input field moving up. Instead of changing the local position value, you can set the pivot Y to 1 if you want the input field to expand downward.
Using trigger:
Instead of using two bool variables, you can simply use one Trigger to trigger the animation start and move to next state.

Cocos2D getting progress of CCAction

I have a Cocos2D game with Box2D physics. In my GameScene.mm, I'm working on a method to zoom to a given scale:
-(void) zoomToScale:(float)zoom withDuration:(ccTime)duration
{
id action = [CCScaleTo actionWithDuration:duration scale:zoom];
[scrollNode runAction:action];
currentZoomLevel = zoom;
}
The problem that I'm having is that currentZoomLevel (which is used in the Scene's update() method) is set to the zoom immediately, and isn't gradually adjusted as per the animation. So while the animation is in progress, the currentZoomLevel variable is totally wrong.
I'm trying to figure out a way to have the currentZoomLevel variable match the progress of the animation as it's happening. According to the CCAction API Reference, the CCAction's update method takes a ccTime that's between 0 and 1 based on the progress of the animation (0 is just started, 1 is just finished).
How can I access this ccTime from outside of the action? I want to have something in my Scene's update method like this:
if(animating)
{
float progress = [action getProgress]; // How do I do this?
// Do math to update currentZoomLevel based on progress
}
Am I missing something obvious here, or am I going to have to subclass CCScaleTo?
You should be able to access the scale directly as it animates.
instead of
float progress = [action getProgress];
try
float current_scale = some_node.scale ;
where "some_node" is the thing you're animating/scaling.
Actually, your best bet is to use the new Cocos2D extension "CCLayerPanZoom", which handles all of this marvellously for you! It should be part of any new cocos2D install (v.1.0+).