NeHe Tutorials Народный учебник по OpenGL
Урок X4. OpenGL

В этом уроке будет продемонстрирован варварский и веселый способ быстрого получения игрового приложения на примере преобразования урока 30 «Определение столкновений и моделирование законов физики» в урок X4 «Игры с УФО» с помощью уроков 07, 11, 20, 32, 34.

 

Все действия будут производиться в среде Visual Studio Professional 2010. С небольшими модификациями все эти манипуляции могут быть осуществлены в любой другой версии Visual Studio от 7 и выше. Для человека, имеющего некоторый опыт работы с  Visual Studio, не составит труда проделать все это независимо от версии.  В среде Visual Studio Professional 2010 можете повторять все этапы, как они здесь описаны.

 

Этапы преобразования:

1.    Преобразование проекта Collision в новый проект UFOgame (урок 30).

2.    Замена цилиндрических колонн на ландшафт поверхности (урок 34).

3.    Применение сменных текстур к стенкам куба и небу (урок 07).

4.    Применение сменных текстур к ландшафту поверхности (урок 11).

5.    Придание шарам вида НЛО.

6.    Замена фиксированных массивов с шарами на объектные списки.

7.    Команды вращения изображения и изменения количества шаров.

8.    Выбор НЛО в качестве объекта наблюдения (урок 32).

9.    Нанесение текстуры на НЛО (урок 20).

10.  Управление ракурсом наблюдения выбранного НЛО.

 

1. Преобразование проекта Collision в новый проект UFOgame (урок 30).

 

Вот последовательность действий:

-        выбираем в директории  LessonsGLCode_2010 урок 30  Lesson30 и делаем рядом его копию (например, LessonXN);

-        в этой вновь созданной папке и во всех вложенных в нее во всех названиях меняем словосочетание Collision на UFOgame;

-        файлы UFOgame.vcproj, UFOgame.vcxproj, UFOgame.vcxproj.filters, UFOgame.rc, UFOgame.sln открываем с помощью обычного Notepad и везде заменяем словосочетание Collision  на UFOgame (команда CTRL + H);

-        во всех файлах проекта заменяем словосочетание Collision на UFOgame (команда CTRLSHIFT + H).

 

            Теперь мы можем запустить отладку (команда «Запуск без отладки»(Start Without Debugging)) и убедиться в том, что в новом проекте UFOgame выполняются все функции исходной программы Collision. То есть мы получили заготовку, в которой все свойства  Collision сохраняются, но уже нигде в тексте это название не употребляется, вместо него используется UFOgame. Для полноты картины мы сделаем  во всех файлах проекта замену идентификатора _30  на  _XN(команда CTRL + SHIFT + H), название файла 30_UFOgameDrawInit.cpp на  XN_UFOgameDrawInit.cpp, название файла 30_GLHelp.txt на XN_GLHelp.txt,  в файле XN_GLHelp.txt поменяем 30 на XN.Теперь наш новый проект  под идентификатором XN будет виден в перечне программ из любой другой программы из директории LessonsGLCode_2010 и может быть из неё запущен, как и все остальные.

Все дальнейшие текстовые преобразования будут производиться в  XN_UFOgameDrawInit.cpp .

 

2. Замена цилиндрических колонн на ландшафт поверхности (урок 34).

 

Следующее наше действие: заменить цилиндрические колонны на ландшафт поверхности. Убрать колонны очень просто: в файле XN_CollisionDrawInit.cpp в подпрограмме DrawGLScene_XN нужно убрать (или заключить в комментарии) блок, относящийся к render columns (cylinders).

 

Для изображения ландшафта обратимся к уроку 34 «Построение красивых ландшафтов с помощью карты высот»:

-        в меню «Проект->Существующий элемент»  присоединим к нашему проекту файл 34_HeightMapDrawInit.cpp;

-        в папку Data копируем файл Terrain.raw из урока 34;

-        в начале файла  вставим объявления из 34_HeightMapDrawInit.cpp:

 

#define             MAP_SIZE       1024        // Size Of Our .RAW Height Map

#define             STEP_SIZE      16          // Width And Height Of Each Quad

#define             HEIGHT_RATIO  1.5f         //Ratio That The Y Is Scaled According To The X And Z

static BYTE g_HeightMap[MAP_SIZE*MAP_SIZE];    // Holds The Height Map Data

static float scaleValue = 0.15f;              // Scale Value For The Terrain

extern RECT m_viewRect;

