#Not understanding enemy movement

1 messages · Page 1 of 1 (latest)

marsh orchid
#

Sounds like you're on the right track with dividing movement into patterns! For the elliptical movement issue (Pattern A), the sudden position jumps are likely happening because you're setting the angle directly instead of incrementing it over time.

var angle = 0.0
var speed = 1.0
var center = Vector2(400, 300)
var radius = Vector2(100, 60)

func _process(delta):
angle += speed * delta
var offset = Vector2(cos(angle), sin(angle)) * radius
position = center + offset

This way, the movement flows naturally along the ellipse. Avoid resetting or hard-setting the angle unless you’re doing a controlled transition.

Also, using a state machine setup (like switching between Pattern A, B, and C based on distance or timers) makes things way easier to manage. Keep going — this kind of structured movement takes a bit to get right but pays off!

heady fossil
#

Ok, so I do have to do the state machine thingie, until now i've been scripting movement and attacking in the same character2d/node scripts and doing the state machine would mean to do all of it again (or al least, relocate them) thank you! I'll see if this works.

marsh orchid
#

good.
Il

#

I hove you are getting better.

heady fossil
#

Ok! The movement works perfectly! I had to make some adjustments to make it work exactly like I wanted. But there is one problem, the thing is that I want the enemy to wait a little before it moves and then slowly starting to move gradually to the standart speed

#

var angle := 0.0
var speed := 1.0
var center := Vector2.ZERO
var axis_major := Vector2.ZERO
var axis_minor := Vector2.ZERO

func _ready():
center = get_viewport_rect().size / 2

var dir = position - center
axis_major = dir                # Vector desde el centro a la posición inicial
axis_minor = Vector2(-dir.y, dir.x) # Perpendicular al vector (rotación 90°)

# Normalizamos el eje menor para que tenga la misma "fuerza" proporcional
axis_minor = axis_minor.normalized() * dir.length() * 2 # Ajustable

func _process(delta):
await get_tree().create_timer(2.0).timeout
angle += speed * delta
var offset = axis_major * cos(angle) + axis_minor * sin(angle)
position = center + offset

#

With only the await there is a little sudden position change but the course is the intended

marsh orchid
#

nice.

#

Mmmm....

#

About that sudden position change after the await...

#

It happens bececause _process() keeps running every frame, but awit only pauses that one frame.

#

so It ends up recalculating position instantly right after the delay, witch causes the jump.

#

try it...

#

add a timer variable and check it in _process() instead of using await.

#

other way..

#

let use a a "ramp-up"variable that eases the speed from 0 to your target speed.

#

var angle := 0.0
var max_speed := 1.0 # NEW: Max speed target
var speed := 0.0 # CHANGED: Start from 0
var center := Vector2.ZERO
var axis_major := Vector2.ZERO
var axis_minor := Vector2.ZERO

NEW: Delay and ramp-up control

var ramp_duration := 1.5
var timer := 0.0
var delay := 2.0
var moving := false

func _ready():
center = get_viewport_rect().size / 2

var dir = position - center
axis_major = dir
axis_minor = Vector2(-dir.y, dir.x)
axis_minor = axis_minor.normalized() * dir.length() * 2

func _process(delta):
if not moving:
timer += delta
if timer >= delay:
moving = true
timer = 0.0
return

if speed < max_speed:
    speed += delta / ramp_duration
    speed = min(speed, max_speed)

angle += speed * delta
var offset = axis_major * cos(angle) + axis_minor * sin(angle)
position = center + offset
#

try this.

heady fossil
#

Ok...

#

Lemme try

#

Omg

#

It works

#

I've been exactly 16-17 days learning godot and almost one week stuck in this and you fixed it in an instant

marsh orchid
#

haha...

#

I've been there too,

#

maybe it was a year ago.

#

you are doing great,

#

especially for just 2 weeks in!

heady fossil
#

Wow all in a year, i can't wait to go there!

#

Yeah, is just that i have a really big proyect in mind and I can't wait doing small proyects

