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 * Copyright 2010 Mario Zechner (contact@badlogicgames.com), Nathan Sweet (admin@esotericsoftware.com) 18 * 19 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the 20 * License. You may obtain a copy of the License at 21 * 22 * http://www.apache.org/licenses/LICENSE-2.0 23 * 24 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" 25 * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language 26 * governing permissions and limitations under the License. 27 */ 28 29 package com.badlogic.gdx.tests.box2d; 30 31 import com.badlogic.gdx.ApplicationListener; 32 import com.badlogic.gdx.Gdx; 33 import com.badlogic.gdx.InputProcessor; 34 import com.badlogic.gdx.graphics.GL20; 35 import com.badlogic.gdx.graphics.OrthographicCamera; 36 import com.badlogic.gdx.graphics.g2d.BitmapFont; 37 import com.badlogic.gdx.graphics.g2d.SpriteBatch; 38 import com.badlogic.gdx.math.Vector2; 39 import com.badlogic.gdx.math.Vector3; 40 import com.badlogic.gdx.physics.box2d.Body; 41 import com.badlogic.gdx.physics.box2d.BodyDef; 42 import com.badlogic.gdx.physics.box2d.BodyDef.BodyType; 43 import com.badlogic.gdx.physics.box2d.Box2DDebugRenderer; 44 import com.badlogic.gdx.physics.box2d.Fixture; 45 import com.badlogic.gdx.physics.box2d.QueryCallback; 46 import com.badlogic.gdx.physics.box2d.World; 47 import com.badlogic.gdx.physics.box2d.joints.MouseJoint; 48 import com.badlogic.gdx.physics.box2d.joints.MouseJointDef; 49 import com.badlogic.gdx.utils.TimeUtils; 50 51 /** Base class for all Box2D Testbed tests, all subclasses must implement the createWorld() method. 52 * 53 * @author badlogicgames@gmail.com */ 54 public abstract class Box2DTest implements ApplicationListener, InputProcessor { 55 /** the camera **/ 56 protected OrthographicCamera camera; 57 58 /** the renderer **/ 59 protected Box2DDebugRenderer renderer; 60 61 SpriteBatch batch; 62 BitmapFont font; 63 64 /** our box2D world **/ 65 protected World world; 66 67 /** ground body to connect the mouse joint to **/ 68 protected Body groundBody; 69 70 /** our mouse joint **/ 71 protected MouseJoint mouseJoint = null; 72 73 /** a hit body **/ 74 protected Body hitBody = null; 75 createWorld(World world)76 protected abstract void createWorld (World world); 77 78 /** temp vector **/ 79 protected Vector2 tmp = new Vector2(); 80 81 @Override render()82 public void render () { 83 // update the world with a fixed time step 84 long startTime = TimeUtils.nanoTime(); 85 world.step(Gdx.app.getGraphics().getDeltaTime(), 3, 3); 86 float updateTime = (TimeUtils.nanoTime() - startTime) / 1000000000.0f; 87 88 startTime = TimeUtils.nanoTime(); 89 // clear the screen and setup the projection matrix 90 Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); 91 camera.update(); 92 93 // render the world using the debug renderer 94 renderer.render(world, camera.combined); 95 float renderTime = (TimeUtils.nanoTime() - startTime) / 1000000000.0f; 96 97 batch.begin(); 98 font.draw(batch, "fps:" + Gdx.graphics.getFramesPerSecond() + ", update: " + updateTime + ", render: " + renderTime, 0, 20); 99 batch.end(); 100 } 101 102 @Override create()103 public void create () { 104 // setup the camera. In Box2D we operate on a 105 // meter scale, pixels won't do it. So we use 106 // an orthographic camera with a viewport of 107 // 48 meters in width and 32 meters in height. 108 // We also position the camera so that it 109 // looks at (0,16) (that's where the middle of the 110 // screen will be located). 111 camera = new OrthographicCamera(48, 32); 112 camera.position.set(0, 15, 0); 113 114 // create the debug renderer 115 renderer = new Box2DDebugRenderer(); 116 117 // create the world 118 world = new World(new Vector2(0, -10), true); 119 120 // we also need an invisible zero size ground body 121 // to which we can connect the mouse joint 122 BodyDef bodyDef = new BodyDef(); 123 groundBody = world.createBody(bodyDef); 124 125 // call abstract method to populate the world 126 createWorld(world); 127 128 batch = new SpriteBatch(); 129 font = new BitmapFont(Gdx.files.internal("data/arial-15.fnt"), false); 130 } 131 132 @Override dispose()133 public void dispose () { 134 renderer.dispose(); 135 world.dispose(); 136 137 renderer = null; 138 world = null; 139 mouseJoint = null; 140 hitBody = null; 141 } 142 143 @Override keyDown(int keycode)144 public boolean keyDown (int keycode) { 145 return false; 146 } 147 148 @Override keyTyped(char character)149 public boolean keyTyped (char character) { 150 return false; 151 } 152 153 @Override keyUp(int keycode)154 public boolean keyUp (int keycode) { 155 return false; 156 } 157 158 /** we instantiate this vector and the callback here so we don't irritate the GC **/ 159 Vector3 testPoint = new Vector3(); 160 QueryCallback callback = new QueryCallback() { 161 @Override 162 public boolean reportFixture (Fixture fixture) { 163 // if the hit point is inside the fixture of the body 164 // we report it 165 if (fixture.testPoint(testPoint.x, testPoint.y)) { 166 hitBody = fixture.getBody(); 167 return false; 168 } else 169 return true; 170 } 171 }; 172 173 @Override touchDown(int x, int y, int pointer, int button)174 public boolean touchDown (int x, int y, int pointer, int button) { 175 // translate the mouse coordinates to world coordinates 176 camera.unproject(testPoint.set(x, y, 0)); 177 // ask the world which bodies are within the given 178 // bounding box around the mouse pointer 179 hitBody = null; 180 world.QueryAABB(callback, testPoint.x - 0.0001f, testPoint.y - 0.0001f, testPoint.x + 0.0001f, testPoint.y + 0.0001f); 181 182 if (hitBody == groundBody) hitBody = null; 183 184 // ignore kinematic bodies, they don't work with the mouse joint 185 if (hitBody != null && hitBody.getType() == BodyType.KinematicBody) return false; 186 187 // if we hit something we create a new mouse joint 188 // and attach it to the hit body. 189 if (hitBody != null) { 190 MouseJointDef def = new MouseJointDef(); 191 def.bodyA = groundBody; 192 def.bodyB = hitBody; 193 def.collideConnected = true; 194 def.target.set(testPoint.x, testPoint.y); 195 def.maxForce = 1000.0f * hitBody.getMass(); 196 197 mouseJoint = (MouseJoint)world.createJoint(def); 198 hitBody.setAwake(true); 199 } 200 201 return false; 202 } 203 204 /** another temporary vector **/ 205 Vector2 target = new Vector2(); 206 207 @Override touchDragged(int x, int y, int pointer)208 public boolean touchDragged (int x, int y, int pointer) { 209 // if a mouse joint exists we simply update 210 // the target of the joint based on the new 211 // mouse coordinates 212 if (mouseJoint != null) { 213 camera.unproject(testPoint.set(x, y, 0)); 214 mouseJoint.setTarget(target.set(testPoint.x, testPoint.y)); 215 } 216 return false; 217 } 218 219 @Override touchUp(int x, int y, int pointer, int button)220 public boolean touchUp (int x, int y, int pointer, int button) { 221 // if a mouse joint exists we simply destroy it 222 if (mouseJoint != null) { 223 world.destroyJoint(mouseJoint); 224 mouseJoint = null; 225 } 226 return false; 227 } 228 229 @Override mouseMoved(int x, int y)230 public boolean mouseMoved (int x, int y) { 231 return false; 232 } 233 234 @Override scrolled(int amount)235 public boolean scrolled (int amount) { 236 return false; 237 } 238 pause()239 public void pause () { 240 241 } 242 resume()243 public void resume () { 244 245 } 246 resize(int width, int height)247 public void resize (int width, int height) { 248 249 } 250 } 251