3
\$\begingroup\$

I'm working on a 2D fighting game (using SDL) much like the original Killer Instinct on SNES. I want the camera to keep both players an equal distance from the left and right sides of the viewport. When either player moves, the camera adjusts to keep this equal distance and both players in view, except for when both players are at either end of the stage, during which the camera remains still. Here is an example of how the original KI camera works: http://youtu.be/eFgfaP7f7Rs?t=8m22s

I will provide a diagram of what I am trying to achieve.

enter image description here

The red box is the viewport (camera) which slides over the background image file to display the portion of the stage the players are currently in.

Goal: Each frame the player positions are checked and an algorithm is used to calculate the src.x clipping position for the camera. The midpoint, I believe, in addition with the distance between the players can be used to calculate this value. The viewport width and image width are stored in memory and can also be used. If one player moves, the camera moves at the same velocity, and if both are moving in the same direction, the camera should double its velocity to keep up, all whilst keeping both player's distances from the left and right sides in sync.

Currently, I am using integer math for all positions. I specify the clipping width on the image file using configuration files, so for example, my current background is 768 pixels wide and I clip it to 425 pixels wide, which is displayed in the viewport. The fighters have basic acceleration and max velocity. I use a Camera class to logically represent its x value from 0 to the right edge. The camera's x position is subtracted from the player's x position before rendering. Before rendering the background, I add the camera's x value to the clipping x value (src.x).

I have tried many silly things such as using the ratios of the image and clipping widths to get weird x values. I've tried simply using the midpoint and modifying it with whatever I could think of using the distance, but no luck. I do have semi correct movement by setting the camera x position to the midpoint - (image width - clipping width). However this of course does not keep the players at equal distances.

I've been trying to figure this out for a while and it seems so simple, yet the solution continues to elude me (I'm probably exhausted at the moment). It is possible there are some strange architectural decisions in my code that are making this needlessly difficult. If someone could help me figure out an algorithm, that would be all I need. I can provide more information as needed.

\$\endgroup\$
  • \$\begingroup\$ src.x = midpoint.x - (src.w / 2) ? \$\endgroup\$ – Trevor Powell Oct 14 '14 at 13:50
  • \$\begingroup\$ Thanks, this did not work, but src.x = midpoint.x - src.w appears to work. I will do rigorous testing to verify, and if it works then I'll post it as an answer. Seems too simple, but could be it. Also note that the midpoint I calculate is the midpoint in the viewport itself, not relative to the image coordinates. \$\endgroup\$ – Blue Wizard Oct 14 '14 at 16:24
2
\$\begingroup\$

This indeed should be very simple, so I suspect you may have gotten some details wrong.

The overall goal is to match up the center of the camera with the midpoint of the players. As you've found though, those values aren't immediately available to you, so you need to work them out. What you might have are (leaving out the Y axis stuff since we don't need them):

  • The top-left of the camera (let's call it src.x)
  • The size of the camera view port (call it src.w)
    • So the center of the camera is actually src.x + src.w / 2
  • The player positions (call them player1.x, player2.x)
    • I'm assuming your player positions are anchored at their midpoint, as this means you don't need to make any adjustments when they turn around (just do a flip). This does mean that when you render them, you need to draw their sprites from player.x - player.w / 2.

So altogether, you want this to be true:

src.x + src.w / 2 == (player1.x + player2.x) / 2

Rearranging for src.x, you want to perform the following:

src.x = (player1.x + player2.x) / 2 - src.w / 2

There are a few more details for a nice fighting game camera:

  • Don't let the camera go outside the stage or "world": clamp src.x between 0 and world.w - src.w.
  • You actually want to pan the camera towards the midpoint, rather than setting it to the midpoint immediately, as the code above does. This is so that when your players do teleporting special moves, you don't want the camera to jump around. You can play around with a few methods of movement to see what feels better without being nauseating or obtrusive - constant speed, tweening, panning with acceleration. From the video, it looks like KI is using constant speed, which is perfectly fine.
  • What happens if the players want to move further apart than the camera can see? In old-school fighting games they can't move further as scaling didn't work well, but modern 3D fighting games do often support this. Think about whether you want to also have zooming, or even panning vertically as players perform aerial moves.
\$\endgroup\$
  • \$\begingroup\$ Thanks for breaking this down, it clears it up, and this is a working solution. Indeed, I did get some details wrong, tends to happen when the code gets large. Also, excellent point on the camera panning. \$\endgroup\$ – Blue Wizard Oct 15 '14 at 0:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.