Showing posts with label State machine. Show all posts
Showing posts with label State machine. Show all posts

Sunday, May 3, 2015

Color Animation using Animator with Unity3D

I created a small demo application to demonstrate how Animation can be done using Animator and State Machine with Unity5. This demo creates a Blinking Animation on Mouse click.

Following is final output of this demo.


Below post shows, how above animation can be created.

-> To begin, First create a simple cube and apply a material on the cube. Setup should look like below.

-> Then using "Add Component", add Animator to this cube.

-> Once Animator is added, open Animation window using "Window" -> "Animation", We will need to use while performing the animation.


Animator performs animation using State Machine and this state machine should have default state. Animator will transit to this default State when object is created. In Animator, Animation clip is considered as a State, so lets add a Animation clip and name it default.


-> Our default state will not have any animation, it should show just initial color. Let's just add one frame with current color. Like below.


-> Now we have default state, let's add another state which will perform "Blinking" animation.



-> Now we should add frames, so let's add color property and frames to animate color.




After adding these frames color should animate like below.



-> Now we have Blinking animation state, we are now ready to create a State Machine. Open Animator window by clicking on "Animator" object, it should look like below.

-> We should now add a Parameter which will be used to Trigger animation. On "Animator" window add new boolean parameter and name it "blink".



Following video shows how to create transition and how to add condition to those transition.


-> Now we have state machine with transition and condition, but we want Blink Animation to terminate once its finished. Let's open "Blink Animation" and add Animation event line shown in below image.


This will prompt you to select function to be invoked when Animation frame is reached. You can select function from attached Script.


Following video shows the same process.



-> Finally, We also need to add a script to Cube object. Following is code for the script. In script we are setting "blink" transition parameter of Animator to true on mouse click. While StopAnimation sets "blink" parameter to false when animation event is called.

using UnityEngine;
using System.Collections;

public class MyAnimation : MonoBehaviour {

 private Animator animator;

 void Awake() {
  animator = GetComponent ();
 }

 void OnMouseUp() {
  startAnimation ();
 }

 public void startAnimation() {
  animator.SetBool ("Blink", true);
 }

 public void stopAnimation() {
  animator.SetBool ("Blink", false);
 }
}

And now if run project and click cube, you should see blink animation as per demo video. That's it hope this post will be helpful.

Thursday, October 21, 2010

Using QStateMachine with sprite animation

In 4.6 Qt introduced new State machine framework. Framework looks quite easy to use and extensible for complex use-case.
To explore Qt's State machine framework I thought to use it with sprite animation, as a complex sprite also holds many state and maintaining sprite state and transition from one state to another can become pain if not done properly.

So following is my sample code for prince sprite which use QStateMachine to maintain sprite's state and transition from one state to another. From somewhere in Internet I found sprite sheet for Prince of Persia, to make it easy for sample code I created another simple version of original sprite sheet.
PrinceSprite::PrinceSprite(QGraphicsItem * parent)
    :QGraphicsObject(parent)
{
    mSpriteImage = new QPixmap(":/prince.png");
    changeDir(this);

    //creating different state object , 
    //which are derived from QState and l
    //istening to timer's timeout signal 
    //and also modify frame according to animation
    StandingState* standing = new StandingState(this);
    RunningState* running = new RunningState(this);
    PrepareForAttack* prepareForAttack = 
                        new PrepareForAttack(this);
    Attack* attack = new Attack(this);
    InAttackMode* inAttackMode = new InAttackMode(this);

    //adding transition to state
    //goto running state from stating state at left click
    standing->addTransition(this,SIGNAL(leftClick()),running);
    running->addTransition(this,SIGNAL(leftClick()),standing);
    standing->addTransition(this,SIGNAL(rightClick())
                                    ,prepareForAttack);
    prepareForAttack->addTransition(prepareForAttack,
                        SIGNAL(exited()),inAttackMode);
    inAttackMode->addTransition(this,SIGNAL(leftClick()),attack);
    attack->addTransition(attack,SIGNAL(exited()),inAttackMode);
    inAttackMode->addTransition(this,
                     SIGNAL(rightClick()),standing);

    //adding all state to QStateMachine
    _stateMachine.addState(standing);
    _stateMachine.addState(running);
    _stateMachine.addState(prepareForAttack);
    _stateMachine.addState(attack);
    _stateMachine.addState(inAttackMode);

    //setting initial state and then starting state machine
    _stateMachine.setInitialState( standing);
    _stateMachine.start();
}

In above code I have create different state object for different sprite state, like for StandingState or Attack state.
This state classes are derived from QState class and listen to QTimer's timeout signal to change frame according to animation.

For example following code for Attack state.
#include <QState>

class Attack : public QState
{
    Q_OBJECT
public:
    Attack(PrinceSprite* prince);
    void onEntry ( QEvent * event );
    void onExit ( QEvent * event );

signals:
    void exited();

private slots:
    void nextFrame();
};

#include "attack.h"

Attack::Attack(PrinceSprite* prince)
    :QState()
{}

void Attack::nextFrame()
{    
    _prince->_x += 1;
    _prince->setX(_prince->x() + 7);
    if (_prince->_x >= 4 ) {
        emit exited();
    }
}

void Attack::onEntry ( QEvent * event )
{
    QObject::connect(_prince,SIGNAL(tick()),
                     this,SLOT(nextFrame()));
    _prince->_x = 0;
    _prince->_y = 2;
}

void Attack::onExit ( QEvent * event )
{
    QObject::disconnect(_prince,SIGNAL(tick()),
                        this,SLOT(nextFrame()));
}

So finally, I am not sure if this is correct approach to implement sprite or not, but using Qt's State machine framework is helping a lot to make it simpler.

Follwing is demo of my implementation.