Ir al contenido

publicidad

Foto

Curso MM: 3 Dibujando gráficos básicos


Este tema ha sido archivado. Esto significa que no puedes responder en este tema.
4 respuestas en este tema

#1

Escrito 03 agosto 2009 - 14:34

Aprendiendo a dibujar gráficos básicos

Elementos gráficos básicos

- el sistema de coordenadas: en Windows el eje de coordenadas empieza en la esquina superior izquierda.

- colores: blanco (255,255,255) , negro(0,0,0), gris claro(192,192,192), gris oscuro(128,128,128), rojo(255,0,0), verde(0,255,0), azul(0,0,255), amarillo (255,255,0), morado(255,0,255). El API Win32 tiene una estructura llamada COLORREF que combina los tres componentes RGB en un solo valor. Para crear una estructura de éste tipo se utiliza la macro RGB() como en éste ejemplo: COLORREF green = RGB(0,255,0);

Examinando los gráficos en Windows

En Windows se utiliza el Graphics Device Interface (GDI) para dibujar gráficos. El componente clave del GDI es el "contexto de dispositivo" que actúa como pasarela a un dispositivo gráfico físico. Normalmente se obtiene un contexto de dispositivo llamando a la función BeginPaint(). Por ejemplo:

[code:1]PAINTSTRUCT ps;
HDC hDC = BeginPaint(hWindow, &ps);
*** operaciones de dibujado GDI aquí ***
EndPaint(hWindow,&ps);[/code]

BeginPaint() necesita un manejador de ventana y una estructura PAINTSTRUCT que contiene toda la información necesaria sobre el contexto de dispositivo. BeginPaint() devuelve un manejador a un contexto de dispositivo que es lo que necesitamos para dibujar. EndPaint() libera ese manejador. Si vamos a pintar fuera de éstas funciones habrá que hacerlo con la función GetDC() que necesita sólo un manejador de ventana. Posteriormente usaremos ReleaseDC().

[code:1]hDC = GetDC(hWindow);
*** operaciones de dibujado GDI aquí ***
ReleaseDC(hWindow,hDC);[/code]

El GDI también soporta otros componentes gráficos aparte del contexto de dispositivo: lápices, pinceles, paletas y bitmaps.

- lápices (pens) se utilizan para dibujar líneas y curvas. Pueden ser creados con distintos grosores y colores. Hay dos tipos: cosméticos y geométricos. Los cosméticos dibujan líneas de ancho fijo y que necesitan ser dibujadas rápido. Los geométricos dibujan líneas escalables, más anchas que un simple pixel y líneas con estilos únicos.

- pinceles(brushes) se utilizan para pintar el interior de polígonos, elipses y caminos. Pueden pintar colores sólidos o tomando patrones de un bitmap. Para dibujar un círculo se utilizaría un lápiz para el círculo y un pincel para rellenar.

- Bitmaps son imágenes almacenadas como una tabla de pixeles.

- paletas son juegos de colores que se utilizan con los bitmaps.

Pintando Ventanas

- Hay que tratar el mensaje WM_PAINT cada vez que haya que redibujar la ventana. En nuestro caso éste mensaje pasa por el motor del juego que llama a GamePaint(). A su vez ésta función está en medio de BeginPaint() y EndPaint(). Con éste sistema ocultamos la obtención del contexto de dispositivo y simplemente dibujamos.

[code:1]case WM_PAINT:
HDC hDC;
PAINTSTRUCT ps;
hDC = BeginPaint(hWindow, &ps);

// Paint the game
GamePaint(hDC);

EndPaint(hWindow, &ps);
return 0;[/code]

Luego simplemente se puede hacer ésto:

[code:1]void GamePaint(HDC hDC)
{
MoveToEx(hDC, 0, 0, NULL);
LineTo(hDC, 50, 50);
}[/code]

Ahora vamos a ver cómo dibujamos texto: la función principal es ésta:

[code:1]BOOL TextOut(HDC hDC, int x , int y , LPCTSTR szString, int iLength);[/code]

Ejemplo:

[code:1]void GamePaint(HDC hDC)
{
TextOut(hDC, 10, 10, TEXT("Michael Morrison"), 16);
}[/code]

Otra función es DrawText() que permite dibujar texto dentro de un rectángulo.

[code:1]void GamePaint(HDC hDC)
{
RECT rect;
GetClientRect(hWindow, &rect);
DrawText(hDC, TEXT("Michael Morrison"), -1, &rect,
DT_SINGLELINE | DT_CENTER | DT_VCENTER);
}[/code]