void RenderHeightMap(BYTE pHeightMap[]);        // This Renders The Height Map As Quads

void LoadRawFile(LPSTR strName, int nSize, BYTE *pHeightMap);

int Height(BYTE *pHeightMap, int X, int Y);    // This Returns The Height From A Height Map Index

void SetVertexColor(BYTE *pHeightMap, int x, int y);// Sets The Color Value For A Particular Index,     

                                                    //  Depending On The Height Index

static bool         bRender = TRUE;

 

Чтобы привести размеры ящика к размерам ландшафта, введем объявление

 

GLfloat aLen = 512;      // len of wall(original 320);

 

и заменим все значения 320 на aLen(команда CTRL + H);

 

Вставляем в конец процедуры int InitGL_XN(void) процедуру:

 

LoadRawFile("Data/Terrain.raw", MAP_SIZE * MAP_SIZE, g_HeightMap); // (Lesson 34)

 

Для изображения ландшафта вставляем в конец процедуры int DrawGLScene_XN(GLvoid) строки:

 

      glMatrixMode(GL_MODELVIEW);

            glPushMatrix();

       glTranslatef(-aLen,-aLen,-aLen);

       RenderHeightMap(g_HeightMap);                  // Render The Height Map

       glPopMatrix();

 

Запускаем отладку (команда «Запуск без отладки»(Start Without Debugging)) и убеждаемся в том, что в новом проекте UFOgame появился ландшафт. Но пейзаж бледноват, и мы переходим к следующему этапу.

 

3. Применение сменных текстур к стенкам куба и небу (урок 07).

 

Введем объявления:

 

extern CWordArray m_globTexture;        // список всех текстур

extern CDWordArray m_maskTexture;       // список текстур, имеющих маски

 

static CWordArray m_groundTexture;             //список текстур ландшафта

static CWordArray m_skyTexture;         //список текстур стенок и неба

static GLuint m_idPortHoles;              //текстура иллюминатора УФО  

static GLuint m_idCrossHair; ;            //текстура перекрестия прицела  

static GLuint m_idSpark;            //текстура взрыва   

static GLuint filterF = 0;                       //текущая текстура ландшафта

static GLuint filterG = 0;                       //текущая текстура стенок и неба

 

void LoadGLTexturesImages(CStringArray * sArray);  // Создание текстур из изображений в файлах

void RemoveAllTextures(void);

int LoadGLTextureImage(CString fName, BOOL bMask);

GLuint LoadGLTextureImage(CString fName);

COLORREF ColorRandom(int rMin, int rMax);

 

и процедуру void LoadGLTextures_XN() заменим на следующую:

 

void LoadGLTextures_XN()

{

       CStringArray sArray;                //список имен файлов для текстур 

       sArray.Add("data/boden.jpg");

       sArray.Add("data/marble.jpg");

       sArray.Add("data/Base.JPG");

       sArray.Add("data/Bumps.JPG");

       sArray.Add("data/Glass.JPG");

       sArray.Add("data/Lights.JPG");

       sArray.Add("data/Wand.JPG");

       sArray.Add("data/Logo.bmp");

 

       sArray.Add("data/zodiak.jpg");

       sArray.Add("data/sky_01.jpg");

       sArray.Add("data/sky_02.jpg");

       sArray.Add("data/sky_03.jpg");

       sArray.Add("data/sky_04.jpg");

       sArray.Add("data/sky_05.jpg");

       sArray.Add("data/sky_06.jpg");

       sArray.Add("data/Logo.bmp");

 

   LoadGLTexturesImages(&sArray);

   sArray.RemoveAll();

 

for( int i = 0; i < 8; i++)

  m_groundTexture.Add(m_globTexture.GetAt(i));

 

for( int i = 0; i < 8; i++)

  m_skyTexture.Add(m_globTexture.GetAt(i+8));

 

 

 m_idPortHoles = LoadGLTextureImage("data/PortHoles_1.bmp", TRUE);

 m_idCrossHair = LoadGLTextureImage("data/Crosshair.bmp", TRUE);

 m_idSpark = LoadGLTextureImage("data/Spark.bmp");

 

}

 

Естественно, все перечисленные в LoadGLTextures_XN файлы должны находиться в директории Data (или вы можете поместить вместо них любые другие файлы изображений, только не забудьте вписать их в текст).

 

В процедуре DrawGLScene_XN перед отрисовкой стен заменим фильтр установки текстур на следующий: 

 

