Knockback standalope error

Godot Version

4.1.2

I made a knockback code for an enemy but it gives me a stadalope expression

extends CharacterBody2D

@export var movement_speed = 40.0

@onready var planta =  get_tree().get_first_node_in_group("planta")
@onready var sprite = $Sprite2D
@export var knockback_recovery: float = 3.5
@onready var vida = 20
var knockback = Vector2.ZERO

func _physics_process(_delta):
	knockback = knockback.move_toward(Vector2.ZERO, knockback_recovery)
	velocity += knockback * _delta
	global_position += velocity
	move_and_slide()
	if is_instance_valid(planta):
		var direction = global_position.direction_to(planta.global_position)
		velocity = direction*movement_speed
		move_and_slide()

		if direction.x > 0:
			sprite.flip_h = false
		
		elif direction.x < 0:
			sprite.flip_h = true
			
	else:
		planta = get_tree().get_first_node_in_group("planta")
		move_and_slide()
	



func _ready():
	$lil.play("move")








func _on_area_2d_area_entered(_area):
	if _area.is_in_group("planta_area"):
		$lil.play("attack")
	elif _area.is_in_group("bala"):
		knockback
		vida -= 9
	if vida <= 0:
		queue_free()


func _on_area_2d_area_exited(_area):
	$lil.play("move")```

It’s not an error but just a warning. I believe what you’re trying to do is add to the “knockback” variable after elif _area.is_in_group(“bala”):. But you have only mentioned the variable and not performed any operation on it, that’s why you’re getting the error.

how can I fix it? When I hit ignore the enemy breaks completely

So what are you exactly trying to do here? Are you trying add to the knockback? Are you trying to do something like knockback += Vector2.ONE * 100? Because you have just written “knockback” and not specified anything.

In your physics process you have writting velocity += knockback * delta but knockback is zero which will make the velocity always zero

1 Like

I mean, I thought that if I put knockback, the knockback would be executed, the enemy would push back.

Looks like you’re a bit confused. Knockback is not a function so it cannot be executed like that. knockback is a variable.

1 Like

Let’s break down your logic. In physics process you wrote velocity += knockback * delta, but knockback is always zero, so velocity is always zero. You are talking about “executing” knockback, in other words, you want to call a function called knockback. But knockback is not a function, its a variable. You can create a Knockback function and then called it using Knockback() Inside the function write code that is to be executed when the function is called.

func Knockback():
	knockback = Vector2.ONE * 100

func _on_area_2d_area_entered(_area):
	if _area.is_in_group("planta_area"):
		$lil.play("attack")
	elif _area.is_in_group("bala"):
		Knockback()
		vida -= 9
	if vida <= 0:
		queue_free()

1 Like

At first I had put it in a function but I didn’t know how to replace the delta

For a one-time knockback impulse you don’t want delta time, only to set the knockback value. The knockback hit doesn’t happen over time, it’s instant.

I already set the value and put it in a function but these errors appear
Cannot find property “move_toward” on base “Callable”
Function “move_toward()” not found in base Callable.
Cannot assign a new value to a constant.

You need a knockback variable, I wouldn’t recommend making a knockback function to go with it, instead setting the variable on it’s own.

#func Knockback(): # Do not use a function, delete this
	#knockback = Vector2.ONE * 100

func _on_area_2d_area_entered(_area):
	if _area.is_in_group("planta_area"):
		$lil.play("attack")
	elif _area.is_in_group("bala"):
		knockback = Vector2.ONE * 100 # Assign knockback

		# Bonus knockback in direction of enemy
		var diff: Vector2 = self.global_position - _area.global_position
		knockback.x *= sign(diff.x)

		vida -= 9
	if vida <= 0:
		queue_free()

It still doesn’t work. I don’t get any errors, but it doesn’t work. I saved the knockback in a variable. I don’t know if I should have done that.

You will have to paste your updated code for me to help, I don’t know what you changed. What do you mean by “it doesn’t work”, did nothing happen when the player was attacked? Try increasing the knockback assignment, 100 is actually a very low value.

The knockback is made for the enemy not for the player and if I say it worked because nothing happened

extends CharacterBody2D

@export var movement_speed = 40.0

@onready var planta =  get_tree().get_first_node_in_group("planta")
@onready var sprite = $Sprite2D
@export var knockback_recovery = 3.5
@onready var vida = 20
var knockback = Vector2.ONE * 100

func _physics_process(_delta):
	if is_instance_valid(planta):
		var direction = global_position.direction_to(planta.global_position)
		velocity = direction*movement_speed
		move_and_slide()

		if direction.x > 0:
			sprite.flip_h = false
		
		elif direction.x < 0:
			sprite.flip_h = true
			
	else:
		planta = get_tree().get_first_node_in_group("planta")
		move_and_slide()
	






func _ready():
	$lil.play("move")








func _on_area_2d_area_entered(_area):
	if _area.is_in_group("planta_area"):
		$lil.play("attack")
	elif _area.is_in_group("bala"):

		var diff: Vector2 = self.global_position - _area.global_position
		knockback.x *= sign(diff.x)
		move_and_slide()
		
		vida -= 9
	if vida <= 0:
		queue_free()


func _on_area_2d_area_exited(_area):
	$lil.play("move")

Ah. Notice how you’ve removed any mention of knockback in your _physics_process function. There is no way for knockback to be applied now, I’d recommend reverting that function to how your initial post looks here:

Once that’s done you also only apply a value to knockback on instantiation, since this is in global scope (no indentation) it will only run once, not every time the enemy is hit. We still need the variable, so you could replace this line with var knockback := Vector2.ZERO alike your initial post as well.

You will need to set this value within the _on_area_2d_area_entered function like in my example here:

there I already replaced the code although it still does nothing

Help me out here and paste what you’ve changed. Maybe we need to do some more fundamental debugging, like adding prints after applying knockback.

extends CharacterBody2D

@export var movement_speed = 40.0

@onready var planta =  get_tree().get_first_node_in_group("planta")
@onready var sprite = $Sprite2D
@export var knockback_recovery = 3.5
@onready var vida = 20
var knockback = Vector2.ONE * 100

func _physics_process(_delta):
	knockback = knockback.move_toward(Vector2.ZERO, knockback_recovery)
	velocity += knockback * _delta
	if is_instance_valid(planta):
		var direction = global_position.direction_to(planta.global_position)
		velocity = direction*movement_speed
		move_and_slide()

		if direction.x > 0:
			sprite.flip_h = false
		
		elif direction.x < 0:
			sprite.flip_h = true
			
	else:
		planta = get_tree().get_first_node_in_group("planta")
		move_and_slide()
	






func _ready():
	$lil.play("move")








func _on_area_2d_area_entered(_area):
	if _area.is_in_group("planta_area"):
		$lil.play("attack")
	elif _area.is_in_group("bala"):
		knockback = Vector2.ONE * 100 

		var diff: Vector2 = self.global_position - _area.global_position
		knockback.x *= sign(diff.x)
		move_and_slide()
		
		vida -= 9
	if vida <= 0:
		queue_free()


func _on_area_2d_area_exited(_area):
	$lil.play("move")

Cool, again 100 is a really low value, first thing I’d do is try to increase that. Of course your units are pretty wonky, some as pixels per frame others and pixels per second. If planta is valid then all of this knockback stuff is thrown out the window from this line:

So that’s now where I imagine you’d want to insert your knockback.

Here’s what I’d change, a lot of it is cleaning up units. If it still doesn’t work, tell me if you see the print show up at least.

extends CharacterBody2D

@export var movement_speed = 40.0

@onready var planta =  get_tree().get_first_node_in_group("planta")
@onready var sprite = $Sprite2D
@export var knockback_recovery = 300 # increasing recovering to match per-second change
@onready var vida = 20
var knockback: Vector2 # instantiate with nothing

func _physics_process(delta):
	if is_instance_valid(planta):
		var direction = global_position.direction_to(planta.global_position)
		velocity = direction * movement_speed

		# Apply knockback after setting velocity

		# add *delta otherwise move_toward is decelerating per-frame
		knockback = knockback.move_toward(Vector2.ZERO, knockback_recovery * delta)
		# remove *delta, as velocity is already per-second
		velocity += knockback

		if direction.x > 0:
			sprite.flip_h = false
		
		elif direction.x < 0:
			sprite.flip_h = true
			
	else:
		planta = get_tree().get_first_node_in_group("planta")
	move_and_slide()

func _ready():
	$lil.play("move")

func _on_area_2d_area_entered(_area):
	if _area.is_in_group("planta_area"):
		$lil.play("attack")
	elif _area.is_in_group("bala"):
		knockback = Vector2.ONE * 1000 # much higher knockback value
		print("Knocked back! ouch!") # A print statement for testing.

		var diff: float = self.global_position.x - _area.global_position.x
		knockback.x *= sign(diff.x)
		
		vida -= 9
	if vida <= 0:
		queue_free()


func _on_area_2d_area_exited(_area):
	$lil.play("move")

I don’t think the knockback should be in the if, plus with the diff variable it gives me errors and if I put only vector2 it gives me errors and also if I try to remove the knockback from the if it gives me errors
it gives me these errors
Expected statement, found “Indent” instead.
Expected statement, found “Indent” instead.
“elif” in class body.
Unexpected “Indent” in class body.
Expected end of file.