#

So i wanna learn while i do this one

marsh orchid
#

good.

#

keep going.

#

you will be a senior.

#

someday...

heady fossil
#

Still, i have a question with this code

#

If i change the npcs position, the ellipse will adapt?

marsh orchid
#

if you change the npcs position before _ready() runs.

#

then yes...

heady fossil
#

Oh then it's perfect

marsh orchid
#

the ellipse will adapt because it recalculates based on the NPC's starting position relative to the center.

heady fossil
#

This is the beginning only, when I'm ready i'll do the spawn animations and with that the adaptation will be automatic

marsh orchid
#

but if you cange the position after _ready() (like during gameplay), it won't update automatically unless you reclaculate axis_major and axis_minor.

#

yes...

heady fossil
marsh orchid
#

for this,

#

you can move that setup code into a custom function and call it whenever the position changes.

#

func setup_ellipse():
var dir = position - center
axis_major = dir
axis_minor = Vector2(-dir.y, dir.x).normalized() * dir.length() * 2

#

like this.

#

then call setup_ellipse() after you respoition the npc.

heady fossil
#

Ok, i'll keep that in mind

#

Thanks again and I'll leave this "not solved" just in case i need another advice with npc movement

marsh orchid
#

yes...

#

May I ask you a question?

heady fossil
#

Ok

marsh orchid
#

are you a student?

heady fossil
#

In university terms, yes. In godot terms would be more like recently starting

#

I have some experience with Python, that's why it was a bit easier to understand gdscript, it's just that I still don't relate all the in-engine functions

marsh orchid
#

wow.

#

awesome

#

how old are you?

heady fossil
#

Not too young

#

23

marsh orchid
#

is studying fun?

heady fossil
#

It depends, if you're in one of the best universities on your country, then no, it's not because of the pressure. But if not, then yeah, it's fun when you have free time

marsh orchid
#

yeah...

#

I think so.

#

If you have any question, feel free to ask.

#

I'll welcome to you, always.

heady fossil
#

Ok, new problem: When I attack the enemy, the course of the ellipse changes so much that the enemy goes out of the camera

#

I'm gonna paste the important parts where the problem is happening

#

func _ready():
current_health = max_health
$HitBox.hit.connect(_on_Hit) # Se conecta al método que maneja el daño
animation_player.play("idle")
original_material = head.material # Guarda el material base
flash_material = ShaderMaterial.new()
flash_material.shader = flash_shader

center = get_viewport_rect().size / 2

var dir = position - center
axis_major = dir
axis_minor = Vector2(-dir.y, dir.x)
axis_minor = axis_minor.normalized() * dir.length() * 2

func _process(delta):
if not moving:
timer += delta
if timer >= delay:
moving = true
timer = 0.0
return

if speed < max_speed:
    speed += delta / ramp_duration
    speed = min(speed, max_speed)

angle += speed * delta
var offset = axis_major * cos(angle) + axis_minor * sin(angle)
position = center + offset

func setup_ellipse(from_position := position):
var dir = from_position - center
axis_major = dir
axis_minor = Vector2(-dir.y, dir.x)
axis_minor = axis_minor.normalized() * dir.length() * 2
timer = 0.0
speed = 0
angle = 0.0

#

func _on_Hit(damage: int, hit_type: int, hit_origin):
if moving:
moving = false

if current_health <= 0:
    return  # Ya está muerto

flash_white()

if animation_player.is_playing():
    animation_player.stop()  # Esto interrumpe cualquier animación en curso

match hit_type:
    1:
        animation_player.play("punched1")
    2:
        animation_player.play("punched2")
    3:
        animation_player.play("punched3")
    _:
        animation_player.play("hurt")

current_health -= damage

var original_pos = global_position
var push_direction = (global_position - hit_origin).normalized()
global_position += push_direction * 5  # puedes probar con 5-15 según lo sutil que quieras
position = global_position

setup_ellipse(original_pos)

if current_health <= 0:
    await animation_player.animation_finished
    _die()