How to make game using Qt - Lesson 2. Animation game hero (2D)

GameDev, QPainter, Qt, анимация, написать игру

In the second lesson we'll get to the next aspect of the writing of the game - the hero Animation. In the last lesson it was considered as a control object in the graphic scene, and the main character played a red triangle, but it is not very interesting. So we will turn the triangle into an animate object, namely the Fly, which will crawl under the control of the keyboard and move the legs when moving.

In this lesson, the adjustment made in the code triangle.h, triangle.cpp and just a little in widget.cpp file.

Animation Fly on steps

We describe an algorithm, which should be the rendering Flies:

  1. Initialize variable in the class constructor, which will be responsible for the number of legs position. There will be three positions fly legs.
  2. Initialize variable in the class constructor, which will be useful to consider the timer ticks of the game, then those ticks during which the fly moved. It is necessary to weed out those tics, in which there was no movement Flies Fly otherwise be constantly iterate legs, even if we do not manage Fly .
  3. Draw Fly in the paint method, choosing which of the provisions of the flies legs will be drawn.
  4. The slot that handles the event starting the game timer produces accumulation and reset the counter ticks useful game timer and depending on its value set position Flies legs, namely completely redraw the Fly with the correct position of the legs.

triangle.h

In this file add only two integer variables:

  • steps - position number of flies legs;
  • countForSteps - a counter for counting clock ticks for which the keyboard interface produced.
#ifndef TRIANGLE_H
#define TRIANGLE_H

#include <QObject>
#include <QGraphicsItem>
#include <QPainter>
#include <QGraphicsScene>

#include <windows.h>

class Triangle : public QObject, public QGraphicsItem
{
    Q_OBJECT
public:
    explicit Triangle(QObject *parent = 0);
    ~Triangle();

signals:

public slots:
    void slotGameTimer(); 

protected:
    QRectF boundingRect() const;
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);

private:
    qreal angle;     
    int steps;          // Number position flies legs
    int countForSteps;  // The counter for counting clock ticks for which we pressed the button

};

#endif // TRIANGLE_H

triangle.cpp

In general, changes were made completely whole file. The class constructor assigns values to two new variables. In the paint method is completely rendered the whole fly with three possible positions of the feet. To apply draw objects such as ellipses, lines and QPainterPath class objects.

In order to fly turned to the appropriate appearance, it was made a sketch of Flies, which coordinates the program was moved to the lesson code.

With the fun is present in the method slotGameTimer() , in which the tracking button states conducted countdown useful ticks, and if countForSteps variable equal to 4, 8, 12 and 16, chosen one of the provisions of the Flies legs and initiated redrawing Flies with this provision, legs.

#include "triangle.h"

Triangle::Triangle(QObject *parent) :
    QObject(parent), QGraphicsItem()
{
    angle = 0;      
    steps = 1;      // Set starting position flies legs
    countForSteps = 0;      // The counter for counting clock ticks for which we pressed the button
    setRotation(angle);     
}

Triangle::~Triangle()
{

}

QRectF Triangle::boundingRect() const
{
    return QRectF(-40,-50,80,100);  
}

