Tuesday, April 12, 2011

Magnetic Floors

Few weeks ago we started with the magnetic floors.
Those floor will attract or repel the player when it's on its range (represented by lines).

Tuesday, April 5, 2011

Zoom effect

While finishing new magnetics level I wanted to add this simple but interesting effect... a zoom at the beginning of each level, displaying a huge part of the level and focusing the main character.

As usual, video recorder from the Symbian emulator provided in QtCreator IDE.

Actually, the code is pretty simple.

Just note we will have a QTimeLine, sending the current frame from 100 to a minimum. We get the max distance zoom of the current level and we do a "cross multiplication". If 100 is the higher value, and the max distance is the max distance (well... this is pretty obvious :P), we want to know the desired distance for the current frame.

qreal m_rMaxZoom;

    m_rMaxZoom = MyPointerToGameEngine->GetZoomValueForTheCurrentLevel();
    QTimeLine *timeLine = new QTimeLine(4000, this); //4 seconds
    //The timeline will start sending the frame 100, and going down to 100/m_rMaxZoom.
//This is needed because if we allow lower numbers to zoom goes too far. 
    timeLine->setFrameRange(100, 100/m_rMaxZoom);
//Connections. If the frame changes it sends the calculated frame. 
//If the timeLine finishes, "startPlayingNextLevel" from the Game Engine is called.
    connect(timeLine, SIGNAL(frameChanged(int)), this, SLOT(zoomOut(int)));
    connect(timeLine, SIGNAL(finished()), this, SIGNAL(startPlayingNextLevel()));
//The desired first zoom (100) is not sent by the timeLine 
void CAnimationEngine::zoomOut(int iCurrentFrame)
    //Cross multiplication
    qreal rZoom = iCurrentFrame * m_rMaxZoom / 100;

    if(rZoom > 0.05)
        {//Basic scale transformation to the view
                QTransform trans = pointerToMyView->transform();
                 trans.translate((width() / 2), (height() / 2));
                 trans.scale( 1 / (rZoom ), 1 / (rZoom ) );
                 trans.translate(-(width() / 2), - (height() / 2));

        qDebug()<< "ERROR: AnimationEngine.cpp ------ ZoomOut(). Too close to zero"; 
 //When the scalation is finished, move the view in order to ensure the visibility of the player.
//It's not a complicated function; basically QGraphicsPixmapItem::ensureVisible(); 

Wednesday, March 2, 2011

Moving platforms

So far all the levels were designed with just three static colliding forms: rectangles, right rectangles and convex forms. All the floors were created implementing that forms or mixing them (looking for the desired floor). Being honest, after finishing five levels I felt like I was repeating the same puzzles over and over.

But in level six the moveable rectangular platforms appear. The next levels will be a mix of new features and puzzles with the old ones, providing a lot more of possibilities when I start the development of a new level.

        CFloorMovRec(QList<QPointF> lPos, QList<qreal> lSpeed, QList<int> lStopTime, bool bActive = true,
                     int iWidth = 0, int iHeight = 0, QPixmap pix = QPixmap());

The first list sends the positions the platform will move foward to, the second are the list with all the different speed between travel and travel, the third is a list with the time the platform is stopped before starting its movement again. bActive is used if we want a platform stopped (we need to activate it later). Width and height are used for the engine when the collisions are calculated and the pixmap is just a temporaly pixmap shown in the screen for testing purposes. When the final pixmaps are ready, all of them are hidden. So far all the floors in the videos uploaded are those "temporary collision floors".

Well, the code might seem too much complicated. I mean, why do you want to add a list with all the speeds? you can use just one, you can simplify it a lot removing the lists... but in my opinion making the things a bit more flexible give good results later. Work a bit more at the present so the code will be ready for improvements in the future.
In this case they show me its flexibility soon. I implemented the tipycal "falling floors when the characters is on them". You know, you are jumping to a new platform and you need to move forwards as fast as possible to the next platform because it's falling.
I implemented it and something weird happened. When the player was on the platform it went down after few miliseconds, but nothing noticed the player this could happen. In the games is usual to find elements warning the players of those things. I solved the problem "shaking" the platform when the character is on it, so he knows something "bad" is going to happen if he doesn't go forward as fas as possible. And "shake" the platform was as easy as adding more points and changing the speeds of the movements before the real fall starts. Being farsighted!

Level 7, called "RickDangerous"

Thursday, February 10, 2011

QGraphicsView performance

Few days ago I realized the game was having a horrible performance when I added a background. It started to be slower and slower until it was impossible to be at all.

I started changing  the image. Less resolution, less colors, less quality... but it wasn't enough. Actually, it seemed like I did nothing. And when I tried to use the cache it went even worse...

So, I started to read, read and read about QGraphicsView performance and right now is going as expected. Actually, it´s going even better.

So, how to improve QGraphicsView's performance?

This video should be the starting point. Actually, most of the things I found on the web are already said.

So, what to do?

First of all: use the raster. OpenGL graphic system is still experimental so it's quite slow. The "normal" option is quite slow... use raster instead.
To do it, you just need to call the static function QApplication::setGraphicsSystem("raster") before the QApplication constructor is called. Basically, at the beginning of the main.

If you mix that with an openGL object taking care of the render you will have all the major improvements. Note Symbian^3 does this by default. On the other hand OviStore is still not compatible with Qt4.7.1, and that's te first version when they add the openGL files.
How to do it? don't forget to add opengl to your pro file (QT += core gui opengl) and:

        ui.m_pView->setViewport(new QGLWidget());

I think you can setup a proper QGLWidget, depending your needs... but  it's pretty ok. 
Those are the major issues, but there are still more minor improvements:
 - Use the proper viewportUpdateMode. It's better if you test, test, test, test and test it again. In my opinion
fullviewportUpdateMode works better in most cases when we are talking about videogames. The device won't
be trying to guess what to paint, what he shouldn't paint and you will surely have some animations on screen (in
the end it was going to paint almost everything, so "stop calculating and draw it all!").
 - DON'T USE UPDATES IN YOUR GAME LOOP: actually, if you can, don't use updates. It
