Автор: Антон Овчинников «CoderAX27»

Опубликовано: 24.05.2010

Изменено: 24.05.2010

Постоянная ссылка

Комментарии [14]

Создание простейшего движка, с разработкой собственной физики (Simple Runner)


В статье представлено описание основных компонентов, необходимых при начальном создании собственного простейшего движка с элементарной физикой, на основе процедурного подхода.



Страницы: 1 2

Содержание

1. Введение
2. Структура движка
3. Типы данных
4. Создание объектов
5. Вывод объектов
6. Физика и обработка столкновений с объектами
7. Демонстрационный код
8. Литература

1. Введение

Разрабатывать свой собственный движок с нуля очень трудно, долго и дорого. Данная статья призвана хоть как-то облегчить и без того сложную жизнь разработчиков разного уровня. В данной статье представлено краткое описание некоторых основных элементов, необходимых при начальной разработке собственного движка.

Создание простейшего движка, с разработкой собственной физики (Simple Runner)

Перед началом описания движка, следует отметить некоторые особенности, которым есть свое объяснение:

1) Процедурный код
Почти весь код движка – процедурный. Это связано с тем, что новичкам было проще в нем разобраться, т.е. не "зацикливаться" на ООП. Что касается более опытных программистов, то им достаточно будет, лишь подхватить для себя некоторые идеи реализации тех или иных процессов в движке.

2) Объекты и персонажи в сцене создаются вручную
Безусловно, более простой вариант - это просто загружать объекты и персонажи из файла, но этого не было сделано, с целью помочь начинающим быстрее и лучше разобраться в коде, начав экспериментировать с созданием объектов, им проще будет разобраться с остальными частями данной программы.

3) Звук средствами xAudio
Runner позволяет озвучивать многие процессы, для этого достаточно в файле "Runner\DateGlobals.h" , в уже готовых константах прописать пути к Wav файлам. В текущей версии движка звук есть только во время загрузки приложения. Это связано с тем, что звук в Wav может занимать слишком много места, в то время как, даже, в наши дни есть много людей сидящих с низкими скоростями и более того возможно у них вообще помегабайтная оплата. В конце концов – главное не наличие самих звуков, а наличие средств озвучки игровых процессов.
Примечание: xAudio в Windows работает только при специально установленных его компонентов, которые можно установить вместе с DirectX SDK (вер. Март 2009). А это значит, что если нет звука, то нет и необходимых компонентов.

2. Структура движка

Структура движка – это то, с чего необходимо начинать изучение его, даже в том случае, если размер кодов совсем небольшой. Все дело в том, что структура, даже, некоторой небольшой разработки, может иметь очень сложную и запутанную логику взаимодействия, различных процессов, протекаемых внутри самой программы.

Ниже представлен упрощенный вариант иерархии функций, характеризующий и демонстрирующий сам движок, его устройство, логику и работу:

