move_and_collide not working properly (body can slide on top of it without registering collision)

Godot Version

3.2.3

Question

Hi everyone,
i’m recreating arkanoid on godot, and i have a weird bug. Both the platform (vaus) and the powerups falling from destroyied blocks are using move_and_collide: the first to detect collisions with ball and powerups and the latter to be destroyied when goin out the screen.

However, it happens that if the platform is still when the powerup touches it the collision is registered, instead if the platform moves while the powerup touches, the platform slides under it and as soon as the powerup can move it continues descending.

Content not found | LimeWire (example video)

platform code:

func _physics_process(delta: float) -> void:

	if (not global_node.running):
		ball.global_position = self.global_position + Vector2(0.0, -30.0)
	
	velocity = calculate_velocity()
	var body = move_and_collide(velocity * delta)
	
	# Collision with powerup
	# Body.collider is the object is colliding with
	if body and body.collider.is_in_group("powerups"):
		body.collider.queue_free()
		activate_powerup(body.collider.type)
		sound_player.play_sound(sound_player.supported_audio.POWERUP);

powerup code

func _on_DebugTimer_timeout():
	
	print_debug("spawned powerup");
	
	var temp = powerup.instance();

	temp.global_position = Vector2(self.position.x, self.position.y + OFFSET);
	temp.type = global_node.powerup_type[rand_range(0, global_node.powerup_type.size() - 1)];
	
	get_parent().add_child(temp);

What could be the reason?

Thanks in advance

What kind of nodes are they?

Both are KinematicBody2D

That may be part of the problem. You are overcomplicating your powerups. A KinematicBody2D is meant for player-controlled characters, or characters with complex physics needs like enemies in an action RPG. You have something falling that needs to collide and then disappear. An Area2D is enough. It also has collision signals which are easier to implement.

You also should check your physics collision masks and layers. If the layer is set, but not the mask, it would behave the way you’re describing.

Thank you so much, with Area2d the powerup works with every paddle movement or position like it should.
The only question is: can i keep the paddle detection code and let in powerup’s area2d detection signal only the code for when it goes out of bound and gets deleted?

Because i’ve tryied with putting all powerup related code in powerup physics, and even thought this works and is conceptually correct, i dislike it because i initially designed all collision responses involving paddle IN the paddle script and i’d like to keep it that way. Do you think this is a poor design choice?

TBH, it doesn’t matter. It’s more important for the game to function.

If this were a more complex game, or if you wanted to code this in a more object-oriented (OOP) manner, I would recommend keeping the single responsibility principle (SRP) in mind. It’s part of SOLID, which TBH I like, but have some philosophical differences with.

At any rate, the single responsibility principle says that an object should be responsible for one thing and one thing only. I interpret that broadly, meaning that an object should be responsible for it’s own sh*t.

So in a Breakout/Arkanoid style game, I would make the powerups responsible for their own collisions, and give them a signal to broadcast their powerup when they collide with the player. Then either the player or some event bus or autoload would listen for the signal and the player would be informed and handle powering themselves up.

For example, let’s say the powerup is increased speed, and we have three versions of it. All the speed powerup knows is how much speed it’s adding and if it collides with the player it send s a signal containing that info, and it it hits the screen terminus, it deletes itself.

The player, if it gets a speed powerup signal, knows what to do with it. Internally let’s say you have an exported variable which is your speed multiplier. We set it to 50%. Then our speed powerup level defaults to 0. So the paddle speed is speed * direction.normalized() * (1 + (speed_multiplier * speed_powerup_level)) This results in speed being 100%, 150%, 200%, or 250% of normal speed. So Our three powerups have speed equal to 1, 2, and 3.

After some testing you decide to let those powerups stack, so getting three level 1 speed powerups is the same as getting a level 3 powerup. You also decide that the max power up is 5, which is 350% increase because after that the controller is too hard to control. So you add some code into the player to monitor that.

var speed_powerup_level: int = 0:
	set(value):
		if value > 5:
			speed_powerup_level = 5
		else:
			speed_powerup_level = value

All of this happens in the player. Because the player needs to know what the powerups do. However the powerup just needs to know what it has hit and when to send a signal.


In the same vein, the paddle needs to know how to move, but it doesn’t need to know what happens to the ball. The ball itself can handle the own physics of where it goes when it hits the paddle. In effect, the paddle doesn’t need to know if it hits anything. All the collision detection can be done outside it. All it needs to know is what powerups it has and how that affects its size, etc. Even if you were to create a sticky paddle that catches the ball, as long as the ball knows when the paddle is sticky, it can halt its own momentum, and the paddle just needs to know how to launch the ball.


Ultimately though, as long as your game works, that’s what’s important.

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.