4
\$\begingroup\$

My question is relatively hard to explain(for me, at least), so I'll go one step at a time and just tell me in the comments if it's not clear enough.

So I'm making a "Defend Your Castle" type 2D game, where two players own a castle and create units that will move horizontally to try to destroy the opponent's base. Here's a screenshot of the game:

The distance between both castles is much bigger in a real game though, bigger than the screen's width actually.

Because the distance is bigger than the screen's width, I had to implement a simple 2D camera: Camera2D, which only holds a Location Vector2 (and I always make sure this camera is within the field area).

Then, I just move all the game elements(castles, units, health bars) by that location, so that if a unit is at (5, 0), and the camera's location is (5, 0), then the unit's position will be moved by 5 units to the left, making it (0, 0) on the screen.

At first, I simply used a static background with mountains and clouds(yeah, those are supposed to be mountains and clouds). Obviously, this looked awful: when you moved the camera, the background would stay immobile.

Instead, I'd like to make a moving background, kind of a "scrolling" one. But rather than making a background with the same width as the distance between the castles, I'd like to make one that is a little bit smaller(but still bigger than the screen's width). I thought this would create an effect of "distance" with the background(but it might just look awful, too).

Here's the background I'm testing with: enter image description here

I tried different ways, but none of them seems to work. I tried this:

float backgroundFieldRatio = BackgroundTexture.Width / fieldWidth;//find the ratio between the background and the field.
float backgroundPositionX = -cam.Location.X * backgroundFieldRatio;//move the background to the left

When I run this with fieldWith = 1600, BackgroundTexture.Width = 1500 and while looking at the rightmost area, the background is offset to the left by a too big amount, and we can see the black clear color in the back, as you can see here: enter image description here

I hope I explained properly what I'm trying to achieve.

Thank you for your time.

Note: I didn't know what to look for on Google, so I thought I'd ask here.

\$\endgroup\$
0

3 Answers 3

2
\$\begingroup\$

The solution to your problem is actually quite simple. Instead of calculating the ratio, you calculate the possible movement-distances for camera and background and interpolate them.

For the background this is going to be: bgMovement = fieldWidth - backgroundWidth (results in 100)

For the camera it's camMovement = fieldWidth - viewPortWidth.

Assuming that the camera x-coordinate is at the left, your background position would be:

background.X = -cam.X + (bgMovement / camMovement * cam.X) (assuming cam.X goes from 0 to camMovement)

Update: If you want to stick with the backgroundFieldRatio (which is probably more intuitive) you can calculate it like this:

backgroundFieldRatio = (backgroundWidth - viewPortWidth) / (fieldWidth - viewPortWidth);

This should give you the proper movement ratio to plug into your code (or the one proposed by Andrew Russell in his answer).

\$\endgroup\$
3
  • \$\begingroup\$ This is exactly what I've been looking for! Thanks a LOT! \$\endgroup\$ Mar 14, 2011 at 12:00
  • 1
    \$\begingroup\$ is there a name for this technique? \$\endgroup\$
    – Spooks
    Mar 14, 2011 at 20:41
  • 2
    \$\begingroup\$ Parallax scrolling (en.wikipedia.org/wiki/Parallax_scrolling) \$\endgroup\$
    – bummzack
    Mar 14, 2011 at 22:14
4
\$\begingroup\$

First of all, you've got a bit of a maths problem:

I can't be entirely sure from the code you've posted, but if fieldWidth is an int and not a float, then your backgroundFieldRatio will not be set correctly (you are dividing two integers and getting an integer result). It will be set to 0.0f. Based on the results you are getting, I suspect this is the case.

Second of all, the way you are setting your object positions based on the camera is quite ugly.

Basically when you do parallax scrolling you have multiple 2D "cameras". You should set your camera position to target somewhere in world space

Vector2 cameraTarget;

You can have your parallax camera as:

float ratio = 0.9f;
Vector2 parallaxCameraTarget = cameraTarget * ratio;

Then just draw your parallax scene first using the parallax camera, and then draw your main scene on top using the main camera.

Now, don't draw sprites like this:

sb.Draw(texture, position - cameraTarget, Color.White); // BAD!

What you should do is create a translation matrix in your Begin call and simply draw all your sprites in World Space:

Matrix camera = Matrix.CreateTranslation(-cameraTarget.X, -cameraTarget.Y, 0f);
sb.Begin(SpriteSortMode.Deferred, null, null, null, null, camera);

sb.Draw(texture, position, Color.White);

That way you can modify how your camera works without having to adjust every single Draw call!

\$\endgroup\$
3
  • \$\begingroup\$ While your answer contains excellent advice and best-practice, it doesn't answer the OPs question (which is how to properly calculate movement in order to prevent the black bars from appearing). \$\endgroup\$
    – bummzack
    Mar 14, 2011 at 9:02
  • \$\begingroup\$ I appreciate the advices on the camera. I knew it was ugly, but I didn't really know how to do it differently, thanks for correcting me! :) \$\endgroup\$ Mar 14, 2011 at 11:54
  • \$\begingroup\$ @bummzack Ah - yes - I had assumed his ratio calculation was correct. But your answer is quite right in pointing out that you also need to take into account the viewport width. \$\endgroup\$ Mar 14, 2011 at 12:41
1
\$\begingroup\$

Sounds like you are indeed talking about parallax scrolling.

(it's not c# or XNA, but the skills are transferable)
You can read up on some simple scrolling backgrounds in an sdl tutorial actually
http://lazyfoo.net/SDL_tutorials/lesson22/index.php

(one of my all time favorite tutorials)

Then you can make multiple layers, and move them relative to the camera's position.

\$\endgroup\$
2
  • \$\begingroup\$ But is parallax scrolling only for looping backgrounds? I just want the background to move from left to right once, at a constant speed. Basically I want to find this exact speed based on the fieldWidth, the background's width and the camera's location. \$\endgroup\$ Mar 14, 2011 at 5:14
  • 2
    \$\begingroup\$ I believe (I could be wrong) that parallax scrolling is for adding a feeling of depth to a 2d environment: in other words, more than one scrolling background to create a more "realistic" environment. Well finding the speed isn't a problem, especially if you're setting it =) \$\endgroup\$ Mar 14, 2011 at 5:17

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .