0
\$\begingroup\$

I am building an interactive application in Starling for which a camera system is required. Since there is no existing camera system in flash and the addons for starling do not meet our requirements, I am writing my own. Basically, it moves and scales all assets depending on the position of the camera.

However, I am having trouble with zooming towards a specific point on the screen. Every object has a pivotpoint in the topleft corner - so it scales relative to the topleft corner. For all kinds of reasons, I cannot change the pivotpoint of the objects.

To compensate for this, the camera needs to move towards the point we want to zoom towards on the x/y-plane, but I cannot figure out how much it should move. Are there any known formulas for this? How do I calculate how the camera should move?

EDIT: I can actually move the pivotpoint to the center of the assets if that makes it much easier.

EDIT: This method is used on each sprite to update its position:

var zPos:Number = Number(this.z - Game.cameraZ);
var scale:Number = Game.focalLength / (Game.focalLength + zPos);
var correctedScale:Number = scale * (1 / (Game.focalLength / (Game.focalLength + this.z)));
this.scaleX = this.scaleY = correctedScale;
this.x = Game.cameraX * scale + this.defaultX * scale;
this.y = Game.cameraY * scale + this.defaultY * scale;
\$\endgroup\$
  • \$\begingroup\$ In general I would recommend using matrices for this, rather than writing it all out longhand. Also, if you can somehow access the view/projection matrix Flash is using to draw stuff, it will be much, much easier. \$\endgroup\$ – mklingen Apr 22 '15 at 17:55
1
\$\begingroup\$

Expressing your camera using bounds

If I noticed correctly, you are currently expressing your camera as a focuspoint (= center of the camera) and a zoom level (how closely zoomed in you are). I'm also assuming your game is two-dimensional, with assets rendered in the XY-plane, and the camera looking along the Z-axis.

While parametrizing your camera like this could definitely work, you could also think of it differently. Instead of stating what where your camera is looking at, you could specify what area you want to be onscreen. In this case, you would parameterize your camera in terms of bound. On the X-axis, you have the left bound and the right bound. On the Y-axis, you have the top bound and the bottom bound. (Assuming the X-axis is your horizontal axis, pointing to the right, and the Y-axis is your vertical axis, pointing upward.)

Using this parameterization, you are always 100% what is being shown onscreen. Note that you can always translate back and forth between this representation and your original one (this requires the "scale" parameter to be split in a "xScale" and "yScale", as scaling is not necessarily uniform).


World coordinates and Screen coordinates

Your question basically relates to moving from world coordinates to screen coordinates.

  1. The world coordinates of an asset express its place in your game world. You could think of this as the position where you place the asset with your map editor. They remain unchanged if you move the camera around.
  2. The screen coordinates of an asset express its location on your screen. You can think of this as follows: assume you jump into your game and take a photograph of the scene, through the lens of your camera. The place where your asset ends up on the photograph, are the screen coordinates of the asset. They are affected by the camera. If you move the camera to the left, your asset will move to the right in screen coordinates.

Lets assume your screen has a width of screen_w (e.g. 800 pixels), and a height of screen_h (e.g. 600 pixels). To translate a single point from world coordinates to screen coordinates, you'd do the following:

x_screen = screen_w * (x_world - cam_left_bound) / (cam_right_bound - cam_left_bound) 
y_screen = screen_h * (y_world - cam_bottom_bound) / (cam_top_bound - cam_bottom_bound)

If you use a y-axis that points downward, this last line becomes:

y_screen = screen_h * (y_world - cam_top_bound) / (cam_bottom_bound - cam_top_bound)

For example, a point that is exactly at the left bound of your camera will have a screen x-coordinate of 0. A point exactly at the right bound of your camera will have a screen x-coordinate of screen_w. Other points will evaluate to their correct position as well.


Solution: Calculating the bounds of your assets

The above explains how to find where a single point would end up in screen coordinates. You can use this information to figure out where an asset goes as well.

Again, rather than thinking of an asset as a centerpoint on top of which a scalable sprite is drawn, you could think of it in terms of bounds. If you know the left, right, top and bottom bounds of your sprite (in screen coordinates), you know exactly where and how to draw it. In essence, you are just drawing a rectangle on your screen, and you are drawing the asset inside of this rectangle.

Thus, to figure out how to draw your asset in screen coordinates, do the following:

  1. Use the left, right, top and bottom bounds of your asset in world space (these are 2 x-coordinates and 2 y-coordinates)
  2. Transform these coordinates to screen coordinates
  3. Draw your asset on a rectangle that uses those screen coordinate bounds

In summary, you might find your problem easier by thinking in terms of bounds, rather than a position and a scaling factor. Thinking of the "position finding problem" as a transformation between world space and screen space may also help you. In fact, transformations between different coordinate systems or spaces are ubiquitous in 2D and 3D rendering for games! The difference is that they use matrices rather than separate equations, as these are easier when combining multiple transformations (e.g. translations, rotations and scalings).

\$\endgroup\$

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.