• Hey Guest! Ever feel like entering a Game Jam, but the time limit is always too much pressure? We get it... You lead a hectic life and dedicating 3 whole days to make a game just doesn't work for you! So, why not enter the GMC SLOW JAM? Take your time! Kick back and make your game over 4 months! Interested? Then just click here!

SOLVED Camera Issues - Click and Drag Camera + Zoom In/Out

P

paulomtts

Guest
Hello,

I have recently started a small project, and while setting up the basic functionalities I have encountered some issues while trying to combine a click and drag style camera with the ability to zoom in and out.

THE PROBLEM AT HAND

The problem I have been experincing happens whenever I zoom in or out and then try to move the camera. Before I attempt any zooming, the camera will move smoothly via click and drag, but after I have zoomed, the slightest flick will update the camera position a little bit in a somewhat rash manner. It seems as if instead of updating center of the screen gradually as per the click and drag functionality, the zooming somehow displaces it.

Therefore, I'd like to ask for the help of any who might know what causes the issue. I'd be grateful for any ideas.

OBJECT & CODE

My camera consist of an object (objCamera) that has the following events inside it:
  • Create - Initialize camera
GML:
/// @description Initialize camera
//Resolution
#macro RES_W 1024
#macro RES_H 768
#macro RES_SCALE 1

//Enable views
view_enabled = true;
view_visible[0] = true;

//Create camera
camera = camera_create_view(0, 0, RES_W, RES_H);

view_set_camera(0, camera);

//Resize window & application surface
window_set_size(RES_W * RES_SCALE, RES_H * RES_SCALE);
surface_resize(application_surface, RES_W * RES_SCALE, RES_H * RES_SCALE);

display_set_gui_size(RES_W, RES_H);

//Center window in display
var display_width = display_get_width();
var display_height = display_get_height();

var window_width = RES_W * RES_SCALE;
var window_height = RES_H * RES_SCALE;

window_set_position(display_width/2 - window_width/2, display_height/2 - window_height/2);
  • Step - Zoom in/out
GML:
/// @description Zoom in/out
camW = camera_get_view_width(camera);
camH = camera_get_view_height(camera);

var wheel = mouse_wheel_down() - mouse_wheel_up();

if(wheel != 0){
    wheel *= 0.05;
    
    //Add to size
    var addW = camW * wheel;
    var addH = camH * wheel;

    camW += addW;
    camH += addH;

    //Clamp zoom
    camW = clamp(camW, RES_W / 2, room_width);
    camH = clamp(camH, RES_H / 2, room_height);

    camera_set_view_size(camera, camW, camH);
}//IF
  • Global Drag Start - Get start position
GML:
/// @description Get start position
//Get last position in which mouse was pressed
startX = event_data[? "posX"]
startY = event_data[? "posY"]
  • Global Dragging - Move camera to point
GML:
/// @description Move camera to point
//Subtract START POSITION by CURRENT POSITION
var currX = startX - event_data[? "rawposX"];
var currY = startY - event_data[? "rawposY"];

//Clamp to room limits
currX = clamp(currX, 0, room_width - camW);
currY = clamp(currY, 0, room_height - camH);

//Set camera to position
camera_set_view_pos(camera, currX, currY);

As you may expect, startX and startY are initialized in Variables Definitions, both with value equal to 0.

Thanks in advance for any comments!
 

rytan451

Member
You'll likely want to keep track of your current zoom level and divide your event_data[? "rawposX"] by the zoom level before adding it to the camera position.
 
P

paulomtts

Guest
You'll likely want to keep track of your current zoom level and divide your event_data[? "rawposX"] by the zoom level before adding it to the camera position.
Hi :). Could you please write an example of what you mean? Im very much learning as I go, so Im not sure that I understood what you meant. Here's what I tried while considering what you've said:

  1. Changed the code in Step event to End Step.
  2. Added zLvl = 1; and then zLvl += wheel; to the End Step event.
  3. Changed the following code in the Global Dragging event:
GML:
var currX = startX - (event_data[? "rawposX"]/zLvl);
var currY = startY - (event_data[? "rawposY"]/zLvl);
Still, nothing came of it. So Im thinking I didn't properly understand your suggestion!
 

Yal

