Mi Desktop

Snapshot
G.I.R.

Impacto Visual

iv(218).jpg

Dicen los que saben

You better live every day like your last because one day you're going to be right.

Ray Charles

Encuesta

Paranoid Puppets
 

Syndicate

Estadisticas

OS: Linux
PHP: 5.2.11
MySQL: 5.0.84-percona-highperf-b18
Time: 21:18
Caching: Disabled
GZIP: Disabled
News: 177
Visitors: 171052
We have 13 guests online

Buscar en el sitio

Fedora 12 - Countdown


Start arrow Tutoriales arrow Hagase el sonido [Tutorial DirectX #4]
Hagase el sonido [Tutorial DirectX #4] E-mail
domingo, 27 julio 2008

Este es el cuarto tutorial sobre desarrollo de videojuegos sobre la plataforma DirectX, en esta ocasión abordaremos otra tecnología… XACT, la cual sirve para manejar audio.

Como se ha dicho se trabajara sobre los tutoriales previos, así que antes de entrar de fondo a este podrías darle una checada a los 3 anteriores, para que aprendas o refresques algunos conceptos.

1.- PrimerF5 [Tutorial DirectX #1]

2.- Pong [Tutorial DirectX #2]

Siguiendo con lo acordado, aquí se mostrara el código de los dos anteriores tutoriales, aunque se mostraran en color morado y no se explicaran, aunque por ser mas el código viejo  que el nuevo, también se cambiara el tamaño y se pondrá en cursiva, el nuevo mantendrá la fuente básica y por convención: Courier New 10 Normal y además tendrá los cambios de colores a azul para tipos primitivos.

Para este tutorial hay que hacer un poco de trabajo extra ya que debemos de crear nuestros “Bancos de Sonidos” y “Bancos de Ondas”.

Así que deberás seguir un pequeño tutorial, solo toma 10 min. Para poder continuar, el link es:

3.- XACT Creation Tool [Tutorial DirectX #3]

Lo primero [que ya es los segundo] que debemos hacer es agregar a nuestro código una librería que nos ayudara a manejar el audio y definir un macro

El macro es _WIN32_DCOM, necesario para el uso de múltiples hilos [o procesos].

#define _WIN32_DCOM

#define null NULL

 

#include <d3d9.h>

#include <d3dx9.h>

#include <d3dx9core.h>

 

La librería contiene las, clases, estructuras, rutinas y definiciones básicas para poder ejecutar la plataforma XACT

#include <xact.h>

 

struct Objeto

{

IDirect3DTexture9* Textura;

D3DXVECTOR3 Posicion;

};

 

struct ObjetoBola : public Objeto

{

int VelX, VelY;

};

 

Después debemos de crear una estructura que nombraremos AudioSt y que nos ayudara a manejar el audio de nuestro proyecto [videojuego], esta estructura contiene varios tipos, en seguida los explicaremos.

struct AudioSt

{

 

Primero tenemos un puntero a una estructura del tipo IXACTEngine, que es el motor que usaremos en nuestra aplicación.

IXACTEngine* pEngine;

 

Despues declaramos nuestros bancos de ondas y de sonidos

IXACTWaveBank* pWaveBank;

IXACTSoundBank* pSoundBank;

 

El indice de el sonido que vamos a usar, en este caso es solo uno, en proyectos mas grandes pueden ser decenas o miles de sonidos y por tanto la misma cantidad de indices.

unsigned short iSonido;

 

Finalmente dos punteros a los buffers que almacenaran la información.

void* pbWaveBank;

void* pbSoundBank;

};

 

Nota: Puedes observar que hay nombres parecidos como pbWaveBank y pWaveBank, ten en cuenta que son diferentes y checa bien en el código por que pueden causar confusión, una es un puntero a un buffer y la otra es un puntero a la estructura del Banco de Ondas, la única diferencia entre los nombres es una ‘b’ que hace referencia al ‘b’uffer

Después tenemos declaraciones hechas anteriormente, solo agregaremos 1 mas.

IDirect3D9* D3D9 = null;

IDirect3DDevice9* D3D9Dispositivo = null;

ID3DXSprite* Sprite;

 

Objeto* PaletaJugador;

Objeto* PaletaCPU;

ObjetoBola* Bola;

 

Esta será del tipo AudioSt

AudioSt audio;

 

Después esta la función prototipo que libera los recursos y enseguida la función que inicia todo, dentro de este debemos de agregar e código encargado de inicializar la plataforma XACT.

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 = 3;

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

return E_FAIL;

 

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

 

Antes de crear e inicializar el motor de XACT debemos de recolectar la información de los archivos que generamos con nuestra herramienta de creación de audio. Así que declaramos algunas variables que nos ayudaran en esta tarea.

Primero una variable de tipo long que contendrá los mensajes que regresan las funciones que utilizaremos, recordemos que long es igual a HRESULT, pero estamos usando declaraciones con nombre de los tipos primitivos en el último tutorial usaremos los tipos que por convención se deben de usar.

long hr;

 

Un puntero que será el encargado de recorrer los archivos.

void* hFile;

 

Despues 2 variables para el tamaño del archivo y los bytes leídos en cada archivo.

unsigned long dwFileSize;

unsigned long dwBytesRead;

 

Por ultimo otro puntero que se cargara de mapear los archivos.

void* hMapFile;

 

En seguida ponemos en ceros la memoria que ocupa la variable “audio” para evitar errores por basura en memoria.

ZeroMemory(&audio, sizeof(AudioSt));

 

Lo primero que haremos es llamar la función CoInitializeEx, con la cual haremos que nuestro programa manejar varios hilos y ejecutar bien la plataforma y los sonidos de XACT.

hr = CoInitializeEx(null, COINIT_MULTITHREADED);

 

Después llamamos a la función XACTCreateEngine para crear nuestro motor, y checamos si hubo alguna falla para regresar de la función avisando de que ocurrió algún problema.

if(SUCCEEDED(hr))

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

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

return E_FAIL;

Después creamos los parámetros que se usaran para inicializar el motor, recordemos que lo que hicimos antes fue solo crear el motor ahora debemos inicializarlo. Los parámetros quedaran en cero, con lo cual cargara los valores por default.

XACT_RUNTIME_PARAMETERS xrParams = {0};

xrParams.lookAheadTime = XACT_ENGINE_LOOKAHEAD_DEFAULT;

 

Para inicializar llamamos al método que se encuentra dentro del motor y le pasamos los parámetros que deberá de utilizar para iniciar, una vez más checamos si existía alguna falla para reportarlo y detener la aplicación.

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

if(FAILED(hr))

return hr;

 

Los siguientes pasos aparecen algo complicados pero no lo son, loes resumiré en 4 pasos:

1.- Abrir el archivo

2.- Obtener el tamaño del archivo

3.- Asignar el buffer pbWaveBank como el encargado de mapear el archivo.

4.- Crear el banco de ondas [en memoria, en este caso] a partir del buffer que contiene la información del archivo.

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);

}

 

Fácil, aunque hay que agregar que en cada paso se verifican los resultados por si se genero algún error y se deben de “cerrar” los punteros; para después checar si hubo algún error en la creación del Banco de Ondas.

if(FAILED(hr))

return E_FAIL;

 

Lo siguiente es crear el Banco de Sonidos, la operación es parecida a la anterior la resumiré en 5 pasos:

1.- Abrir el archivo

2.- Obtener el tamaño del archivo

3.- Crear un buffer del tamaño del archivo.

4.- Leer el archivo y poner el contenido en el buffer

5.- Crear el banco de sonidos, con la información del buffer.

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);

}

 

Esta vez también hay que “cerrar” los punteros usados y checar si hubo errores.

if(FAILED(hr))

return E_FAIL;

 

Finalmente ya que tenemos nuestros 2 bancos [de ondas y sonidos] debemos de obtener el índice de los sonidos para cuando los queramos usar, esto lo hacemos llamando a la funciones GetCueIndex del banco de sonidos y asignamos el índice a la variable iSonidos de nuestra estructura audio, así ya tenemos almacenado el índice del sonido hará un manejo más fácil.

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

 

Regresamos S_OK, para indicar que todos los dispositivos, motores, objetos, fueron creados satisfactoriamente.

return S_OK;

}

 