Dibujando primitivas gráficas: líneas, rectángulos, círculos, polígonos, óvalos y arcos.

- Líneas: Utilizamos dos funciones:

[code:1]BOOL MoveToEx(HDC hDC, int x, int y, LPPOINT pt);
BOOL LineTo(HDC hDC, int x, int y);[/code]

Las dos tienen un contexto de dispositivo y las coordenadas. MoveToEx() incluye la posibilidad de pasarle una estructura con las coordenadas del último punto. Win32 dispone de la estructura POINT que sólo consta de dos valores long integer para x,y. Un ejemplo:

[code:1]void GamePaint(HDC hDC)
{
MoveToEx(hDC, 10, 40, NULL);
LineTo(hDC, 44, 10);
LineTo(hDC, 78, 40);
}[/code]

- Rectángulos:

[code:1]BOOL Rectangle(HDC hDC, int xLeft, int yTop, int xRight, int yBottom);[/code]

[code:1]void GamePaint(HDC hDC)
{
Rectangle(hDC, 16, 36, 72, 70);
Rectangle(hDC, 34, 50, 54, 70);
}[/code]

- Elipses:

[code:1]BOOL Ellipse(HDC hDC, int xLeft, int yTop, int xRight, int yBottom);[/code]

[code:1]void GamePaint(HDC hDC)
{
Ellipse(hDC, 40, 55, 48, 65);
}[/code]

- Polígonos:

[code:1]BOOL Polygon(HDC hDC, CONST POINT* pt, int iCount);[/code]

[code:1]void GamePaint(HDC hDC)
{
POINT points[3];
points[0] = { 5, 10 };
points[1] = { 25, 30 };
points[2] = { 15, 20 };
Polygon(hDC, points, 3);
}[/code]

Toma una tabla de punteros y el número de puntos como parámetros.

- Trabajando con lápices y pinceles:

- Crear lápices:

[code:1]HPEN CreatePen(int iPenStyle, int iWidth, COLORREF crColor);
Ejemplo: HPEN hBluePen = CreatePen(PS_SOLID, 1, RGB(0,0,255));[/code]

El primer argumento es el estilo que puede ser: PS_SOLID, PS_DASH, PS_DOT, PS_DASHDOT, PS_DASHDOTDOT, o PS_NULL.

- Crear pinceles:

[code:1]HBRUSH hPurpleBrush = CreateSolidBrush(RGB(255, 0, 255));[/code]

- Seleccionando pinceles y lápices:

[code:1]HPEN hPen = SelectObject(hDC, hBluePen);[/code]
hPen es el lápiz anterior, antes de salir del programa debemos volver a ponerlo (SelectObject(hDC, hPen); )
Cuando terminamos con un objeto lo eliminamos: DeleteObject(hBluePen);

Con pinceles es lo mismo:

[code:1]HBRUSH hBrush = SelectObject(hDC, hPurpleBrush);
// *** Do some drawing here! ***
SelectObject(hDC, hBrush);
DeleteObject(hPurpleBrush);[/code]

Programa de ejemplo
Ahora ya no tenemos que ver GameEngine.h y GameEngine.cpp porque no cambian en nada (por ahora). Los archivos Resource.h y Trippy.rc son iguales que en los ejemplos anteriores, sólo se definen los dos iconos que se utilizan en el programa. Nos centramos en lo que hace el juego en los archivos Trippy.h y Trippy.cpp

Trippy.h
[code:1]//-----------------------------------------------------------------
// Trippy Application
// C++ Header - Trippy.h
//-----------------------------------------------------------------

#pragma once

//-----------------------------------------------------------------
// Include Files
//-----------------------------------------------------------------
#include
#include "Resource.h"
#include "GameEngine.h"

//-----------------------------------------------------------------
// Global Variables
//-----------------------------------------------------------------
GameEngine* _pGame; //el puntero al motor del juego.
RECT _rcRectangle; //una estructura que define un rectángulo
//que vamos a usar en Trippy.cpp[/code]

Trippy.cpp
[code:1]//-----------------------------------------------------------------
// Trippy Application
// C++ Source - Trippy.cpp
//-----------------------------------------------------------------

//-----------------------------------------------------------------
// Include Files
//-----------------------------------------------------------------
#include "Trippy.h"

//-----------------------------------------------------------------
// Game Engine Functions
//-----------------------------------------------------------------
BOOL GameInitialize(HINSTANCE hInstance)
{
// Create the game engine
_pGame = new GameEngine(hInstance, TEXT("Trippy"),
TEXT("Trippy"), IDI_TRIPPY, IDI_TRIPPY_SM);
if (_pGame == NULL)
return FALSE;

// Set the frame rate
_pGame->SetFrameRate(15);

return TRUE;
}

