Best way to make a zooming 2D game

Started by
12 comments, last by DvDmanDT 17 years ago
Hi, I'd like to make a 2D DirectX game that can zoom in and out in realtime. What's the best (i.e. most efficient) way of doing this? Please keep in mind that I'm still kind of new to DirectX. I assume there's some way of rendering a texture onto a texture, or a texture onto a surface, but I can't find the functions. ---UltimateWalrus
Advertisement
Use Direct3D. Draw your sprites as textured quads, and move the camera around.
Will Miller | Game Designer | Big Huge Games
OK, that makes sense.

What if I have thousands of sprites onscreen at once (e.g. drops of rain falling from the sky or bullets in a shooting game)? Won't I experience a performance drop then because of all of the thousands of polygons? Would it be more efficient to just draw a bunch of 2D textures onto another 2D texture/surface, and resize it? Or maybe, the most efficient way would be to scale and position each sprite individually?

I don't necessarily know any of this to be true; I'm just asking the questions in the hopes that somebody will elaborate on them.

EDIT: Also, I'm wondering if I'd be able to use capabilities like line drawing... but that's not as important.
Quote:Original post by UltimateWalrus
OK, that makes sense.

What if I have thousands of sprites onscreen at once (e.g. drops of rain falling from the sky or bullets in a shooting game)? Won't I experience a performance drop then because of all of the thousands of polygons? Would it be more efficient to just draw a bunch of 2D textures onto another 2D texture/surface, and resize it?


Probably not.

DirectDraw doesn't make use of 3D acceleration, while Direct3D does. Using Direct3D, and ID3DXSprite (a helper interface designed specifically to simplify drawing sprites), you can utilise the 3D acceleration on a graphics card.

D3DX also provides the ID3DXLine interface, which greatly simplifies line drawing.
NextWar: The Quest for Earth available now for Windows Phone 7.
Quote:Original post by Sc4Freak
Probably not.

DirectDraw doesn't make use of 3D acceleration, while Direct3D does. Using Direct3D, and ID3DXSprite (a helper interface designed specifically to simplify drawing sprites), you can utilise the 3D acceleration on a graphics card.

D3DX also provides the ID3DXLine interface, which greatly simplifies line drawing.


OK, now I'm a little confused, so hopefully someone can clarify this for me.

I've been using Direct3D all along, not DirectDraw. When I use the ID3DXSprite::Draw function, I just give it 2D screen coordinates and it draws a 2D image for me. I'm a little sketchy on how this is implemented --- I'm guessing from the context of what you're saying that the graphics card actually draws it as a textured quad in 3D space?

If this is true, then is there a way to "move the camera around" even when all I've done is draw 2D sprites using ID3DXSPRITE? Or do I have to take a more "3D" approach and create a whole world, with vertices, polygons, etc.? If I did take this 3D approach, wouldn't there be distortion at the edges of the screen from the conical camera view? Is there a way to change the camera to just a flat projection?

