How do I zoom the camera to keep both players in frame?

HuntExe

Member
I'm working on a local multiplayer game, and I already coded the camera to stay in between both my players, but how would I zoom the camera in and out to keep both players in the view, like Super Smash Bros?

GML:
//Create Code:

cam = view_camera[0];

view_w_half = camera_get_view_width(cam) * 0.5;

view_h_half = camera_get_view_height(cam)  * 0.5;

xTo = xstart;

yTo = ystart;

follow = oPlayer1;

shake_length = 0;

shake_magnitude = 0;

shake_remain = 0;

buff = 8;


GML:
//Step Code:

if (instance_exists(follow))

{

    xTo = lerp(oPlayer1.x,oPlayer2.x,.5);

    yTo= lerp(oPlayer1.y,oPlayer2.y,.5);

}

x += (xTo - x) / 8;

y += (yTo - y) / 8;

x = clamp(x,view_w_half+buff,room_width - view_w_half-buff);

y = clamp(y,view_h_half+buff,room_height - view_h_half-buff);

x += random_range(-shake_remain,shake_remain);

y += random_range(-shake_remain,shake_remain);

shake_remain = max(0,shake_remain-((1/shake_length)*shake_magnitude))

camera_set_view_pos(cam,x-view_w_half,y-view_h_half);
 

HeadlessOne

Member
Hi Hunt,

seems like you have the positioning all sorted (full disclosure i have only skimmed your code) so all you need to do is tack on a camera_set_view_size(camera_id, width, height)

I would pre-define a minimum width and height earlier in your code and also tack in some kind of buffer for good measure so that the camera isn't TIGHT on the players.

GML:
minWidth = 900;
minHeight = 600;
xBuffer = 100;
yBuffer = 100;

camWidth = max(point_distance(p1.x,0,p2.x,0)+xBuffer,minWidth)
camHeight = max(point_distance(0,p1.y,0,p2.y)+yBuffer,minHidth)

camera_set_view_size(cam, camWidth, camHeight)
I've used the point_distance() function one dimensionally so we always get a positive number for the distance between the 2 players. (there is a real math way to do that but... this was all that came to mind right now)

You can actually use this same max() for more then 2 players as well, you would just need to add the point distances between p1 -> p3 & p2 -> p3 then the camera will always stay as far apart as the furtherest people. and so on for as many players or objects you would like the camera to keep in scope.


hope that helps, if you have any questions, let me know.
 

HuntExe

Member
I tried adding your code and it doesn't seem to work. 1. It doesn't keep its display ratio, it change, and 2. My player can still leave the screen. How do you think I could solve this?
GML:
//Create
cam = view_camera[0];
view_w_half = camera_get_view_width(cam) * 0.5;
view_h_half = camera_get_view_height(cam)  * 0.5;
xTo = xstart;
yTo = ystart;
follow = oPlayer1;
shake_length = 0;
shake_magnitude = 0;
shake_remain = 0;
buff = 8;
minWidth = 480;
minHeight = 270;
GML:
//Step
if (instance_exists(follow))
{
    xTo = (oPlayer1.x+oPlayer2.x)/2;
    yTo= (oPlayer1.y+oPlayer2.y)/2;
}

x += (xTo - x) / 8;
y += (yTo - y) / 8;

x = clamp(x,view_w_half+buff,room_width - view_w_half-buff);
y = clamp(y,view_h_half+buff,room_height - view_h_half-buff);

x += random_range(-shake_remain,shake_remain);
y += random_range(-shake_remain,shake_remain);
shake_remain = max(0,shake_remain-((1/shake_length)*shake_magnitude))

camera_set_view_pos(cam,x-view_w_half,y-view_h_half);

camWidth = max(point_distance(oPlayer1.x,0,oPlayer2.x,0),minWidth)
camHeight = max(point_distance(0,oPlayer1.y,0,oPlayer2.y),minHeight)

camera_set_view_size(cam, camWidth, camHeight)
Thanks for the response
 
Hello !

The width and height of the visible area indeed have to match the distance between the 2 characters.
I would modify the formula though :

GML:
//init
//the main size the of the camera
cam_base_W = 1920;
cam_base_H = 1080;

//the scaling of this camera (will keep the aspect ratio)
cam_scale = 1;

////////////////////////////////////////////////
//step

var P_Hdist = abs(p1.x - p2.x);        //horizontal distance between players
var P_Vdist = abs(p1.y - p2.y);        //vertical distance

cam_scale = max(1, P_Hdist/cam_baseW, P_Vdist/cam_baseH);    //choose the biggest to have enought space
cam_scale *= 0.1;                                            //adds a 5% margin on each edge

//the final calculation of the camera window
cam_W = cam_base_W * cam_scale;
cam_H = cam_base_H * cam_scale;
And now the second problem : the center of the camera, it should be the point between the two players

Code:
cam_x = p1.x + (p2.x - p1.x)/2 - cam_W/2;
cam_y = p1.y + (p2.y - p2.y)/2 - cam_H/2;
coord = player1 coord + half the vector to the mid distance - half the edge (to get the corner)

