When changing the position of my object it teleports back to where it was before for no reason

Godot Version

v4.2.2

Question

I’m trying to set the .position of my player object and when I do it blips at the spot for a moment and goes back to falling where it was

The deathbox collider is the bottom blue box collider(teleports player):

Nodes (the deathbox is unnamed rn so its just CollisionShape2D):
image

Closeup with visible player:

The player blipping on screen for a frame when tp is attempted:

Code to tp player (at bottom, it comes from an on collide with body trigger on the deathbox):

extends Node2D

# mostly for the cards
@onready var scac = %ScaleContainer
@onready var player = %Player
#@onready var ctext = $Cardtext
@onready var SBC = %ScaleBcon
@onready var gamen = get_tree().get_root().get_node("Game")
#@onready var CTexture = $CardTexture

# Cool hand stuff
@onready var hand = $Camera2D/Hand/Handanimator
@onready var handn = $Camera2D/Hand
@onready var handcool = $Handcool

# ledges
@onready var eledge = $Ledges/Endledge
@onready var sledge = $Ledges/Startledge


@onready var CCon = $Camera2D/Cardcontainer

signal loaded

var starty := 300.0
var startyt := 300.0

var endx := 360.0
var endxt := 360.0

var difficulty = 0
var tdiff = 0

var handst = false
var cardcount = 3
var itstop = false
var canstop = true
var Mprotoscale = load("res://protoscalemenu.tscn")

var card = load("res://propcard.tscn")

@export var invent = []

@export var proplist = {}

func Cselected():
	hand.play("handanim")
	for i in CCon.get_child_count():
		CCon.get_child(i).queue_free()
	handst = false

func loadlvl(idif):

	startyt = starty
	endxt = endx
	
	tdiff = difficulty
	glvl()
	
	sledge.position.y = startyt
	eledge.position.x = endxt
	player.position = Vector2(-480,-starty + 300)
	
	SBC.visible = true
	handst = true
	hand.play("handin")
	for i in cardcount:
		var instance = card.instantiate()
		instance.position = get_global_mouse_position()
		instance.scac = scac
		instance.player = player
		instance.SBC = SBC
		instance.gamen = gamen
		CCon.add_child(instance)
	if idif:
		difficulty += 1
	

func glvl():
	var choice = randi_range(0,2)
	if choice == 0:
		tdiff -= 1
	if choice == 1:
		startyt -= randi_range(-40,5)
		tdiff -= 0.5
	if choice == 2:
		endxt += randi_range(-40,5)
		tdiff -= 0.5
	
	if tdiff > 0:
		glvl()

# Called when the node enters the scene tree for the first time.
func _ready():
	loadlvl(true)


# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta):
	if itstop:
		Engine.time_scale = 0
	else:
		Engine.time_scale = 1
	
	
	if canstop && ((handn.rotation == 134.4 && handst) || (handn.rotation == 0 && !handst)):
		itstop = true
	else:
		itstop = false
	
	
	if Input.is_action_just_pressed("RClick"):
		loadlvl(true)
		
	print(player.position)


func _on_button_pressed():
	pass
	#if itstop && canstop:
		#itstop = !itstop
		#canstop = !canstop


func _on_area_2d_body_entered(body):
	player.position = Vector2(-480,-starty + 300)
	player.linear_velocity = Vector2.ZERO

Rigid bodies don’t like being teleported, you will want to avoid altering position directly wherever possible. In this case to force teleporting you will have to queue the teleport until a _integrate_forces override can handle it. Add this to your player script, then use player.queue_teleport = instead of position.

var queue_teleport: Vector2

func _integrate_forces(state: PhysicsDirectBodyState2D) -> void:
    if queue_teleport != Vector2.ZERO:
        state.transform = Transform2D(0.0, queue_teleport)
        state.linear_velocity = Vector2.ZERO # also only edit linear_velocity in _integrate_forces
        queue_teleport = Vector2.ZERO
1 Like

