How to add RayCast2D collision exceptions externally?

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

I’m trying to do something like that:

if ground_ray1.is_colliding() or ground_ray2.is_colliding():
	ground_ray1.add_exception(player)
	ground_ray2.add_exception(player)
	set_fixed_process(false)

but i don’t know how to do it since the KinematicBody2D node representing the player isn’t on the same scene. Before this, I’ve tried to do that:

onready var scn_player = preload("res://scenes/player.tscn")

func _ready():
	var player = scn_player.instance()

but didn’t worked, i think it’s because that would be a generic copy of this scene and not the one running on the game and whose i’m trying to make an exception.

I would either like to know some other useful functions that are related with RayCast2D’s collisions, they are really useful.

:bust_in_silhouette: Reply From: paolobb4

Use raycast’s method get_collider().

From the documentation (2d or 3d is all the same):

Object get_collider() const

Returns the closest object the ray is pointing to. Note that this does not consider the length of the ray, so you must also use is_colliding() to check if the object returned is actually colliding with the ray.

Example:

if RayCast2D.is_colliding(): var collider = RayCast2D.get_collider()

In this case, the collider can be associated with the player scene? I want to add it as an exception.

What i’m trying to do is, in the game there are various blocks falling, if the block collides with another block, it stops (for optimization and avoid collision mess). But if it collides with the player, it will keep going.

ErnestoGilgamesh | 2018-08-30 15:58

I imagine that there’s the main scene that has both the player and the blocks as children. Well if the blocks are being generated from the main scene script then you could add player to their exception list on instantiation.

paolobb4 | 2018-08-30 16:06

If you still feel like continuing with the approach you’ve taken so far, you could check the collider type to ensure it’s a player.
Here you can find some answers on how to check object type: How to check type of a custom Class? - Archive - Godot Forum

paolobb4 | 2018-08-30 16:35

I did some checking and what is returned when I print the collider is: “[KinematicBody2D:606]”, how can i refer this on code? It can’t be done as a string.

Something like that:

if bottom.is_colliding():
	var collider = bottom.get_collider() 
	if collider == "[KinematicBody2D:606]":
		bottom.add_exception(collider)

Is that an specific ID that just the player has, or this would be the same for any KinematicBody2D?

ErnestoGilgamesh | 2018-08-30 17:48

That’s how it is:

main
block_spawner
container
blocks instanced

I’ll try to instance the player on the container either and see what happens.

ErnestoGilgamesh | 2018-08-30 17:57

I put both in the block spawner and tried to do that:

if container.block_32.bottom.is_colliding():
    		var collider = container.block_32.bottom.get_collider()
    		if collider == container.player:
    			print("check")

But it returns this error:

Imgur: The magic of the Internet

ErnestoGilgamesh | 2018-08-30 18:22

When you call get_collider() it returns the object itself, when you call print(obj) it prints a string representation of the object which, in this case is a KinematicBody2D with obj_id=606.

Anyways, I recommend you to just add player to the block’s rays’ exception list.

So if you have a Block class where every instance will have 2 RayCast2D children, and assuming that player is a brother of block_spawner, and foo the method that spawns the blocks; in your code, where you spawn the new blocks, it should go something like this:

# block_spawner.gd
···
func foo():
    # Do stuff...
    var player = $"../player"    # short for get_parent().get_node("player")
    var new_block = Block.new()
    new_block.ray1.add_exception(player)
    new_block.ray2.add_exception(player)
    
    get_parent().add_child(new_block) # don't forget to add it to the tree

Of course I’m missing certain details about your code but that’s the gist of it, adjust it to your needs.

paolobb4 | 2018-08-30 20:32

There is some difference, specially with the “new()”. Here is the entire code anyway. I’ll do some modifications based on what you said and see what happens.

# Blocks spawner

extends Node2D

const scn_block_32 = preload("res://scenes/block_32.tscn")
const scn_player = preload("res://scenes/player.tscn")
onready var container = get_node("container")

func _ready():
    var player = scn_player.instance()
    container.add_child(player)
	set_fixed_process(true)
	
func _fixed_process(delta):
	#Moving spawner up
	set_pos(Vector2(get_pos().x, get_pos().y - 200 * delta))

# Spawn block 32x32
func spawn_block_32():
	randomize()
	var new_block_32 = scn_block_32.instance()
	new_block_32.set_pos(Vector2(rand_range(16, 240), get_pos().y))
	container.add_child(new_block_32)

# Timer
func _on_timer_0_timeout():
	spawn_block_32()

ErnestoGilgamesh | 2018-08-30 21:36

Now for some reason my player is going left forever if it is on container. This doesn’t make any sense.

I will start all again.

ErnestoGilgamesh | 2018-08-30 22:21

You’ve set player as a child of container and in your code container is constantly moving 200 px/s left. A child always follows it’s parent.

Starting over is ok if you are just at the beginning of a project, but otherwise it’d be better for you to start using a vcs (like git) if you haven’t already, it will save you a loooot of pain. If you don’t know what they are you can find a ton of tutorials online (like this ones for git).

I wish you the best of lucks.

paolobb4 | 2018-08-31 17:51

Didn’t thought about that, makes sense now. It’s my very first project and i was just 2 days working on it, no problem starting over. I’ll take a look on that vcs.

ErnestoGilgamesh | 2018-08-31 18:55

I made it all again and discovered a bunch of things:

  • For some reason, the get_node("player") were adding the player scene to the current node (that would be the container from block_spawner), but i never told it to add a child. That is what causes the player to go left forever. Then i decided to erase my instance and left that one there, but the exception wasn’t working either. Then i’ve put get_node("/root/arcade/player, which solved the problem with the double players.

  • The add_exception(player) is being ignored. I printed the collider and the player to see what they were if the collision is detected, and for my surprise, they were the same! So, i was doing it right, but the condition is being ignored for some reason. Also, i get this error when colliding the block while it is in the air:

ERROR: KinematicBody2D::get-collider: Condition ' !colliding ' is true. returned: 0 At: scene\2D\physics-body_2d.cpp:1326
  • I also tried to make a variable can_stop, that would continue false if the collider was equal to the player. But it didn’t worked either.

What the hell is happening here? The add_exception function works well on the player’s raycast by avoiding any accidental collision with the player collision shape by checking jump disponibility. Don’t know why this doesn’t work here.

I’m doing it on the block scene itself. Code:

extends KinematicBody2D

onready var bottom_ray = get_node("bottom_ray")
onready var player = get_node("/root/arcade/player")
. . .
func _ready():
. . .
	set_fixed_process(true)

func _fixed_process(delta):
. . .
	# Collision
	if bottom_ray.is_colliding():
		bottom_ray.add_exception(player)
		set_fixed_process(false)

I also tried:

if bottom_ray.is_colliding():
	bottom_ray.add_exception(player)
	if bottom_ray.is_colliding():
		set_fixed_process(false)

But the issue continued.

ErnestoGilgamesh | 2018-09-01 00:36