//render walls(planes) with texture

filterF %= m_skyTexture.GetSize();     

glBindTexture(GL_TEXTURE_2D, m_skyTexture.GetAt(filterF));

 

В процедуре ProcessKeyBoard_XN добавим команду изменения текстур стенок и неба:

 

else if (strCmnd == "F")   filterF++;

 

Запускаем отладку (команда «Запуск без отладки»(Start Without Debugging)) и убеждаемся в том, что в новом проекте UFOgame на стенках появилось изображение, и оно меняется при нажатии клавиши F. Однако на небе изображения не появилось, и изображения получаются перевернутыми. Все дело в порядке следования текстурных вершин:

 

//Top Face

       glTexCoord2f(0.0f, 0.0f); glVertex3f(-aLen,aLen,-aLen);

       glTexCoord2f(1.0f, 0.0f); glVertex3f(aLen,aLen,-aLen);

       glTexCoord2f(1.0f, 1.0f); glVertex3f(aLen,aLen,aLen);

       glTexCoord2f(0.0f, 1.0f); glVertex3f(-aLen,aLen,aLen);

 

Можете сами поупражняться поменять их порядок, но для экономии времени просто скопируйте эти блоки из урока X4. Теперь с изображениями на стенках и на небе все должно быть в порядке, а для изображения взрыва заменим выбор текстуры на следующий:

 

   glBindTexture(GL_TEXTURE_2D, m_idSpark); 

 

Запускаем отладку (команда «Запуск без отладки»(Start Without Debugging)) и убеждаемся в том, что в новом проекте UFOgame текстура стенок и неба изменяется, но ландшафт пока еще без текстуры.

 

4. Применение сменных текстур к ландшафту поверхности (урок 11).

 

Чтобы применить сменные текстуры к ландшафту, возьмем процедуру RenderHeightMap из урока 34 и преобразуем ее, используя технологии урока 11:

 

void RenderHeightMap(BYTE pMountMap[], GLuint texid) //Lesson 44 Визуализация карты высоты с помощью квадратов

{

   GLuint B_LIGHTING = glIsEnabled(GL_LIGHTING);

 

   if(texid > 0)

           glDisable(GL_LIGHTING);

   else

        glEnable(GL_LIGHTING);

if(texid > 0)

{

       glEnable(GL_TEXTURE_2D);

       filterG %= m_groundTexture.GetSize();

       glBindTexture(GL_TEXTURE_2D, texid);

}

 

  if(!pMountMap) return;     // Данные корректны?

 if(bRender)            // Что хотим визуализировать?

    glBegin( GL_QUADS ); // Полигоны

  else

    glBegin( GL_LINES ); // Линии

for ( int X = 0; X < MAP_SIZE; X += STEP_SIZE )

   for (int  Y = 0; Y < MAP_SIZE; Y += STEP_SIZE )

    {

      // Получаем (X, Y, Z) координаты нижней левой вершины

 

int X1 = X+STEP_SIZE;

int Y1 = Y+STEP_SIZE;

            

float xx  = X/(float)MAP_SIZE;      

float yy  = Y/(float)MAP_SIZE;     

float xx1 = X1/(float)MAP_SIZE;    

float yy1 = Y1/(float)MAP_SIZE;    

 

 

//vertex X,Y1:

int y = Height(pMountMap, X, Y1 ); 

if(texid <= 0)  SetVertexColor(pMountMap, X, Y1);

else  glTexCoord2f(xx, yy1);

glVertex3i(X, y, MAP_SIZE - Y1);     

 

//vertex X,Y:

y = Height(pMountMap, X, Y ); 

   if(texid <= 0) SetVertexColor(pMountMap, X, Y);

else  glTexCoord2f(xx, yy);

glVertex3i(X, y, MAP_SIZE - Y);   

 

//vertex X1,Y1:

 y = Height(pMountMap, X1, Y );

if(texid <= 0) SetVertexColor(pMountMap, X1, Y);

else  glTexCoord2f(xx1, yy);

glVertex3i(X1, y, MAP_SIZE - Y);     

 

//vertex X1,Y1:

 y = Height(pMountMap, X1, Y1 );

 if(texid <= 0) SetVertexColor(pMountMap, X1, Y1);

else glTexCoord2f(xx1, yy1);

glVertex3i(X1, y, MAP_SIZE -Y1);     

      

       }

 

  glEnd();

 glColor4f(1.0f, 1.0f, 1.0f, 1.0f);      // Сбрасываем цвет

 

 B_LIGHTING ? glEnable(GL_LIGHTING): glDisable;

 

}

 

