Анімація все ще може бути розділена між логікою та візуалізацією. Абстрактним станом даних анімації буде інформація, необхідна графічному API для анімації.
Наприклад, у 2D іграх це може бути область прямокутника, яка позначає область, яка відображає поточну частину вашого спрайтового аркуша, яку потрібно намалювати (коли у вас є аркуш, що складається з, скажімо, 30 малюнків 80x80, що містять різні етапи вашого персонажа стрибати, сідати, рухатися тощо). Це також можуть бути будь-які дані, які вам не потрібні для візуалізації, але, можливо, для управління самими станами анімації, як час, що залишився до закінчення поточного кроку анімації, або назва анімації ("ходьба", "стоячи" і т.д.) Все це можна представити будь-яким способом. Ось логічна частина.
У частині візуалізації ви просто виконайте це, як зазвичай, дістаньте цей прямокутник зі своєї моделі та використовуйте його візуалізатор, щоб реально робити дзвінки до графічного API.
У коді (тут використовується синтаксис C ++):
class Sprite //Model
{
private:
Rectangle subrect;
Vector2f position;
//etc.
public:
Rectangle GetSubrect()
{
return subrect;
}
//etc.
};
class AnimatedSprite : public Sprite, public Updatable //arbitrary interface for classes that need to change their state on a regular basis
{
AnimationController animation_controller;
//etc.
public:
void Update()
{
animation_controller.Update(); //Good OOP design ;) It will take control of changing animations in time etc. for you
this.SetSubrect(animation_controller.GetCurrentAnimation().GetRect());
}
//etc.
};
Ось дані. Ваш рендер візьме ці дані та виведе їх. Оскільки і нормальні спрайти, і анімовані малюються однаково, ви можете використовувати тут поліморфію!
class Renderer
{
//etc.
public:
void Draw(const Sprite &spr)
{
graphics_api_pointer->Draw(spr.GetAllTheDataThatINeed());
}
};
TMV:
Я придумав інший приклад. Скажімо, у вас RPG. Наприклад, вашій моделі, яка представляє карту світу, можливо, потрібно буде зберігати позицію персонажа у світі як координати плитки на карті. Однак, коли ви пересуваєте персонаж, вони проходять за кілька пікселів одночасно до наступного квадрата. Чи зберігаєте ви цю позицію "між плитками" в анімаційному об'єкті? Як ви оновлюєте модель, коли персонаж нарешті "прибув" до наступної координати плитки на карті?
Карта світу не знає про позицію гравців безпосередньо (у неї немає Vector2f або чогось подібного, що безпосередньо зберігає позицію гравців =, натомість вона має пряме посилання на сам об’єкт гравця, що, в свою чергу, походить від AnimatedSprite тож ви можете легко передати його рендерінгу та отримати від нього всі необхідні дані.
В цілому, ваша карта не повинна робити все, я б мав клас "TileMap", який піклується про керування усіма плитками, і, можливо, він також виявляє зіткнення між об'єктами, які я передаю йому та плитки на карті. Тоді у мене з'явиться ще один клас "RPGMap", або як би ви хотіли його назвати, який має посилання на вашу карту плитки та посилання на програвач і робить фактичні дзвінки Update () на ваш плеєр та на ваш карта плитки.
Те, як ви хочете оновити модель при русі гравця, залежить від того, що ви хочете зробити.
Чи дозволяється вашому гравцю переміщатися між плитками самостійно (стиль Zelda)? Просто обробіть вхід і перемістіть програвач відповідно до кожного кадру. Або ви хочете, щоб гравець натискав "праворуч", і ваш персонаж автоматично переміщує одну плитку вправо? Нехай ваш клас RPGMap інтерполює позицію гравців до тих пір, поки він не прибуде до місця призначення, а тим часом заблокує все керування входом за допомогою клавіші руху.
Так чи інакше, якщо ви хочете спростити себе, всі ваші моделі матимуть методи Update (), якщо їм насправді потрібна певна логіка для оновлення (замість того, щоб просто змінювати значення змінних) - Ви не віддасте контролеру у шаблоні MVC таким чином, ви просто перемістіть код від "на один крок вище" (контролер) вниз до моделі, і все, що робить контролер, викликає цей метод оновлення () моделі (Контролер у нашому випадку буде RPGMap). Ви все ще можете легко поміняти код логіки - ви можете просто змінити код класу або, якщо вам потрібна зовсім інша поведінка, ви можете просто вивести з вашого модельного класу і лише замінити метод Update ().
Цей підхід дуже скорочує виклики методів і подібні речі - які раніше були одним з головних недоліків чистого шаблону MVC (ви в кінцевому підсумку дуже часто називаєте GetThis () GetThat () - він робить код і довшим, і крихітні трохи важче для читання, а також повільніше - хоча це може подбати ваш компілятор, який оптимізує багато подібних речей.