I'm using move_and_collide, how do I dispose of the remainder upon collision?

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

const TARGET_FPS = 60
const SPEED = 60

onready var sprite = $Sprite

func move(target):
	var move_tween = get_node("Hammer_Tween")
	move_tween.interpolate_property(self, "position", position, target, 60)
	move_tween.start()
	# Smoothens movement.

var motion = Vector2.ZERO 
var velocity = Vector2() 

func _process(_delta):

	motion.y = 0 # Character is unaffected by gravity.

	move_and_collide(motion, Vector2.LEFT and Vector2.RIGHT) # Tells the program there has been a Wall collision.

	# Movement
	if Input.is_action_pressed("ui_right"):
		motion.x = SPEED
		motion.y = 0
		print("Right pressed.")
	elif Input.is_action_pressed("ui_left"):
		motion.x = -SPEED
		motion.y = 0
		print("Left pressed.")
	else:
		motion.x = 0
		motion.y = 0

I want to clear the warning: Line 22 (RETURN_VALUE_DISCARDED):The function ‘move_and_collide()’ returns a value, but this value is never used.

I’m making a brick breaker game and already have the functionality I want for my hammer. Now I just want to plug the holes and can’t figure out how to get rid of this one. Disclaimer: I’m new to Godot and have only been learning it for about 5 days as of now. I want to tell the program to eliminate all excess movement in the direction of the Wall the Hammer collides with. I’m a rookie, I don’t know anything, please feel free to tear my code and beliefs to shreds so I can get gud. I have to release a game to pass my course and get my certificate.

Thanks in advance.

:bust_in_silhouette: Reply From: njamster

move_and_collide will stop the motion once it hit’s an obstacle. So as of now you already are discarding the remaining motion! To get rid of the warning, you would need to store the value that is returned by move_and_collide like this:

var collision = move_and_collide(velocity * delta)

Which likely will produce another warning, as you’re not using that value somewhere else. To get rid of that warning as well, you’d do:

var collision = move_and_collide(velocity * delta)
if collision:
    pass

Now instead of just passing (i.e. doing nothing) when a collision occurs, you likely want to do something meaningful. The collision-variable is of type KinematicCollision2D. You can use it to get more information about the collision, e.g.:

var collision = move_and_collide(velocity * delta)
if collision:
    print("collided with: ", collision.collider.name)
    print("(discarded) remaining motion: ", collision.remainder)

I would recommend you also read this tutorial carefully.


A few remarks on your code:

  • Your move_tween uses a duration of 60 seconds! That seems very slow.
  • You should only move KinematicBody2D in _physics_process, not process.
  • Setting motion.y = 0 every frame is unnecessary, it is zero by default.
  • The delta-argument of _process contains the time passed since the last frame. The motion-variable should be multiplied by it, to ensure the movement stays consistent even if frames are dropped. Take a look at my examples above.
  • The second argument of move_and_collide is a boolean: infinite_inertia. It’s true by default, but you set it to Vector2.LEFT and Vector2.RIGHT. Which is always true as well! So this is most likely not what you wanted to do.
  • Because you’re checking for input actions after you called move_and_collide, you are creating an input lag of one frame. Depending on your game, that might or might not be quite notable when playing through it.

THANK YOU SOOOOOOO MUCH! This is very helpful information! I’ll come back if I have any follow-up questions or run into any unexpected issues.

GamersPointeGames | 2020-03-02 17:47

So, I scrapped it and started over after reading through the guide and comparing to your answer. These suggestions and the information in that guide solved my problem. The Debugger is reporting no issues now, finally. Thank you very much for helping me. It appears I added way too much code to address the issue and wasn’t actually doing anything effective. It’s way simpler than I imagined it being. Here’s what I’ve got now:

extends KinematicBody2D

const TARGET_FPS = 90

var speed = 5500
var velocity = Vector2()

func move(target):
	var move_tween = get_node("Hammer_Tween")
	move_tween.interpolate_property(self, "position", position, target, 0.01625)
	move_tween.start()
# Smoother movement.

func get_input():
	velocity = Vector2()
	if Input.is_action_pressed("ui_left"):
		velocity.x -= 1
		print("Left pressed.")
	elif Input.is_action_pressed("ui_right"):
		velocity.x += 1
		print("Right pressed.")
	velocity = velocity.normalized() * speed

func _physics_process(delta):
	get_input()
# warning-ignore:return_value_discarded
	move_and_collide(velocity * delta)

	var collision = move_and_collide(velocity * delta)
	if collision:
		print("Collided with: ", collision.collider.name)
		print("[Discarded] remaining motion: ", collision.remainder)
		pass
# Capture remaining value of move_and_collide from line 24 - line 31, then pass.

It’s doing exactly what I want it to do now. It’s a lot cleaner too

GamersPointeGames | 2020-03-02 18:53

Glad I could help. A few more remarks though:

  • In your code the velocity already is normalized. You reset it to (0, 0) at the start of get_input and then either add or subtract One, depending on which key is pressed. So you’ll always end up with a velocity of (1, 0) or (-1, 0). So there’s no need to normalize it again in the end, that won’t do anything.
  • As ui_left is checked before ui_right, pressing both keys at the same time will result in your character still moving to the left. A common fix for this issue looks like this: velocity.x = Input.get_action_strength("ui_right") - Input.get_action_strength("ui_left")
  • At least in the code you posted, you’re performing move_and_collide twice. Once ignoring the warning, once respecting it by assigning the return value to the collision-variable. Only the warning is ignored, not the call!
  • The pass is only required when there’s nothing else under the if-condition, as you’d otherwise get an error because gdscript expects an indented block there. It really does amount to “nothing” though, so if you’re doing something else there (like printing some text) then you’re fine without it.

njamster | 2020-03-03 15:58

You’re the first to explain to me what that really does. I was previously under the impression that get_input was only checking for input and that I was telling it what to look for in the block.

I didn’t even know I could do this: velocity.x = Input.get_action_strength("ui_right") - Input.get_action_strength("ui_left")
I’ll need to ask my instructor to work in a lesson for it because it got missed. This appears to be a pretty useful detail. Thanks a bunch for bringing this up. I’ll make good use of this.

Gotcha. Okay, I’m going to make some more changes to clean this up some more. I’m learning more here than I am in class lol

GamersPointeGames | 2020-03-04 01:14