+1 vote

I tried putting it in sleep and then changing pos. Also tried this inside integrateforces(s).

if teleporting:
  var new_transform = s.get_transform()
  new_transform.o = teleported_pos
  s.set_transform(new_transform)
  teleporting = false

Even creating other functions, yield(get_tree(),"idle_frame") putting these idle frames everywhere and literally every combination of things mentioned above.

The body is always teleported inaccurately. Usually going into walls. It varies around +- 100 for both x and y. I'm really depressed...

What is simple and proper way to teleport RigidBody2D in version 2.1.4?

asked Jun 23, 2018 in Engine by Sprowk (327 points)

2 Answers

0 votes

I don't know of any official "proper" way. The most consistent method I've found is to use set_physics_process(false), wait for a small delay, then set_global_position, then wait again, then reactivate physics.

Usually the delays are not enough to make the player feel lag, especially since teleporting usually happens around a level transition or somewhere players expect it / won't be upset by it.

You might be interested in this question, although it's about a KinematicBody2D.

I've written a script for this exact thing:

extends Node

signal buffer_expired

export(NodePath) var body_path
onready var body = get_node(body_path)

export(float) var time_buffer = 0.02
var time_remaining

var teleporting = false

func _ready():
  set_process(false)

func teleport(new_destination):
  # don't teleport while teleporting!
  if teleporting:
    return

  teleporting = true

  # disable physics
  body.set_physics_process(false)

  # wait for physics engine to chill out
  time_remaining = time_buffer
  set_process(true)
  yield(self, "buffer_expired")

  # do teleport
  body.global_position = new_destination

  # wait again to prevent physics engine from undoing teleport
  time_remaining = time_buffer
  set_process(true)
  yield(self, "buffer_expired")

  # re-enable physics
  body.set_physics_process(true)
  teleporting = false

func _process(delta):
  time_remaining -= delta
  if time_remaining <= 0:
    set_process(false)
    emit_signal("buffer_expired")

Happy to receive feedback or explain more if this doesn't help.

answered Sep 18, 2018 by markopolo (618 points)
0 votes

Is your object moving before teleporting using _integrate_forces()? If yes, I suppose that you also need to reset RigidBody2D's linear and angular velocities to avoid the object going into walls that way. Setting body's transform is usually not enough:

if teleporting:
    var new_transform = s.get_transform()
    new_transform.o = teleported_pos
    s.set_transform(new_transform)

    # Reset velocities to avoid the object going through walls
    s.set_linear_velocity(Vector2())
    s.set_angular_velocity(0.0)

    teleporting = false
answered Sep 18, 2018 by Xrayez (1,236 points)
Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read How to use this Q&A? before posting your first questions.