I don’t actually understand what this does or how to use it. You said to replace player.position with player.queue_teleport but I don’t understand and it also throws an error. How does this work? (_integrate_forces, → void, state)

var queue_teleport: Vector2

func _integrate_forces(state: PhysicsDirectBodyState2D) -> void:
	if queue_teleport != Vector2.ZERO:
		state.transform = Transform2D(0.0, queue_teleport)
		state.linear_velocity = Vector2.ZERO # also only edit linear_velocity in _integrate_forces
		queue_teleport = Vector2.ZERO

func Cselected():
	hand.play("handanim")
	for i in CCon.get_child_count():
		CCon.get_child(i).queue_free()
	handst = false

func loadlvl(idif):

	startyt = starty
	endxt = endx
	
	tdiff = difficulty
	glvl()
	
	sledge.position.y = startyt
	eledge.position.x = endxt
	player.queue_teleport = Vector2(-480,-starty + 300)

Is this script part of the player? Only the player (a RigidBody2D) should have the _integrate_forces function.

queue_teleport is a variable storing the teleport position, if it’s ZERO it’s assumed to be “empty” and has nothing to queue. It uses _integrate_forcesstate to change the player object during the physics thread.

Ohh I put it on the game node oops
The game node was handling tp but yeah I can send a signal to player I think

You won’t need to signal the player, that’s why your changing player.queue_teleport just like you would change player.position

So I put this in the game node where it was tping the player

func loadlvl(idif):

	startyt = starty
	endxt = endx
	
	tdiff = difficulty
	glvl()
	
	sledge.position.y = startyt
	eledge.position.x = endxt
	player.queue_teleport(-480,-starty + 300)
	
	SBC.visible = true
	handst = true

And I put this in the player

#curses
var lessjump = 0
var lessspeed = 0

var queue_teleport: Vector2

func _integrate_forces(state: PhysicsDirectBodyState2D) -> void:
	if queue_teleport != Vector2.ZERO:
		state.transform = Transform2D(0.0, queue_teleport)
		state.linear_velocity = Vector2.ZERO # also only edit linear_velocity in _integrate_forces
		queue_teleport = Vector2.ZERO

func _ready():
	pass # Replace with function body.
func _process(delta):
	isccol = raca.is_colliding() || raca2.is_colliding()

But it’s throwing and error and I bet I’m being an idiot (or this is some big complex bit like messing with the processing order directly)

It’s a variable, not a function. Use assignment, just like player.position

player.queue_teleport = Vector2(-480,-starty + 300)

Make sure to post the error message you recieve and the relevant line.

Not fixed,

The car still blips and doesnt tp, line is

player.queue_teleport = Vector2(-480,-starty + 300)

and there’s no error now though

(Code in player:)

#curses
var lessjump = 0
var lessspeed = 0

var queue_teleport: Vector2

func _integrate_forces(state: PhysicsDirectBodyState2D) -> void:
	if queue_teleport != Vector2.ZERO:
		state.transform = Transform2D(0.0, queue_teleport)
		state.linear_velocity = Vector2.ZERO # also only edit linear_velocity in _integrate_forces
		queue_teleport = Vector2.ZERO

func _ready():
	pass # Replace with function body.
func _process(delta):
	isccol = raca.is_colliding() || raca2.is_colliding()

Interesting, does the _integrate_forces ever run? Could you add a print statement to test?

func _integrate_forces(state: PhysicsDirectBodyState2D) -> void:
	if queue_teleport != Vector2.ZERO:
		print("teleporting transform: ", queue_teleport)
		state.transform = Transform2D(0.0, queue_teleport)
		state.linear_velocity = Vector2.ZERO # also only edit linear_velocity in _integrate_forces
		queue_teleport = Vector2.ZERO

The function runs, but the if statement only runs right at game start hmmm (I used print(“:D”) to test)

Is there any reason queue_teleport would be set to ZERO? Would you normally teleport the player to ZERO?

No the player starts at this pos