Thursday, July 29, 2010

Sprite animation from sprite sheet in Qt

In my previous post I have shown how to create simple sprite animation, but in that sample code I was using different image for each animation sequence.
But most of time we need to work with sprite sheet( image which has all animation sequence) and we need to perform animation using sprite sheet.

In following code I has have done sprite animation using sprite sheet. Trick here is to draw only certain portion of whole pixmap using QPainter's drawPixmap API.

My code goes as below
class Sprite
{
public:

    Sprite();

    void draw( QPainter* painter);

    QPoint pos() const;

    void nextFrame();

private:

    QPixmap* mSpriteImage;
    int mCurrentFrame;
    QPoint mPos;
    int mXDir;

};

Sprite::Sprite():mPos(0,0),mCurrentFrame(0)
{
    mSpriteImage = new QPixmap(":dragon.png");
}

void Sprite::draw( QPainter* painter)
{
    painter->drawPixmap ( mPos.x(),mPos.y(), *mSpriteImage, 
                                   mCurrentFrame, 0, 100,100 );
}

QPoint Sprite::pos() const
{
    return mPos;
}

void Sprite::nextFrame()
{
    //following variable keeps track which 
    //frame to show from sprite sheet
    mCurrentFrame += 100;
    if (mCurrentFrame >= 500 )
        mCurrentFrame = 0;
    mPos.setX( mPos.x() + 10 );
}

Sprite sheet used for above code is as follow.

Tuesday, July 27, 2010

Detecting Long press( Tap and hold) on iPhone application

I was creating one game for iPhone and I required to detect Tap and Hold (Long press ) gesture in application. After trying a bit and reading some documentation, I found following solution. Solution is to perform Selector with some delay, and cancel Selector if touch has ended before enough time is passed.

Following is code from my application.

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
NSLog(@"touch began");
[self performSelector:@selector(longTap) withObject:nil afterDelay:1.0];
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
NSLog(@"touch ended");
[NSObject cancelPreviousPerformRequestsWithTarget:self 
selector:@selector(longTap) object:nil];
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
NSLog(@"touches moved");
[NSObject cancelPreviousPerformRequestsWithTarget:self 
selector:@selector(longTap) object:nil];
}

-(void) longTap 
{
NSLog(@"handle long tap..");
}

Hope this helps...

Saturday, July 24, 2010

Getting UIViewController from UIView

Some time we need reference of view controller from view. While searching for solution I found that view's nextResponder method returns view controller.

In my application I required superview's view controller, Following is code for achieving same.

id superView = [self superview];
id viewController = [superView nextResponder];
[viewController doSomeStuff];

And here is what UIResponder documentation says about nextResponder

UIView implements this method by returning theUIViewController object that manages it (if it has one) or its superview (if it doesn’t); UIViewController implements the method by returning its view’s superview; UIWindow returns the application object, and UIApplication returns nil.

Friday, July 23, 2010

Rotation and mirroring QGraphicsItem in Qt

Recently I started to learn Qt Graphics View to convert one of my existing game to use Qt graphics view framework.

During this I learned some new things that I would like to share here.

Rotating QGraphicsItem,

Generally when you rotate QGraphicsItem, it will rotate in reference to item's origin (0,0). To apply rotation in reference to center of item  use following line of code.

graphicsItem->setTransform(QTransform().translate(centerX, centerY).rotate(angle).translate(-centerX, -centerY));

Mirroring or flipping QGraphicsItem,

To mirror item, you can use scale operation on QGraphicsItem. To flip item on y axis you following code,

graphicsItem->scale(-1,1)

here 1 scale factor will keep size to its original size and negative value will flip item on axis. Similarly to flip item on x axis use following code.

graphicsItem->scale(1,-1)

Monday, July 19, 2010

Creating object dynamically from class name in Qt

Some time it could be useful to be able to create new instance of class just by knowing its name. Such as in situation like when you are receiving XML from network and you want to create certain type of parser depending upon XML received from network.

In Qt its possible by using Qt's meta object system.

Here is my sample implementation that uses QMetaType to achieve the same. In sample code Parser is base class of all parser.
class Parser
{
public:

 virtual void parse() = 0;
 
 virtual ~Parser() {};

};
Now I am creating two dummy parser which are derived from Parser.
class Parser1 : public Parser
{
public:
    