В процедуре ProcessKeyBoard_XN добавим команду изменения текстуры ландшафта:

 

       else if (strCmnd == "G")   filterG++;

 

В процедуре DrawGLScene_XN изображение ландшафта:

 

       filterG %= m_groundTexture.GetSize();  

RenderHeightMap(g_HeightMap, m_groundTexture[filterG]); // Render The Height Map

 

Запускаем отладку (команда «Запуск без отладки»(Start Without Debugging)) и убеждаемся в том, что в новом проекте UFOgame текстура ландшафта изменяется . Но пока мы видим только шарики, а не НЛО.

             

5. Придание шарам вида НЛО

 

Cделаем теперь наши шарики более похожими на НЛО:

 

void DrawUFO(void) 

{

glPushMatrix();

glScalef(1,.3f,1);

gluSphere(cylinder_obj,20,20,20);

glPopMatrix();

}

 

Вставим эту процедуру вместо gluSphere(cylinder_obj,20,20,20):

 

DrawUFO();

 

Запускаем отладку (команда «Запуск без отладки»(Start Without Debugging)) и убеждаемся в том, что в новом проекте UFOgame шарики уже больше похожи на НЛО.

 

6. Замена фиксированных массивов с шарами на объектные списки.

 

Чтобы иметь больше возможностей манипулировать цветом НЛО, введем структуру цвета:

 

struct myColor

{

       GLfloat clr[3];

};

 

Чтобы иметь возможность изменять количество НЛО, заменим фиксированные массивы на объектные списки:

 

static CPtrArray ArrayVel;        // holds velocity of balls

static CPtrArray ArrayPos;           // position of balls

static CPtrArray OldPos;             // old position of balls

static CPtrArray m_colorArray;       // color of balls

 

Чтобы иметь возможность прыгать с одного НЛО на другое, введем номер текущей тарелки:

 

static int m_curObj = 0;

 

Доступ к информации о каждом НЛО в зависимости от его номера задается процедурами:

 

myColor * GetMyColor(int i)      // цвет НЛО

{

       if(i < 0)

             return NULL;

       if(i >= m_colorArray.GetSize())

             return NULL;

       return (myColor *) m_colorArray.GetAt(i);

}

TVector * GetVel(int i)           //скорость НЛО

{

       if(i < 0)

             return NULL;

       if(i >= ArrayVel.GetSize())

             return NULL;

       return (TVector *) ArrayVel.GetAt(i);

}

TVector * GetPos(int i)           //позиция НЛО

 

{

       if(i < 0)

             return NULL;

       if(i >= ArrayPos.GetSize())

             return NULL;

       return (TVector *) ArrayPos.GetAt(i);

}

TVector * GetOldPos(int i)        //старая позиция НЛО

{

       if(i < 0)

             return NULL;

       if(i >= OldPos.GetSize())

             return NULL;

       return (TVector *) OldPos.GetAt(i);

}

 

Чтобы иметь возможность наблюдать свое НЛО со стороны, введем переменную:

 

static TVector m_Var(25,25,0); //позиция с которой наблюдатель смотрит на свое НЛО

 

Чтобы иметь возможность управлять вращением сцены, введем переменную:

 

static BOOL m_bRotate = FALSE;                  //флаг вращения сцены

 

Процедура установки позиции камеры меняется:

 

void CameraLookAt_XN(void)

{

    //set camera in hookmode

       if (hook_toball1)

       {

             TVector unit_followvector=(* GetVel(m_curObj));

             unit_followvector.unit();

 

             gluLookAt((* GetPos(m_curObj)).X()+m_Var.X(),(* GetPos(m_curObj)).Y()+m_Var.Y() ,(* GetPos(m_curObj)).Z()+m_Var.Z() ,

                    (* GetPos(m_curObj)).X()+(* GetVel(m_curObj)).X() ,(* GetPos(m_curObj)).Y()+(* GetVel(m_curObj)).Y() ,

                    (* GetPos(m_curObj)).Z()+(* GetVel(m_curObj)).Z() ,0,1,0); 

   

    }

       else

       {

           gluLookAt(pos.X(),pos.Y(),pos.Z(), pos.X()+dir.X(),pos.Y()+dir.Y(),pos.Z()+dir.Z(), 0,1.0,0.0);

        glRotatef(camera_rotation,0,1,0);

       }

}

 

