Create en Mekanisk Snake Med Inverse Kinematikk 
 3 
 Del 
 to 
 Del 
 
 Dette Cyber mandag Envato Tuts + kurs vil bli redusert til bare $ 3. . Ikke gå glipp av 
 
 Tenk deg en kjede av partikler animere i symfoni sammen: Et tog i bevegelse som alle tilkoblede avdelinger følge etter; et dukketeater dans som sin herre trekker sin string; selv armene, når foreldrene dine holder hendene som de lede deg i en kveldstur. Movevment krusninger ned fra siste node til opprinnelsen, følge til begrensninger som det går. Dette er  inverse kinematikk plakater (IK), en matematisk algoritme som beregner nødvendige bevegelser. Her vil vi bruke den til å lage en slange som er litt mer avansert enn den fra Nokia spill.     La oss ta en ser på det endelige resultatet vi skal jobbe mot. Trykk og hold opp, venstre og høyre piltaster for å gjøre det flytte   En kjede er konstruert av noder. Hver node representerer et punkt i kjeden hvor overføring og rotasjon kan skje. I IK kjeden, krusninger bevegelse ned i revers fra siste node (siste barn) til den første noden (root node) i motsetning til Forward Kinematikk (FK) der kinematikk traversere fra rotnoden til det siste barnet.   Alle kjedene begynner med rotnoden. Dette rotnoden er konstituert forelder til som et nytt barn node er vedlagt. I sin tur, blir dette første barn vil moder den andre barn i kjeden, og dette gjentas inntil den siste barnet blir tilsatt. Animasjonen nedenfor viser et slikt forhold   IKshape klassen implementerer tanken om en node i vår kjede. Forekomster av IKshape klasse huske sine overordnede og underordnede noder, med unntak av rotnoden som ikke har foreldrenoden og den siste node som ikke har noen barn node. Nedenfor er de private eiendommer i IKshape   accessors av disse eiendommene er vist som nedenfor:   Du kan legge merke til at denne klassen gjør lagre en Vector2D som peker fra barn node til foreldrenoden. Begrunnelsen for denne retningen skyldes bevegelse strømmer fra barn til foreldre. Vector2D brukes fordi størrelsen og retningen av vektoren som peker fra barn til forelder vil bli manipulert ofte mens gjennomføringsmåten til en IK kjede. Dermed holde styr på slike data er nødvendig. Nedenfor er metoder for å maniplate vektor mengder for IKshape   Sist men ikke minst, trenger vi en metode for å trekke vår form. Vi skal tegne et rektangel for å representere hver node. Imidlertid kan noen andre preferanser settes i ved å overstyre trekningen metoden her. Iv følger et eksempel på en klasse styrer standard trekningen metoden, Ball klasse. (En rask bytte mellom figurene vil bli demonstrert på slutten av denne opplæringen.) Med dette full vi etableringen av Ikshape klassen   IKine klassen implementerer oppførsel av en IK-kjeden. Forklaring om denne klassen følger denne rekkefølgen   Kode nedenfor viser IKine klasse private variabler   IKine kjeden vil lagre en Sprite datatype som husker forholdet av sin foreldre og barn. Disse sprites er forekomster av IKshape. Den resulterende kjeden ser rotnoden ved indeks 0, det neste barnet ved indeks 1, ... til siste barnet i sekvensiell måte. Imidlertid er byggingen av kjeden ikke fra rot til siste barn; . det er fra siste barn til roten   Forutsatt at kjeden er av lengde n, følger bygge denne sekvensen: n-te node, (n-1) -te node, (n-2) -te node ... 0-th node. Animasjonen nedenfor viser denne sekvensen.   Ved oppretting av IK-kjeden, er den siste noden inn. Parent noder vil bli lagt senere. Den siste node vedlagt er roten. Koden nedenfor er metoder for IK kjeden konstruksjon, tilføye og fjerne noder til kjeden   Disse følgende metoder brukes til å hente noder fra kjeden når det er behov   Vi har sett hvordan kjeden av noder blir representert i en rekke: Root node ved indeks 0, ... (n- 1) 'te node ved indeks (n-2), n-te knutepunktet ved indeks (n-1) hvor n er lengden av kjeden. Vi kan enkelt ordne våre begrensninger i en slik ordre i tillegg. Begrensninger kommer i to former:  avstanden mellom nodene Hotell og  grad av bøying frihet mellom nodene   Avstand for å opprettholde mellom noder er anerkjent som et barn nodes begrensning på sin forelder. . For ordens skyld på å registrere bekvemmelighet, kan vi lagre denne verdien som constraintDistance array med indeks lik som barnet node-tallet. Merk at rotnoden har ingen foreldre. Imidlertid bør avstanden begrensning registreres ved å føye rotnoden, slik at hvis kjeden er forlenget senere, kan den nylig vedlagte "foreldre" av denne rotnoden utnytte sine data.   Deretter vinkelen for bøying en foreldrenoden er begrenset til et område. Vi skal lagre start- og sluttpunkt for serien i constraintRangeStart og ConstraintRangeEnd array. Figuren nedenfor viser et barn node i grønne og to overordnede noder i blått. Bare den noden som er merket "OK" er tillatt fordi den ligger innenfor den vinkel begrensningen. Vi kan bruke samme tilnærming i å registrere verdier i disse arrays. Merk igjen at rotnoden vinkel begrensninger skal registreres, selv om den ikke er i bruk på grunn av lignende begrunnelse som tidligere. Plus, vinkel begrensninger gjelder ikke den siste barnet fordi vi ønsker fleksibilitet i kontroll   Metodene som følger kan være nyttig når du har igangsatt begrensninger på en node, men ønsker å endre verdien i fremtiden Twitter /* Manipulere tilsvarende begrensninger * /public funksjon getDistance (node: Number): Antall {return this.constraintDistance [node];} offentlig funksjon setDistance (. newDistance: Antall, node: Number): void {this.constraintDistance [node] = newDistance;} offentlig funksjon getAngleStart (node: Number): Antall {return this.constraintRangeStart [node];} offentlig funksjon setAngleStart (newAngleStart: Antall, node : Number): void {this.constraintRangeStart [node] = newAngleStart;} offentlig funksjon getAngleRange (node: Number): Antall {return this.constraintRangeEnd [node];} offentlig funksjon setAngleRange (newAngleRange: Antall, node: Number): void {this.constraintRangeEnd [node] = newAngleRange;}   Følgende animasjonen viser beregningen av lengden begrensningen   I dette trinnet skal vi ta en titt på kommandoer i en metode som bidrar til å begrense avstanden mellom nodene. Legg merke til de markerte linjer. Du kan merke bare det siste barnet er påført denne begrensningen. Vel, så langt kommandoen går, dette er sant. Foreldrenodene er nødvendig for å oppfylle ikke bare lengde, men vinkel begrensninger. Alle disse er behandlet med gjennomføringen av metoden  vecWithinRange ()   Først må vi regne ut vinkelen klemt mellom to vektorer, vec1 og vec2. Hvis vinkelen er ikke innenfor anstrengt rekkevidde, tildele minimum eller maksimumsgrense for vinkel. Når en vinkel er definert, kan vi beregne en vektor som er rotert fra vec1 sammen med begrensningen av avstand (magnitude).   Følgende animasjon tilbyr et alternativ for å visualisere ideen.   Gjennomføringen av vinkel begrensninger er like nedenfor.   Kanskje det er verdig til å gå gjennom her ideen om å få en vinkel som tolker med og mot urviseren. Vinkelen mellom to vektorer, si vec1 og vec2, kan lett oppnås fra prikk-produktet av disse to vektorer. Produksjonen vil være den korteste vinkel for å rotere vec1 til vec2. Det er imidlertid ingen oppfatningen av retning som svaret er alltid positive. Derfor modifikasjon på den vanlige produksjonen skal utføres. Før outputing vinkel, anvendes vektorprodukt mellom vec1 og vec2 for å bestemme om den aktuelle sekvensen er positiv eller negativ rotasjon og innlemmet tegnet inn i vinkel. Jeg har markert retnings funksjonen i linjer med kode under   noder som er bokser må være orientert i retning av sine vektorer, slik at de ser fine. Ellers vil du se en kjede som nedenfor. (Bruk piltastene til å flytte.)   Funksjonen nedenfor implementerer riktig orientering av noder   Nå som alt er satt, kan vi animere vår kjede hjelp animere (). Dette er en sammensatt funksjon å ringe til updateParentPosition () og updateOrientation (). Men før det kan oppnås, må vi oppdatere relasjoner på alle noder. Vi gjør et kall til updateRelationships (). Igjen, updateRelationships () er en sammensatt funksjon å ringe til defineParent () og defineChild (). Dette gjøres en gang, og når det er en endring i kjedestrukturen, f.eks noder legges til eller falt under kjøring   For å gjøre IKine klasse jobben for deg, disse er noen metoder du bør se nærmere på. Jeg har dokumentert dem i en tabellform   Merk at vinkel inngangene er i radianer ikke grader   Nå kan opprette et prosjekt i FlashDevelop. I src mappen vil du se Main.as. Dette er rekkefølgen av oppgaver du bør gjøre:   Object er trukket som vi konstruere IKshape. Dette gjøres i en sløyfe. Oppmerksom hvis du ønsker å endre utsiktene av tegningen til en sirkel, aktiverer kommentar på linje 56 og deaktivere kommentar på linje 57. (Du må laste ned mine kildefilene for at dette skal fungere.) Anmeldelser private funksjons drawObjects (): void {for (var i: uint = 0; i < totalNodes; i ++) {var currentObj: IKshape = new IKshape (); //Var currentObj: Ball = new Ball (); currentObj.name = & quot; b & quot; + I; addChild (currentObj); }}   Før initialisering av IKine klassen å konstruere kjeden, private variabler av Main.as er skapt   For tilfelle her, alle nodene er begrenset til en avstand på 40 mellom noder   Neste, vi erklærer variabler som skal benyttes av våre tastatur kontroll   Fest på scenen hovedsløyfe og tastatur lyttere. Jeg har uthevet dem   Skriv lytterne   Legg merke til at jeg har brukt en Vector2D eksempel å føre slangen beveger seg rundt på scenen. Jeg har også begrenset denne vektoren innenfor grensen av scenen så det vil ikke flytte ut. Action utfører denne begrensningen er uthevet   Trykk Ctrl + Enter for å se din slange animere !. Kontrollere sin bevegelse ved hjelp av piltastene.   Denne opplæringen krever litt kunnskap i vektoranalyse. For lesere som ønsker å få et kjent titt på vektorer, har en lese på innlegget fra Daniel Sidhon. Håper dette hjelper deg i å forstå og implementere inverse kinematikk. Takk for lesing. Må slippe forslag og kommentarer som Im alltid ivrige etter å høre fra publikum. Terima Kasih. Anmeldelser
 
 
 
 Endelig resultat Forhåndsvisning 
 
 
 
 Trinn 1:. Sammenhengene i en kjede 
 
 
 
 
 Trinn 2:. Remembering relasjoner 
 
 private Var childNode. IKshape, privat Var parentNode: IKshape; privat Var vec2Parent: Vector2D; 
 offentlig funksjon satt IKchild ( childSprite: IKshape): void {childNode = childSprite;} offentlig funksjon får IKchild (): IKshape {return childNode} offentlig funksjon satt IKparent (parentSprite: IKshape): void {parentNode = parentSprite;} offentlig funksjon får IKparent (): IKshape { returnere parentNode;} 
 
 Trinn 3: Vector fra barn til Parent 
 
 offentlig funksjon calcVec2Parent (): void {var xlength. Number = parentNode.x - this.x; Var ylength: Number = parentNode.y - this.y; vec2Parent = new Vector2D (xlength, ylength);} offentlig funksjon setVec2Parent (vec: Vector2D): void {vec2Parent = vec.duplicate ();} offentlig funksjon getVec2Parent (): Vector2D {return vec2Parent.duplicate ();} offentlig funksjon getAng2Parent (): Antall {return vec2Parent.getAngle ();} 
 
 Trinn 4: Tegning Node 
 
 beskyttet funksjon draw (): void {var col. Number = 0x00FF00; Var w: Number = 50; Var h: Number = 10; graphics.beginFill (col); graphics.drawRect (w /2, -h /2, w, h); graphics.endFill ();} 
 
 Trinn 5: IK Chain 
 
  
 Innføring i private variabler i denne klassen. 
 
 
 
 Implementering av disse spesifikke funksjoner 
 
 
 Trinn 6:. Data i en kjede 
 
