Unity Animation on Button Click returns to Idle animation - unity3d

I have four buttons to select range of numbers. (clicked button should animate and stay scaled just to indicate which button is selected) I am trying to play animation on button click in unity. so when button is clicked, animation is played and returns to idle. But I do not want it to return to idle state instead I want it to remain at the last frame of on click animation clip(at last frame scale is 1.2). Loop time is unchecked.
I have assigned onclick animator play(string) in the inspector. Please help
also tried following code
public GameObject rangeBtn;
public Animator rangeBtnAnim;
private void Start()
{
if ((rangeBtn != null) && (rangeBtn.GetComponent<Animator>() != null))
{
rangeBtnAnim = rangeBtn.GetComponent<Animator>();
}
}
public void PlayAnimation()
{
rangeBtnAnim.Play("RangeSelectionButton_Pressed");
}

I would simply use this setup with Parameters
Make the PressedAnimation clip not Loop Time and use a bool parameter e.g. IsPressed. (One could also use triggers instead but in this case a bool is easier and saver - triggers stack ...)
Than the setup for the transitions:
Idle -> PressedAnimation
and PressedAnimation -> Idle
Than in your code instead you would set
rangeBtnAnim.SetBool("IsPressed", true);
or
rangeBtnAnim.SetBool("IsPressed", false);
to go back to idle.
Note the simplest way in fact of having animations (if they are not complex) would be to simply only have 1 single keyframe in Idle and also in PRessedAnimation. Unity would than simply make a transition animation interpolating between the values according to the transition duration settings.
Alternatively if your animations get more complex you would probably rather do something like
And for the two transitions
PressedAnimation -> StayPRessed
UnPressAnimation -> Idle
use the ExitTime
for the other two use the parameter
and

Something I used in my games. Let's say you have two animations: Idle and Animated.
You want your button, after Animated finishes, to stays on the last frame right ? Then you create a third animation, Animated_Remains, which contains only one frame, the last from Animated.
Then, in your Animation Controller, you put a transition between Animated (no loop) and Animated_Remains (looped). If you want the same behaviour when transiting from Animated to Idle, then you create a 4th anim, Idle_Remains.
So, after clicking on your button, it will play the Animated animation, and automatically transit to the Animated_Remains.
I did that when I had to move my Camera with an animation and make it stay at the last frame position.

Related

Can't make a panel animation work through clicking on UI button