В процедуре DrawGLScene_XN поставим эту команду в самом начале вместо блока //set camera in hookmode.

 

Инициализация  НЛО изменяется:

void AppendUFO(void)

{

           myColor * pM = new myColor;

             m_colorArray.Add(pM);

             COLORREF rgb = ColorRandom(64, 196);

             pM->clr[0] = GetRValue(rgb)/255.f;

             pM->clr[1] = GetGValue(rgb)/255.f;

             pM->clr[2] = GetBValue(rgb)/255.f;

 

             TVector * pV = new TVector;

             ArrayPos.Add(pV);

             pV = new TVector;

             ArrayVel.Add(pV);

             pV = new TVector;

             OldPos.Add(pV);

}

void InitUFO(void)

{

       for(int i = 0; i< NrOfBalls; i++)

             AppendUFO();

}

 

Вместо InitVars :

void InitVars_XN()

{

       GLfloat tLen = aLen - 20;

        //create palnes

       pl1._Position=TVector(0,-tLen+200,0);

       pl1._Normal=TVector(0,1,0);

       pl2._Position=TVector(tLen,0,0);

       pl2._Normal=TVector(-1,0,0);

       pl3._Position=TVector(-tLen,0,0);

       pl3._Normal=TVector(1,0,0);

       pl4._Position=TVector(0,0,tLen);

       pl4._Normal=TVector(0,0,-1);

       pl5._Position=TVector(0,0,-tLen);

       pl5._Normal=TVector(0,0,1);

    pl6._Position=TVector(0,tLen,0);

       pl6._Normal=TVector(0,-1, 0);

 

       cylinder_obj= gluNewQuadric();

       gluQuadricTexture(cylinder_obj, GL_TRUE);

 

 

    //Set initial positions and velocities of balls

       //also initialize array which holds explosions

    InitUFO();

    ResetUFO();

}

 

 

void ResetUFO(void)

{

    //Set initial positions and velocities of balls

       //also initialize array which holds explosions

       ExplosionArray[0]._Alpha=0;

       ExplosionArray[0]._Scale=1;

       ExplosionArray[1]._Alpha=0;

       ExplosionArray[1]._Scale=1;

       ExplosionArray[2]._Alpha=0;

       ExplosionArray[2]._Scale=1;

       GLfloat r = 20;

       GLfloat bLen = aLen * 0.9f;

       for (int i=0; i<NrOfBalls; i++)

       {

             GLfloat vv = 5;

             (* GetVel(i)) =

                    TVector(vv *(1.0f - 2.0f *(float)(rand()%100)*0.01f),

                        vv *(1.0f - 2.0f *(float)(rand()%100)*0.01f),

                    vv *(1.0f - 2.0f *(float)(rand()%100)*0.01f));

            (* GetPos(i))=TVector(-500+i*75, 300, -500+i*50);

              ExplosionArray[i]._Alpha=0;

            ExplosionArray[i]._Scale=1;

       }

       for (int i=10; i<20; i++)

       {

         ExplosionArray[i]._Alpha=0;

            ExplosionArray[i]._Scale=1;

       }

}

 

В процедуре DrawGLScene_XN изображение НЛО:

for (int i=0;i<NrOfBalls;i++)

       {

             myColor * pM = GetMyColor(i);

 

             glPushMatrix();

             glTranslated((* GetPos(i)).X(),(* GetPos(i)).Y(),(* GetPos(i)).Z());

             glColor3f(pM->clr[0],pM->clr[1],pM->clr[2]);

 

    glEnable(GL_DEPTH_TEST);          

       glEnable(GL_LIGHTING);              

       glEnable(GL_AUTO_NORMAL);              

       glEnable(GL_NORMALIZE);

    glDisable(GL_TEXTURE_2D);

   

             DrawUFO();

//ApplyMaskTextureToUFO(LOWORD(m_maskTexture.GetAt(0)),HIWORD(m_maskTexture.GetAt(0)));

 

             glPopMatrix();

       }

 

Процедура FindBallCol_XN тоже соответственно изменяется:

 

int FindBallCol_XN(TVector& point, double& TimePoint, double Time2, int& BallNr1, int& BallNr2)

