SFML и C++ Уроки \ Разработка игр › Форумы › Предложения к администрации сайта › Будующие уроки › Ответ в теме: Будующие уроки
Здравствуйте. Как я понимаю, системы анимации так и не дождемся, да?
Можно кратенько обсудить этот вопрос здесь? Не нужно объяснять научно-популярно, я сам преподаю в универе Системы ИИ, основы openGL и ООП, можно сухо и по делу, так и вам и мне лучше будет.
С SFML столкнулся буквально недавно, студенты курсачи на нём принесли. Как теперь понимаю, по урокам с вашего сайта писали)))
Я вот думал над системой анимации, и пришёл к некоторой форме, но она мне всё равно не очень нравится.
Суть в следующем – у каждого DrawableObject (абстрактный класс, от которого наследуются остальные) есть список/массив объектов класса Animation, а также указатель/номер на текущую анимацию.
Класс Animation содержит в себе указатель на объект-владелец, указатель на текстуру, тип (int type) и подтип (int subtype), время смены кадров (timespan), время показа (showtime), количество кадров и массив IntRect, хранящий позиции кадров в текстуре.
Типы у меня задефайнены как ANIM_TYPE_IDLE – 10000, ANIM_TYPE_WALK – 20000, ANIM_TYPE_FALL – 30000 и т.д. Подтипы задефайнены как ANIM_SUBTYPE_LEFT – 100, ANIM_SUBTYPE_RIGHT – 200 и т.д.
В итоге для каждого DrawableObject будет выдан массив анимаций, из которого можно будет выбирать нужную анимацию по сумме типа и подтипа, а если есть несколько разных анимаций одного типа и подтипа, то добавлять порядковые числа от 0 до 99.
Такой подход мне кажется будет работать быстрее, чем делать ассоциативный массив и искать по текстовым ключам или хеш-кодам.
При выборе анимации у объекта класса Animation вызывается метод startAnimation, который через указатель на владельца берёт его спрайт и подставляет координаты текстуры первого кадра.
Также у анимации есть метод Update, который обновляет showtime для вычисления текущего кадра и подстановки его, опять-таки, в спрайт владельца.
Ну ещё добавил мелочёвки на вроде статичной анимации (т.е. не меняющихся кадров, как для блоков) – убирает лишние проверки и перерисовки; а также возможность задать одиночное проигрывание анимации с “заморозкой” на последнем/первом кадре.
Вроде всё, что нужно реализовано, а всё равно не нравится.
Откомментируйте, пожалуйста.
Даю кусок кода с классами:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
//DrawableObject.h class Animation { int type; int subtype; int slides; uint timespan; // 0 means static picture, no slide changes Texture * texture; IntRect * coords; uint show_time; int current_slide; DrawableObject * owner; public: Animation(DrawableObject * obj, int _type, int _subtype, int _slides, uint _timespan, Texture * _texture, IntRect * _coords); ~Animation(); uint UID(); void startAnimation(); bool isFinished(); void Update(uint time_elapsed); }; class DrawableObject : public GameObject { protected: Sprite sprite; List<Animation> animations; Animation * currentAnimation; bool repeatAnimation; public: DrawableObject(); DrawableObject(Point2D _coords); ~DrawableObject(); Sprite& getSprite(); void addAnimation(Animation * a); void playAnimation(int _type, int _subtype, bool repeat = true); void updateAnimation(uint time_elapsed); void Draw(); }; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
//DrawableObject.cpp DrawableObject::DrawableObject() { } DrawableObject::DrawableObject(Point2D _coords) : GameObject(_coords) { } DrawableObject::~DrawableObject() { animations.clear(); } Sprite& DrawableObject::getSprite() { return sprite; } void DrawableObject::addAnimation(Animation * a) { animations.push(a); } void DrawableObject::playAnimation(int _type, int _subtype, bool repeat) { currentAnimation = animations.lookObj(_type + _subtype); repeatAnimation = repeat; currentAnimation->startAnimation(); } void DrawableObject::updateAnimation(uint time_elapsed) { if (!repeatAnimation && currentAnimation->isFinished()) return; currentAnimation->Update(time_elapsed); } void DrawableObject::Draw() { sprite.setPosition(coords.x, coords.y); window.draw(sprite); } Animation::Animation(DrawableObject * obj, int _type, int _subtype, int _slides, uint _timespan, Texture * _texture, IntRect * _coords) { type = _type; subtype = _subtype; slides = _slides; timespan = _timespan; texture = _texture; show_time = 0; owner = obj; coords = new IntRect[slides]; for (int i = 0; i < slides; i++) coords[i] = _coords[i]; current_slide = 0; } Animation::~Animation() { delete[] coords; } uint Animation::UID() { return type+subtype; } void Animation::startAnimation() { show_time = 0; Sprite &s = owner->getSprite(); if (s.getTexture() != texture) s.setTexture(*texture); s.setTextureRect(IntRect(coords[0])); } bool Animation::isFinished() { if (timespan == 0) return true; return (show_time >= timespan*slides); } void Animation::Update(uint time_elapsed) { if (timespan == 0) return; show_time += time_elapsed; current_slide = ((int)(show_time / timespan)) % slides; Sprite &s = owner->getSprite(); if (s.getTexture() != texture) s.setTexture(*texture); s.setTextureRect(IntRect(coords[current_slide])); } |
Да, да, надо вынести Animation в отдельные файлы, обязательно потом вынесу. Лень пока.