There is a simple task, on click to play the animation, first forward, then backward. I had such a situation that when the clicks are continuous, everything works as it should, but it is worth making a pause between the next click and there is a delay during playback, which feels like exactly the same time while I was waiting. I thought it might be worth resetting Animator-> enabled = false, but then the animation loses its current state and you have to return to the beginning. Here's a piece of code:
if(_currentState == State.Forward)
{
_animator.SetFloat ("Direction", 1);
_animator.Play(clip.name, 0);
}
else
{
_animator.SetFloat ("Direction", -1);
_animator.Play(clip.name, 0);
}
Thanks for any help
If you used arrows to connect the animations for each other:
Select the arrows which connect the animations for each other
Turn (Has exit time) off
Related
edit
After messing with this for a while, what it seems like is that, something was changed in unity. I tried using a bool instead and it works much better. Although I currently have to hold down the gamepad button due to the logic, some progress was made and at least he's going straight out of rolling into running with no problem.
I'm trying to disable the joystick so that after my player does a roll, he will go into an idle animation for a short period and then go back to the blend tree. The blend tree contains idle walk and run animations. At the moment he will roll, transition with "Has Exit Time" into an idle animation (but is still able to slide around if you have the joystick held down) and then transition with "Has Exit Time" to the blend tree.
https://www.youtube.com/watch?v=RVWh-YAQElQ
it's from this tutorial, but I don't know. He never mentions this problem in the video and no one in the comments sections mentions says anything. But basically if you just transition from the roll animation to the blend tree and keep the joystick held down, the animation skips once the roll animation is over. Instead of him just stopping for a second and then allowing the player to move again.
public void OnEnable()
{
if (inputActions == null)
{
inputActions = new PlayerControls();
inputActions.PlayerMovement.Movement.performed += inputActions => movementInput = inputActions.ReadValue<Vector2>();
inputActions.PlayerMovement.Camera.performed += i => cameraInput = i.ReadValue<Vector2>();
if (!animator.GetCurrentAnimatorStateInfo(0).IsName("Idle"))
{
inputActions.PlayerMovement.Movement.performed += inputActions => movementInput = inputActions.ReadValue<Vector2>();
}
}
inputActions.Enable();
}
I've tried disabling the joystick with the code at the bottom, but it just ignores it for some reason.
I have monster named Fungant in my 2D platform game.
It can hide as mushroom and rise to his normal form.
I try to handle it in code, but I don't know how to get information about finished animation (without it, animation of rising and hiding always was skipped).
I think the point there is to get info about complete of the one of two animations - Rise and Hide.
There is current code:
if (
fungantAnimator.GetCurrentAnimatorStateInfo(0).IsName("Fungant Rise")
)
{
fungantAnimator.SetBool("isRising", false);
isRisen = true;
fungantRigidbody.velocity = new Vector2(
walkSpeed * Mathf.Sign(
player.transform.position.x - transform.position.x),
fungantRigidbody.velocity.y
);
}
if (fungantAnimator.GetCurrentAnimatorStateInfo(0).IsName("Fungant Hide"))
{
fungantAnimator.SetBool("isHiding", false);
isRisen = false;
}
I try this two ways:
StateMachineBehaviour
I would like to get StateMachineBehaviour, but how to get it?
No idea how to process this further.
AnimationEvents
Tried to do with animation event but every tutorial have list of functions to choose (looks easy), but in my Unity I can write Function, Float, Int, String or select object (what I should do?).
I decided to write test() function with Debug only inside, and create AnimationEvents with written "test()" in function field, but nothing happens.
Same as above, no more ideas how to process this further.
I personally would use animation events for this. Just add an event to the animation and then the event plays a function after the animation transition is finished.
For more information on how to use animation events you can click here.
This post may also help you to add an event when the animation is finished.
I hope this answer helps you to solve this problem.
I'm designing a typeracer game in unity where the player is in an athletics 100m sprint and the faster they type, the faster the character runs.
I'm just wondering should I be aiming to get an animation that completes between every correct letter entered or working out an algorithm that speeds up, slows down and pauses the animation depending on whether the letter is correct.
Has anyone had any experience with something like this before?
Also, being quite new to unity i'm just using the standard assets with Ethan as my model, is this the right thing to be doing here?
Original Thoughts
You could have it so that every correct character type speeds up the animation of the character and slowly ticks down per millisecond that passes (i.e slowing down if you aren't typing). Then when the user enters a wrong character the animation gets increasingly slower (1/10 of the previous time every time (?)).
Solution
In Unity, working with timing is a little difficult, my class and I had issues with it this year. The best solution we found is working within the FixedUpdate loop itself, as this is run on a more concise time frame than just Update.
Example
For my solution (and what we all ended up doing) was to update the time in FixedUpdate and use it in Update
void FixedUpdate() {
if (timer >= 12f) stopped = true;
if (!stopped) timerDT = updateTimer(Time.deltaTime);
}
If the timer variable is greater than 12 (seconds) then stop movement.
If not stopped, continue updating and adding to the timer, as well as giving the frame time back to timerDT
void Update() {
this.transform.translate(velocity * timerDT);
}
This will run and update the game object attached based on its velocity and the time frame given in FixedUpdate
For you, I would have the script save the animation controller as a variable in the script:
Controller animation = {animation controller};
Note: Don't remember what needs to go here, but I'm pretty sure it's the controller
Then you can change the animation like so:
void Update() {
update_animation(timerDT, anim_speed);
}
void FixedUpdate() {
timerDT = updateTimer(Time.deltaTime);
if (timerDT - oldDT > 0.1) {
oldDT = timerDT;
anim_speed = anim_speed / 0.1; // for decreasing speed
}
}
void update_animation(float deltatime, float speed) {
animation["run"].speed = anim_speed;
}
I have an idle player animation and I want to do a smooth transition between some animations. The idle animation is the default one and from that transition I want to be able to switch to another state(let's say fight) and then back to idle. The code for the idle character animation is currently like :
self.addChild(playerAnimation)
playerAnimation.runAction(SKAction.repeatActionForever(
SKAction.animateWithTextures(playerAnimationManager.idleManAnimation.textureArray, timePerFrame: 0.1)))
Now, this is scheduled to go on forever for now, but I would need to intercept it and add a new animation on top of that (which is the same character, in a new state). I was thinking that I should stop the idle animation, switch to the new one and then back to idle when finished but I am not convinced that this is the best way of chaining animations and I haven't really found a good resource explaining how to go about it.
Any suggestions ? Thanks !
Depending on how short your texture array is, you might be able to do this.
I will try to explain without code seeing how I use objective C and you use Swift
First make a property or variable that can be called by any subroutine in this class file. It should be Boolean and should be set to NO. You could call it idleFlag.
Next make a method that changes the animation to fight mode. This change would be by removing the idle animation and replacing it with the fight animation. This method also set's idleFlag to NO. Let's call the method "beginFightAnim"
And last, in your repeatActionForEver idle animation, right after your animateWithTextures animation, add a runBlock animation. In this block define a static variable (one that will be remembered in the calling of the block over and over) and increment it by +1, add an "if statement" that looks something like this -> if (my_static_var == number_of_frames_in_texture_animations && idleFlag). And in the "if statement" set the static variable to 0 and call "beginFightAnim"
After this all you have to do to change the animation is set idleFlag to YES.
Hope it works!
If you have any problems, please comment below.
I want to do a series of examples to make it easier to understand the matter. Suppose you have your node called playerAnimation, a typical atlasc with a plist where you have
player-idle1.png
player-idle2.png
player-idle3.png
...
If you want to intercept in real-time your animation to know what frame is running in that moment you can do:
override func update(currentTime: CFTimeInterval) {
if String(playerAnimation.texture).rangeOfString("player-idle") != nil {
print(String(playerAnimation.texture))
}
}
At this point, after you have assigned a "key" to your action (withKey:"idleAnimation") you could stop your specific idle action when you preefer to start the other next animation.
Another good thing is to build a structure to know everytime your player status and modify this variable each time you launch a new action or animation:
enum PlayerStatus: Int {
case Idle = 1
case Fight = 2
case Run = 3
case Jump = 4
case Die = 5
...
}
var currentStatus: PlayerStatus!
I have a program that uses a file player audio unit to play, pause and stop a audio file. The way I am accomplishing this is by initializing the file player audio unit to play the file at position zero and then when the user presses the pause button, I stop the AUGraph, capture the current position, and then use that position as the start position when the user presses the play button. Everything is working as it should, but every 3 or 4 times I hit pause and then play, the song starts playing a half to a full second BEFORE the point where I hit pause.
I can't figure out why this is happening, do any of you have any thoughts? here is a simplified version of my code.
//initialize AUGraph and File player Audio unit
...
...
...
//Start AUGraph
...
...
...
// pause playback
- (void) pauseAUGraph {
//first stop the AuGrpah
result = AUGraphStop (processingGraph);
// get current play head position
AudioTimeStamp ts;
UInt32 size = sizeof(ts);
result = AudioUnitGetProperty(filePlayerUnit,
kAudioUnitProperty_CurrentPlayTime, kAudioUnitScope_Global, 0, &ts,
&size);
//save our play head position for use later
//must add it to itself to take care of multiple presses of the pause button
sampleFrameSavedPosition = sampleFrameSavedPosition + ts.mSampleTime;
//this stops the file player unit from playing
AudioUnitReset(filePlayerUnit, kAudioUnitScope_Global, 0);
NSLog (#"AudioUnitReset - stopped file player from playing");
//all done
}
// Stop playback
- (void) stopAUGraph {
// lets set the play head to zero, so that when we restart, we restart at the beginning of the file.
sampleFrameSavedPosition = 0;
//ok now that we saved the current pleayhead position, lets stop the AUGraph
result = AUGraphStop (processingGraph);
}
May be you should use packet counts instead of timestamps, since you just want to pause and play the music, not display the time information.
See BufferedAudioPlayer for an example of using this method.
It may be due to rounding problems with your code:
For example, if every time you hit the pause button, your timer would record at a 0.5/4 seconds before your actual pause time, you would still see a desired result. But after repeating for four more times, the amount of space you have created is 0.5/4 times 4 which is the half of a second you seem to be experiencing.
Thus, I would pay careful attention to the object types you are using and make sure they don't round inappropriately. Try using a double float for your sample times to try to alleviate that problem!
Hope this is clear and helpful! :)