happy ghast
happy ghast

Reputation: 11

How To Change Enemy Speed or make it stop after a few second from spawning. and moving again after a few second in GDscript

I don't Know How to Make The Enemy change speed or not moving after a few second here my code

extends CharacterBody3D

const speed = - 1
func _ready():
    pass # Replace with function body.

func _physics_process(delta):
    position += transform.basis * Vector3(speed,0, 0) * delta * 0.01

Upvotes: 1

Views: 554

Answers (1)

Theraot
Theraot

Reputation: 40295


SceneTreeTimer

If you only need this change a few seconds after spawning, creating a timer is useful, in particular an SceneTreeTimer comes handy:

func _ready() -> void:
    var timer := get_tree().create_timer(a_few_seconds)
    timer.timeout.connect(func(): velocity = Vector3.ZERO)

Where a_few_seconds is the amount of time you want to elapse before the change happens.

As you can see I'm using an anonymous method (lambda) to set velocity to Vector3.ZERO, you could use multiple lines, or connect a full blown method.

No, you do not need to keep a reference of the SceneTreeTimer. I'm using a local variable to avoid making the line too long.

By default the SceneTreeTimer will run even if the game is paused (which you do with get_tree().paused = true), but you can have it stop when paused like this:

func _ready() -> void:
    var timer := get_tree().create_timer(a_few_seconds, false)
    timer.timeout.connect(func(): velocity = Vector3.ZERO)

Time.get_ticks_msec()

However, if the time at which you want the change to happen might change, you are better of using a different approach.

My go-to these days is computing the time at which I want it to happen having Time.get_ticks_msec() as starting point:

var change_msec:int


func _ready() -> void:
    change_msec = Time.get_ticks_msec() + int(a_few_seconds * 1000.0)

And then checking in _process:

func _physics_process(delta:float) -> void:
    if Time.get_ticks_msec() > change_msec:
        velocity = Vector3.ZERO

A variation of this is using float, which also allows to encode INF for something to never happen:

var change_seconds:float


func _ready() -> void:
    change_seconds = (Time.get_ticks_msec() / 1000.0) + a_few_seconds


func _physics_process(delta:float) -> void:
    if (Time.get_ticks_msec() / 1000.0) > change_seconds:
        velocity = Vector3.ZERO

The drawback of this approach is that... It takes extra effort to support pause (you could listen NOTIFICATION_PAUSED, and NOTIFICATION_UNPAUSED, and keep track of accumulated time). It is probably better to change approach if that is important.


delta

Some people prefer a countdown and take advantage of delta.

var remaining_time:float


func _ready() -> void:
    remaining_time = a_few_seconds


func _physics_process(delta:float) -> void:
    remaining_time -= delta
    if remaining_time < 0.0:
        velocity = Vector3.ZERO

This is probably the easier to grasp.


Timer (from the editor)

The above method is also how a regular Timer works behind the scenes, so that is another option:

  • Add a Timer in your scene as a child to your Node in the editor.
  • Configure its wait_time to the few seconds you want to wait.
  • Set its autostart property to true so it starts automatically.
  • Connect the timeout signal to your Node.

Then you will have a method that handles the timeout signal looking like this:

func _on_timer_timeout() -> void:
    velocity = Vector3.ZERO

Timer (from code)

Of course, the above implies that you have a scene where you can do that. If you don't you can still make the timer from code:

var timer:Timer

func _ready() -> void:
    timer = Timer.new()
    timer.wait_time = a_few_seconds
    timer.timeout.connect(_on_timer_timeout)
    timer.start()

func _on_timer_timeout() -> void:
    velocity = Vector3.ZERO

And, of course, SceneTreeTimer is a convenient way of doing that. So we have come full circle.


Thread

There is arguebly another way of doing it: start a Thread and have it sleep with OS.delay_msec for the desired amount of time, then it can use call_deferred or set_deferred to do the change you want.

The only advantage of this approach is that you are not checking every frame in _process, but of course a Thread has its own cost, so this might only make sense for the case of a long wait time. It also has the caveat of not supporting pause.

Upvotes: 1

Related Questions