šŸ§ *penguin noises*
GMC Elder
This might be easier if you keep track of the center of the camera instead of the top left corner, since the center coordinate won't be affected by scaling... so there's no need to keep track of the scaling factors everywhere.
 
P

paulomtts

Guest
This might be easier if you keep track of the center of the camera instead of the top left corner, since the center coordinate won't be affected by scaling... so there's no need to keep track of the scaling factors everywhere.
I have done some more testing via the Output Console, and what I have found is that whenever I zoom, then camW and camH get altered up to their clamping thresholds. But what doesn't change, however, are the viewX and viewY values, represented in the code by event_data[? "rawposX"] and event_data[? "rawposY"]. Therefore, whenever the Click and Drag tries to calculate how much to move, is becomes much less smoother, because the difference between startX and event_data[? "rawposX"] becomes much higher.

I hear you about the camera center, but I am thinking that it might be even easier if instead of comparing values which depend on scaling, maybe I could do this using only the mouse position in the view to calculate how much to move the camera. Perhaps this - aligned with your idea - could work better?
 
P

paulomtts

Guest
Okay, problem solved! The issue was indeed related to comparing a scalable value ( event_data[? "rawposY"] ) with a non-scalable one (event_data[? "posX"], stored in starterX). The zooming would - obviously - alter the scale, and then the click and drag camera movement would act strange. The solution was to simply compare values which stay in the same scale. At first I thought using the camera view width and height would be a good idea, since this wouldn't be altered, but this results in a pan-like movement which - although not bad - wasn't quite what I was looking for. I decided to simply use the mouse position in the room as a reference, and so the codes became:
  • Gobal Drag Start
GML:
/// @description Get start position
//Get START position in which mouse was pressed
startX = event_data[? "posX"];
startY = event_data[? "posY"];
  • Global Dragging
GML:
/// @description Move camera to point
//Subtract START POSITION IN ROOM by CURRENT POSITION IN VIEW

var currX = camera_get_view_x(camera);
var currY = camera_get_view_y(camera);
var addX = startX - event_data[? "posX"];;
var addY = startY - event_data[? "posY"];;

currX += (addX * 1);
currY += (addY * 1);


//Clamp to room limits
currX = clamp(currX, 0, room_width);
currY = clamp(currY, 0, room_height);

//Set camera to position
camera_set_view_pos(camera, currX, currY);

Thanks for the replies though, they gave me some ideas of where to look for the error!
 
N

nardoodle

Guest
Hello, I had a similar problem and your code seemed to fix it but now my camera is zooming into the top left of the view. I was using " camera_set_view_pos(cam_id, x-camW * 0.5, y-camH * 0.5); " in the step event to center the zoom in my view and that worked before the dragging was implemented but now if I leave that in my step the dragging doesn't work because the step event is overriding the camera_set_view_pos in the Global Dragging event. Any Ideas?
Here is my code-
CREATE-
GML:
cam_id = view_camera[0];

drag_roomX = 0;
drag_roomY = 0;

originalX = 1280;
originalY = 720;
zoom = 1;
target_zoom = zoom;
STEP-
GML:
zoom += (target_zoom - zoom) * zoom_spd;

camera_set_view_size(cam_id, originalX * zoom, originalY * zoom);

camW = camera_get_view_width(cam_id);
camH = camera_get_view_height(cam_id);

var mouse_input = mouse_wheel_down() - mouse_wheel_up();

//Clamp zoom
target_zoom += mouse_input;
target_zoom = clamp(target_zoom,1,8);

camW = clamp(camW, 1280 / 2, room_width);
camH = clamp(camH, 720 / 2, room_height);

//camera_set_view_pos(cam_id,x-camW*0.5,y-camH*0.5);
Variable Definitions-
scroll_spr = 0.1;
zoom_spd = 0.1;

and my Global Drag Start & Global Dragging is the same as yours.
I also tried using your exact step and create code but I had the same problem.
 

popley303

Member
I know this post is older, but if anyone could please solve an issue i am having using the OP code. When i zoom in it will lock the screen so it will not go beyond the top left side, which is great, but when i pan to the bottom right corner it goes past the window perimeters. When it does that it creates multiple copies of the background. I was hoping someone could look at this code and see what is missing that would cause it to be able to draft past the boarders of the game on the neg axis grids.

Thank you in advance.
 
Top