Вторник, 26 Ноября 2024, 17:05

Приветствую Вас Гость

[ Новые сообщения · Игроделы · Правила · Поиск ]
  • Страница 1 из 1
  • 1
Одновременное выполнение 2 функций.
MorfayДата: Пятница, 27 Апреля 2012, 11:23 | Сообщение # 1
почетный гость
Сейчас нет на сайте
Здравствуйте. Столкнулся с такой проблемой, что необходимо выполнить 2 функции одновременно, но не знаю как это реализовать лучше.
Подробнее:
Есть класс, работающий с анимациями. В нем все есть, анимации проигрываются. Но, к примеру, прописали мы в коде действий, что при нажатии на кнопку "D" персонаж будет идти вправо. Проигрывается соответствующая анимация, прибавляем координаты по Х к объекту. На деле же, получается, что эти два действия выполняются последовательно: или проигрывается анимация, а потом объект передвигается, или передвигается, а потом проигрывается. Как можно их объединить?
P. S. Читал мануалы по многопоточности. Вроде бы и подходит, но так и не разобрался как их нормально создавать (потоки).

P. P. S. Советы выполнять функцию движения в самом проигрывании анимации не катят - нет смысла в самом классе тогда.
warzesДата: Пятница, 27 Апреля 2012, 12:00 | Сообщение # 2
участник
Сейчас нет на сайте
а зачем в функции обрабаывать всю анимацию и все движение?
У тебя ведь наверняка есть игровой цикл. Сделай функцию которая через определенные промежутки времени* delta time (время между кадрами если что) выполняет ровно один кадр и сдвигает ровно на 1 пиксель и тогда у тебя будет нормальная анимания без всяких ненужных многопоточностей

псеводкод
Code


void AnimDraw()
{
id++;
if (id >= maxanim)
id = 0;

img[id]->draw();
}
void Move()
{
    x+=2;
}

int main()
{
while(1)
{
static float animspeed = animpause*dt;
if (animspeed >= 0.3)
{
AnimDraw();
Move();
animspeed=0;
}
}
}



Мой блог
Вики DirectX


Сообщение отредактировал warzes - Пятница, 27 Апреля 2012, 12:06
MorfayДата: Пятница, 27 Апреля 2012, 12:17 | Сообщение # 3
почетный гость
Сейчас нет на сайте
Дело в том, что анимация проигрывается через класс (назовем его AnimationPlayer). Он содержит массив анимаций, с соответствующими методами. Сам же класс анимации имеет параметры (вроде скорости проигрывания, количества кадров и т. п.), а также методы проигрывания. В итоге мне достаточно прописать animationPlayer.Play("run"); чтобы проиграть анимацию. Мне такая реализация понравилась - удобно, +все работает. А в игровом цикле прописывается:

....//начало цикла, определение состояния клавиш.
case SDLK_d:
{
animationPlayer.Play("run"); // проигрывание анимации с указанным именем
action.Run(cObject object); // допустим action - класс с действиями, Run - метод движения, с параметром object (объект, котороый должен двигаться)
}
....
Вот эти два действия надо выполнить одновременно.

Теперь, почему не хочу двигать объект в самом проигрывании: класс универсальный для всех анимации (конечно, если выполняются определенные требования к спрайту). А вот действия не одинаковые. Да и вплетать действия в анимации не очень нравится - хочу, чтобы части были максимально автономны. Меньшим злом было бы, если бы был аналог call_user_func() в С++. Но ничего подобного я не нашел, а нормальный способ вызвать метод внутри анимации не придумал. Осталась только идея многопоточности (как я понимаю, это один из способов выполнить два действия практически одновременно), но с ней так и не смог разобраться. Или же есть какое-то иное решение, которое я не вижу.
НохчиДата: Пятница, 27 Апреля 2012, 12:50 | Сообщение # 4
заслуженный участник
Сейчас нет на сайте
Morfay, я так понимаю метод Play не возвращает управления до тех пор, пока анимация полностью не будет проиграна? Это неправильно.

Многие вопросы по Windows отпадут, если посмотреть тут
warzesДата: Пятница, 27 Апреля 2012, 12:58 | Сообщение # 5
участник
Сейчас нет на сайте
Quote (Morfay)
Дело в том, что анимация проигрывается через класс (назовем его AnimationPlayer). Он содержит массив анимаций, с соответствующими методами

А ты проигрывай не всю анимацию за раз, а только один кадр. Код останется точно таким же
Code

  animationPlayer.Play("run"); // проигрывание анимации с указанным именем  

В будущем тебе будет тяжко если не научишься рисовать где-то в одном месте а не по всему коду.
В общем так - здесь ты должен не рисовать анимацию а сообщать что данная анимация должна быть проиграна. Далее у тебя должно быть место, где ты рисуешь, и вот уже там нужно рисовать твою анимацию.