schedules a redraw, what means he will think twice what to draw. And he will paint on screen when he's in 
the mood. Let Qt paint whenever he wants to.
- Flag "dontsavepainterstate". If we are not using brush-pens... we don't care if the painter is reset each
time Qt paints.
- setframestyle(0): less to paint.
- setAttribute(Qt::WA_TranslucentBackground, false): seems like it was activated by default.
- Choose the best setItemIndexMethod for your scene (test, test, test, test). You don't like to have a BSP
tree if you don't need it.
-  itemhasnocontents: if you want an invisble item, this is the best choice. In my case, this means all my 
bounding items, which means 95% of the items on the screen won't try to calculate how to be drawn.
- itemcoordinatecache: the item will be store in cache and the paint event won't be called again if you don't
force it (another good reason: don't call an update). In my case, the backgrounds are set as
QGraphicsPixmapItem... it takes 5 msecs to be drawn. Storing it on cache improves the performance.
That's all! 

Tuesday, February 1, 2011

First background!

First background's sketch! Level one.

In game video, recording the device directly (not using the emulator, like I did so far)

Saturday, January 29, 2011

Character's pixmap

So, finally, we have the final character's pixmap prepared.

We are thinking about calling him "FiVe". The name is pretty obvious when you realize the character is no more than a "5" rotated 3D along its own axis.

Thursday, January 27, 2011

The Game

So, finally, how's the game.

It will be a platform-puzzle game  where the player needs to rotate the phone in order to change the gravity of the game. The player will need to hang the mobile in fron of him and rotate it like a steering wheel. Doing this, the main character (a spherical character, like a ball) will roll in the screen, advancing and going through the obstacles, jumping, avoiding the traps... and so on.

Next, a video. Graphically is too poor because there are only collision platforms. They won't appear as they do now, it will be far nicer :)

And this will be the main character!! We were thinking in other type of character, basically a ball with hands and feet... but my girlfriend, while she was doing an university project, did it (notice it's just a 5 rotated along its axis in 3D), when we saw it was like love at first sight...