How do I make camera follow and zoom to 2 players?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By HiddenRealm

I have 2 players in my scene. One is controlled by WASD and the other by the arrow keys. I want the camera to zoom out when one player reaches the edge, so they are still visible. And maybe zoom in when they get closer? How would I do this?

:bust_in_silhouette: Reply From: njamster

Here you go! Attach the following script to your camera node and make sure to set the export variables object1 and object2 to your two player-nodes:

extends Camera2D

export (NodePath) var object1
export (NodePath) var object2

func _ready():
	object1 = get_node(object1)
	object2 = get_node(object2)

func _process(delta):
	self.global_position = (object1.global_position + object2.global_position) * 0.5

	var zoom_factor1 = abs(object1.global_position.x-object2.global_position.x)/(1920-100)
	var zoom_factor2 = abs(object1.global_position.y-object2.global_position.y)/(1080-100)
	var zoom_factor = max(max(zoom_factor1, zoom_factor2), 0.5)

	self.zoom = Vector2(zoom_factor, zoom_factor)

Of course that’s a a very simple and rather limited implementation of the behavior you described, but it should give you a general idea and it’s easily extensible.

Thanks for this! However, when I run the program it gives me this error.
“Invalid get index ‘global_position’ (on base: ‘null instance’).”
I’m not entirely sure what this means?

HiddenRealm | 2020-05-14 20:03

It means that you’re trying to access the property global_position of a non-existent node. The variables object1 and object2 are paths to the nodes the camera is supposed to include at all times. As there’s no way for me to know how these paths look like in your project, I defined them as export variables without a default. So in order for this script to work, you have to set these paths yourself: if you select the Camera2D-node, you should see two entries labeled “Object 1” and “Object 2” at the top of the inspector window, click “Assign”, select your player nodes and the error should be gone.

njamster | 2020-05-14 23:47

thanks so much! works great now. marked as answered.

HiddenRealm | 2020-05-17 04:28

:bust_in_silhouette: Reply From: Wadah

I believe its hard to find something similar online , I am not a pro and not experienced with Vector2D , there might be some built in functions to handle this and am just re inventing the wheel .
Its also my first time to answer but I liked the question so I want to get it starting for you I will give a mathematic/logical answer and WILL NOT WRITE ACTUAL GODOT SCRIPT its just pseducode since I can’t access my Godot editor right now .
First i will write down my mindset
Here I assume Godot vectors work same as math vectirs at algebra lessons
Vector a(5,3)
Vector b(-3,-3)
Vector c(-1,1)
The vector between a and b : (1,0)
The vector between a and c : (2,2)

I assume vector magnitude = vector.length() in godot
Eg vector (500,1720) have magnitude of 1791.2
Vector (100,402) have magnitude of 414.25
If Godot Vectors act different please inform me to add the math calculation formula
In order to make the camera focus both of the players it must be placed in between
And zoom in-out according to the distance between them
So for camera position I will : in pseducode

# start
Get 1st player position
Get 2nd player position
Calculate camera position= 1st player position- 2nd player position
Set the the camera position to the variable above *0.5
# end

Godot camera zoom works with x and y values with 1 as default value

Increase both camera zooms out 
Decrease both camera zooms in

now that we have the camera in the middle , we calculate distance from camera to any of the players as reference .
for the the zoom , you can either use range (steps ) zoom or calculated (real-time) zoom
Steps zoom:
using number of if elif statement
Eg .

# start
Zooming=1 #stores selected zoom
Cam_position = camera position
PlayerA_pisition = Player a position 
Zoom_vector = cam_position - playerA_position 
If Zoom_vector.length()<= 200 :
ElIf Zoom_Vector. Length()<=250:
   Zooming =1.1
..... Till the last elif
Camera.zoom=Vector2(zooming , zooming )

You will have to experiment with outcome of different distances between players to get this right , use print function to print the distance .

Calculated zoom :
take the distance (cam-player) itself and offsets it to match the property of the camera , for example to give range of ( 1 - 1.5 ) which is (start zoom , maximum zoom out )
To get this right , use print function to print the distance between players and distance between player and cam
For example if you find its comfortable to start zooming out from (500,1720) distance between players, (250,860) distance between player and camera
With Magnitudes : 1791.2 and 895.6 respectively . ( we use magnitudes because they express distance , using victors as ranges here will introduce tons of issues)
This gives you maximum zoom out at around 2600 and starts at 1791.2
Let’s get to the pseducode
Your offsetting value would be 895.6 ( as am using the cam-player as reference)

# Start
Offset = 895.6 # you find by experimenting as explained above
Zoom_vector = as calculated in the last pseducode
Zooming = zoom_vector / offset
If (zooming <= Zoom_start || zooming >=Zoom_max):
   Alert_not_zooming(zooming) #function to alert other scripts
   Return # Don't zoom outside the limits , it also saves processing power 
camera . zoom= Vector2(zooming,zooming)
# End 

Notice : this might introduce some glitches or issues depending on your game scale .
Use the Alert_not_zooming(zooming) function to use it for example to tell players to not go further from each other or to limit their movement accordingly

As final word . thank you for being patient enough to read and try to implement my answer in code , I will have email notifications allowed so I can answer any question or issues you might have after trying this