[DirectX] Scrolling/2dCamera..howto?

Started by
9 comments, last by Steve00000 15 years, 3 months ago
Hello again everyone! I've searched google all over but as it hasn't been my friend I resort to my last option, the bay of the pro's! ;D (I hate asking questions that were answered before > >) I searched this forum but sadly only found similar topics which didn't end up the same as what I'm trying, or were outdated to older SDK versions.. Now, I come from SDL, so things used to be a LOT easier than what I'm trying in DirectX. ; I'm working on a 2d game project, something like WarioWare, and it has a small mini-part which is rpg-like. So what I'm trying to do is get a camera in action. In SDL this would've been easy, but I have no idea how to do it in DirectX.. Here is Lazyfoo's page which gives a better description of what I'm trying to do; http://lazyfoo.net/SDL_tutorials/lesson21/index.php I'm getting a bit frustrated as I've looked all over but can't find any source codes or explanations as to how to do this in 2d. Thanks in advance, ~J
------Future C.A.R.D. Game Technologies-----
Advertisement
Sounds like what you want to accomplish can be done with two separate 2D coordinate systems. We can call them Screen Space and World Space.

Screen space is everything on your screen. If your resolution is 800x600, then that is your screen space! You could draw a sprite at screen space 0, 0 and it would appear in the top left corner of the screen.

World space is a little more abstract. It can be any size you wish it to be. Let's say you define it to be 1600x1200, so it would be four times as large as your screen space.

The way it should work is that a sprite is given a world space position (for example, x=900 y = 600), BUT it will be drawn with screen space coordinates.

So how do you know what the screen space coordinates are? Well they can be calculated with the help of a camera object. A camera object will also have world space coordinates which are used to translate sprite world space coordinates to screen space coordinates that are used to calculate the location to draw it.

Here is a diagram I made in MS Paint.


The black box in the image is the world space. Imagine this as the entire game world.
The red box is the screen space. Imagine this as everything that is being viewed on your monitor.
The blue dot/blue text is the camera location.
The green box/green text is a sprite.

So, we can see that the sprite has a world space position of 900, 400. If we subtract the camera position from this, (900-400), (600-300), we get the result of 500, 300, which would be the position in screen space the sprite will be drawn, so on your screen you would see the sprite located just a bit off center. So you see you can change the camera position, and the location at which the sprite is drawn will change too, even though the sprite is not changing its world space location.

Does this make sense? I can explain more if not.

[Edited by - CandleJack on January 6, 2009 11:32:22 PM]
I completely understand the above, and as far as I understood it works almost the same in SDL, but I would have no idea how to do this in DirectX..

I used to draw everything on a seperate surface, and eventually cut the camera rect out and display it on the main surface. (screen)

And that wasn't even the right way to do it, but it did work. ;p

If you have the time I'd love to hear more, I really want to learn/understand this.

~J

P.S. Thanks for the paint image, I understood it the moment I saw it. (At times I understand harder through text only.)
------Future C.A.R.D. Game Technologies-----
Quote:Original post by Auriya
I completely understand the above, and as far as I understood it works almost the same in SDL, but I would have no idea how to do this in DirectX..


That's right, it works no matter what graphics API you are using, since it's really more of a conceptual design that you implement, instead of calling methods in a library. As long as you can draw an image on the screen it will work! So, are you asking how to draw a sprite using DirectX? Do you want to use Direct3D sprites or DirectDraw?
Well thats good to hear! I'm looking forward to be able to pull this off on DirectX as well with help :]

Also I'm using Direct3D, as it was more advised to use. And so far it works pretty well, I can also show you my source code if you want.
Many images seem a bit blurry, but that can be a different topic, I'd rather not mix things up too much~!



Edit: I'm sorry, it's 4AM here at the moment, I lost track of time! I have to go get some sleep now so I'll check back at this topic in about 6~7 hours or so. :) Thanks for the help so far!


Edit:Edit before I go: No, I didn't mean to ask how to draw a sprite :p I can already do that. But I was wondering how I could accomplish a 2d camera in DirectX, if there's a source code or an explanation I could take a look at.

Like in SDL I used to make a surface, draw everything on it, and then get the camera set up on that surface and clip the rect and draw it onscreen. But in DirectX I don't really know how to make a surface like I used to in SDL either. >< (Nor do I know how to do the Screen Space and World Space or get whatever I draw in them on screen in DirectX.)
So I was wondering if anyone knew how to get something like it done in DirectX or not. ;p

Well, I'll check back on this topic tomorrow morning. :] Thanks so far!

[Edited by - Auriya on January 6, 2009 9:09:01 PM]
------Future C.A.R.D. Game Technologies-----
Well if you're able to draw a sprite on the screen you're really all set. You need to keep track of the location of the sprite using x and a y coordinates, so that's as simple as using two integer variables. You also need to keep track of the camera location using an x and y coordinates, so two more integer variables. Here's a simple code snippet that may help.

int spriteX, spriteY; // Sprite locationspriteX = 900;spriteY = 600;int cameraX, cameraY; // Camera location.cameraX = 300;cameraY = 400;void drawSprite(){   // Render the sprite   spriteImage->blit(spriteX - cameraX, spriteY - cameraY);}


So you can move the sprite around by changing the sprite x and y variables, and you can move the camera around by changing the camera x and y variables.

This is of course overly simplified, as you may want to take an object oriented approach, and do things like make sure the camera is within the bounds of the world size.
Hey again!

Thanks for the reply, however the reason I asked is because I don't exactly know how to make a surface I can draw on.. Now when I draw something, it draw it directly on-screen, at least I assume so.

This is how I draw;

int GraphicsHandler::drawSprite(int buffer, float xpos, float ypos){	--buffer;	if(buffer >= images.size()) //Check whether the given buffer is valid or not	{		MessageBox(NULL, L"GraphicsHandler :: Wrong buffer ID given!", L"GraphicsHandler :: Fail", MB_OK);		return -1;	}	imageData &data = images[buffer];    // Draw the sprite    D3DXVECTOR3 center(0.0f, 0.0f, 0.0f);		// Center at the upper-left corner	D3DXVECTOR3 position(xpos, ypos, 0.0f);		// Position the image to the given paramenters		//pseudo	d3ddev->SetRenderState( D3DRS_ALPHABLENDENABLE, true );	d3ddev->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );	d3ddev->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );	d3ddev->SetTextureStageState( 0, D3DTSS_ALPHAARG1,D3DTA_TEXTURE );	//pseudo    d3dspt->Draw(data.sprite, &data.rect, &center, &position, D3DCOLOR_XRGB(255, 255, 255)); // Draw    	return 0;}



And so, this part;

d3dspt->Draw(data.sprite, &data.rect, &center, &position, D3DCOLOR_XRGB(255, 255, 255)); // Draw


Draws directly on-screen, and I wanted to know if there was a way to draw by giving two surfaces, one as source of where to draw from, and one as destination, where I want to draw on.


For example, on SDL it would go like this, at least its how I used to do it;

SDL_Surface *gameScreen = SDL_GetVideoSurface(); //This surface now holds our main video screenSDL_Surface *worldSpace;SDL_Surface *temp, *image; //Creating two surfaces to hold the loaded imagetemp = IMG_Load("data/image.png"); //Load the image into a temporary surfaceimage = SDL_GetOptimizedImage(temp); //Can't exactly remember the function name, but gets the optimized PNG imageSDL_FreeSurface(temp); //Free the surface 'temp'SDL_Rect imagelocation = {0, 0, 16, 16}; //Lets say, the image we loaded, is a 16x16 tileSDL_Rect clip; //Our camera rectclip.x = 100;	clip.y = 100;clip.w = 150;	clip.h = 150;for(int i = 0; i < 100; i++){	for(int j = 0; j < 100; j++)	{		imagelocation.x = (j * 16);		imagelocation.y = (i * 16);		SDL_BlitSurface(image, 0, worldSpace, &imagelocation) //Here's how I used to do it	}}SDL_BlitSurface(worldSpace, &clip, gameScreen, 0); //Here we clip a part out of worldSpace and draw it on screen



Not sure if the above makes sense, I haven't touched SDL in a while either ;p
------Future C.A.R.D. Game Technologies-----
Ah. Hmm, well I'm not too familiar with Direct3D unfortunately, but it sounds like what you are trying to do is draw every sprite to a surface representing the world space, and then copy only a chunk of that surface that is the same size as the screen to the screen. Is that correct?
Yes! That is correct, that's how I used to have the 2d camera in SDL, so I thought a similar approach would be available on Direct3D..
------Future C.A.R.D. Game Technologies-----
I see, I was confused because in my approach only drawing to the screen is required. I would suggest giving it a try doing it the way I've shown you though. It seems like rendering every single tile to an offscreen surface and then displaying only a chunk of it would be somewhat inefficient because you are potentially rendering a bunch of tiles to that offscreen surface that you don't even see! For example, if you have a tile map that is 1000 tiles high and 1000 tiles wide, and your screen size is 800x600 pixels, and 32x32 tiles, you would be drawing 1,000,000 tiles when you are only ever seeing around 500 at a time. With the way I've shown you would only be drawing the tiles that you can see.

You would probably even be able to cut down on that nested loop you've got going from 0 to 100 in both the outer and inner loops. You really only need to loop through the visible tiles, so you would probably be able to cut it down to maybe 0 to 20 in the outer loop, and 0 to 27 in the inner loop (again assuming same sizes as stated above, for the sake of example). It would take significantly less time to go through the loops! With 100 iterations in both, and if each loop iteration takes, for arguments sake, one second, then the entire thing would take 10,000 seconds to execute. if you had say, 25, iterations in each loop it would take 625 seconds. Huge difference there! Obviously it would not be in seconds since computers are so fast, but since the scene is rendered every frame, I suspect if you optimize your render loop you would see a nice boost in the FPS.


- Edited to fix my hasty math

[Edited by - CandleJack on January 7, 2009 7:02:46 PM]

This topic is closed to new replies.

Advertisement