How to FIX invalid call. nonexistent function ouch in base tile map

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

this is my main character call where i create function

extends KinematicBody2D

var velocity = Vector2(0,-1)
var coins = 0
const SPEED = 300
const JUMPFORCE = -940
const GRAVITY = 40
func _physics_process(delta):
if Input.is_action_pressed(“Right”):
velocity.x = SPEED
$Sprite.play(“Running”)
$Sprite.flip_h = false
elif Input.is_action_pressed(“Left”):
velocity.x = -SPEED
$Sprite.play(“Running”)
$Sprite.flip_h = true
else:
$Sprite.play(“Idle”)

if not is_on_floor():
	$Sprite.play("Jumping")
velocity.y = velocity.y + GRAVITY

if Input.is_action_just_pressed("Jump") and is_on_floor():
	velocity.y = JUMPFORCE 
	$Jump.play()
	
if Input.is_action_pressed("Crouch") and is_on_floor():
	$Sprite.play("Crouch")

velocity = move_and_slide(velocity,Vector2.UP)
velocity.x = lerp(velocity.x,0,0.2)

func _on_Area2D_body_entered(body):
get_tree().change_scene(“res://GameOver.tscn”)

func bounce():
velocity.y = JUMPFORCE * 0.7

func hurt(var enemyposx):
set_modulate(Color(1,0.3,0.3,0.3))
velocity.y = JUMPFORCE * 0.5

if position.x < enemyposx:
	velocity.x = -800
elif position.x > enemyposx:
	velocity.x = 800

func _on_Timer_timeout():
get_tree().change_scene(“res://GameOver.tscn”)

func _on_Trophy_body_entered(body):
get_tree().change_scene(“res://Winner.tscn”)

func _on_Coin_body_entered(body):
$CoinSound.play()

Here is the enemy one where I use the function

extends KinematicBody2D

var speed = 50
var velocity = Vector2()
export var direction = -1
export var detects_cliffs = true

func _ready():
if direction == 1:
$AnimatedSprite.flip_h = true
$Floorchecker.position.x = $CollisionShape2D.shape.get_extents().x * direction
$Floorchecker.enabled = detects_cliffs
if detects_cliffs:
set_modulate(Color(.8,1.2,1))
func _physics_process(delta):

if is_on_wall() or not $Floorchecker.is_colliding() and detects_cliffs and is_on_floor():
	direction = direction * -1
	$AnimatedSprite.flip_h = not$AnimatedSprite.flip_h
	$Floorchecker.position.x = $CollisionShape2D.shape.get_extents().x * direction

velocity.y += 20

velocity.x = speed * direction
	
velocity = move_and_slide(velocity,Vector2.UP)

func _on_Topdetector_body_entered(body):
$AnimatedSprite.play(“Dead”)
speed = 0
set_collision_layer_bit(4,false)
set_collision_mask_bit(0,false)
$Topdetector.set_collision_layer_bit(4,false)
$Topdetector.set_collision_mask_bit(0,false)
$SideChecker.set_collision_layer_bit(4,false)
$SideChecker.set_collision_mask_bit(0,false)
$Timer.start()
body.bounce()
$Kill.play()

func _on_Sidechecker_body_entered(body):
body.ouch(position.x)

func _on_Timer_timeout():
queue_free()

:bust_in_silhouette: Reply From: Bean_of_all_Beans

So the signal tied to the function _on_Sidechecker_body_entered will call that function every time it detects any sort of body entering its area – RigidBody, StaticBody, or KinematicBody. What is happening is you have no type checking; you are just assuming that whenever _on_Sidechecker_body_entered is called, it will always be whatever body with a script that defines ouch. This can be fixed by checking to see if the body is the one you actually want – the player body. One simple method is by calling the body’s has_method method:

if body.has_method("ouch"):
    body.ouch(position.x)

That is one way of doing it; another would be to check the name of the body (body.name), but this would cause problems if the name in the SceneTree does not exactly match, and probably should be avoided.