А як щодо двигуна на основі компонентів ?
У вас був би основний клас з іменем Engine
, який би зберігав список GameScreens
, який би сам містив список Components
.
Двигун має Update
і Draw
метод, і виклик GameScreen
's, Update
і Draw
методи, які самі проходять кожен компонент і call Update
і Draw
.
Представлений так, я погоджуюся, що це звучить як поганий і повторюваний дизайн. Але повірте, мій код став набагато чистішим, використовуючи підхід на основі компонентів, ніж це було у всіх моїх старих класах менеджерів .
Набагато простіше підтримувати такий код, оскільки ви просто переживаєте велику ієрархію класів і вам не доведеться шукати BackgroundManager
всі конкретні фони. Ви просто є ScrollingBackground
, ParallaxBackground
, StaticBackground
і т.д. , які все випливають з Background
класу.
Згодом ви створить досить міцний двигун, який зможете повторно використовувати для всіх своїх проектів, використовуючи безліч часто використовуваних компонентів та допоміжних методів (наприклад, FrameRateDisplayer
як утиліта для налагодження, Sprite
клас як базовий спрайт із текстурою та методами розширення для векторів і генерація випадкових чисел).
У вас уже не буде BackgroundManager
класу, а Background
класу, який керував би собою.
Коли ваша гра починається, все, що вам потрібно зробити, це в основному:
// when declaring variables:
Engine engine;
// when initializing:
engine = new Engine();
engine.Initialize();
engine.LoadContent();
engine.AddGameScreen(new MainMenuScreen());
// when updating:
engine.Update();
// when drawing:
engine.Draw();
І це все для вашого стартового коду гри.
Потім для екрана головного меню:
class MainMenuScreen : MenuScreen // where MenuScreen derives from the GameScreen class
{
const int ENEMY_COUNT = 10;
StaticBackground background;
Player player;
List<Enemy> enemies;
public override void Initialize()
{
background = new StaticBackground();
player = new Player();
enemies = new List<Enemy>();
base.AddComponent(background); // defined within the GameScreen class
base.AddComponent(player);
for (int i = 0; i < ENEMY_COUNT; ++i)
{
Enemy newEnemy = new Enemy();
enemies.Add(newEnemy);
base.AddComponent(newEnemy);
}
}
}
Ви отримуєте загальну думку.
Ви також будете зберігати посилання на Engine
всі свої GameScreen
класи, щоб мати можливість додавати нові екрани навіть у межах GameScreen
класу (наприклад, коли користувач натискає кнопку StartGame, перебуваючи в межах вашого MainMenuScreen
, ви можете перейти до GameplayScreen
).
Те ж саме стосується Component
класу: він повинен містити посилання на його батьків GameScreen
, мати як доступ до Engine
класу, так і його батьків, GameScreen
щоб додати нові компоненти (наприклад, ви можете створити клас HUD, DrawableButton
який називається, який містить
DrawableText
компонент і StaticBackground
компонент).
Ви навіть можете застосувати інші шаблони дизайну після цього, як-от "шаблон дизайну сервісу" (не впевнений у точній назві), де ви можете зберігати різні корисні послуги у своєму Engine
класі (ви просто зберігаєте список IService
s та дозволяєте іншим класам самі додавати послуги ). наприклад, я б зберігав Camera2D
компонент у всьому моєму проекті як послуга, щоб застосувати його перетворення під час малювання інших компонентів. Це дозволяє уникнути необхідності передавати його як параметр скрізь.
На закінчення, безумовно, можуть бути й інші кращі конструкції для двигуна, але я вважав, що запропонований цим посиланням двигун дуже елегантний, надзвичайно легко обслуговуваний та багаторазовий. Я особисто рекомендував би принаймні спробувати.