Advertisement
Miziziziz

godot 2d ik

Jun 10th, 2018
2,168
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.54 KB | None | 0 0
  1. # usage: attach to a node2d
  2. # the first child will be the base joint
  3. # the first child of that child will be the next joint
  4. # etc, the first child is always the joint. The
  5. # last child will be the end effector
  6. # move the joint along the x axis to set the length of the limb
  7. # e.g:
  8. # v Base, pos = any
  9. # v Joint, local pos = 0, 0
  10. # v Joint, local pos = 0, 20
  11. # v End, local pos = 0, 30
  12.  
  13. extends Node2D
  14.  
  15. var joints = []
  16. var total_length = 0
  17. var end_effector = null
  18. var target = Vector2(0, 0)
  19.  
  20. func _ready():
  21. load_limb_info()
  22. pass
  23.  
  24. func load_limb_info():
  25. var obj = get_child(0)
  26. while obj.get_child_count() > 0:
  27. var ch = obj.get_child(0)
  28. joints.append([obj, ch.position, ch])
  29. total_length += ch.position.x
  30. obj = ch
  31. end_effector = obj
  32.  
  33. func _process(delta):
  34. target = get_global_mouse_position()
  35. calc_ik()
  36. update()
  37.  
  38. func calc_ik():
  39. var offset = target - global_position
  40. if offset.length() > total_length:
  41. for joint in joints:
  42. joint[0].rotation = 0
  43. #joint[2].position = joint[1]
  44. var r = atan2(offset.y, offset.x)
  45. joints[0][0].global_rotation = r
  46. else:
  47. for i in range(15):
  48. end_to_root()
  49. root_to_end()
  50.  
  51. func constrain_limb(var limb):
  52. var a_min = -50
  53. var a_max = 120
  54. var r = limb.rotation_degrees
  55. if r >= a_min and r <= a_max:
  56. return
  57.  
  58. var max_diff = 180 - a_max
  59. var min_diff = 180 + a_min
  60. if r < 0:
  61. if 180 + r + max_diff < abs(r - a_min):
  62. limb.rotation = a_max
  63. else:
  64. limb.rotation = a_min
  65. else:
  66. if r - a_max < 180 - r + min_diff:
  67. limb.rotation = a_max
  68. else:
  69. limb.rotation = a_min
  70.  
  71. limb.rotation_degrees = clamp(limb.rotation_degrees, 0, 90)
  72.  
  73. func end_to_root():
  74. var tar = target
  75. var joint_dup = joints.duplicate()
  76. joint_dup.invert()
  77.  
  78. for joint in joint_dup:
  79. var base = joint[0]
  80. var end_point = joint[1]
  81. var next = joint[2]
  82. etr_set_limb(base, end_point, tar, next)
  83. tar = joint[0].global_position
  84.  
  85. end_effector.global_position = target
  86.  
  87. #limb = base of limb
  88. #end = local end position of limb
  89. #tar = target position of limb
  90. #next = next limb segment
  91. func etr_set_limb(var limb, var end, var tar, var next):
  92. var next_st_pos = next.global_position
  93. var next_st_rot = next.global_rotation
  94.  
  95. #rotate limb to face point
  96. var t_pos = tar - limb.global_position
  97. var r = atan2(t_pos.y, t_pos.x)
  98. limb.global_rotation = r
  99.  
  100. #constrain_limb(limb)
  101.  
  102. #move limb so end is on target_point
  103. limb.global_position += tar - limb.to_global(end)
  104.  
  105. next.global_position = next_st_pos
  106. next.global_rotation = next_st_rot
  107.  
  108. var c = 0
  109. func root_to_end():
  110. var tar = global_position
  111. for joint in joints:
  112. var base = joint[0]
  113. var next = joint[2]
  114. rte_set_limb(base, tar, next)
  115. tar = joint[0].to_global(joint[1])
  116.  
  117.  
  118.  
  119. func rte_set_limb(limb, limb_tar, next):
  120. var next_st_pos = next.global_position
  121. var next_st_rot = next.global_rotation
  122.  
  123. limb.global_position = limb_tar
  124. var off = next_st_pos - limb.global_position
  125. var r = atan2(off.y, off.x)
  126. limb.global_rotation = r
  127.  
  128. #TODO constraints
  129. #constrain_limb(limb)
  130.  
  131. next.global_position = next_st_pos
  132. next.global_rotation = next_st_rot
  133.  
  134. func _draw():
  135. #var col = Color(1, 1, 1)
  136. var j_count = joints.size()
  137. for i in range(j_count):
  138. var joint = joints[i][0]
  139. var j_pos = joint.global_position
  140. var c_pos = joint.to_global(joints[i][1])
  141. var col = Color(i * 1.0 / j_count, 0, 0)
  142.  
  143. draw_circle(to_local(j_pos), 5, col)
  144. draw_line(to_local(j_pos), to_local(c_pos), col, 5)
  145.  
  146. draw_circle(to_local(end_effector.global_position), 10, Color(1, 1, 0))
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement