Godot smooth transition between players

Viewed 162

I have a "parent" player scene, and I inherit scenes for each player. The parent player scene has a camera. When the game switches between players, one player turns off its camera, and the other player turns its camera on:

if state != State.ACTIVE:
    # If this player is becoming active, also
    # set camera current    
    state = State.ACTIVE
    camera.current = true
else:
    # If player is not becoming active,
    # disable this players camera
    camera.current = false

But players can be in different positions, so the camera "jumps" from one to the other. Can we do something more sophisticated, like set the new camera to the current position so the smooth setting can be used to handle the transition?

One idea is to do get_viewport().get_camera() to find the current position of the camera to try and sync the position of the current camera with the new camera that is about to turn on, but appears to not work for 2D scenes. CF: https://github.com/godotengine/godot/pull/38317

1 Answers

Sadly, as you found out, there is no way to get the current Camera2D in Godot 3.x. And you found the pull request that adds the feature to Godot 4.0.

What I'm going to suggest is to have one sole Camera2D, so that one is always the current one. And you can define Position2D inside your scenes that can serve as interpolation targets to move the Camera2D.


I have an script that I think will be useful for you (I made it to be RemoteTransform2D but backwards, it does push a transform, it pulls it), I call it anchor_transform_2d.gd:

tool
class_name AnchorTransform2D
extends Node2D

export var anchor_path:NodePath setget set_anchor_path
export var reference_path:NodePath setget set_reference_path
export var set_local_transform:bool
export(int, FLAGS, "x", "y") var translation_mode:int
export(int, FLAGS, "x", "y") var scale_mode:int
export var rotation_mode:bool


var _anchor:Node2D
var _reference:Node2D


func _physics_process(_delta: float) -> void:
    if not is_instance_valid(_anchor) or Engine.editor_hint:
        set_physics_process(false)
        return

    #INPUT
    var input := _anchor.global_transform
    if is_instance_valid(_reference):
        input = _reference.global_transform.affine_inverse() * input

    #TRANSLATION
    var origin := Vector2 (
            input.origin.x if translation_mode & 1 else 0.0,
            input.origin.y if translation_mode & 2 else 0.0
        )

    #ROTATION
    var angle := 0.0
    if rotation_mode:
        angle = input.get_rotation()

    #SCALE
    var source_scale = input.get_scale()
    var scaling := Vector2 (
        source_scale.x if scale_mode & 16 else 1.0,
        source_scale.y if scale_mode & 32 else 1.0
    )

    #RESULT
    _set_target_transform(
        Transform2D(angle, origin) * Transform2D.IDENTITY.scaled(scaling)
    )


func set_anchor_path(new_value:NodePath) -> void:
    anchor_path = new_value
    if not is_inside_tree():
        yield(self, "tree_entered")

    _anchor = get_node_or_null(anchor_path) as Node2D
    set_physics_process(is_instance_valid(_anchor) and not Engine.editor_hint)
    if Engine.editor_hint:
        update_configuration_warning()


func set_reference_path(new_value:NodePath) -> void:
    reference_path = new_value
    if not is_inside_tree():
        yield(self, "tree_entered")

    _reference = get_node_or_null(reference_path) as Node2D


func _set_target_transform(new_value:Transform2D) -> void:
    if set_local_transform:
        transform = new_value
        return

    global_transform = new_value


func _get_configuration_warning() -> String:
    if _anchor == null:
        return "Anchor not found"

    return ""

Add this attached to a Node2D in anchor_path set the target from which you want to pull the transform (anchor_path is a NodePath, you can set to it something like $Position2D.get_path()). And set what do you want to copy (you can choose any combination of position x, position y, scaling x, scaling y, and rotation). Then put the Camera2D as a child of the AnchorTransform2D, and set smoothing_enabled to true.

Rundown of the properties:

  • anchor_path: A NodePath pointing to the Node2D you want to pull the transform from.
  • reference_path: A NodePath pointing to a Node2D used to make the transform relative (you will be taking the transform of what you put in anchor_path relative to what you put in reference_path).
  • set_local_transform: Set to true if you want to pull the transform as local (relative to the parent of AnchorTransform2D), leave to false to set the global transform instead.
  • translation_mode: Specifies if you are going to copy the x position, y position, both or neither.
  • scale_mode: Specifies if you are going to copy the x scale, y scale, both or neither.
  • rotation_mode: Specifies if you are going to copy the rotation or not.

The only reason the script is a tool script is to give you a warning in the editor if you forgot to set the anchor_path.

Related