2D Camera follow two players

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By everancii
:warning: Old Version Published before Godot 3 was released.

Hello, i want to add second player to my game, and make camera follow both of them, like this

Now i have this code for camera anchor, when player came to the area camera start following him.

  extends Area2D

var player_class = preload("res://scenes/player.gd")

func _ready():
	get_node("Sprite").hide()

func _on_CameraAnchor_body_enter( body ):
	if (body extends player_class):
		get_node("/root/Controller").cam_target = self

func _on_CameraAnchor_body_exit( body ):
	var c = get_node("/root/Controller")
	if (body extends player_class and c.root.load_state == 0):
		print("aaaa")
		c.cam_target = body

Not sure what you’re asking for.

The example looks like the camera focuses on the mid point between both players, and when they start going beyond a certain margin, it zooms out accordingly to maintain that margin.

avencherus | 2016-12-21 18:44

I need same reaction of the camera, but for platformer with bigger world than showed in this video . Camera must follow two players and when one player star going to certain margin it should zooming out.

everancii | 2016-12-21 19:30

Well that’s exactly how you should write it. There isn’t any built in feature like that in Godot, you have to manually calculate those distances, and set the position and zoom property of your camera according to your preference.

avencherus | 2016-12-21 19:35

Do you know where I can find some examples of the code ?

everancii | 2016-12-21 19:39

First time seeing it. Haven’t seen any examples, sorry.

avencherus | 2016-12-21 19:42

This is sad , but thank you anyway

everancii | 2016-12-21 19:46

:bust_in_silhouette: Reply From: eons

The thing is that the camera there never follows the players but the center of the players.

In godot you can simplify a bit things and make a node as a camera focus (parent of the camera), that node will try to be always in the center of the action, the distance to the nodes the center follows will define the zoom of the child camera (you can make it smooth to add some effects when the camera follows the center).

This style can be used with many players, enemies or something important on the scene, just put all on the same group and search for the max and min xy pairs to get the center position.


An interesting way could be using a moving path, the path with 2 points moving with each player, a pathfollow on unit offset fixed on 0.5 with a child camera, the camera can get the distance with the offset to make the zoom.

This I think has less calculations and fast to prototype, will work easy with 2 objects, but may have problems with zoom.

Thanks you for your answer. Im very new in all of this, you don’t know where i can find some examples? It helps me alot. Now, i’m just shooting in the dark with my pro level scripts :wink:

This is solution for Unity - 2D Camera to follow two players - Questions & Answers - Unity Discussions

everancii | 2016-12-22 09:45

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.

eons | 2016-12-22 12:43

Trying to get distance from players like this

func _process(delta):
    var newpos = (p1.get_global_pos()+p2.get_global_pos())*0.5
    set_global_pos(newpos)
var distance = Vector2(p1).distance_to(p2)

but it says

Invalid call. Nonexistent 'Vector2' constructor.

everancii | 2016-12-22 17:53

distance_to gives a float, it should be:

var distance = p1.distance_to(p2)

Then use that to create the zoom factor.
If you just multiply the distance to a fixed small number(like 0.0005), higher zooms will give bigger separation between players and border of screen (lineal).

A lineal zoom modification may look good on some games, if not a bit of math work will be needed to get the perfect equation.

Finallly, when you got it (be distance*number or something more complex), just do:

set_zoom(Vector2(1,1)*zoom_factor)

eons | 2016-12-22 20:01

Trying like this

  func _process(delta):
        var newpos = (p1.get_global_pos()+p2.get_global_pos())*0.5
        set_global_pos(newpos)
    var distance = p1.distance_to(p2)
    var d = distance * 1
    get_node("Camera2D").set_zoom(d)

But it says Parser Error: Unexpected token: Identifier:get_node

everancii | 2016-12-22 20:51

The indentation is the same as that code block? because then you are writing the get_node outside the function

eons | 2016-12-22 22:41

Yeah this is was indentation ^^
Now i got this error

Invalid call. Nonexistent function 'distance_to' in base 'RigidBody2D

everancii | 2016-12-23 00:19

Solve my problem and make it work with this script

extends Camera2D

func _ready():
	# Initialization here
	set_process(true)
func _process(delta):
	var p1_pos = get_node("/root/world/Player").get_pos()
	var p2_pos = get_node("/root/world/Computer").get_pos()
	var newpos = (p1_pos+p2_pos) * 0.5
	set_global_pos(newpos)
	var distance = p1_pos.distance_to(p2_pos) * 2
	var zoom_factor = distance * 0.005
	set_zoom(Vector2(1,1) * zoom_factor / 2)

But now zoom is too high, from player to margin a very long distance when start zooming out enter image description here

everancii | 2016-12-23 11:26

Keep playing with the zoom factor, use smaller numbers until it feels good for your game.

eons | 2016-12-23 13:58

Thank you for your help

everancii | 2016-12-23 15:27