Solo nos faltan una cuantas líneas más, que serán las encargadas de que el audio suene cada que la pelota rebote en una de las paletas, ya sea del jugador o del CPU

void Update()

{

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

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

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;

 

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;

}

else

{

Justo en el momento en que se verifica que la pelota rebota con la paleta del jugador llamado a la función Play del bando de sonidos, solo hay que pasar el índice del sonido que queremos que toque y listo, creara el sonido

Nota: los otros parámetros se refieren a efectos, offsets, etc., que no usaremos, por eso están en ceros y null [XD que es cero]

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

Bola->VelX *= -1;

}

}

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

{

Bola->VelX *= -1;

Hacemos lo mismo con la paleta del CPU.

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

}

 

Ahora debemos llamar a la función DoWork() para que el motor XACT ejecute las tareas que debe, este método es delicado y se recomienda que se ejecute cada vez que el juego se refresca ósea en la función de actualización [Update en este tutorial] o en la función de rendereo.

audio.pEngine->DoWork();

}

 

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()

{

 

Una vez que vayamos a terminar nuestra aplicación debemos de liberar los recursos usados.

if(audio.pEngine)

{

 

Si el puntero es valido debemos de apagar el motor y liberar los recursos, eso lo hacemos con los métodos ShutDow() y Relace()

audio.pEngine->ShutDown();

audio.pEngine->Release();

}

 

Después debemos de “borrar” el puntero al buffer del Bando de Sonidos, y después hacerlo un puntero “invalido” [o igual a cero [null]]

if(audio.pbSoundBank)

delete[] audio.pbSoundBank;

audio.pbSoundBank = null;

 

Hacemos lo mismo con el puntero del Banco de Ondas, usando la función UnmapViewOfField, para decirle que deje de mapear el contenido de ese archivo. Y después lo hacemos un puntero nulo.

if(audio.pbWaveBank)

UnmapViewOfFile(audio.pbWaveBank);

audio.pbWaveBank = null;

 

Y finalmente llamamos al método CoUninitialize()

CoUninitialize();

 

Y así hemos creado el código que agrega sonido a nuestro videojuego, el resto del código es exactamente igual al anterior, solo resta ejecutarlo.

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();

 

}

 

__w64 long __stdcall Procedimientos(HWND hWindow,

unsigned int Mensaje,

__w64 unsigned int wParametros,

__w64 long lParametros)

{

switch(Mensaje)

{

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;

}

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"Pong";

ClaseWnd.lpfnWndProc = Procedimientos;

ClaseWnd.style = CS_CLASSDC;

ClaseWnd.hInstance = GetModuleHandle(null);

RegisterClassEx(&ClaseWnd);

HWND hWindow = CreateWindow(L"Pong",

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.