Quote (Morfay)
Теперь, почему не хочу двигать объект в самом проигрывании:

Да никто тебя не заставляет, все правильно - рисование и движение должны быть в разных местах. Ты вообще не в ту сторону смотришь, у тебя сама логика игры кода неправильна нельзя рисовать где попало - это приведет к куче проблем.


Мой блог
Вики DirectX
MorfayДата: Пятница, 27 Апреля 2012, 13:27 | Сообщение # 6
почетный гость
Сейчас нет на сайте
Quote
В будущем тебе будет тяжко если не научишься рисовать где-то в одном месте а не по всему коду.
В общем так - здесь ты должен не рисовать анимацию а сообщать что данная анимация должна быть проиграна. Далее у тебя должно быть место, где ты рисуешь, и вот уже там нужно рисовать твою анимацию.


Вроде бы я так и делаю. Метод Play("run") сообщает какая анимация должна быть проиграна. Все параметры для анимации заполнены (имя, количество кадров и прочее). Далее, выполняется таймер, который меняет позицию кадра в спрайте, и выполняется метод CreateScene, который все и рисует (то есть, абсолютно все).

Quote
Morfay, я так понимаю метод Play не возвращает управления до тех пор, пока анимация полностью не будет проиграна? Это неправильно.


Quote
В общем так - здесь ты должен не рисовать анимацию а сообщать что данная анимация должна быть проиграна. Далее у тебя должно быть место, где ты рисуешь, и вот уже там нужно рисовать твою анимацию.


Теплее. Но я не могу понять, как реализовать игровой таймер - каждая анимация может иметь свою скорость проигрывания. Или не может?.

Если посмотреть пример выше - у нас два метода (проигрывание и движение). Убрать таймер из моего метода Play, сделать так, при его вызове, просто менялась позиция кадра. Потом в игровом цикле, при нажатии на клавишу создаем таймер:

Code
case SDLK_d:  
{  
//начинаем таймер
animationPlayer.Play("run"); // проигрывание анимации с указанным именем  
action.Run(cObject object); // допустим action - класс с действиями, Run - метод движения, с параметром object (объект, котороый должен двигаться)  
//заканчиваем
}


Что-то вроде такого должно получиться?
НохчиДата: Пятница, 27 Апреля 2012, 13:43 | Сообщение # 7
заслуженный участник
Сейчас нет на сайте
Quote (Morfay)
Но я не могу понять, как реализовать игровой таймер - каждая анимация может иметь свою скорость проигрывания. Или не может?.

При такой кривой архитектуре
Quote (Morfay)
animationPlayer.Play("run");

не может.


Многие вопросы по Windows отпадут, если посмотреть тут
MorfayДата: Пятница, 27 Апреля 2012, 14:01 | Сообщение # 8
почетный гость
Сейчас нет на сайте
эээ, при такой архитектуре как раз и может - каждая анимация имеет свою скорость проигрывания и проигрывается. Само по себе все прекрасно проигрывается и новые анимации добавляются в класс всего за пару строчек кода. Проблема в том, чтобы увязать все вместе (анимации и действия). Создаваемый движок идет как учебное пособие - через него изучаю с++ и SDL, а также саму работу движка. Поэтому я совсем не против, если меня ткнут носом и скажут как лучше сделать

Нохчи, глянь вышенаписанный пост, скажи, если сделать так как в примере внизу, это будет нормально?


Сообщение отредактировал Morfay - Пятница, 27 Апреля 2012, 14:03
warzesДата: Пятница, 27 Апреля 2012, 14:27 | Сообщение # 9
участник
Сейчас нет на сайте
я тебе не просто так говорил про delta time. Пропускай кадры на каждый кадр анимации выполняй несколько кадров движения, или наоборот. Для разной анимации делай разные значения пауз между сменой кадров. Нафига ты вообще привязываешь анимацию к перемещению? Все что тебе нужно - это подобрать скорость проигрывания анимации так чтобы она совпадала с перемещением по экрану - все.

Из моего движка класс анимации
Code

struct OneFrame
{
      int x;
      int y;
      int w;
      int h;
      Image *img;
};

class Animation
{
public:
      Animation(const std::string &name,float speed);
      ~Animation();

      void Play(int x, int y);
           
      void SetLoop(bool loop){_loop = loop;}
      int GetFrame(){return _curframe;}
      int GetMaxFrame();

      void Clear();
      void Reset();

      bool IsEnd();

private:
      std::string _name;
      std::vector<OneFrame> _frame;
      int _curframe;
      float _speed;
      float _stepspeed;
      bool _loop;
      bool _reverse;
      float _animationTime;

};


Code
#include "animation.h"
#include "global.h"
#include "rect.h"