mainRun
  • mn::FirstRun
    • InitXAudio
    • CreateFon
    • SetupTexParamWithMask
    • DXUtil_MatrixPerspectiveSetup
    • LoadTexture
    • SUtil_CreateAndPlaySound
    • RenderImage
    • SUtil_SleepWhilePlay
  • LoadGame
    • mn::LoadingMenu
    • Clear_last_lavel_profile
    • CreateStandartVertexBuffers
      • CreateBuffersTree
      • CreateBuffersCube
      • CreateBuffersCylinder
      • CreateBuffersCone
      • CreateBuffersCircle
      • CreateBuffersPolygoneV
      • CreateBuffersPolygoneDown
    • SetupTextureFiltres
    • LoadGameInterface
    • Tex::CreateStandartTex
    • LoadModelPlayers
    • LoadXObj
    • Tex::AddTex
    • StandartPlayers
    • CreateStandartObjects
      • AddKit
        • AddObj
          • UpdateMemoryObj
          • InitObject
          • CrObjParam
            • SetMatrixObj
            • adjTerrain->getHeight
            • TheTerrain->getHeight
            • CreateLocalObject
              • InitObject
              • CreateBuffersCube
              ...
              • CreateBuffersPolygoneV
      ...
      • AddSoul
      ...
      • AddTree
      • AddBush_1
      • AddBush_2
    • CreateAndSetupPixelFog
    • UnSetupAllLights
  • GameMenu
    • Dxut_MatrixPerspectiveSetup
    • Phisic
      • KeyManaged
        • DXUtil_getKeyTimeLim
        • SUtil_ReCreateAndPlaySound
        • CollisionsPlwithPl
      • UpdatePl
        • SUtil_ReCreateAndPlaySound
      • CollisionsPlwithPl
      • CollisionsPlwithObj
        • CollisionsPlwithKit
        • CollisionsPlwithArmour
        ...
        • CollisionsPlwithDoor
        • CollisionsPlwithDoorCupe
        • CollisionsPlwithStairs
        • CollisionsPlwithLift
        • CollisionsPlwithCube
          • SetPositionObj
      • CollisionsPltoTerrain
        • TheTerrain->getHeight
        • TheTerrain->hitInTerrain
        • TheTerrain->returnPosInTerrain
        • adjTerrain->getHeight
      • TheCamera.setPosition
    • SetupPlayerLights
    • RenderSky
    • TheTerrain->draw
    • AdjTerrain->draw
    • RenderPlayers
    • RenderObjects
      • RenderObjectAndCrParam
        • UpdateObj
          • SetMatrixObj
        • SetupTexParamWithoutMask
        • SetupObjLights
        • RenderObject_
          • RenderLocalObject
          • RenderObject
          • RenderXobject
        • SetupPixelFog
      • SetupTexParamWithMask
      • vers::RenderVers
  ...
  • MainMenu
    • DXUtil_MatrixPerspectiveSetup
    • RenderFon
    • RenderText
    • RenderImage
    • RenderBorder
    • RenderTextButton
    • RenderCursor
    • DXUtil_getKeyTimeLim
    • RenderEffect
  • Cleanup
    • CleanMsgs
    • CleanGameInterface
    • CleanSounds
    • CleanxObjects
    • CleanPlayers
    • Tex::CleanTex
    • vers::CleanVers
    • CleanObjects
    • CleanStandartVertexBuffers();
  ...
  • Msg::RenderAllMsgs

В выше приведенной иерархии были перечисленны все основные функции - например, первоначальный запуск приложения, инициализация самой сцены, освобождение занятой памяти, на примере уничтожения сцены и т.д.

3. Типы данных

Так как в сцене могут отображаться объекты с разными параметрами, то естественно у них есть свой тип данных. Например, ниже представлена структура данных для обычного объекта:

struct Object_
{
  int obj;                      // Тип выводимого объекта на экран объекта (objType)
  int modelColl;                // Модель столкновения
  bool show;                    // Параметр позволяющий скрывать объекты

  float timeNotShow;            // Фиксация времени деактивации обюъекта
  float timeReShow;             // Время пребывания объекта в деактивном состоянии
  bool animated;                // Включить анимацию
  float speedAnimated;          // Угловая скорость вращения объекта вокруг оси Z в радианах в секунду при animated=true,
                                // или скорость перемещения лифта при animated=false
  bool specialTex;              // Специальная текстура, т.е. не дополнительно загруженная,
                                // а именно для специального объекта (например аптечка, броня и т.д.)
  bool doubleRender;            // Вывод сначала внутренней части объекта а потом наружной, вместо одной последней
  bool blend;                   // Включение и отключения прозрачности объекта (в целях 
                                // оптимизации скоростных характиристик при выводе его на экран)

  D3DMATERIAL9 mtrl;            // Материалы поддержываемые объектом (с учетом цветов отдельно для каждого материала)

