<img src="http://dl.dropbox.com/u/1010927/IMG1.png">
This is part 1 in a planned series of tutorials. like the title suggests, this tutorial will be explaining how to build your very own 2 armed IK solver, and although plugins exist to do so, this is a stepping stone towards creating advanced expressions in construct, and what will be learned here is going to be used in my next tutorial explaining how to build a 3 armed IK solver, something which doesn't have a plugin to do all the work for you. i'll also point out some advantages of doing this on your own vs a plugin towards the end.
For those of you who dont know, an IK (inverse kinematic) solver, is something which can make an articulated group of objects touch a point which you specify. its ultra handy for making dynamic character animation, (make your character hold a gun properly, or move his arm towards your cursor etc.) and it'll add life to your character you just cant get any other way. for example
DOWNLOAD REALTIME EXAMPLE
the robot seen here and at the beginning of this tut is completely rigged up using IK, i can move his arms and legs where ever i want, as can you (its drag and droppable!), and they'll go there and do exactly as i tell them. now if that isn't control over your animation, i dunno what is.
[quote:2cxgz3fd]the only file youll need to download for this tutorial is this small (15.5 kb zip file) containing the two .caps youll be needing.
DOWNLOAD
so without further ado, heres the tutorial! (feel free to skim if your more advanced, this is meant to be descriptive)
Part 1: 2 Armed IK solver
When I set up an ik solve in my caps, I always use the method im about to show you. I import the same graphics that have been provided here, and give them the SAME names. The name part is important, because if you want to be able to reuse long expressions, objects need to have the same names in order to be picked and behave as they have in other caps. Once you copy and paste the expression, you can rename the object in the layout editor, and everything will still work, since the names in the events will all change
<img src="http://dl.dropbox.com/u/1010927/image%202.png">
As you can see here, we have a ?root? object, which is simply the root, or beginning point of the ik, and we use it storing all the linkages variables later on, but for now just remember it?s the point the arms are attached to, a ?shoulder?. Then we have an ?A? object, this is simply the first arm, and a ?B? object, this is the second arm, they share the same graphic, with the same hotspot, and the same image point at the ?point? of the arm, so that we can find the end of the arms. And place other things to that point without having to deal with any trigonometry.Then, we have another important object, the ?End? object, this is a point that the arms will try to touch, and if they cannot, they?ll get the closest possible that they can. Its the control point of the linkage.
<img src="http://dl.dropbox.com/u/1010927/image%203.png">
One important thing to note, is that these 4 objects are in a container. If you don?t already know what these are, I don?t suggest you be doing this tutorial right now, but deadeyes platform school, or ghost shooter instead. But even so, I will give a brief description, because I doubt anyone's going to take my advice .
A container simply means that all the objects are in a group, and one cannot exist on its own, so when you create one, you create a all the objects in said container. An even more important feature of containers, is that it relates objects within the same container for object picking differently than it would, an object that isn't a part of it. What's different is that if you were to lets say, tell "A" to set position to "ROOT", in an always event, which wouldn?t specify which "A" to attach out of a whole bunch, it would only pick the "A" in the same container group of the "ROOT". So if we picked a certain "root" in some other condition, and set "A" to it, without specifying anything about "A", it would know which "A" to pick and it would only pick said "A" for that "ROOT", and none other, even though the event didn?t specify otherwise. I'm going to ask you to all open up the provided cap called "2 arm ik"
Add each object to a container now , if you did everything right it should look like the image below, and add a drag and drop behavior to "END", and "ROOT", this is just to simplify testing.
<img src="http://dl.dropbox.com/u/1010927/image%204.png">
So now we have everything we need so far set up layout wise. Time to move onto the daunting part, EVENTS. Yea this might be a little scary to some people, ?what do I do IZ so hard!??, or some other peoples reaction, ?I cant do anything with this, its for b3ginn3rs and I r is too 1337 for it, I know GML? your both wrong, this is what makes construct so awesome! but anyways, open up the event editor right now.
Were gonna start the IK solver events, add a ?For each? from the system object, and make it a ?for each Root?, it should look like this. For each?s run the event for each object of that type, picking that object when they run for it, and consequently will pick the related objects in the container, if you ever specify an action for those.
<img src="http://dl.dropbox.com/u/1010927/IMG6.png">
Add an action that sets a new private variable your about to create for "ROOT" called ?C? to this
clamp(distance(Root.x,Root.y,End.x,End.y),abs(A.width-B.width)+0.0000000001,A.width+B.width) [/code:2cxgz3fd]
<img src="http://dl.dropbox.com/u/1010927/img7.png">
which ill explain later, and now make another variable called ?AC? and set it to
[code:2cxgz3fd]Angle(Root.x,Root.y,End.x,End.y)[/code:2cxgz3fd]
<img src="http://dl.dropbox.com/u/1010927/img8.png">
Now if these two events look complicated to you, I suggest reading over the SYSTEM EXPRESSIONS article on the construct wiki.
[url=http://sourceforge.net/apps/mediawiki/construct/index.php?title=System_Expressions]http://sourceforge.net/apps/mediawiki/c ... xpressions[/url]
try looking for all the things I used, and understanding what purpose they served.Now that we have all the actual values we need to solve the ik, we can do just that!The method I used was that of the ?intersection of two circles?
[url=http://local.wasp.uwa.edu.au/~pbourke/geometry/2circle/]http://local.wasp.uwa.edu.au/~pbourke/geometry/2circle/[/url]
[url=http://mathworld.wolfram.com/Circle-CircleIntersection.html]http://mathworld.wolfram.com/Circle-Cir ... ction.html[/url]
and another way to look at it is the ?law of cosines? for solving an unknown angle in a triangle who's sides we all know.
[url=http://mathworld.wolfram.com/LawofCosines.html]http://mathworld.wolfram.com/LawofCosines.html[/url]
if you?re pretty good with math, I suggest you try figuring out the rest of what you need to do on your own, as it will be a great exercise, and then look for possible problems with your method. Remember that I figured out how to do this on my own, using only these references a long time ago and sparked the creation of a plug-in by some else to make it even easier. If you can figure out how to convert the above references into a working construct example like I did, I salute you, and I'm sure youll make a fine constructor indeed young padwan.For those of you who are too lazy to try, or don?t believe you can figure it out, don?t worry. I'm going to give you the nice cut and pastable expression, and for those of you who did, please read over this part as there are a number of things you might not of realised while trying to build your own expression, limiting the ability of what you can do with your solver.
<img src="http://dl.dropbox.com/u/1010927/img9.png">
First off, you wanna be sure to set "A"s position to "ROOT" (remember the container we made a while ago) try to think how that would make multiple pairs of "A"s and "ROOTS"s react because of this action in the for each. now make an extra "ROOT" in the layout, run the layout, and see what happens? Were you correct in your assumptions? If you were you should of seen two "ROOTS"s with two "A"s sticking out of them. But you didn?t create two "A"s? it doesn?t matter, everything in the container must exist as long as one of the elements does, destroying one of the elements will destroy them all. There was also an extra "B" and an extra "END", but you didn?t see them because
they were stacked coincidently (in the same position, angle etc.) as the other ones. Anywho, now that "A" is ?tethered? to the "ROOT", we can set its angle in the direction it needs to be for the arms to reach the end point (or the closest point to it). Remember what we are trying to achieve here. IK stands for ?inverse kinematics?, a fancy way of saying, we want to determine the orientation of a bunch of connected arms, so that the arm linkage's very tip, reaches a point that we give it. So right now we are orienting "A" in an angle that would allow it to be exactly an arm "B"?s length away from the endpoint (or the closest real solution near it without breaking the arm,
more about how this is done in our expressions later)
<img src="http://dl.dropbox.com/u/1010927/IMG7%20%282%29.png">
So, remember how I said were using the circle intersection solving method?, what I just said should make you able to understand why we used it. If not ill explain. Imagine the center of the red circle as ?ROOT?, and the center of the blue one as End. The radiuses of said circles are arms ?A? and ?B? in their respective order (red and blue= ?A? and ?B?). If you take a moment to look at how circles intersect, we realise it?s the points where both radiuses can touch each others ends. This can be though of the joint, we also notice that the combination of the distance between the two center points, and the raiduses, make up the sides of a triangle, this explains why we used the distance formula, and why were going to use the law of cosines. Also note how we have two completely opposite triangles formed, since there are two intersections, but more on this later.For now, remember that what were about to do, is find the angle for a ?A? (or the red radius) where it touches the outside (or radius distance from the center point) of the blue circle. If you don?t get this its ok, itll make sense as we near the end of the process, just remember the radius lengths represent arm lengths, and think about that while looking at the above photo.
OK so without further delay, heres what we need to do. Set the angle of ?A?, to
[code:2cxgz3fd]Root('AC')+acos((A.Width^2+Root('C')^2-B.Width^2)/(2*A.width*Root('C')))*Root('dir')[/code:2cxgz3fd]
your going to need to define a variable ?dir? for the object root once you press finish. That?s why the textbox turned yellow. Remember to set the initial value for dir to ?1? or ?-1? nothing else. You won?t be do anything important by making it anything else than those, but I?ll explain later as to why.
Hmm that looks awfully complicated doesn?t it? Well if you read about the law of cosines it should look really familiar, besides one or two things near the beginning and end. Also remember that ?^? means raise to power, so ?DOG?^2, would mean the value ?DOG? to the power of 2, or DOGxDOG. Note how we use the width of the arms as side lengths. And root(?C?) as one as well. Root(?C?), is the distance between ?END? and ?ROOT?, and we called it ?C? because it?s our third arm in the triangle! A.width, B.width, and root(?C?)? get it!? Anyways, this was the last big expression, in fact the last one for this part of the tut. Now all we have to do is position ?B? onto the end of ?A?, by adding an action ?set B?s position to A? and then in the text box below, write ?point? with the quotations ? finally, create an event which sets B?s angle towards ?END?. We could have made another expression like the one above, but that would have just been a waste of time since it would have gave us the exact same result.
If you did everything correctly things should look like this:
<img src="http://dl.dropbox.com/u/1010927/img10.png">
If not I provided a cap called ?2 arm finished? with the completed example. Look at it and see where you went wrong.
So now everything's completed, and you can start playing around with what you made, go to the layout editor and make a bunch of roots. Then run the layout. You should see a whole bunch of arms pointing toward one ?end?, this is simply because you didn?t create any extra ends, and so construct spawned all of them on the same point (coincident and containers again). Drag and drop the ?end/s? to split them apart. To stop this from happening just make extra ends and it'll show you which ones are for which roots. Also try adjusting the widths of certain arms to make asymmetrical ones.
<img src="http://dl.dropbox.com/u/1010927/img11.png">
Now remember the variable you created for the roots called ?dir?? You might be wondering what its for, and its really important. Do you also remember how there were 2 intersections between the circles? Each with a triangle exactly opposite the other one formed by them?. Well, you see, the variable ?dir? in each root allows us to control the orientation of the arm attached to it, by setting ?dir? to either 1, or -1. go ahead try it (you can set variables in the layout editor, look in the properties bar)
<img src="http://dl.dropbox.com/u/1010927/img12.png">
Do you also remember way back when we set root(?C?), how the distance formula had a bunch of other stuff next to it
[code:2cxgz3fd]clamp(distance(Root.x,Root.y,End.x,End.y),abs(A.width-B.width)+0.0000000001,A.width+B.width)[/code:2cxgz3fd]
Well, if we break up this equation we see that the Clamp(param,param,param) encompasses everything, I suggest you actually go read the systen expressions page in the wiki if you already havent, and look at what clamp does. If you know what it does, youll see that the value being clamped is the distance.
<img src="http://dl.dropbox.com/u/1010927/IMG10%20%282%29.png">
why do we need to clamp it? Well if you look at the left most image here, you'll realize, that it has no solutions! If we were to evaluate the expression without clamping distance, it would very well be possible to end up with this result, but instead we clamp it so that it returns a value similar to the middle picture when its too great.
This value is simply the sum of both radiuses, or alternatively, the sum of both our arm lengths. On the other end of the clamping spectrum, what It does isn't very apparent. That?s because the arm lengths are equal. If you stretch the width of one of them longer, youll notice that the arm cant find a real solution if the end comes in too close. Imagine one circle being inside the other, and their edges don?t touch. Well the other end of the clamp makes the arm behave like your seeing, instead of freaking out all over the place do to a lack of solutions, it finds the closes possible one, a distance which is the absolute value (+ version only of a number) of the difference between arm lengths. As a picture it would look like a circle with its edge up against the other, while still remaining completely inside of the bigger one. The addition of 0.000000001 that you see is simply to prevent the value from being zero, as that would cause a distributive property of zero problem or wtv you'd call it, and would return an infinite number of solutions since the circles would be coincident.
If you'd still like to learn more about what I did, simply tinker with my expressions, deleting or altering things you don?t understand, and seeing how the ik solver behaves without those things. I also recommend you read the tuts I pointed out before hand.
Linkman's IK solver plug-in can do almost everything you just learned, but I don?t use because im kind of stubborn in my ways, and it doesn?t seem to account for the ?circle inside circle? problem (if and when you read this linkman! Fix that bug if you already haven't and the principles covered here will need to be used when I show you how to make my 3 armed, isosceles trapezoid method solver, which doesn?t currently have a plug-in (but probably will soon enough ;P)
<img src="http://dl.dropbox.com/u/1010927/3arm.png">
[h2]well thats all for this part of the tutorial folks![/h2]
[i]if you notice any errors or somethings werent clear just point them out in the comments section, and ill explain or fix them![/i]