Mi Desktop

Snapshot
G.I.R.

Impacto Visual

iv(336).jpg

Dicen los que saben

Considero más valiente al que conquista sus deseos que al que conquista a sus enemigos, ya que la victoria más dura es la victoria sobre uno mismo.

Aristóteles

Encuesta

Paranoid Puppets
 

Syndicate

Estadisticas

OS: Linux
PHP: 5.2.11
MySQL: 5.0.84-percona-highperf-b18
Time: 23:59
Caching: Disabled
GZIP: Disabled
News: 177
Visitors: 171129
We have 46 guests online

Buscar en el sitio

Fedora 12 - Countdown


Start arrow Tutoriales arrow Toma el control [Tutorial DirectX #5]
Toma el control [Tutorial DirectX #5] E-mail
miércoles, 03 septiembre 2008

Este es el quito y ultimo tutorial sobre DirectX.

Hemos cubierto las tecnologías principales para el desarrollo de videojuegos sobre la plataforma directx que son:

Direct3D
XACT
DirectInput

La idea es que poco a poco veamos más a fondo cada una de estas tecnologías.

Cabe señalar que estas tecnologías encierran algunas otras, pero ya verán en su momento.

Otra vez partimos del supuesto de que han seguido los 4 tutoriales, así que todo el código que se genero en ellos aquí no se explicara aunque se entregara el proyecto final [de todos los tutoriales] y en el, esta código esta bien documentado.

DirectInput nos permite interactuar con el usuario, específicamente, saber que quiere que hagamos, mediante el teclado o el mouse.

Así que comenzamos agregando dinput8.lib a las dependencias de nuestro proyecto, ya debemos de tener todas las anteriores, mas las que son heredadas por default.

dInput_aDependencies.jpg

 

Después agregar una macro y una librería.

#define _WIN32_DCOM

#define null NULL

 

#include <d3d9.h>

#include <d3dx9.h>

#include <d3dx9core.h>

 

#include <xact.h>

 

La macro solo dicta la versión de DirectInput que usaremos, en este caso será la 8.

#define DIRECTINPUT_VERSION 0x0800

 

Después agregamos la librería dinput.h, la cual contiene todas las funciones, interfaces, clases, tipos y macros que necesitaremos.

#include <dinput.h>

 

struct Objeto

{

      IDirect3DTexture9* Textura;

      D3DXVECTOR3 Posicion;

};

 

struct ObjetoBola : public Objeto

{

      int VelX, VelY;

};

 

struct AudioSt

{

    IXACTEngine* pEngine;

    IXACTWaveBank* pWaveBank;

    IXACTSoundBank* pSoundBank;

    unsigned short iSonido;

 

    void* pbWaveBank;

    void* pbSoundBank;

};

 

IDirect3D9* D3D9 = null;

IDirect3DDevice9* D3D9Dispositivo = null;

ID3DXSprite* Sprite;

 

Objeto* PaletaJugador;

Objeto* PaletaCPU;

ObjetoBola* Bola;

 

IXACTEngine* pXACT3Engine;

AudioSt audio;

 

A continuación debemos de crear nuestras variables que nos ayudaran a manejar DirectInput [ej. obtener información del teclado.

IDirectInput8* DirectInput = NULL;

IDirectInputDevice8* DispositivoDITeclado = NULL;

 

Ahora, al resto del código que se encarga comenzar todos los motores, debemos agregarle las instrucciones que se encargaran de inicializar DirectInput, así que buscamos la siguiente linea: audio.iSonido = audio.pSoundBank->GetCueIndex("sonido") y debajo va el nuevo código.

Recuerda que el código en verde no será explicado por que ya lo tienes.

void Liberar();

 

long Iniciar(HWND hWindow)

{

      if (null == (D3D9 = Direct3DCreate9(D3D_SDK_VERSION)))

            return E_FAIL;

      D3DDISPLAYMODE ModosDisplay = {0};

      D3D9->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &ModosDisplay);

 

      D3DPRESENT_PARAMETERS pPresentacion = {0};

      pPresentacion.Windowed = true;

      pPresentacion.SwapEffect = D3DSWAPEFFECT_DISCARD;

      pPresentacion.BackBufferFormat = ModosDisplay.Format;

      pPresentacion.EnableAutoDepthStencil = true;

      pPresentacion.AutoDepthStencilFormat = D3DFMT_D16;

 

      if (FAILED(D3D9->CreateDevice(D3DADAPTER_DEFAULT,

            D3DDEVTYPE_HAL,

            hWindow,

            D3DCREATE_SOFTWARE_VERTEXPROCESSING,

            &pPresentacion,

            &D3D9Dispositivo)))

      {

            return E_FAIL;

      }

 

      ::D3D9Dispositivo->SetRenderState(D3DRS_ALPHABLENDENABLE, true);

 

      if (FAILED(D3DXCreateSprite(::D3D9Dispositivo, &Sprite)))

            return E_FAIL;

 

      ::PaletaJugador = new Objeto();

      ::PaletaJugador->Posicion = D3DXVECTOR3(5.0f, 200.0f, 0.0f);

      if (FAILED(D3DXCreateTextureFromFile(::D3D9Dispositivo, L"tJugador.jpg", &PaletaJugador->Textura)))

            return E_FAIL;

 

      ::PaletaCPU = new Objeto();

      ::PaletaCPU->Posicion = D3DXVECTOR3(758.0f, 200.0f, 0.0f);

      if (FAILED(D3DXCreateTextureFromFile(::D3D9Dispositivo, L"tCPU.jpg", &PaletaCPU->Textura)))

            return E_FAIL;

     

      ::Bola = new ObjetoBola();

      ::Bola->Posicion = D3DXVECTOR3(350.0f, 250.0f, 0.0f);

      ::Bola->VelX = ::Bola->VelY = 2;

      if (FAILED(D3DXCreateTextureFromFile(::D3D9Dispositivo, L"tBola.jpg", &Bola->Textura)))

            return E_FAIL;

 

      ::D3D9Dispositivo->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);

      long hr;

      void* hFile;

      unsigned long dwFileSize;

      unsigned long dwBytesRead;

      void* hMapFile;

 

      ZeroMemory(&audio, sizeof(AudioSt));

 

      hr = CoInitializeEx(null, COINIT_MULTITHREADED);

      if(SUCCEEDED(hr))

            hr = XACTCreateEngine(0, &audio.pEngine);

 

      if(FAILED(hr) || audio.pEngine == null)

            return E_FAIL;

 

      XACT_RUNTIME_PARAMETERS xrParams = {0};

      xrParams.lookAheadTime = XACT_ENGINE_LOOKAHEAD_DEFAULT;

      hr = audio.pEngine->Initialize(&xrParams);

 

      if(FAILED(hr))

            return hr;

 

      hFile = CreateFile( L"audioWB.xwb", GENERIC_READ, FILE_SHARE_READ, null, OPEN_EXISTING, 0, null );

      if( hFile != INVALID_HANDLE_VALUE )

      {

            dwFileSize = GetFileSize( hFile, null );

            if(dwFileSize != -1)

            {

                  hMapFile = CreateFileMapping( hFile, null, PAGE_READONLY, 0, dwFileSize, null );

                  if(hMapFile)

                  {

                        audio.pbWaveBank = MapViewOfFile( hMapFile, FILE_MAP_READ, 0, 0, 0 );

                        if(audio.pbWaveBank)

                        {

                             hr = audio.pEngine->CreateInMemoryWaveBank( audio.pbWaveBank, dwFileSize, 0, 0, &audio.pWaveBank );

                        }

                        CloseHandle(hMapFile);

                  }

            }

            CloseHandle(hFile);

      }

      if(FAILED(hr))

            return E_FAIL;

 

      hr = E_FAIL;

      hFile = CreateFile( L"audioSB.xsb", GENERIC_READ, FILE_SHARE_READ, null, OPEN_EXISTING, 0, null );

      if( hFile != INVALID_HANDLE_VALUE )

      {

            dwFileSize = GetFileSize( hFile, null );

            if( dwFileSize != -1 )

            {

                  audio.pbSoundBank = new BYTE[dwFileSize];

                  if( audio.pbSoundBank )

                  {

                        if( 0 != ReadFile( hFile, audio.pbSoundBank, dwFileSize, &dwBytesRead, null ) )

                        {

                             hr = audio.pEngine->CreateSoundBank(audio.pbSoundBank, dwFileSize, 0, 0, &audio.pSoundBank);

                        }

                  }

            }

            CloseHandle( hFile );

      }

      if( FAILED( hr ) )

            return E_FAIL;

 

      audio.iSonido = audio.pSoundBank->GetCueIndex("sonido");

 

Lo primero es crear una instancia de DirectInput ayudándonos con el método DirectInput8Create al cual se le pasan algunos los parámetros de creación, como la versión de DirectInput, una identificador de la interfaz que usaremos, en este caso interfaces de DirectInput8, también se le pasa un puntero [de hecho, puntero a puntero) con nuestra variable para que llene los campos del objeto.

      if (FAILED(DirectInput8Create(GetModuleHandle(null), DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&DirectInput, NULL)))

            return E_FAIL;

 

Enseguida creamos el dispositivo al que estará vinculado DirectInput, en este caso será con el teclado, como lo podemos ver en los parámetros que se le pasan a la función.

      if (FAILED(DirectInput->CreateDevice(GUID_SysKeyboard, &::DispositivoDITeclado, NULL)))

            return E_FAIL;

 

Una vez que hemos creado el dispositivo debemos darle el formato de los datos que obtendremos, en este caso seran el formato por default del teclado, osea que ya que lo vinculamos con un dispositivo debemos decirle como nos mandara los datos.

      if (FAILED(DispositivoDITeclado->SetDataFormat(&c_dfDIKeyboard)))

            return E_FAIL;

 

Por ultimo le damos el nivel de operatividad del dispositivo con el entorno, es decir como interactúa con Windows, los parámetros que le pasamos es la ventana al que estará vinculado el dispositivo, después le decimos que será de tipo Exlusive, ósea que la información del teclado que entre cuando la ventana este activa solo será vista por esta venta y por nadie mas, así que si seleccionas esta y durante la ejecución presionas Alt + F4 o Alt + Tab, no se ejecutaran los comandos ya que la entrada es exclusiva y no hace eco en el sistema, esta opción de exclusividad se combina mediante un OR con el tipo Foreground, ósea que la pantalla solo puede recibir información cuando es la ventana activa y no es alguna de las que se encuentra detrás de la ventana activa.

      if (FAILED(DispositivoDITeclado->SetCooperativeLevel(hWindow, DISCL_EXCLUSIVE | DISCL_FOREGROUND)))

            return E_FAIL;

 

Todo lo anterior lleva un manejo de errores para salir de la aplicación en caso de algún fallo.

      return S_OK;

}

 

Dentro del método update debemos a agregar el código para manejar la información sobre que tecla esta presionando el jugador.

void Update()

{

      ::Bola->Posicion.x += ::Bola->VelX;

      ::Bola->Posicion.y += ::Bola->VelY;

     

      //IA

      if (::PaletaCPU->Posicion.y + 64 < Bola->Posicion. y)

            PaletaCPU->Posicion.y += 3.0f;

      else if (::PaletaCPU->Posicion.y + 64 > Bola->Posicion. y)

            PaletaCPU->Posicion.y -= 3.0f;

 

      //Colisiones

      if (::Bola->Posicion.y <= 0.0f)

            ::Bola->VelY *= -1;

      else if (::Bola->Posicion.y + 32.0f + 24.0f >= 600.0f)

            Bola->VelY *= -1;

 

      if (::PaletaJugador->Posicion.y <= 0.0f)

            ::PaletaJugador->Posicion.y = 0.0f;

      if (::PaletaJugador->Posicion.y + 160.0f >= 600.0f)

            ::PaletaJugador->Posicion.y = 440.0f;

     

      if (::PaletaCPU->Posicion.y <= 0.0f)

            ::PaletaCPU->Posicion.y = 0.0f;

      if (::PaletaCPU->Posicion.y + 160.0f >= 600.0f)

            ::PaletaCPU->Posicion.y = 440.0f;

     

      if (Bola->Posicion.x < ::PaletaJugador->Posicion.x + 32)

      {

            if (Bola->Posicion.y + 16.0f < ::PaletaJugador->Posicion.y ||

                  Bola->Posicion.y + 16.0f > ::PaletaJugador->Posicion.y + 128.0f)

            {

                  MessageBox(null, L"Has perdido", L"Has perdido", MB_OK);

                  ::Bola->Posicion = D3DXVECTOR3(350.0f, 250.0f, 0.0f);

                  ::Bola->VelX *= -1; // GAME OVER

            }

            else

            {

                  audio.pSoundBank->Play(audio.iSonido, 0, 0, null );

                  Bola->VelX *= -1;

            }

      }

      if (Bola->Posicion.x + 33.0f > ::PaletaCPU->Posicion.x)

      {

            Bola->VelX *= -1;

            audio.pSoundBank->Play(audio.iSonido, 0, 0, null );

      }

           

      audio.pEngine->DoWork();

 

Primero creamos un arreglo con capacidad de 256 elementos y lo ponemos todo en ceros.

      unsigned char Teclas[256];

      ZeroMemory(&Teclas, sizeof(Teclas));

 

Obtenemos el dispositivo, es decir tomamos una muestra de este y enseguida obtenemos el estado del dispositivo al momento de tomar la muestra.

      DispositivoDITeclado->Acquire();

      DispositivoDITeclado->GetDeviceState(sizeof(Teclas), &Teclas);

 

Y verificamos que teclas se presionaron, si fue DIK_UP, ósea flecha->arriba, decrementamos la posición de la paleta del jugador.

      if (Teclas[DIK_UP] & 0x80)

      {

            ::PaletaJugador->Posicion.y -= 3.0f;

      }

 

Después checamos si se presiono DIK_DOWN [flecha-abajo] y si fue presionada incrementamos la posición de la paleta del jugador en 3 pixeles.

      else if (Teclas[DIK_DOWN] & 0x80)

      {

            ::PaletaJugador->Posicion.y += 3.0f;

      }

 

Solo nos falta el código para liberar los recursos usados por DirectInput, que esta mas abajo, en el método Liberar.

}

 

void Renderear()

{

      if (::D3D9Dispositivo == null)

            return;

      ::D3D9Dispositivo->Clear(0, null, D3DCLEAR_TARGET, 0xFFFFFFFF, 1.0f, 0);

      if (SUCCEEDED(::D3D9Dispositivo->BeginScene()))

      {

            if (SUCCEEDED(::Sprite->Begin(D3DXSPRITE_ALPHABLEND)))

            {

                  ::Sprite->Draw(::PaletaJugador->Textura, null, null, &::PaletaJugador->Posicion, 0xFFFFFFFF);

                  ::Sprite->Draw(::PaletaCPU->Textura, null, null, &::PaletaCPU->Posicion, 0xFFFFFFFF);

                  ::Sprite->Draw(::Bola->Textura, null, null, &::Bola->Posicion, 0xFFFFFFFF);

                  ::Sprite->End();

            }

            ::D3D9Dispositivo->EndScene();

      }

      ::D3D9Dispositivo->Present(null, null, null, null);

}

 

void Liberar()

{

if(audio.pEngine)

      {

            audio.pEngine->ShutDown();

            audio.pEngine->Release();

      }

 

      if(audio.pbSoundBank)

            delete[] audio.pbSoundBank;

      audio.pbSoundBank = null;

 

      if(audio.pbWaveBank)

            UnmapViewOfFile(audio.pbWaveBank);

      audio.pbWaveBank = null;

 

      CoUninitialize();

 

Antes de cualquier cosa debemos de des-ligarnos del dispositivo.

      if (::DispositivoDITeclado)

            ::DispositivoDITeclado->Unacquire();

 

Los siguientes pasos son básicos, verificamos si existe el puntero, si es así, liberamos los recursos usados y finalmente hacemos nuestro puntero inválido.

      if (::DispositivoDITeclado)

            ::DispositivoDITeclado->Release();

      ::DispositivoDITeclado = null;

 

Ya lo hicimos con el dispositivo ligado a DirectInput, ahora debemos de hacerlo con el mismo DirectInput.

      if (::DirectInput)

            ::DirectInput->Release();

      ::DirectInput = null;

 

      if (::Sprite != null)

            ::Sprite->Release();

 

      if (::PaletaCPU->Textura != null)

            ::PaletaCPU->Textura->Release();

 

      if (::PaletaJugador->Textura != null)

            ::PaletaJugador->Textura->Release();

 

      if (::Bola->Textura != null)

            ::Bola->Textura->Release();

 

      if(::D3D9Dispositivo != null)

        ::D3D9Dispositivo->Release();

 

    if(::D3D9 != null)

        ::D3D9->Release();

 

}

 

Para terminar debemos borrar el siguiente código de la  función de procedimientos de la ventana.

case WM_KEYDOWN:

            {

                  switch(wParametros)

                  {

                  case VK_UP:

                        ::PaletaJugador->Posicion.y -= 4.0f; break;

                  case VK_DOWN:

                        ::PaletaJugador->Posicion.y += 4.0f; break;

                  case VK_ESCAPE:

                        {

                             Liberar();

                             PostQuitMessage(0);

                             return 0;

                        }

                  }

                  break;

            }

Ya que en caso de que exista alguna tecla presionada, DirectInput es el que se encargara de manejar este evento y ya no este método.

Quedara como a continuación:

__w64 long __stdcall Procedimientos(HWND hWindow,

                                                     unsigned int Mensaje,

                                                     __w64 unsigned int wParametros,

                                                     __w64 long lParametros)

{

      switch(Mensaje)

{

      case WM_DESTROY:

            {

                  Liberar();

                  PostQuitMessage(0);

                  return 0;

            }

      }

      return DefWindowProc(hWindow, Mensaje, wParametros, lParametros);

}

 

int __stdcall WinMain(HINSTANCE hInst, HINSTANCE, char*, int)

{

      WNDCLASSEX ClaseWnd = {0};

      ClaseWnd.cbSize = sizeof(ClaseWnd);

      ClaseWnd.lpszClassName = L"PrimerF5";

      ClaseWnd.lpfnWndProc = Procedimientos;

      ClaseWnd.style = CS_CLASSDC;

      ClaseWnd.hInstance = GetModuleHandle(null);

      RegisterClassEx(&ClaseWnd);

      HWND hWindow = CreateWindow(L"PrimerF5",

            L"PrimerF5",

            WS_SYSMENU,

            10,

            10,

            800,

            600,

            null,

            null,

            ClaseWnd.hInstance,

            null);

 

      if (SUCCEEDED(::Iniciar(hWindow)))

      {

            ShowWindow(hWindow, SW_SHOWDEFAULT);

            UpdateWindow(hWindow);

            MSG Mensaje;

            ZeroMemory(&Mensaje, sizeof(Mensaje));

            while (Mensaje.message != WM_QUIT)

            {

                  if (PeekMessage(&Mensaje, null, 0U, 0U, PM_REMOVE))

                  {

                        TranslateMessage(&Mensaje);

                        DispatchMessage(&Mensaje);

                  }

                  else

                  {

                        ::Update();

                        ::Renderear();                    

                  }

            }

      }

      UnregisterClass(L"PrimerF5", ClaseWnd.hInstance );

      return 0;

}

 
< Prev   Next >
© 2009 scumbag > scmbg
Joomla! is Free Software released under the GNU/GPL License.