В настоящее время я работаю над системой, в которой объекты анимируются по кривой Безье. В различных, определенных пользователем точках на кривой, может возникнуть событие, на которое должен реагировать анимирующий объект. Это может быть изменение скорости, изменение анимации, изменение направления движения и т. Д.
Пока у меня есть следующий класс AnimationEvent.
class AnimationEvent
{
private:
unsigned int m_eventID;
float m_InteroplationPoint;
float m_SpeedInMPS;
public:
AnimationEvent(unsigned int id, float interpolationPoint);
~AnimationEvent(void);
const unsigned int getEventID();
void setInterpolationPoint(float interpPoint);
const float getInterpPoint();
const float getSpeed();
};
Каждое событие назначается как объект вдоль кривой, и когда достигается точка его интерполяции, класс кривой вызывает getSpeed()
функция для изменения текущей скорости анимации.
Что я действительно хочу сделать, так это реализовать систему, например, с помощью шаблона проектирования Decorator, в котором событие может быть украшено несколькими объектами, и когда оно будет достигнуто, будут применены все украшения. У меня проблема в том, что я не могу передать указатель на родительский объект дочернему элементу, так как это создаст циклическую зависимость, но у меня также есть проблема, когда я не знаю (при компиляции), какой тип действий событие будет украшено.
Любые идеи о том, как преодолеть это, будет принята с благодарностью! Если я забыл какую-либо информацию, которая может помочь, я постараюсь отредактировать ее.
Вы можете применить шаблон, похожий на декоратор, к этой проблеме, если вы хотите отслеживать все события, которые произошли с объектом ранее. Все, что вам нужно сделать, это сохранить каждое событие в каком-либо векторе. Тогда вы можете делать любые манипуляции, которые вам нравятся.
#include <iostream>
#include <vector>
using namespace std;
class Animatee;
class AnimateEvent
{
public:
virtual Animatee & perform(Animatee & on) = 0;
};
class Animatee
{
public:
Animatee() : value(0){};
void addEvent(AnimateEvent * event)
{
if(event != NULL)
{
events.push_back(event);
}
}
Animatee & act()
{
for(vector<AnimateEvent * >::iterator it = events.begin(); it != events.end();++it)
{
AnimateEvent * event = *it;
event->perform(*this);
}
return *this;
}
double value; //don't do this, but something more encap'ed
private:
vector<AnimateEvent * > events;
};
class Add : public AnimateEvent
{
virtual Animatee & perform(Animatee & on)
{
on.value = on.value + 1;
return on;
}
};
class Subtract : public AnimateEvent
{
virtual Animatee & perform(Animatee & on)
{
on.value = on.value - 1;
return on;
}
};
class Multiply : public AnimateEvent
{
virtual Animatee & perform(Animatee & on)
{
on.value = on.value * 2;
return on;
}
};
class Div : public AnimateEvent
{
virtual Animatee & perform(Animatee & on)
{
on.value = on.value / 2.0;
return on;
}
};
int main() {
Animatee matee;
matee.addEvent(new Add());
//cout << "Before: " << matee.value << " After: " << matee.act().value << endl; <~~~ Undefined btw, acting on the object twice in one "statement"double before = matee.value;
cout << "Before: " << before << " After: " << matee.act().value << endl;
matee.addEvent(new Subtract());
before = matee.value;
cout << "Before: " << before << " After: " << matee.act().value << endl;
matee.addEvent(new Subtract());
before = matee.value;
cout << "Before: " << before << " After: " << matee.act().value << endl;
matee.addEvent(new Add());
matee.addEvent(new Add());
matee.addEvent(new Add());
before = matee.value;
cout << "Before: " << before << " After: " << matee.act().value << endl;
matee.addEvent(new Multiply());
before = matee.value;
cout << "Before: " << before << " After: " << matee.act().value << endl;
before = matee.value;
cout << "Before: " << before << " After: " << matee.act().value << endl;
return 0;
}
Как описано, вы поддерживаете только один раз дифференцируемые функции скорости, которые будут выглядеть ужасно, за исключением множества точек.
Есть две разные проблемы. Первое — это возможное изменение параметров внутренней анимации (что может быть непрозрачным для механизма позиционирования), а второе — изменение скорости (которое не является непрозрачным).
Я бы решил оба ортогонально.
Сосредоточив внимание на скорости, следующий вопрос — как вы хотите, чтобы декораторы сочиняли друг с другом. Добавляют ли они, умножают, заменяют, формируют верхние или нижние границы выходной скорости?
К какой информации о местном штате им разрешен доступ?
Предполагая, что им задают положение вдоль кривой, и только последний декоратор скорости означает что-либо, std::function<double(double)>
подойдет как тип декоратора скорости.
Это на том же уровне эффективности, что и вызов virtual
функция или два. И инжектор или декоратор может захватывать все, что хочет для внутреннего состояния …