There might be some errors in formulas ... like invert some terms but the system should be fine.
Hope it helps ;)
 

HeadlessOne

Member
hmmm... im not sure why the player is leaving... it looks like in your follow code you have smoothed the camera movement with
GML:
x += (xTo - x) / 8;
y += (yTo - y) / 8;
which could temporarily allow a player to be out of frame... if they moved really fast... but only breifly.

and then if the player gets too close to the edge of the room then your clamp script here would allow them to leave the cameras range if they also leave the room.
GML:
x = clamp(x,view_w_half+buff,room_width - view_w_half-buff);
y = clamp(y,view_h_half+buff,room_height - view_h_half-buff);
I've made up a quick example just to test and the player can't leave the area... for the aspect ratio i have set up a variable called aspect ratio that the camera will maintain in the create event
GML:
cam = view_get_camera(0);
cam_x = 0;
cam_y = 0;
cam_minWidth = 1366/4;
cam_minHeight = 768/4;
cam_width = cam_minWidth;
cam_height = cam_minHeight;
cam_aspect = cam_minWidth/cam_minHeight
cam_xBuffer = 100;
cam_yBuffer = 100;
and then in the step function i have used that aspect ratio when compareing the width and height, and then adjusting the final output width and height based on which of them is larger.

Code:
//set x & y
cam_x = (player1.x+player2.x)/2
cam_y = (player1.y+player2.y)/2

//set base width & hight
cam_width = max(point_distance(player1.x,0,player2.x,0)+cam_xBuffer,cam_minWidth)
cam_height = max(point_distance(0,player1.y,0,player2.y)+cam_yBuffer,cam_minHeight)

    ///fixing aspect ratios for width and height
    var cur_aspect;
    cur_aspect = max(cam_width,cam_height*cam_aspect)
    cam_width = cur_aspect
    cam_height = cur_aspect/cam_aspect


camera_apply(cam)
camera_set_view_pos(cam,cam_x-cam_width/2,cam_y-cam_height/2);
camera_set_view_size(cam,cam_width,cam_height);
afew other notes for anyone else who is new to cameras and is wanting to follow along, under room you need to tick enable viewports in your room settings and have atleast one of the viewports marked as visible. if you have more then one viewport then you will have to do a check that you are in the right viewport before using camera_apply() otherwise all your viewports will have the same view.
1629950137454.png

Here is a link to the example file

hope that works now.
 

HuntExe

Member
hmmm... im not sure why the player is leaving... it looks like in your follow code you have smoothed the camera movement with
GML:
x += (xTo - x) / 8;
y += (yTo - y) / 8;
which could temporarily allow a player to be out of frame... if they moved really fast... but only breifly.

and then if the player gets too close to the edge of the room then your clamp script here would allow them to leave the cameras range if they also leave the room.
GML:
x = clamp(x,view_w_half+buff,room_width - view_w_half-buff);
y = clamp(y,view_h_half+buff,room_height - view_h_half-buff);
I've made up a quick example just to test and the player can't leave the area... for the aspect ratio i have set up a variable called aspect ratio that the camera will maintain in the create event
GML:
cam = view_get_camera(0);
cam_x = 0;
cam_y = 0;
cam_minWidth = 1366/4;
cam_minHeight = 768/4;
cam_width = cam_minWidth;
cam_height = cam_minHeight;
cam_aspect = cam_minWidth/cam_minHeight
cam_xBuffer = 100;
cam_yBuffer = 100;
and then in the step function i have used that aspect ratio when compareing the width and height, and then adjusting the final output width and height based on which of them is larger.

Code:
//set x & y
cam_x = (player1.x+player2.x)/2
cam_y = (player1.y+player2.y)/2

//set base width & hight
cam_width = max(point_distance(player1.x,0,player2.x,0)+cam_xBuffer,cam_minWidth)
cam_height = max(point_distance(0,player1.y,0,player2.y)+cam_yBuffer,cam_minHeight)

    ///fixing aspect ratios for width and height
    var cur_aspect;
    cur_aspect = max(cam_width,cam_height*cam_aspect)
    cam_width = cur_aspect
    cam_height = cur_aspect/cam_aspect


camera_apply(cam)
camera_set_view_pos(cam,cam_x-cam_width/2,cam_y-cam_height/2);
camera_set_view_size(cam,cam_width,cam_height);
afew other notes for anyone else who is new to cameras and is wanting to follow along, under room you need to tick enable viewports in your room settings and have atleast one of the viewports marked as visible. if you have more then one viewport then you will have to do a check that you are in the right viewport before using camera_apply() otherwise all your viewports will have the same view.
View attachment 42436

Here is a link to the example file

hope that works now.
Thanks for the reply,

I wasn't sure why my code wasn't working either, my room settings were correct and everything, so I put some of your code into my camera and it all works. I understand all the code too.

Thanks
 
Top