void Triangle::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    // Draw the legs, without legs as a fly can not creep
    painter->setPen(QPen(Qt::black, 2));
    if(steps == 0){     // The first position of the legs
        // Left 1
        painter->drawLine(-24,-37,-22,-25);
        painter->drawLine(-22,-25,-17,-15);
        painter->drawLine(-17,-15,-10,-5);
        // Right 1
        painter->drawLine(37,-28,28,-18);
        painter->drawLine(28,-18,24,-8);
        painter->drawLine(24,-8,10,-5);

        // Left 2
        painter->drawLine(-35,-20,-25,-11);
        painter->drawLine(-25,-11,-14,-5);
        painter->drawLine(-14,-5,0,5);
        // Right 2
        painter->drawLine(37,-12,32,-4);
        painter->drawLine(32,-4,24,2);
        painter->drawLine(24,2,0,5);

        // Left 3
        painter->drawLine(-35,35,-26,24);
        painter->drawLine(-26,24,-16,16);
        painter->drawLine(-16,16,0,0);
        // Right 3
        painter->drawLine(37,26,32,17);
        painter->drawLine(32,17,24,8);
        painter->drawLine(24,8,0,0);
    } else if (steps == 1){     // The second position of the legs
        // Left 1
        painter->drawLine(-32,-32,-25,-22);
        painter->drawLine(-25,-22,-20,-12);
        painter->drawLine(-20,-12,-10,-5);
        // Right 1
        painter->drawLine(32,-32,25,-22);
        painter->drawLine(25,-22,20,-12);
        painter->drawLine(20,-12,10,-5);

        // Left 2
        painter->drawLine(-39,-15,-30,-8);
        painter->drawLine(-30,-8,-18,-2);
        painter->drawLine(-18,-2,0,5);
        // Right 2
        painter->drawLine(39,-15,30,-8);
        painter->drawLine(30,-8,18,-2);
        painter->drawLine(18,-2,0,5);

        // Left 3
        painter->drawLine(-39,30,-30,20);
        painter->drawLine(-30,20,-20,12);
        painter->drawLine(-20,12,0,0);
        // Right 3
        painter->drawLine(39,30,30,20);
        painter->drawLine(30,20,20,12);
        painter->drawLine(20,12,0,0);
    } else if (steps == 2){     // The third position of the legs
        // Left 1
        painter->drawLine(-37,-28,-28,-18);
        painter->drawLine(-28,-18,-24,-8);
        painter->drawLine(-24,-8,-10,-5);
        // Right 1
        painter->drawLine(24,-37,22,-25);
        painter->drawLine(22,-25,17,-15);
        painter->drawLine(17,-15,10,-5);

        // Left 2
        painter->drawLine(-37,-12,-32,-4);
        painter->drawLine(-32,-4,-24,2);
        painter->drawLine(-24,2,0,5);
        // Right 2
        painter->drawLine(35,-20,25,-11);
        painter->drawLine(25,-11,14,-5);
        painter->drawLine(14,-5,0,5);

        // Left 3
        painter->drawLine(-37,26,-32,17);
        painter->drawLine(-32,17,-24,8);
        painter->drawLine(-24,8,0,0);
        // Right 3
        painter->drawLine(35,35,26,24);
        painter->drawLine(26,24,16,16);
        painter->drawLine(16,16,0,0);
    }
    // Antennae
    QPainterPath path(QPointF(-5,-34));
    path.cubicTo(-5,-34, 0,-36,0,-30);
    path.cubicTo(0,-30, 0,-36,5,-34);
    painter->setBrush(Qt::NoBrush);
    painter->drawPath(path);

    painter->setPen(QPen(Qt::black, 1));
    // carcass
    painter->setBrush(Qt::black);
    painter->drawEllipse(-15, -20, 30, 50);
    // Head
    painter->drawEllipse(-15, -30, 30, 20);
    // eyes
    painter->setBrush(Qt::green);
    painter->drawEllipse(-15, -27, 12, 15);
    painter->drawEllipse(3, -27, 12, 15);

    // Left wing
    QPainterPath path2(QPointF(-10, -10));
    path2.cubicTo(-18, -10, -30, 10, -25, 35);
    path2.cubicTo(-25,35,-20,50,-15,40);
    path2.cubicTo(-15,40,0,20,-3,5 );
    path2.cubicTo(-3,5, -8,8,-10,-10);
    painter->setBrush(Qt::white);
    painter->drawPath(path2);

    // Right wing
    QPainterPath path3(QPointF(10, -10));
    path3.cubicTo(18, -10, 30, 10, 25, 35);
    path3.cubicTo(25,35,20,50,15,40);
    path3.cubicTo(15,40,0,20,3,5 );
    path3.cubicTo(3,5, 8,8,10,-10);
    painter->setBrush(Qt::white);
    painter->drawPath(path3);

    Q_UNUSED(option);
    Q_UNUSED(widget);
}

void Triangle::slotGameTimer()
{
    /* Check if pressed any of the object control buttons. Before you consider steps
     * */
    if(GetAsyncKeyState(VK_LEFT) ||
       GetAsyncKeyState(VK_RIGHT) ||
       GetAsyncKeyState(VK_UP) ||
       GetAsyncKeyState(VK_DOWN))
    {
        if(GetAsyncKeyState(VK_LEFT)){
            angle -= 5;        
            setRotation(angle); 
        }
        if(GetAsyncKeyState(VK_RIGHT)){
            angle += 5;        
            setRotation(angle); 
        }
        if(GetAsyncKeyState(VK_UP)){
            setPos(mapToParent(0, -2));    
        }
        if(GetAsyncKeyState(VK_DOWN)){
            setPos(mapToParent(0, 2));      
        }

        countForSteps++;
        if(countForSteps == 4){
            steps = 2;
            update(QRectF(-40,-50,80,100));
        } else if (countForSteps == 8){
            steps = 1;
            update(QRectF(-40,-50,80,100));
        } else if (countForSteps == 12){
            steps = 0;
            update(QRectF(-40,-50,80,100));
        } else if (countForSteps == 16) {
            steps = 1;
            update(QRectF(-40,-50,80,100));
            countForSteps = 0;
        }
    }

    if(this->x() - 10 < -250){
        this->setX(-240);      
    }
    if(this->x() + 10 > 250){
        this->setX(240);       
    }

    if(this->y() - 10 < -250){
        this->setY(-240);       
    }
    if(this->y() + 10 > 250){
        this->setY(240);        
    }
}

