1 /******************************************************************************* 2 * Copyright 2011 See AUTHORS file. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 ******************************************************************************/ 16 17 package com.badlogic.gdx.tests; 18 19 import com.badlogic.gdx.Gdx; 20 import com.badlogic.gdx.graphics.GL20; 21 import com.badlogic.gdx.graphics.OrthographicCamera; 22 import com.badlogic.gdx.graphics.glutils.ShapeRenderer; 23 import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType; 24 import com.badlogic.gdx.math.Vector2; 25 import com.badlogic.gdx.math.Vector3; 26 import com.badlogic.gdx.tests.utils.GdxTest; 27 28 public class InverseKinematicsTest extends GdxTest { 29 30 static class Bone { 31 final float len; 32 final Vector3 position = new Vector3(); 33 final Vector3 inertia = new Vector3(); 34 35 public String name; 36 Bone(String name, float x, float y, float len)37 public Bone (String name, float x, float y, float len) { 38 this.name = name; 39 this.position.set(x, y, 0); 40 this.len = len; 41 } 42 toString()43 public String toString () { 44 return "bone " + name + ": " + position + ", " + len; 45 } 46 } 47 48 static final float GRAVITY = 0; 49 OrthographicCamera camera; 50 ShapeRenderer renderer; 51 Bone[] bones; 52 Vector3 globalCoords = new Vector3(); 53 Vector3 endPoint = new Vector3(); 54 Vector2 diff = new Vector2(); 55 56 @Override create()57 public void create () { 58 float aspect = Gdx.graphics.getWidth() / (float)Gdx.graphics.getHeight(); 59 camera = new OrthographicCamera(15 * aspect, 15); 60 camera.update(); 61 renderer = new ShapeRenderer(); 62 renderer.setProjectionMatrix(camera.combined); 63 64 bones = new Bone[] {new Bone("bone0", 0, 0, 0), new Bone("bone1", 0, 2, 2), new Bone("bone2", 0, 4, 2), 65 new Bone("bone3", 0, 6, 2), new Bone("end", 0, 8, 2)}; 66 globalCoords.set(bones[0].position); 67 } 68 69 @Override dispose()70 public void dispose () { 71 renderer.dispose(); 72 } 73 74 @Override render()75 public void render () { 76 Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); 77 78 camera.update(); 79 renderer.setProjectionMatrix(camera.combined); 80 81 if (Gdx.input.isTouched()) camera.unproject(globalCoords.set(Gdx.input.getX(), Gdx.input.getY(), 0)); 82 solveFakeIK(globalCoords); 83 renderBones(); 84 } 85 renderBones()86 private void renderBones () { 87 renderer.begin(ShapeType.Line); 88 renderer.setColor(0, 1, 0, 1); 89 for (int i = 0; i < bones.length - 1; i++) { 90 renderer.line(bones[i].position.x, bones[i].position.y, bones[i + 1].position.x, bones[i + 1].position.y); 91 } 92 renderer.end(); 93 94 renderer.begin(ShapeType.Point); 95 renderer.setColor(1, 0, 0, 1); 96 for (int i = 0; i < bones.length; i++) { 97 renderer.point(bones[i].position.x, bones[i].position.y, 0); 98 } 99 renderer.end(); 100 } 101 solveFakeIK(Vector3 target)102 public void solveFakeIK (Vector3 target) { 103 float gravity = Gdx.graphics.getDeltaTime() * GRAVITY; 104 105 endPoint.set(target); 106 bones[0].position.set(endPoint); 107 108 for (int i = 0; i < bones.length - 1; i++) { 109 Bone bone = bones[i]; 110 endPoint.set(bone.position); 111 112 diff.set(endPoint.x, endPoint.y).sub(bones[i + 1].position.x, bones[i + 1].position.y); 113 diff.add(0, gravity); 114 diff.add(bones[i + 1].inertia.x, bones[i + 1].inertia.y); 115 diff.nor().scl(bones[i + 1].len); 116 117 float x = endPoint.x - diff.x; 118 float y = endPoint.y - diff.y; 119 float delta = Gdx.graphics.getDeltaTime(); 120 bones[i + 1].inertia.add((bones[i + 1].position.x - x) * delta, (bones[i + 1].position.y - y) * delta, 0).scl(0.99f); 121 bones[i + 1].position.set(x, y, 0); 122 } 123 } 124 } 125