Help me please my npc needs work

Godot Version 4.2.1

can someone help me get my npc to move back and forth across the bottom of the game screen


You never change it’s position, if this is a CharacterBody2D then set velocity = move_dir and use move_and_slide() otherwise, add move_dir to it’s position.

can you please provide more information i am trying to learn while creating my own original project

You need to alter the node’s position for it to move. That code is not present in your screenshot.

Depending on the type you will need one of two options as I outlined before. Does your NPC extends CharacterBody2D or something else?

it extends area2d

Then you will need to add your movement to their position at the end of your npc_movement function

position += move_dir

There are a few logical issues with the code, you are resetting move_dir every frame, so it cannot really increment or move backwards.

var move_dir = Vector2(MOVE_SPEED)

Parts of your if statements are constants, notice Vector2(SCREEN_WIDTH_MIN/MAX) doesn’t compare against anything? This will always be true, with the and your if statement can be reduced to just npc_move

if npc_move == true and Vector2(SCREEN_WIDTH_MIN):
# equivalent to:
if npc_move == true:

You could try this process function instead, it keeps a moving_right variable much like yours to track which direction the NPC is moving, then adds or subtracts position.x, flipping when reaching past the max/min screen values.

const SPEED: float = 20
const SCREEN_WIDTH_MAX: float = 1051
const SCREEN_WIDTH_MIN: float = -80

var moving_right: bool = true

func _process(delta: float) -> void:
	if moving_right:
		position.x += SPEED * delta
		if position.x > SCREEN_WIDTH_MAX:
			moving_right = false
	else:
		position.x -= SPEED * delta
		if position.x < SCREEN_WIDTH_MIN:
			moving_right = true
1 Like

i tried something similar before i even asked for help it got stuck in the top left corner of the game screen

here is my updated code with some of your updates

extends Area2D

const MOVE_SPEED = 200.0
const SCREEN_WIDTH_MAX = 1000
const SCREEN_WIDTH_MIN = 0
var npc_move = true

func npc_movement():
var move_dir = Vector2(MOVE_SPEED, 519)
if npc_move == true:
position += move_dir
move_dir.x -= 200
npc_move = false
if npc_move == false:
position += move_dir
move_dir.x += 200
npc_move = false

func _process(_delta):
npc_movement()

func _on_area_entered(area):
if area.is_in_group(“npc”):
queue_free()

What happens when you run that code? It looks to me like it will make your character move extremely fast and disappear off the edge of the screen.

Let’s get movement in one direction working first. So remove this block of 5 lines:

npc_move = false
if npc_move == false:
    position += move_dir
    move_dir.x += 200
    npc_move = false

Next, let’s try reducing those speed numbers so that you can better see what is happening:

  • MOVE_SPEED can be 3 for now
  • The 519 in move_dir can be 0, unless you want the character to move down as well as horizontally, in which case maybe make it 1.
  • This line might not be doing what you expect it to:
move_dir.x -= 200
  • It doesn’t set x to -200, it makes x 200 smaller. Since this runs every frame (because it is called from _process) that will cause the speed to be 200 pixels faster to the left every frame! Try this instead:
move_dir.x = -MOVE_SPEED

Now it will make x equal to -MOVE_SPEED. Since we made MOVE_SPEED equal 3, that will be -3 (which means 3 pixels to the left every frame).

Finally, it will also help a little if you use _physics_process instead of _process when dealing with movement, so that everything runs at a consistent speed. Just swap the method name “_process” in your code for “_physics_process”. I can explain more about why later if you want me to.

If you do all that, your character should now move slowly to the left. Play around with it and see if you can understand what it is doing and why. Then we can work on the rest.

Also, when writing replies, there is a button above the forum’s text area that looks like this: </>

If you use it when pasting code it will be easier to read and people can help more easily. It’s how I made the code in my answer look the way it does as well.

thanks duckbadnitdan by the way all that happens is it appears on multiple parts of the screen at once

You’re very welcome.

I see. That’s because of the way _process() works. Any code you put there runs many times a second, which means your character changes position many times a second. Since it is travelling very fast (due to the high speed numbers you had), it looks like it is in multiple places at once.

Did you try making the changes I suggested?

now it just appears when started but than disappears without reappearing

Hmm, ok. Does it disappear instantly or does it move off screen slowly?

What does your code look like now? Paste it in using the </> button so we can read it clearly.

it disappears instantly

extends Area2D

const MOVE_SPEED = 200.0
const SCREEN_WIDTH_MAX = 1000
const SCREEN_WIDTH_MIN = 0
var npc_move = true

func npc_movement():
	var move_dir = Vector2(MOVE_SPEED, 519)
	if npc_move == true:
		position += move_dir
		move_dir.x -= 200
		npc_move = false
	if npc_move == false:
		position += move_dir
		move_dir.x += 200
		npc_move = false


# Called every frame. 'delta' is the elapsed time since the previous frame.
func _physics_process(delta):
	npc_movement()


func _on_area_entered(area):
	if area.is_in_group("npc"):
		queue_free()

Try this

extends Area2D

var MOVE_SPEED = 200
const SCREEN_WIDTH_MAX = 1000
const SCREEN_WIDTH_MIN = 0
var npc_move = true

func npc_movement(move_direction: float) -> void:
	if npc_move == true:
		global_position.x += move_direction


# Called every frame. 'delta' is the elapsed time since the previous frame.
func _physics_process(delta) -> void:
	if global_position.x + size.x >= SCREEN_WIDTH_MAX or global_position.x <= SCREEN_WIDTH_MIN:
		MOVE_SPEED *= -1
	npc_movement(MOVE_SPEED * delta)


func _on_area_entered(area) -> void:
	if area.is_in_group("npc"):
		queue_free()
1 Like

that doesn’t work

I THOUGHT I FOUND A CODE THAT WORKS BUT THIS DOESN’T WORK EITHER

extends Area2D

const MOVE_SPEED = 20
const SCREEN_WIDTH_MAX = 1000
const SCREEN_WIDTH_MIN = 0
var npc_move = true

func npc_movement():
	var move_dir = Vector2(1, 519)
	while npc_move == false and self.position >= Vector2(SCREEN_WIDTH_MIN, 519):
		position += move_dir
		move_dir.x -= 10 * MOVE_SPEED
		npc_move = true
	while npc_move == true and self.position <= Vector2(SCREEN_WIDTH_MAX, 519):
		position += move_dir
		move_dir.x += 10 * MOVE_SPEED
		npc_move = false


# Called every frame. 'delta' is the elapsed time since the previous frame.
func _physics_process(_delta):
	npc_movement()


func _on_area_entered(area):
	if area.is_in_group("npc"):
		queue_free()

You have not updated the major problems.

  • declaring move_dir every frame
  • not checking screen bounds
  • flipping between npc_move every frame
  • adding and subtracting speed instead of multiplying by -1

I would highly recommend using the _process sample I provided, if you need help understanding certain parts of it I would be happy to go into more detail.

1 Like

please do because if i learn more about this particular code maybe ill find my answer

I recommended this snippet instead of your npc_movement function. Try it out, if it doesn’t work tell me why and paste your script. If it does work, ask for any details you need help understanding.