widget.cpp

To improve the smoothness of drawing was increased frequency of signal processing from the timer.

timer->start(1000 / 100);

Result

As a result, you should get a fly that the motion will cycle through the tabs.

A full list of articles in this series:

Video

Virtual hosting with 10 percent discount
Virtual hosting with 10 percent discount
EVILEG offers reliable hosting with a 10% discount for virtual hosting and 5% for VPS
Support the author Donate
M

Здравствуйте,
Подскажите, почему муха может оставлять следы на игровой сцене?

Добрый день. Артефакты обычно остаются в том случае, если не обновляется полностью тот участок графической сцены, в котором находится муха. Скорее возможно boundingRect() написали не совсем правильно, если писали его самостоятельно для своего собственного варианта. Также как вариант можете запускать метод update() на графической сцене с указание того пространства, которое требуется перерисовать.

Comments

Only authorized users can post comments.
Please, Log in or Sign up
N
June 25, 2019, 2:41 p.m.
Nico03

C++ - Test 001. The first program and data types

  • Result:40points,
  • Rating points-8
S
June 25, 2019, 9:16 a.m.
SabaNtuy

C ++ - Test 004. Pointers, Arrays and Loops

  • Result:40points,
  • Rating points-8
SZ
June 24, 2019, 5:49 p.m.
Serg Zhi

C++ - Тест 003. Условия и циклы

  • Result:78points,
  • Rating points2
Last comments
June 24, 2019, 10:23 a.m.
Евгений Легоцкой

Хорошо, ну будут проблемы помимо того, что касается статей, то не стесняйтесь задавать вопросы на форуме.
МБ
June 24, 2019, 10:21 a.m.
Михаил Булатов

Извиняюсь, все работает(из-за невнимательности).
June 24, 2019, 9:52 a.m.
Евгений Легоцкой

Придётся делать ещё сигнал в дочернем qml и пробрасывать через коннекты и обработчики. А вообще нужно смотреть конкретный код и что вы пытаетесь сделать. Так что лучше будет, если вы зад...
June 21, 2019, 8:31 a.m.
Ruslan Polupan

Вот моя строка по которой все отлично сработало %cqtdeployer% -bin c:/CentralMposKeys/CentalMposKeys.exe -qmake c:/Qt/5.12.2/mingw73_64/bin/qmake.exe
June 21, 2019, 8:24 a.m.
Андрей Янкович

Возможно кому то пригодится сqtdeployer для windows работает точно так же как и для Linux разница лишь в команде запуска Linux: cqtdeployer Windows: %cqtdeployer...
Now discuss on the forum
June 25, 2019, 6:16 p.m.
Алексей Внуков

только через webengine, прямого апи у Яндекса нет, вроде что-то есть у гугла, сам только начал интересоваться этим вопросом
June 25, 2019, 5:05 p.m.
Михаиллл

Само заработало. Странно.
June 25, 2019, 2:32 p.m.
Михаиллл

Похоже глюк вебсокета. К другим вебсокетам подключаюсь.
June 25, 2019, 1:55 p.m.
Андрей Янкович

падало потому что boolStatus был на стеке метода, после завершения метода переменная убивалась, и на обращении к ней было падение.просто сделай вот так: connect(&t, &QTimer::timeou...
June 25, 2019, 10:55 a.m.
IscanderChe

По пункту 3 попытался переписать метод setData. В итоге комбобокс перестал работать. bool MySqlTableModel::setData(const QModelIndex& index, const QVariant& value, int /* role */){...
Looking for a Job?
10,000.00 руб. - 15,000.00 руб.
Нужен помощник для создания API.
Moscow, Moscow, Russia
25,000.00 руб. - 30,000.00 руб.
Разработчик Qt/C++
Barnaul, Altai Krai, Russia

For registered users on the site there is a minimum amount of advertising

EVILEG
About
Services
Join us
© EVILEG 2015-2019
Recommend hosting TIMEWEB