I'm trying to make a "Try Again" button work with a panel animation that's supposed to go from transparent to thick black before loading the game scene again. But for some reason the animation is not running nor the load scene line.I'm finding it odd.
At first I thought the panel was blocking me from clicking the button, so I set it inactive as default, and activate it through script.
I think I've set the references correctly, one for the panel animator, one for the panel itself (to set it active), one for "OnClick" section of the tryagain button and assigning the correct function from it in the inspector.
public class Tryagainscript : MonoBehaviour
{
public Animator tryagain;
public AudioSource audios;
public AudioClip tsu;
public GameObject panel;
IEnumerator TryCo()
{
tryagain.SetInteger("try", 1);
yield return new WaitForSeconds(1.2f);
SceneManager.LoadScene("Game");
}
public void Trybutton()
{
StartCoroutine(PanelCo());
}
IEnumerator PanelCo()
{
panel.SetActive(true);
audios.PlayOneShot(tsu);
yield return new WaitForSeconds(0.1f);
StartCoroutine(TryCo());
}
}
The names of the variables might be confusing, but you get the idea.
This is the script I assign to the TryAgain button to run the "Trybutton()" function so it runs both coroutines, one at a time. The integer "try" referes to the animator in the panel to go pitch black.
As I said though, nothing is working from this code: the panel is not going pitch black nor the game is loading back.
Thanks in advance!
Edit:
I've changed the code to something simpler:
public void Trybutton()
{
StartCoroutine(PanelCo());
}
IEnumerator PanelCo()
{
audios.PlayOneShot(tsu);
panel.SetActive(true);
yield return new WaitForSeconds(1.2f);
SceneManager.LoadScene("Game");
}
Instead of changing animation states, I set the desired one as default and just set the panel active.
The wierd part is (because I don't have the knowledge to understand it), the TryAgain button belongs to a GameOver menu panel. When the game starts with this GameOver panel active (but not the fading to black one), the script runs just fine. On the other hand, when I play and lose on purpose, the game over menu pops up, I press the TryAgain button and all it does is play the sound reffered by "tsu" before "waitforseconds()". No panel, no scene restart, although in the Inspector the panel shows as Active and full black.
Thanks again for your responses!
So, I'm feeling kind of dumb right now. I figured that the panel animation wasn't running after the player died so I investigated around it. I remembered then that I'd set the timeScale to 0f when the player dies. That's why the fading panel was not animating and the scene was not restarting.
I did not think about this before because I did not know the scene could not load if the timeScale was set to 0f.
Thank you again for your time, attention and answers guys!
I'm a newbie at this still.
This is the standard way to use couroutines in Unity (Fade out example):
IEnumerator Fade()
{
for (float ft = 1f; ft >= 0; ft -= 0.1f)
{
Color c = renderer.material.color;
c.a = ft;
renderer.material.color = c;
yield return new WaitForSeconds(.1f);
}
}
Don't try to reinvent the wheel this is the standard way to do a Fade Out (I think you want a Fade In). Here its changing the alpha value (c.a) decreasing it 0.1 each 0.1 seconds.
Source: https://docs.unity3d.com/Manual/Coroutines.html

Is it possible to navigate the graph of an Animator Controller?

Is it possible to navigate the graph represented by an Animator Controller in Unity by code at runtime?
Setup
For example, if I have two states "Idle" and "Clicked". In order to transition from "Idle" to "Clicked" state, I have to issue a SetTrigger("Clicked") call on the animator, which then starts playing the "SwiperItemClicked" animation clip.
Now to the question
When I know the name of the trigger ("Clicked"), how can I find out programmatically, what animation clip will be played after I reach state "Clicked"? I need to know the name of the animation clip on the "Clicked" state (in this example "SwiperItemClicked").
I am using Unity 2018.3.0f2.
Only available with editor script
public static string FindClipName(AnimatorController controller, string triggerName)
{
foreach (var layer in controller.layers)
foreach (var state in layer.stateMachine.states)
foreach (var transition in state.state.transitions)
foreach (var condition in transition.conditions)
if (condition.parameter == triggerName)
return transition.destinationState.motion.name;
return null;
}
Vectors have no right angles graphs. I believe it is not possible to navigate the graph of an animator controller. Only parallel and angle lines are accepted in an animated controller.

Changing the players sprite with animator

i have a 2d platformer with a player. The players default sprite is set to idle. There is 4 sprites and states in total --> idle, jumping, left, right.
Im trying to get the player to switch sprites depending on what their doing eg jumping or moving right.
This is my first time using unity and animator so im not experienced at all.
So each of my animations look something like this. 1 frame and one for each state:
And then I open up the animator:
Im not too sure what the arrows do but i figured its like a flow chart so you go from idle to left so i matched up the arrows. I then also made 4 booleans for each state.
Then on the script attached to the player, i added this code:
private Animator animator;
void Start () {
animator = GetComponent<Animator>();
}
//This is in the update function
if (!playerLeft && !playerRight && !jumping)
{
setAnimationState("playerIdle");
}
else if (jumping)
{
setAnimationState("playerJumping");
}
}
private void setAnimationState(String state){
animator.SetBool("playerJumping", false);
animator.SetBool("playerLeft", false);
animator.SetBool("playerRight", false);
animator.SetBool("playerIdle", false);
animator.SetBool(state, true);
}
So i made a function that cancels of the animations and switches it to the correct one which is called. You can see how i call it with jumping and i also have the same for left and right but i know they are all being called correctly from the animator.
In the animator, only the right grey box is running. I can see because it has a blue bar and its not switching animations. The booleans are switching but thats it.
On the top of my head:
You need a transition from right to left and left to right.
You need one from right, left and jumping back to idle.
You can click on the arrows and select which booleans need to be checked to enable the transition.
Fore each animation state you need to upload a spritesheet. You can drag and drop this in the animation tab. The animation will play untill there are no more sprites. It will then check if it can transition into another state or loop the current state. (Do note that you need to enable looping on each state, except jumping i guess?)
Welcome to Unity development :)
I don't want to make this too long, so let's just use playerLeft as an example.
So you've set the Idle state as the default state - meaning if all the booleans are false, the player is idle. But once you press the left key, you would want the player to transition from the idle state to the Left state.
First step is to click on the transition (the arrow) from idle to playerLeft.
Next, is to add the playerLeft boolean as the condition. This means that when the playerLeft boolean becomes true, we start transitioning from Idle to Left.
And finally, tinker with the code. We need to tell Unity to set playerLeft to true when we press the "D" button for example.
Update()
{
if(Input.GetKeyDown(KeyCode.D))
animator.SetBool("playerLeft",true);
}
We place it in the Update() method to make sure it runs every frame. Then, we have a condition where it waits for the player to press D.
There's still a whole lot to do after this such as doing return transitions but well, you'll figure out the rest as you go so don't hesitate to ask ;)

