dx9 pong game

Started by
9 comments, last by scott8 6 months, 3 weeks ago

I am trying to get paddles to move in a pong game using dx9 I put y variables in the WM_KEYDOWN function but they don't seem to work even though exit(0) works.

// include the basic windows header files and the Direct3D header file
#include <windows.h>
#include <windowsx.h>
#include <d3d9.h>

// define the screen resolution
#define SCREEN_WIDTH 800
#define SCREEN_HEIGHT 600

// include the Direct3D Library file
#pragma comment (lib, "d3d9.lib")

// global declarations
LPDIRECT3D9 d3d;    // the pointer to our Direct3D interface
LPDIRECT3DDEVICE9 d3ddev;    // the pointer to the device class
LPDIRECT3DVERTEXBUFFER9 v_buffer = NULL;    // the pointer to the vertex buffer

// function prototypes
void initD3D(HWND hWnd);    // sets up and initializes Direct3D
void render_frame(void);    // renders a single frame
void cleanD3D(void);    // closes Direct3D and releases memory
void init_graphics(void);    // 3D declarations

struct CUSTOMVERTEX { FLOAT X, Y, Z, RHW; DWORD COLOR; };
#define CUSTOMFVF (D3DFVF_XYZRHW | D3DFVF_DIFFUSE)

// the WindowProc function prototype
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);


// the entry point for any Windows program
int WINAPI WinMain(HINSTANCE hInstance,
	HINSTANCE hPrevInstance,
	LPSTR lpCmdLine,
	int nCmdShow)
{
	HWND hWnd;
	WNDCLASSEX wc;

	ZeroMemory(&wc, sizeof(WNDCLASSEX));

	wc.cbSize = sizeof(WNDCLASSEX);
	wc.style = CS_HREDRAW | CS_VREDRAW;
	wc.lpfnWndProc = WindowProc;
	wc.hInstance = hInstance;
	wc.hCursor = LoadCursor(NULL, IDC_ARROW);
	wc.lpszClassName = "WindowClass";

	RegisterClassEx(&wc);

	hWnd = CreateWindowEx(NULL,
		"WindowClass",
		"Pong",
		WS_OVERLAPPEDWINDOW,
		0, 0,
		SCREEN_WIDTH, SCREEN_HEIGHT,
		NULL,
		NULL,
		hInstance,
		NULL);

	ShowWindow(hWnd, nCmdShow);

	// set up and initialize Direct3D
	initD3D(hWnd);

	// enter the main loop:

	MSG msg;

	while (TRUE)
	{
		while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}

		if (msg.message == WM_QUIT)
			break;

		render_frame();
	}

	// clean up DirectX and COM
	cleanD3D();

	return msg.wParam;
}

float x = 0.0f, y = 0.0f;
// this is the main message handler for the program
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	switch (message)
	{
	case WM_DESTROY:
	{
		PostQuitMessage(0);
		return 0;
	} 
	case WM_KEYDOWN:
	{
		if (wParam == VK_UP)
		{
			y--;
		}
		if (wParam == VK_DOWN)
		{
			y++;
		}
	}
	break;
	}
	return DefWindowProc(hWnd, message, wParam, lParam);
}

// this function initializes and prepares Direct3D for use
void initD3D(HWND hWnd)
{
	d3d = Direct3DCreate9(D3D_SDK_VERSION);

	D3DPRESENT_PARAMETERS d3dpp;

	ZeroMemory(&d3dpp, sizeof(d3dpp));
	d3dpp.Windowed = TRUE;
	d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
	d3dpp.hDeviceWindow = hWnd;
	d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
	d3dpp.BackBufferWidth = SCREEN_WIDTH;
	d3dpp.BackBufferHeight = SCREEN_HEIGHT;

	// create a device class using this information and the info from the d3dpp stuct
	d3d->CreateDevice(D3DADAPTER_DEFAULT,
		D3DDEVTYPE_HAL,
		hWnd,
		D3DCREATE_SOFTWARE_VERTEXPROCESSING,
		&d3dpp,
		&d3ddev);

	init_graphics();    // call the function to initialize the triangle
}


// this is the function used to render a single frame
void render_frame(void)
{
	d3ddev->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);

	d3ddev->BeginScene();

	// select which vertex format we are using
	d3ddev->SetFVF(CUSTOMFVF);

	// select the vertex buffer to display
	d3ddev->SetStreamSource(0, v_buffer, 0, sizeof(CUSTOMVERTEX));

	// copy the vertex buffer to the back buffer
	d3ddev->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
	d3ddev->DrawPrimitive(D3DPT_TRIANGLESTRIP, 4, 2);
	d3ddev->DrawPrimitive(D3DPT_TRIANGLESTRIP, 8, 2);

	d3ddev->EndScene();

	d3ddev->Present(NULL, NULL, NULL, NULL);
}


// this is the function that cleans up Direct3D and COM
void cleanD3D(void)
{
	v_buffer->Release();    // close and release the vertex buffer
	d3ddev->Release();    // close and release the 3D device
	d3d->Release();    // close and release Direct3D
}