void Animation::Play(int x, int y)
{
      if (_frame.empty())
       return;

      // рисуем кадр
      Recti rect(_frame[_curframe].x, _frame[_curframe].y, _frame[_curframe].w, _frame[_curframe].h);
      _frame[_curframe].img->Draw(rect, x,y);

      // переключаем на новый кадр
      _animationTime += GetDeltaTime();
      if (_animationTime > _stepspeed)
      {
        _animationTime = 0.0f;
        // проверяем не вышел ли текущий кадр за предел массива
        if (_curframe < (_frame.size()-1))
         _curframe++;
        else
         if (_loop == true)
          Reset();
      }
}

void Animation::Reset()
{
      _curframe = 0;
}



Лишний код убрал. Как видишь - можно легко задавать скорость

Я тоже вызываю только одну функцию Play(). Но посмотри внимательно - кажый ее вызов рисуется ровно один (!!!) кадр. Все что мне нужно - это где-то расчитать координаты и задать скорость анимации так - чтобы она совпадала со скорость сдвига аниматора


Мой блог
Вики DirectX


Сообщение отредактировал warzes - Пятница, 27 Апреля 2012, 14:33
ТритонДата: Пятница, 27 Апреля 2012, 15:00 | Сообщение # 10
постоянный участник
Сейчас нет на сайте
Quote (Morfay)
Здравствуйте. Столкнулся с такой проблемой, что необходимо выполнить 2 функции одновременно, но не знаю как это реализовать лучше.
Подробнее:
Есть класс, работающий с анимациями. В нем все есть, анимации проигрываются. Но, к примеру, прописали мы в коде действий, что при нажатии на кнопку "D" персонаж будет идти вправо. Проигрывается соответствующая анимация, прибавляем координаты по Х к объекту. На деле же, получается, что эти два действия выполняются последовательно: или проигрывается анимация, а потом объект передвигается, или передвигается, а потом проигрывается. Как можно их объединить?
А помимо анимации ты вообще где нибудь видишь, что объект перемещается? У одноядерных машин есть одна особенность: они в принципе не способны выполнять два дела одновременно. Но почему то это ни одной машине не помешало обрабатывать клавиатурный ввод и движение крысиного курсора одновременно. А фокус в разделении времени: в каждый момент времени машина делает что то одно, но в каждый период времени чередует свои действия и делает сразу всё, но делает это так, чтоб пользователь не успевал заметить неодновременности. А пока пользователь не способен заметить неодновременность, можно отождествлять режим разделения времени с логически параллельным исполнением.


Не всё так плохо, как оно есть на самом деле.
НохчиДата: Пятница, 27 Апреля 2012, 15:02 | Сообщение # 11
заслуженный участник
Сейчас нет на сайте
Morfay, вот посмотри на класс warzes`a, его класс Animation содержит и проигрывает всего одну анимацию, для каждого объекта типа Animation можно задать свои параметры(в том числе и скорость воспроизведения). А у тебя что-то странное в коде щ_Щ

Многие вопросы по Windows отпадут, если посмотреть тут
MorfayДата: Пятница, 27 Апреля 2012, 15:44 | Сообщение # 12
почетный гость
Сейчас нет на сайте
warzes, я правильно понял, что метод Play, запущенный в игровом цикле, просто с каждой итерацией проверяет "а не настало ли время поменять кадр", и в зависимости от прошедшего времени либо меняет кадр, либо выходит из метода, если время еще не пришло? Забавная реализация, я нахардкодил. Радует, что нужно убрать минимум, чтобы все работало также (почти так же как и у тебя все в методе, но я вводил таймер, который пока не проиграет анимацию полностью, не выйдет. Убрать его и добавить твой подсчет времени - и все). Опробуем, спасибо.
ТритонДата: Суббота, 28 Апреля 2012, 06:05 | Сообщение # 13
постоянный участник
Сейчас нет на сайте
Morfay, всё, что ты не можешь решить, в каком порядке должно исполняться, должно исполнятся логически одновременно, тем более это относится ко всему, что по задаче одновременным должно казаться. Но логическая одновременность не требует истинного параллелизма, а лишь допускает его. Минимально необходимо и достаточно только чтоб все эти действия одновременными казались. Очевидных вариантов решения здесь два: использовать потоки и самостоятельно реализовать разделение времени с той частотой, какая будет достаточной для обмана юзверей. На многоядерной машине использование потоков может привести и к истинному параллелизму, но гарантировать параллельное исполнение можно только многооперабельными опкодами EPIC.

Не всё так плохо, как оно есть на самом деле.
MorfayДата: Суббота, 28 Апреля 2012, 11:00 | Сообщение # 14
почетный гость
Сейчас нет на сайте
Я сделал по примеру кода warzes'а - все получилось. Появились мелкие неудобства, но они решаемы. Всем спасибо.
  • Страница 1 из 1
  • 1
Поиск:

Все права сохранены. GcUp.ru © 2008-2024 Рейтинг