  int texture;                  // Номер текстуры загруженной в массиве
  float scU,scV,scU1,scV1;      // Параметры масштаббирования для локальных объектов

  bool local;                   // Является ли объект локальным
  bool optionslod;              // Параметр определяющий уровень детализации объхекта (LOD) - системный или песональный
  buffers buf[maxbuf];          // Буферы объекта если он локальный, причем само значение LOD находится именно здесь

  bool rendered;                // Выведен ли объект в текущем кадре (для прозрачных объектов)
  float rx, ry, rz;             // Текущие перпендикулярные расстояния от игрока до граней куба 
                                // (а не предельно допустимое как rminx!)
  float r;                      // Квадратное расстояние до объекта ( необходимо для сортировки
                                // прозрачных объектов, с целью их корректного отображения)

  D3DXVECTOR3 pos;              // Перенос объекта по осям X, Y, Z (Можно tr, но тогда будет путаться с rt)
  D3DXVECTOR3 sc;               // Масштаббирование объекта по осям X, Y, Z
  D3DXVECTOR3 rot;              // Повороты объекта вокруг осей X, Y, Z
  D3DXVECTOR3 vec;              // Вектор перемещения или точка прибытия через телепорт
  D3DXMATRIX ObjWorldMatrices;  // Матрица положения объекта необходима для того, что бы при выводе объекта не
                                // вычислять каждый раз его матрицу и тем самым снизить нагрузку на процессор

  bool phisic;                  // Физика - вычисление столкновения персонажей с объектами и обработка этих столкновения
  bool activate;                // Активация, например, дверь открыта-закрыта или сообщение об открытии двери
}

Причем следует отметить, что объекты могут быть разные, например, примитивы - параллелепипед, сфера, цилиндр, конус, полигон и другие. Также на их основе могут строиться специальные объекты - аптечка, лестница, забор, дверь и другие. Специальные объекты при выводе используют примитивы, в то время как при обработке столкновений могут использоваться специальные модели обработки столкновений, например, взятие аптечки, подъем по лестнице, открытие-закрытие двери, подъем-спуск лифта и т.д.

Помимо обычных объектов можно добавить, более узкий тип, например растительность, для которой требуется гораздо меньше данных. Более того упрощается вывод данных объектов, связи с необходимым для них минимумом параметров, а самое главное, то что нет смысла обрабатывать столкновения, к примеру, с травой (опять же здесь все зависит, от инноваций проекта, да и трава может иметь разные размеры).

// Структура данных для растительности
struct verObj
{
  int texture;                  // Номер текстуры загруженной в массиве

  D3DMATERIAL9 mtrl;            // Материалы поддержываемые объектом (с учетом цветов отдельно для каждого материала)

  D3DXVECTOR3 pos;              // Перенос объекта по осям X, Y, Z (можно tr, но тогда будет путаться с rt)
  D3DXVECTOR3 sc;               // Масштабирование объекта по осям X, Y, Z
  D3DXVECTOR3 rot;              // Повороты объекта вокруг осей X, Y, Z
  D3DXVECTOR3 vec;              // Вектор перемещения или точка прибытия через телепорт
  D3DXMATRIX ObjWorldMatrices;  // Матрица положения объекта необходима для того, что бы при выводе объекта не
                                // вычислять каждый раз его матрицу и тем самым снизить нагрузку на процессор
}

Ниже представлена область данных, отвечающая за вывод объектов, обработку столкновений и загрузку текстур для специальных объектов.

// Специальные объекты поставлены первыми, потому что некоторым из них требуются источники света: конец уровня, 
// телепорт, секретное место. То есть, источник света, что окружает ближайшее пространство вокруг персонажа имеет 
// номер 0, то объекты начинаются с 1. и самое гланое пропадает необходимость создавать отдельные константы, для 
// работы со светом - достаточно использовать номера объектов и все! От этого есть еще один плюс: номера текстур 
// в массиве к специальным объектам соответствуют номерам этих объектов.
namespace objType
{
  const int vb_end_lavel    = 0;   // Конец уровня
  const int vb_teleport     = 1;   // Телепорт
  const int vb_secret_place = 2;   // Секретное место