    Parser1()
    {
        qDebug() <<"Parser1::Parser1()";
    }
    
    void parse()
    {
        qDebug() << "Parser1::parse()";
    }
    
    ~Parser1()
    {
       qDebug() <<"Parser1::~Parser1()";
    }
};
Q_DECLARE_METATYPE(Parser1)
  
class Parser2 : public Parser
{
public:
    
    Parser2()
    {
        qDebug() <<"Parser2::Parser2()";
    }
    
    void parse()
    {
        qDebug() << "Parser2::parse()";
    }
    
    ~Parser2()
    {
       qDebug() <<"Parser2::~Parser2()";
    }
};
Q_DECLARE_METATYPE(Parser2)
Now in parse function I am trying to create meta type from its name.
void parse( const char* parserName ) 
{
     int id = QMetaType::type( parserName );
     if (id != -1) {
        Parser *parser = static_cast< Parser* > 
                         ( QMetaType::construct( id ) );
        parser->parse();
        delete parser;
    }
}
Some sample code to test above function.
int main ( int argc, char* argv[] )
{
    qRegisterMetaType("Parser1");
    qRegisterMetaType("Parser2");
    
    qDebug() << "###### Trying create Parser1";
    parse("Parser1");
    
    qDebug() << "###### Trying create Parser2";
    parse("Parser2");
}
and finally output.
###### Trying create Parser1 
Parser1::Parser1() 
Parser1::parse() 
Parser1::~Parser1() 
###### Trying create Parser2 
Parser2::Parser2() 
Parser2::parse() 
Parser2::~Parser2() 
so that was all, but remember to use Q_DECLARE_METATYPE, qRegisterMetaType macros for registering your custom type with Qt meta object system.

Friday, July 9, 2010

Recording screen acrivity on Ubuntu

Some time we need to record screen activity in video, there are many option in windows but on Ubuntu I found one cool command line utility that can record your screen activity.

Tool is "recordmydesktop", there is also GUI version of it but I found it quite limited in capability. Like I can not record some portion on particular windows. Using this command line tool I can do so and there are quite other interesting feature as well.

To install this tool use "sudo apt-get install recordmydesktop" on command line.

And to start recording particular portion of you desktop, you can use following command.

"recordmydesktop -x 700 -y 180 --width 720 --height 400"

This command will start recording your screen activity, to stop just press CTRL + C on command prompt and it will save recorded video on out.ogv file in current directory.

Monday, July 5, 2010

Scrolling in custom widget using QScrollArea in Qt

I remembered when I was creating custom view in S60 and I required to implement scrolling. I needed to create my own logic for scrolling using windowing and drawing component manually when comes in to visible area.

Now I am doing similar thing using Qt and and can't believe that solution can be so simple. Qt has class named QScrollArea which main purpose it to support scrolling for such custom view.

Following is code from my application. In this code I want to make certain part of my view to be scrollable and certain part to be remain static.

The part where I want scrolling, for that part I am creating widget with layout and adding all its child widget in layout and then adding that widget to QScrollArea.

QWidget* SampleUI::createMessageWidget()
{
    QLable  label= new QLabel("");
    label->setAlignment(Qt::AlignLeft);
    label->setWordWrap( true );

    ignoreBtn = new QPushButton("Ignore Message");
    ignoreBtn->setEnabled( false );
    QObject::connect(ignoreBtn,SIGNAL(clicked()),SLOT(ignoreMessage()));

    QWidget* messageWidget = new QWidget;
    QVBoxLayout* mainLayout = new QVBoxLayout( messageWidget);
    mainLayout->addWidget( label );
    mainLayout->addWidget( ignoreBtn);

    QScrollArea* scrollArea = new QScrollArea(this);
    scrollArea->setWidgetResizable(true);
    scrollArea->setWidget(messageWidget);
    return scrollArea;
}


Now I am adding this scrollable widget and static widget in custom view's layout.

void SampleUI::SampleUI(QWidget *parent) :QWidget(parent)
{
    QWidget* messageWidget = createMessageWidget();
    QLabel status = new QLabel("");
    status->setAlignment(Qt::AlignRight);

    QVBoxLayout* mainLayout = new QVBoxLayout(this);
    mainLayout->addWidget(messageWidget);
    mainLayout->addWidget( mStatus );
}