0 votes

Hey there !
Working with line 2D to give my projectile a trail.

Simple code, simple process. But for some reasons my trail is all over the place and on thhe edge of the map...

do you guys see anything wrong ?

here is the video : (Look on the edge top right and bottom left when the projectile is fire)
https://www.youtube.com/watch?v=p_dqozOANs8

these are my nodes :
enter image description here
and this is my super short script from trail2d node :

extends Line2D

var point

func ready():
pass

func physicsprocess(delta):
point = getparent().globalposition
add_point(point)

if points.size() >150:
    remove_point(0)

Now, i print(point) and pick one of the point to double chheck that i have the right location : (912.511902, 437.014679)
I do. 900 with, 437 heights. that matches the screen position of the projectile.

asked May 23 in Engine by quizzcode (152 points)

Not sure, but try to add:

func _process(delta):
    global_position = Vector2(0, 0)

Your Line2D-position is relative to you missile, so it moves with it. With that code you get sure, that the Line2D keeps itself in place.

1 Answer

+1 vote
Best answer

But for some reasons my trail is all over the place

The point coordinates of the trail are relative to the position of the Line2D-node. If that node is attached to the Missile node, a point with coordinates (0, 0) would land precisely on the Missile. However, you set the coordinates to the Missiles global position, which moves the trail by that amount away from the Missile.

This should work:

extends Line2D

var point

func ready():
    set_as_toplevel(true)

func _physics_process(delta):
    point = get_parent().global_position
    add_point(point)

    if points.size() > 150:
        remove_point(0)

The call to set_as_toplevel makes the Line2D independent of it's parent's position and rotation, so it stays in the global origin at (0, 0) while the missile moves.

answered May 23 by njamster (9,950 points)
selected May 25 by quizzcode

I see.
Thank you for your reply.
Sadly, it still doesn't work, I have the same exact result.

It's like if setastop_level doesnt not "work"

perhaps it's because my whole node, that include the trail is moving ?
Would setastoplevel take that in consideration ?

"Returns whether this node is set as Toplevel, that is whether it ignores its parent nodes transformations."

perhaps it's because my whole node, that include the trail is moving? Would set_as_toplevel take that in consideration?

Yes. That's the whole point. If you can upload an (preferably minimal) example project with the issue , I can take a look at it. Otherwise I won't be able to help you: the code I provided about works for me, I've tested it.

hey njamster,
I might do that yes, but I will need to shrink the game down, this might take a bit.
Always appreciate your input helping a new comer.

Before I do this tho, considering the the WHOLE tree node move. How would you separate the line2d's position from it other than setastoplevel ?

from my tower.gb, this is my "shooting" function :

func shoot(multi = 0):
if multi == 1 and can_shoot: #multi shoot, cool down is handled in "in target"
    var m = Missile.instance()
    get_parent().add_child(m) #Instance the Missile (Linked above)
    m.start($spawn.global_transform, target)

elif can_shoot and is_instance_valid(target): ##single target shoot
    var m = Missile.instance()
    get_parent().add_child(m) #Instance the Missile (Linked above)
    m.start($spawn.global_transform, target)
    can_shoot = false
    yield(get_tree().create_timer(cooldown), "timeout") #Attack speed
    can_shoot = true

as soon as the projectile is spawn, i call the function start() with the target argument.
This is my projectile tree :
projectile
This is start() (Very simple) :

func start(_transform, _target):  #moving the projectile toward the target
global_transform = _transform
velocity = transform.x * speed
target = _target

Now in the process delta, i use 2 functions : seek and steer to face the enemy, go toward the enemy and my steering force :

acceleration += seek()

This is seek :

func seek(): #seek the enemy
var steer = Vector2.ZERO
if target and is_instance_valid(target):

        var desired = (target.position - position).normalized() * speed
        steer = (desired - velocity).normalized() * steer_force 


return steer

That's about it.
My line2d is the one listed in the main post.

How would you separate the line2d's position from it other than set_as_toplevel?

I wouldn't. That's what the set_as_toplevel-method is there for. You could set the Line2D's global_position to (0, 0) and global_rotation to 0 on every frame and it should have the same effect. But using set_as_toplevel is a lot cleaner.

alright I figured it out !
You were right all along. I didn't realize that you had quoted "setastoplevel(true)" for precess(delta), i put it onready.

Didn't think that it would need to be done every frames.
Just pout setastoplevel(true) on every frames and it worked !

As usual, thank you for you help. i will credit you <3

It should be enough to call set_as_toplevel once in _ready, at least it was enough in my tests. Calling it every frame (i.e. in _process) will of course also work, but is as pointless as setting a variable to the same value each frame.

I worked on my trail again... and all of this happened because i wrote ready() and not _ready() which is why when i tested your option : no difference, but worked in process(delta).
Thought i would share.

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.