  const int vb_kit          = 3;   // Аптечка
  const int vb_armour       = 4;   // Броня
  const int vb_armour_mini  = 5;   // Малая броня
  const int vb_soul         = 6;   // Монета
  const int vb_artefact     = 7;   // Артефакт

  const int vb_javelin      = 8;   // Дротик
  const int vb_stake        = 9;   // Осиновый кол	
  const int vb_spade        = 10;  // Лопата

  const int vb_tree         = 11;  // Дерево
  const int vb_bush_1       = 12;  // Куст
  const int vb_bush_2       = 13;  // Куст

  const int vb_grass_1      = 14;  // Трава
  const int vb_grass_2      = 15;  // Трава

  const int vb_fence        = 17;  // Железный забор

  const int vb_door         = 18;  // Дверь
  const int vb_door_cupe    = 20;  // Дверь-купе
  const int vb_stairs       = 21;  // Лестница
  const int vb_lift         = 22;  // Лифт
  const int vb_jump_rope    = 23;  // Прыгалка 

  const int tex_wall        = 24;  // Стена
  const int tex_barrel      = 25;  // Бочка
  const int tex_sky         = 26;  // Небо
  const int vb_sp_max       = 27;  // Константа, для отдельного массива текстур специальных объектов

  // -------- Обычные объекты --------
  const int vb_cube                     = vb_sp_max + 1;   // Куб
  const int vb_sphere                   = vb_sp_max + 2;   // Сфера
  const int vb_cylinder                 = vb_sp_max + 3;   // Цилиндр
  const int vb_cylinder_without_bottoms = vb_sp_max + 4;   // Цилиндр без оснований
  const int vb_cone                     = vb_sp_max + 5;   // Конус
  const int vb_cone_without_bottom      = vb_sp_max + 6;   // Конус без основания
  const int vb_polygoneV                = vb_sp_max + 7;   // Вертикальный полигон

  // -------- Все остальные импортированные объекты --------
  const int vb_max = vb_sp_max + 9;
}

Также в этой области данных есть константа для работы с импортированными объектами X формата, которая позволяет отличить данные объекты от остальных: xObjCount + ObjType::vb_max.

Аналогичным образом представлен тип данных персонажей:

struct pl_
{
  D3DXVECTOR3 vec;          // Вектор передвижения
  D3DXVECTOR3 Mres;         // Предыдущее положение
  D3DXVECTOR3 pos;          // Текущее положение
  D3DXVECTOR3 sc;           // Размеры
  D3DXVECTOR3 rot;          // Повороты

  int type;                 // Тип игрока
  bool phantom;             // Является ли приведением (вкл-откл физ)

  float spHealthRegen;      // Скорость регенерации здоровья (1 - раз в секунду, 2 - 1 раз в 2 секнды ...)
  int healthRegenTo;        // Регенерация здоровья до (например 30)
  int stepHealthRegen;      // Шаг регенерации
  float timeHealthRegen;    // Время последней регенерации

  int health;               // Текущее здоровье
  int maxHealth;            // Максимальное здоровье

  int armour;               // Текущая броня
  int maxArmour;            // Максимальная броня

  bool fire;                // Огонь
  int losses;               // Урон
  int active_ws;            // Активное оружие, т.е. в руках
  int weapons[ws::count];   // Оружейный инвентарь;

  float timeDeath;          // Время смерти (для плавного закраснения экрана)
  float lastStepTime;       // Время последнего шага (для озвучки)