. private Var IKineChain. Vector < IKshape >; //medlemmer av kjeden //Datastruktur for constraintsprivate Var constraintDistance. Vector < Number >; . //avstand mellom nodesprivate Var constraintRangeStart: Vector < Number >; //starten av rotasjons freedomprivate Var constraintRangeEnd. Vector < Number >; //slutten av rotasjons frihet 
 
 Trinn 7: instantiate Chain 
 
 
 
 offentlig funksjon IKine (lastChild: IKshape, avstand: Number) {//initiere alle private variabler IKineChain = new Vector < IKshape > ()..; Number >; constraintDistance = new Vector <. (); Number >; constraintRangeStart = new Vector <. (); Number >; constraintRangeEnd = new Vector <. (); //Set begrensninger this.IKineChain [0] = lastChild; this.constraintDistance [0] = avstand; this.constraintRangeStart [0] = 0; this.constraintRangeEnd [0] = 0;} /* Metoder for å manipulere IK kjetting * /public funksjon appendNode (nodeNext: IKshape, avstand: Number = 60, angleStart: Number = -1 * Math.PI, angleEnd: Number = Math. PI): void {this.IKineChain.unshift (nodeNext); this.constraintDistance.unshift (avstand); this.constraintRangeStart.unshift (angleStart); this.constraintRangeEnd.unshift (angleEnd);} offentlig funksjon removeNode (node: Number): void {this.IKineChain.splice (node, 1); this.constraintDistance.splice (node, 1); this.constraintRangeStart.splice (node, 1); this.constraintRangeEnd.splice (node, 1);} 
 
 Trinn 8: Få Chain Nodes 
 
 offentlig. funksjon getRootNode (): IKshape {return this.IKineChain [0];} offentlig funksjon getLastNode (): IKshape {return this.IKineChain [IKineChain.length - 1];} offentlig funksjon getNode (node: Number): IKshape {return denne .IKineChain [node];} 
 
 Trinn 9: Begrensninger 
 
 
 
 
 
 Trinn 10:. Begrensninger: Komme og sette 
 
 
 Trinn 11:. Lengde Constraint, Concept 
 
 
 
 Trinn 12: Lengde Constraint, Formula 
 
. Siste barnet trenger ikke være begrenset i vinkel fordi vi trenger maksimal bøy fleksibilitet 
 privat funksjon updateParentPosition (): void {for (var i: uint = IKineChain.length - 1; i > 0; I--). {IKineChain [i] .calcVec2Parent (); Var vec: Vector2D; //håndtering av siste barnet hvis (i == IKineChain.length - 1) {var ang: Number = IKineChain [i] .getAng2Parent (); vec = new Vector2D (0, 0); vec.redefine (this.constraintDistance [IKineChain.length - 1], ang); } Else {vec = this.vecWithinRange (i); } IKineChain [i] .setVec2Parent (vec); IKineChain [i] .IKparent.x = IKineChain [i] .x + IKineChain [i] .getVec2Parent () x.; IKineChain [i] .IKparent.y = IKineChain [i] .Y + IKineChain [i] .getVec2Parent () y.; }} 
 
 Trinn 13: Angle tvang, Concept 
 
 
 
 < h2> Trinn 14: Angle Constraint, Formula 
 
 privat funksjon vecWithinRange (currentNode: Number): Vector2D {//får riktig vektorer Var child2Me: Vector2D = IKineChain [currentNode] .IKchild.getVec2Parent (); Var me2Parent: Vector2D = IKineChain [currentNode] .getVec2Parent (); //Implementere vinkel grenser begrensning Var currentAng: Number = child2Me.angleBetween (me2Parent); Var currentStart: Number = this.constraintRangeStart [currentNode]; Var currentEnd: Number = this.constraintRangeEnd [currentNode]; Var limitedAng: Number = Math2.implementBound (currentStart, currentEnd, currentAng); //Implementere avstand begrensning child2Me.setMagnitude (this.constraintDistance [currentNode]); child2Me.rotate (limitedAng); returnere child2Me} 
 
 Trinn 15: Vinkel med beskrivelser 
 
 offentlig funksjon vectorProduct (vec2: Vector2D): Antall {return this.vec_x * vec2.y - this.vec_y * vec2.x;} offentlig funksjon angleBetween (vec2.: Vector2D): Antall {var vinkel. Number = Math.acos (this.normalise () dotProduct (vec2.normalise ())); Var vec1: Vector2D = this.duplicate (); if (vec1.vectorProduct (vec2) < 0) {vinkel * = 1; } Avkastning vinkel;} 
 
 Trinn 16: Orientere Knuter 
 
 
 privat funksjon updateOrientation (): void {for (var i. Uint = 0; i < IKineChain. lengde - 1; i ++) {var orientering. Number = IKineChain [i] .IKchild.getVec2Parent () getAngle (); IKineChain [i] .rotation = Math2.degreeOf (orientering); }} 
 
 Trinn 17: Siste Bit 
 
 
 
 Trinn 18:. Essential Metoder i IKine 
 
 MethodInput ParametersRoleIKine () lastChild. IKshape, avstand: NumberConstructor.appendNode () nodeNext: IKshape, [distanse: Antall, angleStart: Antall, angleEnd: Number] legge til noder i kjeden, definere begrensninger implementert av node.updateRelationships () NoneUpdate foreldre-barn-relasjoner for alle nodes.animate () NoneRecalculating posisjonen til alle nodene i kjeden. Må kalles hver ramme 
 
 
 Trinn 19:.. Opprette en Snake 
 
  
 Start kopier av IKshape eller klasser som strekker seg fra IKshape på scenen 
 
 Initiere IKine og bruke den til å kjede seg kopier av IKshape. på scenen 
 
 Oppdater relasjoner på alle nodene i kjeden 
 
 Implementere brukerkontroller 
 
 Animate 
 
 
 Trinn 20...!: tegne objekter 
 
 
 Trinn 21: Initial Chain 
 
 privat Var currentChain. IKine; private Var lastNode : IKshape; private Var totalNodes: uint = 10; 
 privat funksjon initChain (): void {this.lastNode = this.getChildByName (. & quot; b & quot; + (totalNodes - 1)) som IKshape; currentChain = new IKine (lastNode, 40); for (var i: uint = 2; i < = totalNodes; i ++) {currentChain.appendNode (this.getChildByName (& quot; b & quot; + (totalNodes - i)) som IKshape, 40, Math2.radianOf ( -30), Math2.radianOf (30)); } CurrentChain.updateRelationships (); //sentrum slange på scenen. currentChain.getLastNode () x = stage.stageWidth /2.; . currentChain.getLastNode () y = stage.stageHeight /2} 
 
 Trinn 22:. Legg tastaturkontroller 
 
 privat Div leadingVec: Vector2D; private Var currentMagnitude: Antall = 0; privat Var currentAngle: Antall = 0; privat Var increaseAng: Number = 5; privat Var increaseMag: Number = 1; privat Var decreaseMag: Number = 0.8; privat Var capMag: Number = 10; private Var pressedUp: Boolean = false; privat Var pressedLeft: Boolean = false; privat Var pressedRight: Boolean = false; 
 privat funksjon init (e: Hendelses = null). Void {removeEventListener (Event.ADDED_TO_STAGE init,); //Entry point this.drawObjects (); this.initChain (); leadingVec = new Vector2D (0, 0); stage.addEventListener (Event.ENTER_FRAME, handleEnterFrame); stage.addEventListener (KeyboardEvent.KEY_DOWN, handleKeyDown); . stage.addEventListener (KeyboardEvent.KEY_UP, handleKeyUp);} 
 privat funksjon handleEnterFrame (e: Hendelses): void {if (pressedUp == true) {currentMagnitude + = increaseMag; currentMagnitude = Math.min (currentMagnitude, capMag); } Else {currentMagnitude * = decreaseMag; } If (pressedLeft == true) {currentAngle - = Math2.radianOf (increaseAng); } If (pressedRight == true) {currentAngle + = Math2.radianOf (increaseAng); } LeadingVec.redefine (currentMagnitude, currentAngle); Var futureX: Number = leadingVec.x + lastNode.x; Var futureY: Number = leadingVec.y + lastNode.y; futureX = Math2.implementBound (0, stage.stageWidth, futureX); futureY = Math2.implementBound (0, stage.stageHeight, futureY); lastNode.x = futureX; lastNode.y = futureY; lastNode.rotation = Math2.degreeOf (leadingVec.getAngle ()); currentChain.animate ();} private funksjon handleKeyDown (e: KeyboardEvent): void {if (e.keyCode == Keyboard.UP) {pressedUp = true; } If (e.keyCode == Keyboard.LEFT) {pressedLeft = true; } Else if (e.keyCode == Keyboard.RIGHT) {pressedRight = true; }} privat funksjon handleKeyUp (e: KeyboardEvent): void {if (e.keyCode == Keyboard.UP) {pressedUp = false; } If (e.keyCode == Keyboard.LEFT) {pressedLeft = false; } Else if (e.keyCode == Keyboard.RIGHT) {pressedRight = false; }} 
 
 
 Trinn 23:.! Animate 
 
 
 
 Konklusjon 
 

