Position offset between character and character hairs

Godot Version

v4.4.1.stable.flathub [49a5bc7b6]

Question

Hi,
The position of my character hairs got an offset from the character itself. I don’t understand why as I’m using global_position to set the hair position.
Moreover, the closer the character is to (0, 0) the little the offset will be.

Here’s the code to set the position of the hairs.

for i in range(len(hairPoints)-1, -1, -1):
		if i == 0:
			hairPoints[i][0] = hairGenerator.global_position

Is the hair a child of the character’s node? If so, you probably just want to set its position to 0, 0; the position of a child node is the sum of its position and that of all its ancestors in the node hierarchy.

1 Like

I tried it but if I do so, the wiggle effect disappear. I may create a dedicated node for the hairs ?

It seems like what you want is something like:

Character
  Hair
    Hair
      Hair

Where each is the child of the one above, and each has an offset of a few pixels in the appropriate dimension of their position.

The hairs are not directly children of the character as they drawn with the _draw function.Tthe main hair point (the biggest circle) position is based on the hairGenerator node position, and the other hairs position depend on the main hair position, and here’s my tree:

@onready var hairGenerator: Node2D = $HairGenerator

# ARRAY
#[(pos_x, pos_y), (offset_x, offset_y), max_dist, radius]
var hairPoints: Array = [
	[Vector2(0, 0), Vector2(0, 0), 0, 10],
	[Vector2(0, 0), Vector2(-2, 3), 4, 8],
	[Vector2(0, 0), Vector2(-1, 3), 3.5, 7]
]

func _draw() -> void:
	if sprite.visible:
		for p in hairPoints:
			print(p[0], hairGenerator.global_position)
			draw_circle(p[0], p[3], Color.PURPLE)
			draw_circle(p[0], p[3], Color.BLACK, false)

func _physics_process(delta: float) -> void:
	for i in range(len(hairPoints)-1, -1, -1):
		if i == 0:
			hairPoints[i][0] = hairGenerator.global_position
		else:
			hairPoints[i][0] = hairPoints[i][1]+hairPoints[i-1][0]
	for i in range(len(hairPoints)):
		if i != 0 && hairPoints[i][0].distance_to(hairPoints[i][1]+hairPoints[i-1][0]) > hairPoints[i][2]:
				var dir = (hairPoints[i-1][0]+hairPoints[i][1]).direction_to(hairPoints[i][0])
				var offset = dir*hairPoints[i][2]
				hairPoints[i][0] = hairPoints[i-1][0]+offset+hairPoints[i][1]
	
	queue_redraw()

You might find this simpler if you make your hair points out of Sprite2D.

It’s weird because I followed a tutorial and it was working find in the video:

What sets the position of HairGenerator?

I set it with the 2d editor (the highlighted point):

It looks to me like what’s happening is when you set the position of the first point from the global_position of the hair node, all your offsets are blowing up. It’s a little hard to read with the array-of-arrays thing you have going there, but I think the reverse order offset calculation may be at fault.

1 Like

Sooooo, I may changed something in total despair and it works. I love programming :sob:

func _draw() -> void:
	if sprite.visible:
		for i in range(len(hairPoints)):
			if i==0:
				draw_circle(hairGenerator.global_position-VAR.player.global_position, hairPoints[i][3], Color.PURPLE)
				draw_circle(hairGenerator.global_position-VAR.player.global_position, hairPoints[i][3], Color.BLACK, false)
			else:
				draw_circle(hairPoints[i][0]-VAR.player.global_position, hairPoints[i][3], Color.PURPLE)
				draw_circle(hairPoints[i][0]-VAR.player.global_position, hairPoints[i][3], Color.BLACK, false)

Thanks for your help

You’ve certainly changed a few things from this tutorial, including a major version upgrade. Regardless you should be able to use local coordinates to draw in a chain.

func _physics_process(delta: float) -> void:
	for i in range(len(hairPoints)-1, -1, -1):
		if i == 0:
			hairPoints[i][0] = Vector2.ZERO
		else:
			hairPoints[i][0] = hairPoints[i][1]+hairPoints[i-1][0]

This code will have the effect of making the distance between each hair constant, I’ll stick with what I’ve found.
Thanks for helping me!