How to stop KinematicBody2D from moving if colliding with StaticBody2D and allow it to move again?

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

Hello!

I’m new to game development, but have done some tutorials for 2D platformer and top down game.

I’m trying to implement a point-and-click behavior with collision objects. The main point and click movement flow is described nicely here:

I’m using it in a similar way with move_and_slide, however when bringing in some collision objects the KinematicBody2D still slides on a collision object if colliding it with a definitive size greater or lower than 90 deg angle. I’d like the player(KinematicBody2D) to stop or slide it across the colliding body(wall - StaticBody2D) without slowing down gradually.

Currently I’m detecting a move_and_slide collision and forcing the KinematicBody2D to move_and_collide which nicely stop the player but I’m unable to get the player away from the collision object. It’s just snapped to it and can’t make it back to move.

How to make a player back to move after move_and_collide stopped it with a point and click moves used in my script? I tried it with setting a new position but seems I don’t know how to use the ‘set_position(value)’ in Node2D

Here’s my script:

extends KinematicBody2D
    
    var speed = 200
    # original starting point for character
    var targetPos = Vector2(980, 1200)
    
    var velocity = Vector2()
    var distance = 0
    
    var floor_normal = Vector2(0, 0)
    var max_bounces = 0
    var collision
    var collided = false
    
    func _input(event):
    	if event.is_action_pressed('click'):
    		targetPos = get_global_mouse_position()
    		distance = position.distance_to(targetPos)
    
    func _physics_process(delta):
    	velocity = (targetPos - position).normalized() * speed
    	movePlayer(delta)
    
    func movePlayer(delta):
    	for i in get_slide_count():
    		collision = get_slide_collision(0)
    	
    	if get_slide_count() > 0:
    		collided = true
    	else:
    		collided = false
    	
    	if collided:
    		move_and_collide(velocity * 0 * delta)
    		var newPosition = Vector2(668, 1031)
    		# error
    		# set_position(newPosition)
    
    	# make it move to a target position
    	elif (targetPos - position).length() > 5:
    		move_and_slide(velocity, floor_normal, true)
    
    	# need to stop movement if clicking too close to a character
    	elif distance < 5:
    		move_and_slide(velocity * 0, floor_normal, true)
    	

Ok, I know it’s a noob question, but I haven’t found the good way to solve this.

Anyhow now I’ve implemented a solution where I just set the player’s target position to current position of a player when collision (actually a slide) occurred.

It kind of does the trick but for point and click game it still feels a bit weird. Anyone can comment on that?

Modified script (the part where it says 'if slided: ’ ):

extends KinematicBody2D

var speed = 200
# original starting point for character
var targetPos = Vector2(980, 1200)

var velocity = Vector2()
var distance = 0

var floor_normal = Vector2(0, 0)
var max_bounces = 0
var collision
var slided = false

func _input(event):
	if event.is_action_pressed('click'):
		targetPos = get_global_mouse_position()
		distance = position.distance_to(targetPos)

func _physics_process(delta):
	velocity = (targetPos - position).normalized() * speed
	movePlayer(delta)

func movePlayer(delta):
	for i in get_slide_count():
        # last slide detected
		collision = get_slide_collision(0)
	
	if get_slide_count() > 0:
		slided = true
	else:
		slided = false
	
	if slided:
		targetPos = position
		move_and_slide(velocity, floor_normal, true)
		
	# make it move to a target position
	elif (targetPos - position).length() > 5:
		move_and_slide(velocity, floor_normal, true)

	# need to stop movement if clicking too close to a character
	elif distance < 5:
		move_and_slide(velocity * 0, floor_normal, true)
	

talupoeg | 2019-05-23 15:25

You can just assign a value to the position variable:

position = Vector2(200,100)
position.x += 200
position.y = 10

etc.

Jowan-Spooner | 2019-05-23 15:34

Thanks!

Seems to do the trick yes. I have found that for this current point and click solution it still better to reassign current position to target position and still use move_and_slide because with point and click mechanics you mostly are clicking on collisions to move the player.

talupoeg | 2019-05-24 09:29

KidsCanCode has made this explanation of KinematicBody2dMovement (move_and_slide and move_and_collide) that is pretty good. Just if you are looking for a deeper explanation and custom reactions for collisions.

Jowan-Spooner | 2019-05-24 09:34

In case someone is still looking for options with this. I solved the problem by updating the ‘speed’ variable to 0 until the action I wanted is done, then resetting it back to its original value.