The more struct and function names you can use to describe what you are saying, the better (remember I am still fairly new at this). :)
First, look at D3DXMatrixOrtho* functions (I think that's what they are called), cause if you are developing a 2d game, you likely want to use Orthographic projection. To zoom in and out, change the resolution params you send to that function (it won't change real resolution, but it'll scale things for you, so that it looks zoomed).

When it comes to sprites.. You normally render them as textured quads yes. You CAN also use something called Point sprites, checkout codesampler.com for more details. Very nice for things like rain and particles, uses one vertex per sprite and one texture.

I took a look at the D3DXMatrixOrtho functions. I think that I'm supposed to feed the matrix into the SetTransform function --- is that right?

I tried using the following function in a program in which sprites are being drawn with ID3DXSPRITE::Draw (nothing happened):

void ZoomPlayArea(float width, float height) {  D3DXMATRIX matrix;  d3ddev->SetTransform(D3DTS_PROJECTION, D3DXMatrixOrthoRH(&matrix, width, height, -1000, 1000)); }


I wasn't sure what to put for the zn and zf values, so I tried to specify a broad range, -1000 to 1000.

Am I at least on the right track? Is there something I did wrong or something I still need to do? Am I supposed to use the D3DTS_PROJECTION type?
You are correct, you are supposed to feed it to SetTransform.. Although, for znear, use a small value, such as 1. I'm not sure it's supposed to be a positive number, but it seems to be working for me anyway.

void ZoomPlayArea(float width, float height) {  D3DXMATRIX matrix;  d3ddev->SetTransform(D3DTS_PROJECTION, D3DXMatrixOrthoRH(&matrix, width, height, 1, 1000)); }/*I tend to have something like this:*/void ZoomPlayArea(float zoom)  // zoom may never be 0! {  D3DXMATRIX matrix;  d3ddev->SetTransform(D3DTS_PROJECTION, D3DXMatrixOrthoRH(&matrix, m_width/zoom, m_height/zoom, 1, 1000));// or:// D3DXMatrixOrthoRH(&matrix, m_width - zoom * 0.1f, m_height - zoom * 0.1f, 1, 1000)); }


Which way you want depends completely on you.
Ah shoot [sad]

If it works for you and not for me, then maybe there's a problem in the way I draw sprites, or initialize Direct3D... If you don't mind, could you take a look at it, and see if there's anything that needs to be changed?

When I draw a sprite, I do it like this:

  if(d3ddev->BeginScene())   {    sprite_handler->Begin();    sprite_handler->Draw     (      texture,      NULL,      NULL,      NULL,      0.0,      &D3DXVECTOR2(x,y),      0xFFFFFFFF     );    sprite_handler->End();    d3ddev->EndScene();   }  d3ddev->Present(NULL,NULL,NULL,NULL);


And when I initialize Direct3D, I do it like this:

int Init_Direct3D(HWND hwnd, int width, int height, bool fullscreen){    //initialize Direct3D    d3d = Direct3DCreate9(D3D_SDK_VERSION);    if (d3d == NULL)    {        MessageBox(hwnd, "Error initializing Direct3D", "Error", MB_OK);        return 0;    }    //set Direct3D presentation parameters    D3DDISPLAYMODE dm;    d3d->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &dm);    D3DPRESENT_PARAMETERS d3dpp;     ZeroMemory(&d3dpp, sizeof(d3dpp));    d3dpp.Windowed = (!fullscreen);    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;    d3dpp.EnableAutoDepthStencil = TRUE;    d3dpp.AutoDepthStencilFormat = D3DFMT_D16;    d3dpp.PresentationInterval   = D3DPRESENT_INTERVAL_IMMEDIATE;    d3dpp.BackBufferFormat = dm.Format;    d3dpp.BackBufferCount = 1;    d3dpp.BackBufferWidth = width;    d3dpp.BackBufferHeight = height;    d3dpp.hDeviceWindow = hwnd;    //Only needed for dialog boxes    d3dpp.Flags=D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;    //create Direct3D device    d3d->CreateDevice(        D3DADAPTER_DEFAULT,         D3DDEVTYPE_HAL,         hwnd,        D3DCREATE_SOFTWARE_VERTEXPROCESSING,        &d3dpp,         &d3ddev);    if (d3ddev == NULL)    {        MessageBox(hwnd, "Error creating Direct3D device", "Error", MB_OK);        return 0;    }    //clear the backbuffer to black    d3ddev->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,0), 1.0f, 0);    //create pointer to the back buffer    d3ddev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &backbuffer);    D3DXCreateSprite(d3ddev, &sprite_handler);    return 1;}


Or maybe, could you point me towards an example that shows how to do this?

Thanks!
Again, checkout codesampler.com, LOTS of examples of just about everything.

I'm not sure, but I do believe ID3DXSprite thingy sets alot of render states and transform matrices, which can sometimes cause great headache.

This topic is closed to new replies.

Advertisement