What's a good way to code a multi-directional, one-way teleport?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By System_Error

Hey all. I have an idea for instantly moving my player a decent distance nigh-instantly. I’d like to know a very simple way to make the teleport work at the push of a button (spacebar).

Other features I’d like are: Inability to teleport if the destination is blocked, ability to completely bypass other Bodies if destination isn’t blocked, Teleport destination depends on which direction the PlayerShip was moving last.

Here’s the player.gd code for those who need a reference to what I have.

extends KinematicBody2D 
# The Class above ^ {KinematicBody2D} being used.


# Class CONSTANTS. These cannot be changed by code.
const MAX_SPEED = 200
const MAX_FORCE = 15
const ACCELERATION = 20
const DECELERATION = 10
const floor_normal = Vector2()

# Class VARIABLES. These can be changed by code.
var speed = 0.0
var velocity = Vector2() # speed + direction = velocity


func _ready(): # Upon program start-up, run code in this block.
	set_process(true)

func _process(delta): # All the code in this function is called about every 0.133 seconds.
	var direction = Vector2()

	# This section listens for User Input.
	if Input.is_action_pressed('move_up'):
		direction.y = -1
	if Input.is_action_pressed('move_left'):
		direction.x = -1
	if Input.is_action_pressed('move_down'):
		direction.y = 1
	if Input.is_action_pressed('move_right'):
		direction.x = 1

	if direction:
		speed = MAX_FORCE

	# Normalize the movement Vector and modulate the speed
	var movement = direction.normalized() * speed * 7
	
	# Move the body based on the calculated speed and direction
	move_and_slide(movement)

System_Error | 2018-12-03 23:08

:bust_in_silhouette: Reply From: p7f

Hi,

Assuming you already have the direction of movement, i would use Area2D to check if there is some body on destination, and RayCast2D to teleport to nearest place if there was something in destination. Both Area2D and RayCast2D should be childs of your character (i assume kinematicbody2d), And area2D should be at the distance from the character you want to teleport. Also, due to comments, i would use a timer to check if the key was hold enough. This one with one_shot enabled. Also, timeout signal of timer, connected to _on_TeleportTimer_timeout() function. Then, something like this:

teleport_distance = 500 #or whatever you like    

func _input(event):
    if event.is_action_pressed("teleport"):
           $TeleportTimer.start()
    if event.is_action_released("teleport):
           $TeleportTimer.stop()

func _on_TeleportTimer_timeout():
 if Input.is_action_pressed("teleport"):
	if len($Area2D.get_overlapping_bodies()) == 0:
		position = $Area2D.global_position
	else:
		position = $RayCast2D.get_collision_point()

func _physics_process(delta): 
    var direction = Vector2()

# This section listens for User Input.
    if Input.is_action_pressed('move_up'):
        direction.y = -1
    if Input.is_action_pressed('move_left'):
        direction.x = -1
    if Input.is_action_pressed('move_down'):
        direction.y = 1
    if Input.is_action_pressed('move_right'):
        direction.x = 1

    direction = direction.normalized()
    $Area2D.position = teleport_distance * direction
    $RayCast.rotate(direction.angle())
    if direction:
        speed = MAX_FORCE

# Normalize the movement Vector and modulate the speed
    var movement = direction * speed * 7

# Move the body based on the calculated speed and direction
    movement = move_and_slide(movement)

Honestly, i just tried two way teleport. Tell me if it’s work and if not i’ll try to fix.

Note: i changed _process by _physics_process cause you use move_and_slide there and i think that involves physics. I also changed the movement line to movement = move_and_slide(movement) so you have updated real movement after calling the function.

Note2: for RayCast2D to work correctly in this context, you should have multiple raycasts that cover all your area (until in 3.1 we can do it with just one). This is because the Area2D may be overlaping a little in a position when Raycast does not collide and the code will take you to position (0,0)

Ah.

So I’m working on a top-down space-maze. The ship would teleport after the spacebar was held down for a couple seconds, and has a recharge time that lasts a little longer. Teleporting would fail if there’s a wall (StaticBody2D) or other object (RigidBody2D) at the teleport destination.

System_Error | 2018-12-03 21:48

Ok, but teleport would have to pass through walls if there is nothing at destination?

p7f | 2018-12-03 21:57

That wasn’t implied?

But yes, the teleport should be able to bypass walls, so long as nothing is at the destination.

System_Error | 2018-12-03 22:25

Ok, i’ll edit my answer. Could you edit your question for adding all this? And how do you want to get the destination direction? with mouse? with character rotation?

p7f | 2018-12-03 22:30

Alright. Consider the question “edited”.

System_Error | 2018-12-03 22:51

I’ve never used RayCast2D before.

System_Error | 2018-12-04 15:55

RayCast2D are not difficult to use. You set it as child of your character. Rotate it to the direction you want the ray to go. Then modify the “cast to” attribute to set how long it will go. All this from inspector. Then you can modify this from code. Do you need any help with it? if you share me the complete code of the game i think i could add the teleport if you wait me a few days. Do you have it on github or somethin?

p7f | 2018-12-04 18:23

I only have it on my computer right now. I don’t remember my GitHub login, so that’s always a problem.

System_Error | 2018-12-04 18:25