Unity 3d OnClick to ignore specific layer (or fire only on specific laye

Is there a way to make standard unity OnClick even fire while ignoring specific layers?
For example, i have army of soldiers on layer "Units" and ground on Layer "Ground". When i click on soldier, it gets selected. Then i click on the ground, soldier moves there. But if i click on the ground obscured by another soldier, it fires even for that soldier rather than ground, cos he is closer to the camera.
Can i ignore "Units" layer without rewriting whole mouse click even handling and using my custom raycast?
EDIT:
code is here, dont thnk it will show anything but
static public void Interact2(Cell target) //this fires from OnClick
{
if (GameLogic.Mode == mode.move)
{
grid.MoveTo(target);
if (selected.actionsAvilable[action.move])
selected.actionsAvilable[action.move] = false;
else
selected.actionsAvilable[action.standard] = false;
GameLogic.Mode = GameLogic.mode.normal;
}
}
MORE EDIT:
void OnMouseDown() {
if (!UnityEngine.EventSystems.EventSystem.current.IsPointerOverGameObject())
GameLogic.Interact2(this);
}
The PhysicsRaycaster/PhysicsRaycaster2D/GraphicsRaycaster components have an Event Mask property which allows you to limit the layers they raycast against. You should update that property from code when you want to block/allow certain layers.

A panel to change 3d object properties when right click on it

I'm building a UI system to edit selected 3D objects. I have spheres on the screen and I want to be able to edit their proprieties (radius for example). In order to do that I want the user to be able to click on a sphere and then it show a panel next to the object. When the user changes slider value the radius of the sphere which as been clicked on change. Using the new unity event system, I think it's easy to achieve, but I'm a new to unity and even if I know the basic I don't know how to organize this properly.
At the end my goal would be to select multiple sphere, right click and edit the radius to all selected spheres.!
Any tips on how to do that ? Sorry for my poor english. Thanks
Here's how you can do it:
Keep a bool for tracking if the object is selected, say, bool _isSelected
Toggle this boolean in the OnMouseUpAsButton() function. This function is called when you click on an object and release that click on the same object. Unity's OnMouseXXX() interfaces are very good for handling mouse events. You just need to define this function in the sphere objects' script.
Put together a Slider and arrange its value interval from editor. Define a function that will edit the scale value of the spheres and tie that function to that slider.
Below you can see an example of how I did that in a game of mine.
Unity simply catches the slider's value if you provide it with a public void _f(float val). It will appear on the top of the list as "Dynamic float". So, in your case, your slider update function should look like this:
public void SphereScaleSliderUpdate(float val)
{
foreach (GameObject sphere in GameObject.FindGameObjectsWithTag("your tag here"))
{
if (sphere.IsSelected) // don't forget to provide a public getter for _isSphere variable
{
sphere.transform.localScale = new Vector3(val, val, val);
}
}
}
Also, you need to create another script for toggling the menu(Canvas/Panel(optional)) that contains the slider, and you may add it to another object, like a UIManager. Assign the Canvas in the game hierarchy to a variable in that script, and then scan for RClick in the Update() function of the UIManager.
.
void Update()
{
if (Input.GetMouseButtonDown(1) // RClick event
{
// makes the slider appear through enabling canvas
_canvasHandle.enabled = true;
}
}