2d Arm berechnen mit Inverser Kinematik o.ä

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • 2d Arm berechnen mit Inverser Kinematik o.ä

    Also Freunde der Sonne,

    Gegeben sind : Position des Schultergelenks, Position der Hand, Länge des Oberarms, Länge des Unterarms und sehr schlechte Mathekenntnisse.

    Ich möchte also (in 2d, versteht sich) die Positionen und Winkel der Armsegmente berechnen, damit mein Spieler verschiedenste Items/Waffen halten kann ohne das es extrem Schei*e aussieht. Mit einem Arm hab ich das sogar gebastelt bekommen, allerdings mehr schlecht als recht, hinzukommt, dass ich beide Arme haben muss, hält er also eine ump45 dann soll er mit dem anderen Arm weiter vorne an der Waffe greifen. Mit dem Code den ich benutze, kriege ich leider in allen Versuchen die ich angestellt habe einen Fehler da der input zB der arccos Funktion ausserhalb des Wertebereichs liegt. Was sowas angeht bin ich leider der totale Noob.

    Wie man letztendlich zum gewünschten Effekt kommt ist mir ziemlich egal, es soll nur Funktionieren.

    GML-Quellcode

    1. bicep_length = (sprite_get_width(bicepSprite) - sprite_get_height(bicepSprite))*drawScale; // length of bicep element
    2. forearm_length = (sprite_get_width(forearmSprite) - sprite_get_height(forearmSprite))*drawScale; // length of forearm element
    3. arm_dist = point_distance(armF_x, armF_y, handF_x, handF_y); // distance from shoulder to hand
    4. phi = arccos((sqr(arm_dist)-sqr(bicep_length)-sqr(forearm_length))/(-2*bicep_length*forearm_length)); // phi
    5. theta = pi - phi; // theta
    6. omega = arcsin(forearm_length*sin(phi) / arm_dist); // omega
    7. bicep_x = armF_x; // bicep xpos
    8. bicep_y = armF_y; // bicep ypos
    9. bicep_angle = point_direction(armF_x, armF_y, handF_x, handF_y) - radtodeg(omega); // bicep angle
    10. forearm_x = armF_x + lengthdir_x(bicep_length, bicep_angle); // forearm xpos
    11. forearm_y = armF_y + lengthdir_y(bicep_length, bicep_angle); // forearm ypos
    12. forearm_angle = bicep_angle + radtodeg(theta); // forearm angle
    Alles anzeigen


    Also ich wäre für jeden Ansatz und jede Erklärung dankbar, vielleicht kann man meine Dummheit ja noch heilen. Wenn Ich im Internet zum Thema suche beschleicht mich das Gefühl das ich noch eher chinesisch lerne als zu verstehen was da vor mir auf dem Bildschirm steht.

    Danke im Vorraus :thumbup:
    132 little bugs in the code. 132 little bugs. Fix a few, set the compiler to stew, 172 little bugs in the code... :vogel:
  • GML-Quellcode

    1. looking_dir = 1; //-1 = Schaut nach links / 1 = Schaut nach rechts
    2. //armF_x = x;
    3. //armF_y = y;
    4. //handF_x = mouse_x;
    5. //handF_y = mouse_y;
    6. bicep_length = (sprite_get_width(bicepSprite) - sprite_get_height(bicepSprite))*drawScale;
    7. forearm_length = (sprite_get_width(forearmSprite) - sprite_get_height(forearmSprite))*drawScale;
    8. c = handF_x-armF_x;
    9. ch2 = sqr(c);
    10. d = handF_y-armF_y;
    11. dh2 = sqr(d);
    12. g = sqr(bicep_length);
    13. h = sqr(forearm_length);
    14. res_x = -2*dh2*(sqr(dh2) + 2*dh2*(ch2-g-h) + ch2*(ch2-2*g-2*h) + sqr(g-h));
    15. res_y = -2*ch2*(sqr(ch2) + 2*ch2*(dh2-g-h) + dh2*(dh2-2*g-2*h) + sqr(g-h));
    16. if(res_x >= 0 && res_y >= 0)
    17. {
    18. forearm_x = c*(dh2+ch2+g-h);
    19. forearm_x -= sqrt(res_x)*sign(d)*looking_dir;
    20. forearm_x /= 2*(dh2+ch2);
    21. forearm_x += armF_x;
    22. forearm_y = d*(ch2+dh2+g-h);
    23. forearm_y += sqrt(res_y)*sign(c)*looking_dir;
    24. forearm_y /= 2*(ch2+dh2);
    25. forearm_y += armF_y;
    26. }
    27. else
    28. {
    29. forearm_x = (armF_x+handF_x)*0.5;
    30. forearm_y = (armF_y+handF_y)*0.5;
    31. }
    32. bicep_angle = point_direction(armF_x, armF_y, forearm_x, forearm_y);
    33. forearm_angle = point_direction(forearm_x, forearm_y, handF_x, handF_y);
    Alles anzeigen


    Danach kann man sich die Winkel leicht durch point_direction berechnen lassen. Das Problem entsteht dadurch, dass deine Arme zu kurz sind um das Ziel zu erreichen. Bei dieser Lösung werden die Arme gedehnt, sodass sie das Ziel trotzdem erreichen können. Dadurch ist der Code stabieler. Entweder musst du die Arme länger machen oder das wonach er greift erreichbar machen (in diesem Fall eine Waffe oder ein Item). Zudem habe ich eine Richtungsangabe eingebaut, wo man angeben kann in welche Richtung der Spieler schaut. Ich bin mir nicht sicher ob mein Code schneller ist, aber dieser kommt im Grunde ohne Winkelberechnungen aus. Falls jemand interesse hat wie ich auf die Lösung komme:
    I: a² + b² = g²
    II: (a - c)² + (b - d)² = h²

    a = forearm_x - armF_x
    b = forearm_y - armF_y
    c = handF_x - armF_x
    d = handF_y - armF_y
    g = bicep_length
    h = forearm_length

    Dieses Gleichungssystem habe ich dann jeweils "einfach" nach a und b aufgelöst.


    Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von Chris987 ()

  • Jau, Danke sehr für deine Bemühungen! :thumbsup:
    Habe zwar mittlerweile das Problem so gelöst, das ich den input für arccos() zwichen -1 und 1 clampe, aber wie du schon sagst ist bei manchen Stellungen dann der Arm zu kurz und erreicht sein Ziel nicht (Das ist eigentlich nur beim hinteren Arm problematisch, wenn man nach ganz oben oder unten schaut, habe halt auch die direction geclampt damit das nicht passiert, denn er soll ja die Waffe damit weiter vorne halten.) Hatte jetzt leider schon angefangen das ganze umzuschreiben weil ich schon dachte da kann mir niemand eine gescheite Antwort drauf geben, will allerdings auch deine Lösung ausprobieren. Mir ist jetzt allerdings nicht auf die Schnelle ersichtlich, wie genau das mit dem dehnen des Arms funktionieren soll. Das Problem ist halt das der charakter recht flexibel verschiedene Posen einnehmen muss, zB hält er eine Pistole ja ganz anders als Ein Gewehr. Und da gibt es ja dann auch wieder unterschiede da eine UMP zb länger ist als eine UZI, er sie aber so halten soll dass die waffe an die schulter gestützt ist
    und er vorne ja dann auch etwas anders festhalten muss.

    Habe bis jetzt das hier in meinem scr_player_draw_right, habe auch noch nicht alles rübergeportet aus dem alten draw script, vielleicht lässt sich deine Lösung und das Vorhandene ja irgendwie kombinieren.

    Spoiler anzeigen

    GML-Quellcode

    1. texture_set_interpolation(false); // disable linear interpolation
    2. var bicep_length,forearm_length,arm_dist,clampDist,phi,theta,omega,bicep_x,bicep_y,forearm_x,forearm_y,forearm_angle;
    3. var drawScale = .5; // used to bring artwork back to 100% scale
    4. var armAngOffset =-30; // front arm rotation offset
    5. var armRad = 12; // radius, determines hand position
    6. var armDistOffset = 8; // distance from back hand to front hand towards aim direction
    7. var torsoSprite = spr_plr_torso_right;
    8. var headSprite = spr_plr_head_right;
    9. var weaponSprite = spr_wep_ump45;
    10. var bicepSprite = spr_plr_bicep;
    11. var forearmSprite = spr_plr_forearm;
    12. var weaponOffset_x = 20;
    13. var weaponOffset_y = 12;
    14. sprite_set_offset(weaponSprite,weaponOffset_x,weaponOffset_y); // set the weapons offset
    15. var torsoOffset_x = sprite_get_xoffset(torsoSprite)*drawScale; // torso xoffset
    16. var torsoOffset_y = sprite_get_yoffset(torsoSprite)*drawScale; // torso yoffset
    17. var armF_x = x - torsoOffset_x + 7; // front arm shoulder joint xpos
    18. var armF_y = yDrawPos - torsoOffset_y + 14; // front arm shoulder joint ypos
    19. var armB_x = x - torsoOffset_x + 15; // back arm shoulder joint xpos
    20. var armB_y = yDrawPos - torsoOffset_y + 14; // back arm shoulder joint ypos
    21. aimDir = point_direction(armF_x, armF_y,mouse_x, mouse_y); // aim direction
    22. aimDir = scr_clamp_direction(aimDir,0,60); // clamp direction
    23. handF_x = armF_x + lengthdir_x(armRad,aimDir + armAngOffset); // front arm hand xpos
    24. handF_y = armF_y + lengthdir_y(armRad,aimDir + armAngOffset); // front arm hand ypos
    25. var handDirB = point_direction(handF_x,handF_y,mouse_x,mouse_y); // direction from front to back hand
    26. handDirB = scr_clamp_direction(handDirB,0,60); // clamp direction
    27. var handB_x = handF_x + lengthdir_x(armDistOffset,handDirB); // back arm hand xpos
    28. var handB_y = handF_y + lengthdir_y(armDistOffset,handDirB); // back arm hand ypos
    29. //BACK ARM//
    30. bicep_length = (sprite_get_width(bicepSprite) - sprite_get_height(bicepSprite))*drawScale; // length of bicep element
    31. forearm_length = (sprite_get_width(forearmSprite) - sprite_get_height(forearmSprite))*drawScale; // length of forearm element
    32. arm_dist = point_distance(armB_x, armB_y, handB_x, handB_y); // distance from shoulder to hand
    33. clampDist = clamp((sqr(arm_dist)-sqr(bicep_length)-sqr(forearm_length))/(-2*bicep_length*forearm_length),-1,1);
    34. phi = arccos(clampDist); // phi
    35. theta = pi - phi; // theta
    36. omega = arcsin(forearm_length*sin(phi) / arm_dist); // omega
    37. bicep_x = armB_x; // bicep xpos
    38. bicep_y = armB_y; // bicep ypos
    39. bicep_angle = point_direction(armB_x, armB_y, handB_x, handB_y) - radtodeg(omega); // bicep angle
    40. forearm_x = armB_x + lengthdir_x(bicep_length, bicep_angle); // forearm xpos
    41. forearm_y = armB_y + lengthdir_y(bicep_length, bicep_angle); // forearm ypos
    42. forearm_angle = bicep_angle + radtodeg(theta); // forearm angle
    43. draw_sprite_ext(forearmSprite,0,forearm_x,forearm_y,drawScale,drawScale,forearm_angle,image_blend,image_alpha); // draw front arm forearm element
    44. draw_sprite_ext(bicepSprite,body_index,bicep_x,bicep_y,drawScale,drawScale,bicep_angle,image_blend,image_alpha); // draw front arm bicep element
    45. //--------//
    46. //FRONT ARM//
    47. bicep_length = (sprite_get_width(bicepSprite) - sprite_get_height(bicepSprite))*drawScale; // length of bicep element
    48. forearm_length = (sprite_get_width(forearmSprite) - sprite_get_height(forearmSprite))*drawScale; // length of forearm element
    49. arm_dist = point_distance(armF_x, armF_y, handF_x, handF_y); // distance from shoulder to hand
    50. clampDist = clamp((sqr(arm_dist)-sqr(bicep_length)-sqr(forearm_length))/(-2*bicep_length*forearm_length),-1,1);
    51. phi = arccos(clampDist); // phi
    52. theta = pi - phi; // theta
    53. omega = arcsin(forearm_length*sin(phi) / arm_dist); // omega
    54. bicep_x = armF_x; // bicep xpos
    55. bicep_y = armF_y; // bicep ypos
    56. bicep_angle = point_direction(armF_x, armF_y, handF_x, handF_y) - radtodeg(omega); // bicep angle
    57. forearm_x = armF_x + lengthdir_x(bicep_length, bicep_angle); // forearm xpos
    58. forearm_y = armF_y + lengthdir_y(bicep_length, bicep_angle); // forearm ypos
    59. forearm_angle = bicep_angle + radtodeg(theta); // forearm angle
    60. //---------//
    61. draw_sprite_ext(sprite_index,image_index,x,y,drawScale,drawScale,0,feet_colour,image_alpha); // draw feet
    62. draw_sprite_ext(torsoSprite,body_index,x,yDrawPos,drawScale,drawScale,0,image_blend,image_alpha); // draw torso
    63. draw_sprite_ext(headSprite,head_index,x,yDrawPos,drawScale,drawScale,0,image_blend,image_alpha); // draw head
    64. draw_sprite_ext(weaponSprite,0,handF_x,handF_y,drawScale,drawScale,aimDir,c_white,1); // draw weapon
    65. draw_sprite_ext(forearmSprite,0,forearm_x,forearm_y,drawScale,drawScale,forearm_angle,image_blend,image_alpha); // draw front arm forearm element
    66. draw_sprite_ext(bicepSprite,body_index,bicep_x,bicep_y,drawScale,drawScale,bicep_angle,image_blend,image_alpha); // draw front arm bicep element
    Alles anzeigen
    132 little bugs in the code. 132 little bugs. Fix a few, set the compiler to stew, 172 little bugs in the code... :vogel: