0 votes

I'm attempting to make an enemy entity that will copy the player's input and movement by a slight delay. I can't really describe it better than that.
A good example if you want to know what i want is a section in the game Celeste where you are chased by doppelgangers that can copy your movements but follow you behind by a second.

The video for those who never played the game: https://youtu.be/eFuUojykT9w

Below is some basic platformer code which I'm using as a basis. I want to know what I need to make the code function as indented.

Basic platforming code copied from HeartBeast's 2D kinematic tutorial part 1.

EDIT: I've tried using yield(get_tree().create_timer(2), "timeout") however, the enemy sometimes lags behind for a tiny bit causing it to separate from the player's position.

Godot version 3.2.3
in Engine by (12 points)

1 Answer

0 votes

One way would be to use timed Signals

Basically you add the time of the input + the delay to an Array then consume those stored events in the process function

CopycatEnemy.gd

var movement = Array()
var delta_time = 0

func _ready():
    $Player_node.connect("follow", self, "copy_input")

func copy_input (direction, time, speed)
    var move = Dictionary()
    move.direction = direction
    move.time = time
    move.speed = speed
    movement.append(move)

func _physics_process(delta):
    motion.y += 10

    if not movement.empty():
        delta_time += delta
        var move = movement.front()
        if delta_time >= move.time:
            if move.direction in ["left", "right"]:
                motion.x = move.speed
            elif move.direction in ["up", "down"]:
                motion.y = move.speed
            movement.pop_front()
            delta_time = 0

    motion = move_and_slide(motion, UP)

Player.gd

Signal follow(direction, time, speed)

func _physics_process(delta):
    if Input.is_action_pressed("ui_right"):
        motion.x = 150
        emit_signal("follow", "right", 2, 150)
   Etc. . . . . . .
by (4,308 points)

Alright so I've tinkered around with the code for a bit. I've tried making the signals seperate and then put them back as you had stated, however, the copycat decides that it'll take the signal and constantly do it.

Basically, if I tap left and don't do anything, it'll keep going left until it hits a wall.
However, if I tap right after it hits a wall, it won't move.

When I signal it to jump, it jumps normally.
If I signal it to jump up and move left in the air, the copycat will jump and wait for itself to land, then it'll start moving left.

I've tried making an idle signal but when I do that, it won't move at all and doesn't take any inputs. I don't know, maybe I didn't put the code in right or something.

This part of your code

motion.y += 10

Is kind of odd as it always ensures that there is motion regardless of input also make sure the move direction and speed are correct

func copy_input (direction, time, speed):
    #if direction is "ui_right"
        #speed must be a positive number for motion.x
    #if direction is "ui_left"
        #speed must be a negative number for motion.x
    #if direction is "ui_down"
        #speed must be a positive number for motion.y
    #if direction is "ui_up"
        #speed must be a negative number for motion.y
    pass

I forgot to mention, the reason why I have motion.y += 10 is because it's a platformer; its included for gravity purposes.

Understood.

The only other thing that comes to mind is to completely copy the players movement script and lerp the motion ‍♂️

Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to webmaster@godotengine.org with your username.