  float lastActivObjTime;   // Время последнего активированного объекта (например, открытой двери)
  float lastShootTime;      // Время последнего выстрела
  float lastSquatTime;      // Время последнего приседания (человек не может приседать с нереальной скоростью!)
  bool activateObj;         // Активация объекта
  bool squat;               // Для приседаний
  float hSquat;             // Высота приседаний
  float hmin;               // Максимальное и минимальное значения для 
  float hmax;               // приседания и стоячем состояниях соответственно
  float jump;               // Высота прыжка
  bool fly;                 // Режим падения (нет звуков топота)
  bool CollisionYup;        // Столкновение с объектом сверху
  bool CollisionYdown;      // Столкновение с объектом снизу
}

4. Создание объектов

Как уже было отмечено ранее, объекты в сцене создаются вручную, что позволяет подробно изучить весть данный процесс. Функции, отвечающие за создание объектов, представляют собой целую иерархию, начиная от самых общих функций, заканчивая созданием конкретных объектов.

Создание простейшего движка, с разработкой собственной физики (Simple Runner)

Ниже представлены самые главные из функций создания объектов.

// Общая функция настройки различных параметров объектов
void CrObjParam (IDirect3DDevice9* pd3dDevice, int number, int ObjType, 
                 float trX, float trY, float trZ, float scX, float scY, float scZ,
                 float r, float g, float b, float a, int tex, bool terrain, bool local,
                 float scu, float scv, float scu1, float scv1)
{
  objects[number].obj = ObjType;  // Тип объекта

  if (ObjType < objType::vb_max) // Если объект не импортир, то модель столкновений может быть любой
     objects[number].modelColl = ObjType;

  objects[number].local = local;

  if (Sc::terrain && terrain) 
     trY = trY + TheTerrain->getHeight( trX, trZ ) +scY;
  // Создание матрицы объекта
  SetMatrixObj(number,trX,trY,trZ,scX,scY,scZ,0,0,0);
  // Инициализация материалов
  objects[number].mtrl = InitMtrl(D3DXCOLOR(r,g,b,a),D3DXCOLOR(r,g,b,a),D3DXCOLOR(0,0,0,0),D3DXCOLOR(0,0,0,0),2);
  if (a >= 1.0f)
     objects[number].blend = false;
  else
     objects[number].blend = true;

  objects[number].texture = tex;
  objects[number].phisic = true;
  objects[number].show = true;
  objects[number].doubleRender = false;
  objects[number].sort = false;
  // Настройка текстурных координат (если объект локальный)
  objects[number].scU = scu;
  objects[number].scV = scv;
  objects[number].scU1 = scu1;
  objects[number].scV1 = scv1;
  objects[number].specialTex = false;

  // Если объект локальный, то создаем для него отдельный буфер
  if (local)
    CreateLocalObject(pd3dDevice, number, options.LODparam, true);
}
// Более упрощенный вариант этой-же процедуры
void CrObjParam (IDirect3DDevice9* pd3dDevice, int number, int ObjType, 
                 float trX, float trY, float trZ, float scX, float scY, float scZ,
                 float r, float g, float b, float a, int tex, bool terrain)
{
    CrObjParam (pd3dDevice,number,ObjType,trX,trY,trZ,scX,scY,scZ,r,g,b,a,tex,terrain,false,1,1,1,1);
}
// Добавление объекта с уменьшенным количеством параметров
void AddObj (IDirect3DDevice9* pd3dDevice, int ObjType, float trX, float trY, float trZ, 
             float scX, float scY, float scZ, float r, float g, float b, float a, int tex, bool terrain)
{
	AddObj(pd3dDevice,ObjType,trX,trY,trZ,scX,scY,scZ,r,g,b,a,tex,terrain,false,1,1,1,1);
}
// Создание специального объекта
void AddKit(IDirect3DDevice9* pd3dDevice, float trX, float trY, float trZ)
{
  AddObj(pd3dDevice,objType::vb_cube,trX,trY,trZ,0.5,0.5,0.5,1,1,1,1,objType::vb_kit,true);
  objects[objCount-1].modelColl = objType::vb_kit;   // Модель обработки столкновений
  objects[objCount-1].timeReShow = 120;              // Время нахождения объекта в скрытом режиме
  objects[objCount-1].speedAnimated = Pid3;          // Угловая скорость вращения
  objects[objCount-1].animated = true;               // Активация вращения
}
// Создание специального объекта
void AddArmour(IDirect3DDevice9* pd3dDevice, float trX, float trY, float trZ)
{
  AddObj (pd3dDevice,objType::vb_cylinder_without_bottoms,trX,trY,trZ,0.5,0.5,0.5,1,1,1,1,objType::vb_armour,true);
  objects[objCount-1].modelColl = objType::vb_armour;   // Модель обработки столкновений
  objects[objCount-1].speedAnimated = Pid3;             // Угловая скорость вращения
  objects[objCount-1].animated = true;                  // Активация вращения
  objects[objCount-1].blend = true;                     // Прозрачность
  objects[objCount-1].doubleRender = true;              // Двойной вывод, сначала вутреняя часть, потом наружная
}