void GameStart(HWND hWindow)
{
// Seed the random number generator
srand(GetTickCount());

// guardar la posición y tamaño del rectángulo inicial.
_rcRectangle.left = _pGame->GetWidth() * 2 / 5;
_rcRectangle.top = _pGame->GetHeight() * 2 / 5;
_rcRectangle.right = _rcRectangle.left + _pGame->GetWidth() / 5;
_rcRectangle.bottom = _rcRectangle.top + _pGame->GetHeight() / 5;
}

void GameEnd()
{
// Cleanup the game engine
delete _pGame;
}

void GameActivate(HWND hWindow)
{
}

void GameDeactivate(HWND hWindow)
{
}

void GamePaint(HDC hDC)
{
// Dibujar una rejilla como fondo para los rectángulos.
const int iGridLines = 50;
for (int i = 1; i <= iGridLines; i++)
{
// Dibujar una línea de rejilla horizontal.
MoveToEx(hDC, _pGame->GetWidth() * i / iGridLines , 0, NULL);
LineTo(hDC, _pGame->GetWidth() * i / iGridLines, _pGame->GetHeight());

// Dibujar una línea de rejilla vertical.
MoveToEx(hDC, 0, _pGame->GetHeight() * i / iGridLines, NULL);
LineTo(hDC, _pGame->GetWidth(), _pGame->GetHeight() * i / iGridLines);
}
}

void GameCycle()
{
HDC hDC;
HWND hWindow = _pGame->GetWindow();
HBRUSH hBrush;

// Alterar aleatoriamente la posición y el tamaño del rectángulo.
int iInflation = (rand() % 21) - 10;
InflateRect(&_rcRectangle, iInflation, iInflation);
OffsetRect(&_rcRectangle, (rand() % 19) - 9, (rand() % 19) - 9);

// Dibujar el nuevo rectángulo con un color aleatorio.
hBrush = CreateSolidBrush(RGB(rand() % 256, rand() % 256, rand() % 256));
hDC = GetDC(hWindow);
FillRect(hDC, &_rcRectangle, hBrush);
ReleaseDC(hWindow, hDC);
DeleteObject(hBrush);
}[/code]

Hay que observar como las líneas dibujadas en GamePaint() se conservan al minimizar la ventana pero los cuadros dibujados en GameCycle() se pierden. Aquí podéis ver un ejemplo del uso de GetDC() y ReleaseDC(). GameInitialize() pone el programa a 15 frames por segundo. GameStart() alimenta el generador de números aleatorios y crea las coordenadas del primer rectángulo. GamePaint() dibuja una rejilla de líneas que se redibujan automáticamente al minimizar la ventana y volverla a abrir. GameCycle() calcula las nuevas coordenadas y dibuja otro rectángulo. Con InflateRect() y OffsetRect() se cambia el tamaño y la posición del rectángulo con los valores calculados.

Código fuente

  • Ellolo17

  • Ganondorf

  • vida restante: 100%
  • Registrado: 16 nov 2006
  • Mensajes: 6.208
#2

Escrito 03 agosto 2009 - 18:33

Cuando termines de escribir esto, si lo recopilas en un hilo lo pongo en el indice ;)

Un saludo.

#3

Escrito 03 agosto 2009 - 21:43

Lo estoy poniendo separado por capítulos para responder a las dudas en cada uno, pero si veo que nadie responde a ninguno puede que hable contigo para borrarlos todos y ponerlo todo en uno sólo.

O quizás cuando termine (son 21) hagamos eso que digo.

  • Ellolo17

  • Ganondorf

  • vida restante: 100%
  • Registrado: 16 nov 2006
  • Mensajes: 6.208
#4

Escrito 04 agosto 2009 - 09:08

Na, no hace falta borrarlos, quizas aun no se ha pasado nadie que se haya puesto a trastear con esto pero cuando suceda puede que le venga bien preguntar por capitulos -O quizas es tan bueno el tuto que ni lo necesitan ^^ -

Yo lo que veria mejor seria al final hacer un recopilatorio/indice y para que no desaparezca linkarlo al indice del foro ;)

#5

Escrito 04 agosto 2009 - 15:56

Entonces ya estoy haciendo un índice, en el mensaje de presentación:

Primer mensaje


Este tema ha sido archivado. Esto significa que no puedes responder en este tema.
publicidad