Velocity overwriting each other?

So basically i am struggling to udnerstand the reasoning behind why velocity does or does not overwrite each other. So in my enemy chase state script i have this

func _process(delta):
	player = get_tree().get_nodes_in_group("player")[0]
	distance_to_player = player.position - enemy.position
	direction = player.position - enemy.position
	direction = direction.normalized()

	if direction && state_machine.check_if_can_move():
		enemy.velocity.x = direction.x * movement_speed * delta
	elif state_machine.current_state != hit_state:
		enemy.velocity.x = move_toward(enemy.velocity.x, 0, movement_speed)

there is more to the state but nothing else that affect velocity.
and then on the attack state i have this in the code

func on_enter():
	playback.travel("attack")
	enemy.velocity.y = -200       # this works
	# enemy.velocity.x = 200     # <-have also tried this but doesnt work
	enemy.velocity.x = move_toward(100,500, 500)  #doesnt work

This function triggers when the attack state is entered and i know this is working becasue the y velocity change works. It makes the enemy hop up but no x axis change happens.

if i comment out the if(direction… block of code it works so it is definately this part that is stopping it.

i believe that because its in the _process function it is overwriting but if i dont have it in the process function then it wont chase the player continually, i have no idea why it is still getting triggered when in this state as as soon as it switches to attack state shouldnt the finite state machine stop the other code being executed.

Am i misunderstanding how FSM’s work or is it something else?
even if i put a bool variable on the on_enter function of attack state that should be false the whole time the attack state is running it still runs the script even with the bool that should stop the script from running

The way you’re describing your issue sows some confusion in how I understand your problem. Could you describe how your FSM system works? Unless the state-scripts are disabled by a “state manager”, or similar, the scripts will continue running.

What do you mean by “putting a bool variable on the on_enter function”? You can’t just add a boolean parameter to a function and expect that to magically control the execution of code.

Please be more specific. What is being overwritten here, and how do you understand your code? I suspect that you are not aware of what your code is doing.

Due to previous experiences, here are the questions I want you to answer:

  1. How does your FSM system work? (Scene tree setup, code, signals etc.)
  2. What do you mean with “putting a bool variable” on a method?
  3. What exactly is being overwritten, you think? I can’t quite tell from your description.
  4. Do you understand the execution loop in Godot?
    (_process(), _physics_process(), _ready(), _input() etc.)
1 Like

Okay, so im new to this so will try my best on being as clear as possible because i know its hard to understand people like me who have no clue haha.
I appreciate the reply and will try to answer your questions as best i can :smiley:
I think also you have answered one important gap in my knowledge that to make the state machine only run one script at a time it needs to be implemented in the state manager… i thought i had done this but maybe i am wrong

so this is the layout of my enemy scene

this is my state machine manager or CharacterStateMAchine code

extends Node

class_name CharacterStateMachine

@export var character : CharacterBody2D 
@export var animation_tree : AnimationTree
@export var current_state : State

var states : Array[State]

func _ready() -> void:
	#creating array of states
	for child : State in get_children():
		if (child is State):
			states.append(child)
			#telling the states what they need to function
			child.character = character
			child.playback = animation_tree["parameters/playback"]
			
			#connect to interrupt signal
			child.connect("interrupt_state", on_state_interrupt_state)
			
		else:#warning if a child is not a state
			push_warning("Child " + child.name + " is not a State for CharacterStateMachine")
			
func _physics_process(delta : float) -> void:
	if (current_state.next_state != null): #if current state holds something switch
		switch_states(current_state.next_state)
	
	current_state.state_process(delta)
	
func check_if_can_move() -> bool: #checking if the state allows the character to move
	return current_state.can_move

func switch_states(new_state : State) -> void: #creating new_state argument to pass into function
	 
	if (current_state != null):
		current_state.on_exit()#if i need to do anything else when state exits
		current_state.next_state = null #resets state to null for next change
		
	current_state = new_state #change of state
	current_state.on_enter() #any code i want to execute upon entering a new state
	
func _input(event :InputEvent) -> void:
	current_state.state_input(event)

func on_state_interrupt_state(new_state : State):
	switch_states(new_state)

All the State scripts are extensions of this script State.gd
which is below

extends Node

class_name State

@export var can_move : bool = true
#@export var cancel_velocity : bool = false

var character : CharacterBody2D
var playback : AnimationNodeStateMachinePlayback
var next_state : State

signal interrupt_state(new_state : State)

func state_process(delta : float) -> void:
	pass

func state_input(event : InputEvent) -> void:
	pass

func on_enter() -> void:
	pass

func on_exit() -> void:
	pass

so the problem being either the two states that seem to be running at the same time or maybe the velocity is just overwriting somehow. My lack of understanding of either state machines or of how to move a CharacterBody2D using velocityis the issue.

here is the chase state

extends State

class_name ChaseState

@export var movement_speed : float = 1200.0
@export var chase_state : String = "chase"
@export var idle_state : State
@export var attack_state : State
@onready var hit_state : State = $"../Hit"
@onready var state_machine : CharacterStateMachine = $".."
@onready var enemy : CharacterBody2D = $"../.."
@onready var distance_to_player : Vector2
@onready var direction : Vector2 = Vector2.ZERO
@onready var player : CharacterBody2D

func on_enter():
	playback.travel(chase_state)
	
func _process(delta):
	player = get_tree().get_nodes_in_group("player")[0]
	distance_to_player = player.position - enemy.position
	direction = player.position - enemy.position
	direction = direction.normalized()

	if direction && state_machine.check_if_can_move():
		enemy.velocity.x = direction.x * movement_speed * delta
	elif state_machine.current_state != hit_state:
		enemy.velocity.x = move_toward(enemy.velocity.x, 0, movement_speed)

func _on_player_detection_body_exited(body):
	next_state = idle_state

func _on_attack_range_body_entered(body):
	next_state = attack_state


and here is the attack state

extends State

@onready var state_machine : CharacterStateMachine = $".."
@onready var enemy : CharacterBody2D = $"../.."
@export var return_state : State

func on_enter():
	playback.travel("attack")
	enemy.velocity.y = -200       # this works
	# enemy.velocity.x = 200     # <-have also tried this but doesnt work
	enemy.velocity.x = move_toward(100,500, 500)  #doesnt work

func _on_animation_tree_animation_finished(anim_name):
	next_state = return_state

By putting a bool on i mean i am declaring a bool that is supposed to check if in the attack state.
Then the chase state script checks if this is true so that if false it stops applying its change in velocity.

But i know now what im saying in this sentance above is completely dumb because i shouldnt have any code in the chase state running whilst it is in a different state.

The code i think is being overwritten is below which is (inside the AttackState) because the Y velocity change works but the X velocity change doesnt and when commented out the attack state velocity chage works.

func on_enter():
	playback.travel("attack")
	enemy.velocity.y = -200       # this works
	# enemy.velocity.x = 200     # tried this but commented out to try code below
	enemy.velocity.x = move_toward(100,500, 500)  #doesnt work

I think i may have a poor understanding of using velocity to change the players position.
As i never know when to multiply by delta or if i need to at all.
Even after reading the documentaion i feel like im still a bit confused between changing the velocity and using move_toward.

In honesty thats the first time ive heard the term execution loop i will look that up tonight and try to get an understanding.
I dont really get the difference between _process and _physics_process but i know that they execute every frame.
i think i know _ready executes the code when you start the game up for the first time.
_input i think i know thar it only is triggered when you press a key that you have assigned to something.

Sorry about such an essay just trying to be as thorough as possible to make it easier but i may have made it confusing bringing up so much haha i really appreciate you taking the time to reply :smiley:

Do not apologize for providing a thorough answer to my questions – it is highly appreciated. Your own thoughts on the subjects also help me understand the areas where you lack a bit of knowledge.


As a starting point I would like to address your actual issue. Unless I’m missing something, it seems that you have not utilized your State (base) correctly. State defines the function state_process() but in your ChaseState you’re using _process() in its stead. You’re not using the function provided by the base and this causes your entire system to function incorrectly as _process() is not accounted for in your CharacterStateMachine.

I believe that substituting _process() for state_process() in ChaseState will fix your issue.

There are two key things to remember about the concept of velocity. First is that it is a vector that describes an object’s change in position over time through a single variable: a vector. The vector representation is convenient because it implicitly contains two pieces of information: direction, and magnitude. The second thing to remember is that the SI unit used for velocity is metres per second (m/s). As such, velocity always describes an object’s change in position over 1 second.

In terms of how you should use velocity to change the player’s position, it is easiest to make use of move_and_slide(). This function will move your CharacterBody2D over time based on its velocity without the need to implement your own system for collision responses. You can read more about this on Godot Docs.

The only case where you should multiply with delta is when you need to move something over time. delta has a different value in _process() and _physics_process(), but it always describes the same thing: the time it took to perform a single update to the game.

If you’re interested in understanding this, and many other concepts, I recommend that you research how physics simulations manage to simulate the motion of objects. It’s highly relevant to game development as many game mechanics are essentially just contained real-time simulations.

I’m not sure how you interpret your own use of move_toward(). It’s just a utility function to make it easier to move towards a target value. On the other hand, changing the velocity is mandatory to move a CharacterBody2D with move_and_slide(). The way you change velocity is up to you.

Here’s the Godot Docs page on these functions. In a nutshell, _process() runs every frame and provides you with a delta that describes how long it took to process it – as a result, delta will vary. On the contrary, _physics_process() runs at a fixed rate. The reason for its fixed update rate has to do with physics stability and is why there are two process functions (or similar) in almost any game engine; one for physics, and one for generic stuff like game logic and what not.


Hopefully this fixes your issue and helped you grasp some of the concepts you’re actively using. Let me know if you have any further questions.

1 Like

Glad my long reply was useful :smiley:
Thankyou so much for your help and time to give me a greater understanding you are a legend!
Changing process to state_process fixed the problem immediately and i now understand what that state process is for.
Thanks for explaining velocity and delta and the process differences it has made it a lot clearer and i will have to look up all you suggested.
really appreciate the in depth explanations and you have helped me a lot, time to start looking this all up :smiley:

1 Like

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