{

       TVector RelativeV;

       TRay rays;

       double MyTime=0.0, Add=Time2/150.0, Timedummy=10000, Timedummy2=-1;

       TVector posi;

      

       //Test all balls against eachother in 150 small steps

       for (int i=0;i<NrOfBalls-1;i++)

       {

        for (int j=i+1;j<NrOfBalls;j++)

        {    

                 RelativeV=(* GetVel(i))-(* GetVel(j));

                    rays=TRay((* GetOldPos(i)),TVector::unit(RelativeV));

                    MyTime=0.0;

 

                    if ( (rays.dist((* GetOldPos(j)))) > 40) continue;

 

                    while (MyTime<Time2)

                    {

                       MyTime+=Add;

                       posi=(* GetOldPos(i))+RelativeV*MyTime;

                       if (posi.dist((* GetOldPos(j)))<=40)

{

                                  point=posi;

                                  if (Timedummy>(MyTime-Add)) Timedummy=MyTime-Add;

                                  BallNr1=i;

                                  BallNr2=j;

                                  break;

                           }

                    }

        }

       }

       if (Timedummy!=10000) { TimePoint=Timedummy;

                               return 1;

       }

       return 0;

}

 

Вместо процедуры idle тоже соответственно  будет idle_XN, но она длинная, поэтому скопируйте сразу ее из проекта урок X4 «Игры с УФО», и в ней все изменения связаны только со сменой адресации НЛО.

 

Запускаем отладку (команда «Запуск без отладки»(Start Without Debugging)) и убеждаемся в том, что в новом проекте UFOgame картинка не сильно изменилась. Но теперь мы можем управлять количеством НЛО и выбирать дно из них.

 

7. Команды вращения изображения и изменения количества шаров.

 

Для управления количеством НЛО добавим процедуры:

 

void IncreaseUFOnum(void)

{

       if( NrOfBalls >= 50)

       return;

       AppendUFO();

 

             GLfloat vv = 5;

             (* GetVel(NrOfBalls)) =

                    TVector(vv *(1.0f - 2.0f *(float)(rand()%100)*0.01f),

                        vv *(1.0f - 2.0f *(float)(rand()%100)*0.01f),

                    vv *(1.0f - 2.0f *(float)(rand()%100)*0.01f));

 

             GLfloat bLen = aLen - 20;

        GLfloat xx = -bLen + 2*bLen*(rand()%100)*0.01f;

             GLfloat yy = -bLen + 200 + (2*bLen - 200)*(rand()%100)*0.01f;

             GLfloat  zz = -bLen + 2*bLen*(rand()%100)*0.01f;

             (* GetPos(NrOfBalls))= TVector(xx, yy,zz);

 

NrOfBalls++;

}

void DecreaseUFOnum(void)

{

       if(ArrayPos.GetSize() <=1)

             return;

          TVector * pV = (TVector *)ArrayPos.GetAt(0);

          ArrayPos.RemoveAt(0);

          delete pV;

 

          pV = (TVector *)ArrayVel.GetAt(0);

          ArrayVel.RemoveAt(0);

          delete pV;

       

          pV = (TVector *)OldPos.GetAt(0);

          OldPos.RemoveAt(0);

          delete pV;

      

          myColor * pC = (myColor *)m_colorArray.GetAt(0);

          m_colorArray.RemoveAt(0);

       delete pC;

   NrOfBalls --;

   if(m_curObj>=NrOfBalls)

      m_curObj = 0;

 

}

 

Теперь в процедуре ProcessKeyBoard_XN добавим команды:

 

       else if (strCmnd == "A")   IncreaseUFOnum();

       else if (strCmnd == "D")   DecreaseUFOnum();

       else if (strCmnd == "B")   m_bRotate = !m_bRotate;

 

Запускаем отладку (команда «Запуск без отладки»(Start Without Debugging)) и убеждаемся в том, что в новом проекте UFOgame вновь введенные команды работают.

 

Если вы добрались до этого момента, и у вас все получилось, то это означает, что вы уже все поняли из того, что я хотел рассказать в этом уроке. Поэтому, чтобы не терять время на дальнейшее изложение, вы можете просто скопировать участки программы, соответствующие пунктам 8, 9, 10 из проекта урок X4 «Игры с УФО» и у вас получится точная его копия, в которой вы можете навешивать свои собственные эффекты и команды. И, если вы добрались до конца этого урока, то вы уже точно можете это делать.

 

Код к уроку

 

LessonsCode_2010.7z (5.09 Mb)

© Владимир Петров
petrov@msun.ru
Моя страница

PMG  17 апреля 2013