5. Вывод объектов

В выводе объектов наблюдается иерархия еще более массивная, чем в создании объектов. Это связанно, лишь с целью исключения повторения кода. В виду значительного его объема, ниже рассмотрены всего две процедуры: вывод объектов с настройкой параметров и вывод всех объектов сцены, с сортировкой прозрачных объектов.

Создание простейшего движка, с разработкой собственной физики (Simple Runner)
// Вывод конкретного объекта, с настройкой его параметров
void RenderObjectAndCrParam(IDirect3DDevice9* pd3dDevice, int i)
{
  if (!Sc::gamePause ) UpdateObj(i);

  if (objects[i].show)
  {
    // Настройка положения объекта в мировом пространстве
    pd3dDevice->SetTransform(D3DTS_WORLD, &objects[i].ObjWorldMatrices); 

    pd3dDevice->SetMaterial(&objects[i].mtrl);        // Настройка материалов
    pd3dDevice->SetTexture( 0, tex[objects[i].texture]);  // Выбор текстуры

    if (objects[i].specialTex)
        // Выбор специальной текстуры, например, для аптечки
        pd3dDevice->SetTexture(0,sp_tex[objects[i].texture]); 
    else // Выбор обычной загруженной текстуры текстуры
        pd3dDevice->SetTexture( 0, tex[objects[i].texture] ); 

    // Подсвечиваем объект если он телепорт, портал или секретное место
    if ( objects[i].modelColl == objType::vb_end_lavel|| objects[i].modelColl == objType::vb_teleport ||
         objects[i].modelColl == objType::vb_artefact || objects[i].modelColl ==  objType::vb_secret_place)
    {
      pd3dDevice->SetRenderState(D3DRS_FOGENABLE, false);
      SetupTexParamWithoutMask(pd3dDevice);
      if (objects[i].modelColl !=  objType::vb_artefact)
      SetupObjLights(pd3dDevice, objects[i].modelColl+1, objects[i].pos, 0xffff0000,10);
    }
		
    if (objects[i].doubleRender)
    {
      // Отбрасываем все треугольники с порядком обхода вершин по часовой стрелке
      pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_CW);
      // Отображаем внутренюю часть объекта
      RenderObject_( pd3dDevice, i );
      // Отбрасываем все треугольники с порядком обхода вершин против часовой стрелки
      pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_CCW);
    }

    // Отображаем наружную часть объекта
    RenderObject_( pd3dDevice,i );

    // Восстанавливаем настройки после вывода объекта, если он телепорт, портал или секретное место
    if ( objects[i].modelColl == objType::vb_end_lavel|| objects[i].modelColl == objType::vb_teleport || 
         objects[i].modelColl ==  objType::vb_artefact || objects[i].modelColl == objType::vb_secret_place)
    {
       SetupPixelFog(pd3dDevice, &fog);
       SetupTexParamWithMask(pd3dDevice, Sc::alphaRef);
    }
  }
}
void RenderObjects(IDirect3DDevice9* pd3dDevice, float zFar)
{
  // Вывод непрозрачных объектов
  for (int i = 0; i < objCount; i++)
    if (!objects[i].blend && fabs(objects[i].rx)<zFar && fabs(objects[i].rz)<zFar)
      RenderObjectAndCrParam(pd3dDevice,i);

  // Настройка прозрачности
  pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
  pd3dDevice->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE);
  SetupTexParamWithMask(pd3dDevice, Sc::alphaRef);

  int sort = 0;
  // Вывод прозрачных объектов без сортировки
  vers::RenderVers(pd3dDevice, pl[agp].pos.x, pl[agp].pos.z, Sc::zFar);
  for (int i = 0; i < objCount; i++)
    if (objects[i].blend && fabs(objects[i].rx)<zFar && fabs(objects[i].rz)<zFar && !objects[i].sort)
      RenderObjectAndCrParam(pd3dDevice, i);
    else
      // Очищаем значение о выводе прозрачных объектов (для их сортировки)
      if (objects[i].sort)
      {
         sort++;
         objects[i].rendered = false;
         /* Вычисляем квадратичное расстояние до текущего объекта, причем один раз за кадр
         r = sqrt((x1-x2)^2 + (y1-y2)^2 + (z1-z2)^2) - нахождение действительного расстояния до объекта
         r = (x1-x2)^2 + (y1-y2)^2 + (z1-z2)^2 - нахождение квадратного расстояний до объекта (оптимизация)
         r = |x1-x2| + |y1-y2| + |z1-z2| - нахождение относительного расстояния между объектами 
         (сильно оптимизировано и есть небольшие погрешности в высчитывании относительного расстояния)*/
         objects[i].r = objects[i].rx*objects[i].rx + objects[i].ry*objects[i].ry + objects[i].rz*objects[i].rz;
      }

  /* Вывод прозрачных объектов с сортировкой
  Данный алгорим при выводе прозрачных объектов методом сортировки производит 100% качественную сортировку вывода 
  объектов с минимальными	затратами. Он не меняет положение объектов в массиве, потому что игрок постоянно меняет 
  свое положение. Если бы производилась сортировка объектов с их большим количеством свойств в массиве, то это 
  заняло бы гораздо больше времени, нежели просто отсортированный вывод. Качество данной сортировки заключается 
  в том, что она не учитывает положения и размеры объектов. Она пользуется растояниями от персонажа до граней 
  объектов по осям X, Y, Z, которые вычислялись в физике. Также, расстояния вычисляются относительные, 
  т.е. по отношению к самой сцене	они не верные, но по отношению к расположению этих объетов друг-относительно-друга 
  они правильные.*/

  for (int i = 0; i<sort; i++)
  {
    float rmax = 0;  // Минимальное расстояние до объекта
    int num = -1;    // Номер соответствующего объекта

    // Ищем очередной прозрачный объект
    for (int j = 0; j < objCount ; j++)
      if (!objects[j].rendered)  // Необходимы только непрозрачные и не выводимые в данном кадре объекты
        if (rmax<=objects[j].r)
        {
           rmax = objects[j].r;
           num  = j;
        }
    // Выводим очередной самый дальний после предыдущева объекта объект
    if (num >= 0 && fabs(objects[num].rx)<zFar && fabs(objects[num].rz)<zFar)
         RenderObjectAndCrParam(pd3dDevice, num);
		
    objects[num].rendered = true;
    /* Данная операция находится в конце функции вывода объекта, но она срабатывает только тогда, 
    когда выводимый объект зоне видимости! А это значит, что после прозрачного сортируемого объекта находящегося зоны 
    видимоси ни какой другой прозрачный сортируемый объект не отобразится на экране!*/
  }
}
 
Страницы: 1 2