CC++Qt « Движение объекта (графика)

Использую: Visual Studio 2008, TXLib(графическая библиотека).

Проблема: Нужно заставить двигаться объект так, чтобы при движении он изменялся в соответствии с заданной функцией. Конкретно в этой задаче объект должен искажаться косинуидально по горизонтали и синусоидально по вертикали. Проблема заключается в том, что надо реализовать функцию, которая могла бы искажать любой заданный объект.

Вопрос: Какие можете предложить идеи по алгоритму?

Код:
/** * GeSHi (C) 2004 - 2007 Nigel McNie, 2007 - 2008 Benny Baumann * (http://qbnz.com/highlighter/ and http://geshi.org/) */ .cpp.geshi_code {font-family:monospace;} .cpp.geshi_code .imp {font-weight: bold; color: red;} .cpp.geshi_code .kw1 {color: #0000ff;} .cpp.geshi_code .kw2 {color: #0000ff;} .cpp.geshi_code .kw3 {color: #0000dd;} .cpp.geshi_code .kw4 {color: #0000ff;} .cpp.geshi_code .co1 {color: #666666;} .cpp.geshi_code .co2 {color: #339900;} .cpp.geshi_code .coMULTI {color: #ff0000; font-style: italic;} .cpp.geshi_code .es0 {color: #000099; font-weight: bold;} .cpp.geshi_code .es1 {color: #000099; font-weight: bold;} .cpp.geshi_code .es2 {color: #660099; font-weight: bold;} .cpp.geshi_code .es3 {color: #660099; font-weight: bold;} .cpp.geshi_code .es4 {color: #660099; font-weight: bold;} .cpp.geshi_code .es5 {color: #006699; font-weight: bold;} .cpp.geshi_code .br0 {color: #008000;} .cpp.geshi_code .sy0 {color: #008000;} .cpp.geshi_code .sy1 {color: #000080;} .cpp.geshi_code .sy2 {color: #000040;} .cpp.geshi_code .sy3 {color: #000040;} .cpp.geshi_code .sy4 {color: #008080;} .cpp.geshi_code .st0 {color: #FF0000;} .cpp.geshi_code .nu0 {color: #0000dd;} .cpp.geshi_code .nu6 {color: #208080;} .cpp.geshi_code .nu8 {color: #208080;} .cpp.geshi_code .nu12 {color: #208080;} .cpp.geshi_code .nu16 {color:#800080;} .cpp.geshi_code .nu17 {color:#800080;} .cpp.geshi_code .nu18 {color:#800080;} .cpp.geshi_code .nu19 {color:#800080;} .cpp.geshi_code .me1 {color: #007788;} .cpp.geshi_code .me2 {color: #007788;} .cpp.geshi_code span.xtra { display:block; }

#include "TXLib.h"
#include "graphics.h"
#include <iostream>
using namespace std;
 
void main(){

  // Класс графика.
  class Graphic{
  public:
    float red, green, blue;

    // Конструктор по умолчанию.
    Graphic() : red(1.0), green(0.5), blue(0.25){}
    // Конструктор с тремя аргументами.
    Graphic(float r, float g, float b) : red(r), green(g), blue(b){}
    ~Graphic(){}
  };

  // Класс крест.
  class Cross : public Graphic{
  public:
    // Координаты горизонтальной линии.
    int GorX_1, VerX_1, GorX_2, VerX_2;

    // Координаты вертикальной линии.
    int GorY_1, VerY_1, GorY_2, VerY_2;

    // Конструктор по умолчанию.
    Cross() : GorX_1(0), VerX_1(100), GorX_2(50), VerX_2(100), GorY_1(25), VerY_1(10), GorY_2(25), VerY_2(130){}
    // Конструктор с четыремя параметрами.
    Cross(int gls, int gle, int vls, int vle, int glsy, int gley, int vlsy, int vley) : GorX_1(gls), VerX_1(gle), GorX_2(vls), VerX_2(vle), GorY_1(glsy), VerY_1(gley), GorY_2(vlsy), VerY_2(vley){}
    ~Cross(){}
  };

  txCreateWindow(800, 600, 1);
  // Создать объект.
  Cross KREST;

  for(int i=0; i<750; i++){
    // Задать цвет.
    txColor(KREST.red=1.0, KREST.green=0.5, KREST.blue=0.25);
    // Начертить вертикальную линию.
    txLine(KREST.GorY_1+i, KREST.VerY_1, KREST.GorY_2+i, KREST.VerY_2);
    // Задать цвет (стирающий).
    txColor(KREST.red=0.0, KREST.green=0.0, KREST.blue=0.0);
    // Начертить вертикальную линию (стирающую).
    txLine(KREST.GorY_1+i-1, KREST.VerY_1, KREST.GorY_2+i-1, KREST.VerY_2);
   
    // Задать цвет.
    txColor(KREST.red=1.0, KREST.green=0.5, KREST.blue=0.25);
    // Начертить горизонтальную линию.
    txLine(KREST.GorX_1=i, KREST.VerX_1, KREST.GorX_2+i, KREST.VerX_2);
    // Задать цвет (стирающий).
    txColor(KREST.red=0.0, KREST.green=0.0, KREST.blue=0.0);
    // Начертить горизонтальную линию (стирающую).
    txLine(KREST.GorX_1=0, KREST.VerX_1, KREST.GorX_2-KREST.GorX_2+i, KREST.VerX_2);

    Sleep(3);
  }

}
 

1 ответов


Вот более локализованно к данной задаче:



class AnimationObject // Интерфейс анимируемого объекта
{
public:
  virtual float GetPositionX() = 0;
  virtual float GetPositionY() = 0;
  virtual bool MoveObjectAndChildren( float dX, float dY ) = 0;
};

class AnimationPoint
{
public:
  int AnimationPoint::Work()
  {

    int dX = std::abs( _iX - _pAnimationObject->GetPositionX() );
    int dY = std::abs( _iY - _pAnimationObject->GetPositionY() );
    int speed = (int)(_fSpeed0 + _fCountTick*_fAcceleration);

    if( dX > speed )
      dX = speed;

    if( dY > speed )
      dY = speed;

    if( _iX < _pItemShowing->_x )
      dX = -dX;

    if( _iY < _pItemShowing->_y )
      dY = -dY;

    _fCountTick += 1.0f;

    _pAnimationObject->MoveObjectAndChildren( dX, dY );

    if( _iX == _pAnimationObject->GetPositionX() && _iY == _pAnimationObject->GetPositionY() )
    {
      return 0;
    }

    return 1;
  }
  void Init( AnimationObject* pAnimationObject );     // Настроиться на новый объект

  int             _iX;
  int             _iY;
  float           _fSpeed0;       // Начальная скорость движения
  float           _fAcceleration; // Ускорение движения
  float           _fCountTick;    // Количество отработанных тиков, сбрасывается в ноль при инициализации
  AnimationObject*     _pAnimationObject; // То что анимируем

};
 
AnimationPoint конкретная функция движения, в твоем случае нужно реализовать аналогично объект AnimationSin
AnimationObject интерфейс который должны реализовывать все объекты которые нужно анимировать.
Далее в основном цикле программы вызываешь метод Work анимирующего объекта ( в данном примере AnimationPoint )

Здесь интересно описано движение шара http://orenstudent.ru/CometD.htm + можно программку с исходным кодом скачать.Хз.Я заказывал у автора немного переделанную работу,все очень хорошо выполнил


Использую что то подобное для анимации диалоговых элементов, привожу только интерфейс без реализации, если заинтересует приложу основные части:

1. Объект высокого уровня, с которым работает непосредственный клиент,
через него запускается определенный фрейм ( набор точек ).


///////////////////////////////////////////////////////////////////////////////
//        DialogAnimation
//
//    Декаратор диалоговых элементов,
//  анимирует диалоги и/или отдельные элементы
//  на входе принимает указатель на DialogItem,
//  а также данные( фреймы ), являющиеся точками
//  через которые и проходит анимация.
//    Использование:
//  Загрузить данные( метод Load)
//  Инициализировать наблюдаемый объект( метод Init )
//  Запустить фрейм( метод StartAnimation )
//  Переодически обробатывать анимацтю( метод Work )
//
///////////////////////////////////////////////////////////////////////////////
class DialogAnimation
{
public:
  // Конструктор/Деструктор
  DialogAnimation();
  ~DialogAnimation();

  void Init( DialogItem* pItemAnimation );                  // Инициализировать данные и декарируемый объект
  void Load( TiXmlElement* pXmlAnimationData );             // Загрузить анимацию из Xml
  void Work();                                              // Обработать логику
  void StartAnimation( String sNameAnimation );             // Запустить фрейм sNameAnimation
  String& GetCurrentFrameName();                            // Получить имя текущего фрейма
 
  void RegisterPointFunction( String sNameFunction,
    PPoint_Function pPointFunction );                     // Зарегистрировать функцию обработчик

  PPoint_Function GetPointFunction( String sNameFunction ); // Получить указатель на функцию оброботчик


private:
  struct PointFunctionByName
  {
    String        _sNameFunction;
    PPoint_Function  _pPointFunction;
  };
  typedef std::vector<PointFunctionByName> PointFunctionList;

  FrameList               _listFrames;               // Список фреймов
  PointFunctionList       _listPointFunctions;       // Список функций обработчиков

  DialogItem*            _pItemAnimation;           // Декарируемый элемент
  AnimationFrame*        _pCurrentFrame;            // Текущий работающий фрейм

  int                    _iDeltaXPosInit;           // Начальный сдвиг наблюдаемого объекта по X
  int                    _iDeltaYPosInit;           // Начальный сдвиг наблюдаемого объекта по Y

};
 
2. Объект перебирающей конкретные точки анимации

class AnimationFrame
{
public:
  // Конструктор/Деструктор
  AnimationFrame();
  ~AnimationFrame();

  void Load( TiXmlElement* pXmlFrameData,
    DialogAnimation* pAnimation );               // Загрузить анимацию из Xml
  int Work();                                      // Обработать логику
  void StartFrame( DialogItem* pItemShowing );     // Запустить фрейм
  DialogAnimation* GetAnimation();                 // Получить анимацию в которой находимся
  String& GetName();                               // Получить имя фрейма

private:

  String              _sNameFrame;             // Имя фрейма
  DialogAnimation*    _pAnimation;             // Анимация в которой мы находимся

  PointList           _listPoints;             // Список точек фрейма

  PointList::iterator _itCurrentPoint;         // Текущая точка фрейма
  DialogItem*         _pItemShowing;           // Декарируемый Элемент
};  
 
3. Непосредственно передвигает элемент, стремясь к какой то точке, по окончанию вызывает функцию обработчик если задана.

// Обработчик точек анимации, вызывается при достижении точки
typedef void (Point_Function)( String& sParam1, String& sParam2 );
typedef Point_Function* PPoint_Function;

class AnimationPoint
{
public:
  // Конструктор/Деструктор
  AnimationPoint();
  ~AnimationPoint();

  enum eAnimationWork
  {
    AW_NORMAL = 0,
    AW_END
  };

  void Load( TiXmlElement* pXmlPointData,
    AnimationFrame* pFrame );              // Загрузить анимацию из Xml
  int Work();                                // Обработать логику
  void Init( DialogItem* pItemShowing );     // Настроиться на новый объект

private:

  // Разброс координат
  int             _iMinX;
  int             _iMinY;
  int             _iMaxX;
  int             _iMaxY;

  int             _iX;             // Утонавливается в Init Rand( _iMinX, _iMaxX )
  int             _iY;             // Утонавливается в Init Rand( _iMinY, _iMaxY )

  float           _fSpeed0;        // Начальная скорость движения
  float           _fAcceleration;  // Ускорение движения
  float           _fCountTick;     // Количество отработанных тиков, сбрасывается в ноль при инициализации
  DialogItem*     _pItemShowing;   // То что анимируем

  PPoint_Function  PointFunction;   // Функция обработчик
  String          _sParam1;        // Параметр1 Точки
  String          _sParam2;        // Параметр2 Точки

  AnimationFrame* _pFrame;         // Фрейм в котором находится точка
};
 


Как это все работает:
DialogAnimation это контейнер AnimationFrame, который в свою очередь контейнер AnimationPoint.
вот непосредственно анимация:

/////////////////////////////////////////////////////////////////////////////////////////////
// Обработать логику
/////////////////////////////////////////////////////////////////////////////////////////////
int AnimationPoint::Work()
{

  int dX = abs( _iX - _pItemShowing->_x );
  int dY = abs( _iY - _pItemShowing->_y );
  int speed = (int)(_fSpeed0 + _fCountTick*_fAcceleration);

  if( dX > speed )
    dX = speed;

  if( dY > speed )
    dY = speed;

  if( _iX < _pItemShowing->_x )
    dX = -dX;

  if( _iY < _pItemShowing->_y )
    dY = -dY;

  int iDeltaX[2] = { dX, 0 };
  int iDeltaY[2] = { dY, 0 };

  _fCountTick += 1.0f;

  _pItemShowing->MoveItemAndChildren( iDeltaX, iDeltaY, false );

  if( _iX == _pItemShowing->_x && _iY == _pItemShowing->_y )
  {
    if( PointFunction )
      PointFunction( _sParam1, _sParam2 );
    return AW_END;
  }

  return AW_NORMAL;
}
 
то есть анимируемый объект должен поддерживать метод MoveItemAndChildren и предоставлять доступ к текущим координатам( _x, _y )