3
\$\begingroup\$

I am fairly new to game maker, and I am trying to create a directional smooth scaling camera. Think Civilization 5's camera, when you zoom the camera, it zooms in towards the mouse, keeping the in-game world location where the mouse is pointed at, regardless of zoom level.

I have mostly gotten the system working, however, there are some weird scrolling issues, mainly whenever I move the scroll wheel, the viewport will jerk around while the code narrows down the actual coordinates it should be focusing the camera on.

Here's what it looks like: http://i.imgur.com/x0g5zLu.gifv

I can't figure out why the camera does this.

Step event:

//Move camera object
if keyboard_check(vk_left) x -= scroll_speed;
if keyboard_check(vk_right) x += scroll_speed;
if keyboard_check(vk_up) y -= scroll_speed;
if keyboard_check(vk_down) y += scroll_speed;

if mouse_wheel_up() || mouse_wheel_down() {

    //Adjust the target zoom scale to necessary
    if mouse_wheel_up() target_zoom_scale -= zoom_scale_adjust;
    if mouse_wheel_down() target_zoom_scale += zoom_scale_adjust;   
    scale_ratio = abs(target_zoom_scale - current_zoom_scale) / zoom_speed;

    //set movement steps. x_ratio is the number
    x_ratio = abs(target_x - x) / zoom_speed;
    if target_x > x x_ratio *= -1;
    y_ratio = abs(target_y - y) / zoom_speed;
    if target_y > y y_ratio *= -1;

    //Get the new w/h of the final target zoom
    var new_width, new_height;
    new_width = room_width * target_zoom_scale;
    new_height = room_height * target_zoom_scale;

    //Get the ratio of the mouse to the screen
    var mouse_x_ratio = window_mouse_get_x() / window_get_width();
    var mouse_y_ratio = window_mouse_get_y() / window_get_height();

    //Translate the point. The point will be in the same exact spot in game window
    //this is obtained by taking the new width/height, multiplying it by the respective ratio
    //and then subtracting that from the target location. Then, the target is added half of the new width/height
    target_x = mouse_x - (new_width * mouse_x_ratio) + (new_width / 2);
    target_y = mouse_y - (new_height * mouse_y_ratio) + (new_height / 2);
}

//correct any out of bounds issues for the target zoom scale
if target_zoom_scale > max_zoom_scale target_zoom_scale = max_zoom_scale;
if target_zoom_scale < min_zoom_scale target_zoom_scale = min_zoom_scale;

//adjust the zoom scale.
if current_zoom_scale != target_zoom_scale {
    if target_zoom_scale > current_zoom_scale current_zoom_scale += scale_ratio;
    else if target_zoom_scale < current_zoom_scale current_zoom_scale -= scale_ratio;
    if abs(target_zoom_scale - current_zoom_scale) < scale_ratio current_zoom_scale = target_zoom_scale
}

//adjust camera location. Snap if necessary.
if x != target_x {
    x += x_ratio;
    if abs(x - target_x) > abs(x_ratio) x = target_x;
}
if y != target_y {
    y += y_ratio;
    if abs(y - target_y) > abs(y_ratio) y = target_y;
}

//Redundantly check against out of bounds for the current zoom.
if current_zoom_scale > max_zoom_scale current_zoom_scale = max_zoom_scale;
if current_zoom_scale < min_zoom_scale current_zoom_scale = min_zoom_scale;

//Set the width and height of the viewport accordingly
view_wview[0] = room_width * current_zoom_scale;
view_hview[0] = room_height * current_zoom_scale;

//set the view centered around the camera object
view_xview[0] = x - (view_wview[0] / 2);
view_yview[0] = y - (view_hview[0] / 2);

//Clean up camera out of bounds
if x < 0 x = 0;
if x > room_width x = room_width;
if y < 0 y = 0;
if y > room_height y = room_height;
if view_xview[0] < 0 view_xview[0] = 0;
if view_xview[0] + view_wview[0] > room_width view_xview[0] = room_width - view_wview[0];
if view_yview[0] < 0 view_yview[0] = 0;
if view_yview[0] + view_hview[0] > room_height view_yview[0] = room_height - view_hview[0];

constructor:

//Center the camera
x = room_width / 2;
y = room_height / 2;

//max_zoom_scale is the maximum zoom that the camera is capable of (zoomed out)
max_zoom_scale = 1.0;

//min_zoom_scale is the minimum zoom that the camera is capable of (zoomed in)
min_zoom_scale = 0.05;

//zoom_scale_adjust is the amount the target zoom scale is adjusted
//by when the mouse wheel is moved.
zoom_scale_adjust = 0.25;

//zoom_speed is the number of steps it takes to complete a zoom.
zoom_speed = 40;

//current_zoom_scale is zoom scale that will be actively used by the camera
current_zoom_scale = 1;

//target_zoom_scale is the zoom scale the camera will move towards.
target_zoom_scale = current_zoom_scale;

//original zoom scale is the zoom scale when the change was initiated
original_zoom_scale = current_zoom_scale;

//This is the change per step to the current scale to the target scale
scale_ratio = 0;

//Target x/y coordinates for directional zoom
target_x = x;
target_y = y;

//If under this amount, the directional zoom will snap to the target coordinate
x_ratio = 0;
y_ratio = 0;

//Scroll Speed The number of pixels per step to adjust the camera view
scroll_speed = 100;

Can anybody else see what I am doing wrong?

\$\endgroup\$
  • \$\begingroup\$ No, sorry. As an additional tip, by using an actual .gif image, you could embed it in the post. But it's much better now than it was before :) \$\endgroup\$ – Alexandre Vaillancourt Jul 15 '16 at 13:15
  • \$\begingroup\$ Just making sure: the problem you're trying to fix is when you zoom in or zoom out? \$\endgroup\$ – DH. Jul 15 '16 at 13:40
  • \$\begingroup\$ Right, the problem is that the display seems to be bumping the view when the target zoom scale changes, and it recalculates the target scale and location. Also, there is likely a bug in the mathematics because the location is almost always incorrect, but 'nearby' \$\endgroup\$ – CorrieKay Jul 15 '16 at 13:46

Your Answer

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

Browse other questions tagged or ask your own question.