// this is the function that puts the 3D models into video RAM
void init_graphics(void)
{
	// create the vertices using the CUSTOMVERTEX struct
	CUSTOMVERTEX vertices[] =
	{
		{ 0.0f, 250.0f+y, 0.0f, 1.0f, D3DCOLOR_XRGB(255, 0, 0), },
		{ 25.0f, 250.0f+y, 0.0f, 1.0f, D3DCOLOR_XRGB(255, 0, 0), },
		{ 0.0f, 350.0f+y, 0.0f, 1.0f, D3DCOLOR_XRGB(255, 0, 0), },
		{ 25.0f, 350.0f+y, 0.0f, 1.0f, D3DCOLOR_XRGB(255, 0, 0), },

		{ 775.0f, 250.0f, 0.0f, 1.0f, D3DCOLOR_XRGB(0, 0, 255), },
		{ 800.0f, 250.0f, 0.0f, 1.0f, D3DCOLOR_XRGB(0, 0, 255), },
		{ 775.0f, 350.0f, 0.0f, 1.0f, D3DCOLOR_XRGB(0, 0, 255), },
		{ 800.0f, 350.0f, 0.0f, 1.0f, D3DCOLOR_XRGB(0, 0, 255), },

		{ 395.0f, 295.0f, 0.0f, 1.0f, D3DCOLOR_XRGB(255, 255, 255), },
		{ 405.0f, 295.0f, 0.0f, 1.0f, D3DCOLOR_XRGB(255, 255, 255), },
		{ 395.0f, 305.0f, 0.0f, 1.0f, D3DCOLOR_XRGB(255, 255, 255), },
		{ 405.0f, 305.0f, 0.0f, 1.0f, D3DCOLOR_XRGB(255, 255, 255), },
	};

	// create a vertex buffer interface called v_buffer
	d3ddev->CreateVertexBuffer(12 * sizeof(CUSTOMVERTEX),
		0,
		CUSTOMFVF,
		D3DPOOL_MANAGED,
		&v_buffer,
		NULL);

	VOID* pVoid;    // a void pointer

	// lock v_buffer and load the vertices into it
	v_buffer->Lock(0, 0, (void**)&pVoid, 0);
	memcpy(pVoid, vertices, sizeof(vertices));
	v_buffer->Unlock();
}

Advertisement

You're not doing anything to translate the paddle. The only place ‘y’ is used is in the init function and that is only called once at the beginning as is correct for an init function. The GPU has no clue of the existence of the variable ‘y’, much less its value.

No, I am not a professional programmer. I'm just a hobbyist having fun...

how do I solve this problem?

Try defining the value of “Y” and making “Y” exist in the code (going by what MarkS said).

-- Tom Sloper -- sloperama.com

pbivens67 said:
how do I solve this problem?

Two options: Either you move the vertices and reupload them every frame, or you use a transformation matrix so the GPU moves the vertices for you.

The latter option is more common, because if your objects have thousands of vertices, it's faster to upload just the numbers making the matrix.
It's probably also easier to do, but i don't know the DirectX calls needed. In OpenGL this was glLoadMatrix, glTralate, glRotate, etc. The interface also needs to specify if you change modelview (object transforms) or projection (camera) matrix.
It seems you currently don't handle any matrices, but leave them at default values of the API.

To transform vertices, you could change the init_graphics() function so it uses your y variable to set the y coordinates of each vertex.
And you need to call the function each frame before you render.
But you must make sure the vertex buffer on GPU is either updated or deleted and recreated. To avoid the problem that after 1000 frames you don't have 999 old and unused vertex buffers to fill your GPU RAM until there is no more free space.

So you need to lookup more DirectX tutorials to see examples for either solution.

Tom Sloper said:

Try defining the value of “Y” and making “Y” exist in the code (going by what MarkS said).

can you go into more detail

You have an “y” variable, you update the “y” with the key events, but where do you change the position of the paddle(s?) in the graphics so it gets drawn at a different spot?

Alberth said:
but where do you change the position of the paddle(s?) in the graphics so it gets drawn at a different spot?

Now that you ask, it's actually there:

void init_graphics(void)
{
	// create the vertices using the CUSTOMVERTEX struct
	CUSTOMVERTEX vertices[] =
	{
		{ 0.0f, 250.0f+y, 0.0f, 1.0f, D3DCOLOR_XRGB(255, 0, 0), },
		{ 25.0f, 250.0f+y, 0.0f, 1.0f, D3DCOLOR_XRGB(255, 0, 0), },
		{ 0.0f, 350.0f+y, 0.0f, 1.0f, D3DCOLOR_XRGB(255, 0, 0), },
		{ 25.0f, 350.0f+y, 0.0f, 1.0f, D3DCOLOR_XRGB(255, 0, 0), },

I did not see this before.

So the problem is: init_graphics(), as the name suggests, is called only once at startup.
But you want to do it every frame, so the vertices get changed and uploaded to GPU and the change becomes visible. Option 2 of my former answer.

how do I do thiusAlberth said:

You have an “y” variable, you update the “y” with the key events, but where do you change the position of the paddle(s?) in the graphics so it gets drawn at a different spot?

so how do I do this?

I wouldn't recomment rebuilding the vertices when you need to change the position of your paddle. What's usually done is you build your model so it's centered at the origin. This is called ‘Model space’. If you want to draw it on screen you have to set up the world-view-projection matrices. See this link This is the approach Joel mentioned.

What's great about this approach is you only need one model (set of vertices) no matter how many paddles you have in your game! Say you want to draw a paddle on the left hand of the screen. Set the world transform to transform vertices 100 units to the left. Make the draw call for the paddle vertices. Now set the world transform 100 units to the right, make the draw call. You get two paddles on screen for the price of one.

You can do more than just move it around. You can resize (scale) the paddles using a scaling matrix (wouldn't that be a nice power up if your paddle became twice as big for a while?). You can rotate the paddles using a rotation matrix.

This topic is closed to new replies.

Advertisement