Godot 4.2
I am trying to code procedural animation for a 2D bird, and so far it is going pretty well. But the knee keeps bending into the floor and I also can’t find a good way to make the foot raise while stepping into the target position. This is my script for the leg:
extends Node2D
@onready var foot = $Foot
@onready var lower_leg = $LowerLeg
@onready var upper_leg = $UpperLeg
@onready var leg_pos = $leg_pos
@onready var target_pos = $target_pos
@onready var rest_pos = $rest_pos
@onready var floorcast = $FloorCast
@onready var frontcast = $FrontCast
@onready var footcast = $Foot/FootCast
@onready var parent = $“…”
@onready var kneeshape = $“…/KneeShape”
@onready var footshape = $“…/FootShape”
@onready var wing = $“…/Wing”
@export var lower_leg_offset := 1.0
#Leg lengths
var upper_leg_length = 150.0
var lower_leg_length = 150.0
#Step threshold
var step_threshold = 20.0
var max_distance = 10.0
#Easing parameters
var easing_speed = 0.2
var stepped := false
var line_color = Color(0, 0, 0)
var line_thickness = 4
func _ready():
#leg_pos.top_level=false
#leg_pos.position = rest_pos.position
foot.global_position = leg_pos.global_position
wing.rotation_degrees = 180.0
func _draw():
var previous_position = null
for child in get_children():
if !child is Marker2D and !child is RayCast2D:
if previous_position != null:
draw_line(previous_position, child.position, line_color, line_thickness)
previous_position = child.position
func _process(_delta):
queue_redraw()
var target_vector = target_pos.global_position - leg_pos.global_position
var _distance_to_target = target_vector.length()
if frontcast.is_colliding():
var collision_point = frontcast.get_collision_point()
target_pos.global_position = collision_point
# Check if the raycast is colliding
if floorcast.is_colliding():
if leg_pos.top_level==false:
var collision_point = floorcast.get_collision_point()
leg_pos.position.y = lerp(leg_pos.position.y, collision_point.y, 1)
leg_pos.top_level=true
#if distance_to_target < upper_leg_length + lower_leg_length:
#leg_pos.global_position.y = lerp(leg_pos.global_position.y, collision_point.y, 0.1)
wing.rotation_degrees = lerp(wing.rotation_degrees, 90.0, 0.1)
foot.global_position = leg_pos.global_position
if leg_pos.global_position.distance_to(target_pos.global_position) > upper_leg_length + lower_leg_length and frontcast.is_colliding():
#Calculate the midpoint
var midpoint = (leg_pos.position - target_pos.position) / 2
#Add a vertical offset to the midpoint
midpoint.y -= 20.0 # Adjust this value to control the height of the raise
leg_pos.global_position = lerp(leg_pos.global_position, target_pos.global_position, 1)
else:
leg_pos.global_position = lerp(leg_pos.global_position, rest_pos.global_position, 0.1)
foot.global_position = leg_pos.global_position
wing.rotation_degrees = lerp(wing.rotation_degrees, 180.0, 0.1)
leg_pos.top_level=false
footshape.global_position = foot.global_position
var foot_position = leg_pos.global_position
var base_position = upper_leg.global_position
var leg_vector = foot_position - base_position
var distance_to_foot = leg_vector.length()
if distance_to_foot > upper_leg_length + lower_leg_length:
leg_vector = leg_vector.normalized() * (upper_leg_length + lower_leg_length)
#Calculate the knee position
var mid_point = base_position + leg_vector * 0.5
var offset_length = sqrt(upper_leg_length * upper_leg_length - (distance_to_foot * 0.5) * (distance_to_foot * 0.5))
var offset = Vector2(-leg_vector.y, leg_vector.x).normalized() * offset_length
var knee_position = mid_point + offset
if target_pos.position.x > 0.0:
#Target is on the right
knee_position = lerp(knee_position, mid_point + offset, 1)
else:
#Target is on the left
knee_position = lerp(knee_position, mid_point - offset, 1)
lower_leg.global_position = knee_position
kneeshape.global_position = lower_leg.global_position
This is my first time asking on a site like this, so apologies if I forget something. (I’m also not the best at math in this sort of situation, so I would appreciate a comprehensible answer)
Here’s a video too: