I don't have any in mind but...
You can do this with a camera as children of a center node or directly with the camera (I prefer to leave the cameras alone when possible).
The camera/focus position will be updating constantly at (node1.get_pos()+node2.get_pos())/2
, or global pos if the scene is more complex.
Camera should follow smooth if possible for better look, drag margin can be a problem when zooming.
Something quick and dirty and using the camera directly instead of a parent as focus:
edit: realized that got a problem with the code, you get NodePath from export, could be better to assign groups to the player and just call that group to get an array of players
extends Camera2D
export(NodePath) var player_1
export(NodePath) var player_2
var p1
var p2
func _ready():
p1 = get_node(player_1)
p2 = get_node(player_2)
if p1!=null&&p2!=null:
set_process(true)
func _process(delta):
var newpos = (p1.get_global_pos()+p2.get_global_pos())*0.5
set_global_pos(newpos)
#then comes the zoom
For zooming, get camera/focus difference with positions of one of the nodes and use that as a zoom factor to set a target zoom (adjust until it feels good for your game).
Or distance_to could be useful for this too.
Depending on the type of zoom you want, you may need to make the zoom factor related on the viewport size to keep characters to the same distance from the border of the screen.