Ця порада насправді не характерна для надання, але повинна допомогти розробити систему, яка значною мірою несе речі. По-перше, спробуйте зберегти дані "GameObject" окремо від інформації про позицію.
Варто зазначити, що проста інформація XYZ про позиції може бути не такою простою. Якщо ви використовуєте двигун фізики, то позиціонуючі дані можуть зберігатися всередині сторонніх двигунів. Вам або доведеться синхронізувати між ними (що передбачає багато безглуздого копіювання пам'яті) або запитувати інформацію безпосередньо з двигуна. Але не всі об’єкти потребують фізики, деякі будуть закріплені на місці, тому простий набір поплавців прекрасно працює там. Деякі можуть бути прикріплені до інших об'єктів, тому їх положення фактично є зміщенням іншого положення. У розширених налаштуваннях у вас може бути збережена позиція лише на графічному процесорі, єдиний раз, коли це знадобиться комп'ютерній стороні, це сценарій, зберігання та реплікація мережі. Таким чином, ви, ймовірно, маєте декілька можливих варіантів для своїх позиційних даних. Тут є сенс використовувати спадщину.
Замість того, щоб об'єкт володів його позицією, натомість сам об'єкт повинен належати структурі даних індексації. Наприклад, "рівень" може мати Октре, або, можливо, "сцену" двигуна фізики. Коли ви хочете візуалізувати (або встановити сцену візуалізації), ви запитуєте у вашій спеціальній структурі об’єкти, видимі для камери.
Це також допомагає забезпечити гарне управління пам’яттю. Таким чином, об’єкт, який насправді не знаходиться в районі, навіть не має положення, яке має сенс, а не повернення 0,0-коордів або тих координат, які він мав, коли він був останній у зоні.
Якщо ви більше не зберігаєте координати в об'єкті, замість object.getX () ви отримаєте level.getX (object). Проблема з тим, що шукати об'єкт на рівні, швидше за все, буде повільною роботою, оскільки йому доведеться переглядати всі об'єкти, які відповідають його запитам.
Щоб уникнути цього, я, мабуть, створив би спеціальний клас "посилання". Той, який пов'язує між рівнем і об'єктом. Я називаю це "Місцеположення". Це містило б координати xyz, а також ручку до рівня та ручку для об'єкта. Цей клас посилань буде зберігатися в просторовій структурі / рівні, і об'єкт має слабке посилання на нього (якщо рівень / місце розташування знищено, референс об'єктів потрібно оновити до нуля. Можливо, також варто мати клас "Місце" фактично "власний" об'єкт, таким чином, якщо рівень видалений, так само особлива структура індексу, місця, які він містить, і його "Об'єкти".
typedef std::tuple<Level, Object, PositionXYZ> Location;
Тепер інформація про позицію зберігається лише в одному місці. Не дублюється між Об'єктом, структурою просторової індексації, візуалізатором тощо.
Структурам просторових даних, таких як Octrees, часто навіть не потрібно мати координати об'єктів, які вони зберігають. Там позиція зберігається у відносному розташуванні вузлів у самій структурі (це можна розглядати як щось подібне до стиснення втрат, жертвуючи точністю для швидкого часу пошуку). Якщо об'єкт розташування знаходиться в Окремі, то фактичні координати знаходяться всередині нього, як тільки запит буде виконаний.
Або якщо ви використовуєте двигун фізики для управління місцями своїх об'єктів або сумішшю між ними, клас Location повинен це обробляти прозоро, зберігаючи весь код у одному місці.
Ще однією перевагою є позиція та відповідність рівню, які зберігаються в тому самому місці. Ви можете реалізувати object.TeleportTo (other_object) і налагодити його роботу на різних рівнях. Аналогічно, пошук ШІ може знайти щось в іншій області.
Що стосується надання. Ваша візуалізація може бути схожою з Місцеположенням. За винятком того, що там буде відображатися конкретний матеріал. Вам, мабуть, не потрібно зберігати в цій структурі об'єкт або рівень. Об'єкт може бути корисним, якщо ви намагаєтеся зробити щось на кшталт вибору кольорів чи надання візуальної панелі, що пливе над нею тощо, але в іншому випадку рендерінг дбає лише про сітку та інше. RenderableStuff був би Mesh, також міг мати обмежувальні коробки тощо.
typedef std::pair<RenderableStuff, PositionXYZ> RenderThing;
renderer.render(level, camera);
renderer: object = level.getVisibleObjects(camera);
level: physics.getObjectsInArea(physics.getCameraFrustrum(camera));
for(object in objects) {
//This could be depth sorted, meshes could be broken up and sorted by material for batch rendering or whatever
rendering_que.addObjectToRender(object);
}
Можливо, вам не доведеться робити це кожен кадр, ви можете переконатися, що ви займаєте більший регіон, ніж показує на даний момент камера. Кешуйте його, відслідковуйте рухи об’єкта, щоб побачити, чи є обмежувальне поле в межах дальності, відстежуйте рух камери тощо. Але не починайте возитися з подібними речами, поки ви не визначили це.
Сам ваш фізичний двигун може мати подібну абстракцію, оскільки йому також не потрібні дані Об'єкта, а лише сітка зіткнення та фізичні властивості.
Усі ваші основні дані об’єкта містили б ім’я тієї сітки, яку використовує об'єкт. Потім ігровий движок може продовжувати і завантажувати його в будь-якому форматі, який йому подобається, не обтяжуючи клас об'єктів купою конкретних рендерів (що може бути специфічним для вашого API рендерингу, тобто DirectX проти OpenGL).
Він також тримає різні компоненти окремо. Це дозволяє легко робити такі речі, як заміна вашого фізичного двигуна, оскільки цей матеріал здебільшого міститься в одному місці. Це також значно спрощує тестування. Ви можете перевірити такі речі, як фізичні запити, не встановлюючи фактичних підроблених об'єктів, оскільки все, що вам потрібно, це клас Location. Ви також можете простіше оптимізувати матеріали. Це робить більш очевидним, які запити потрібно виконувати в яких класах та окремих місцях, щоб оптимізувати їх (наприклад, вищевказаний level.getVisibleObject був би там, де ви могли б кешувати речі, якщо камера не рухається сильно).
m_renderable
членом. Таким чином, ви можете краще розділити свою логіку. Не застосовуйте передавальний "інтерфейс" на загальних об'єктах, які також мають фізику, ai та інше. Після цього ви можете керувати рендерами окремо. Вам потрібен шар абстрактизації над викликами функції OpenGL, щоб ще більше розв’язати речі. Таким чином, не сподівайтеся, що хороший двигун може здійснювати будь-які дзвінки GL API всередині різних реалізованих реалізацій. Ось це, в мікрокоротці.