This question already has an answer here:
How to make player get destroyed through camera?
(1 answer)
Closed 5 years ago.
I've been having some trouble making the player get destroyed through the camera. In my application, I made the camera follow the player(the ball). But the camera can only follow the ball upwards. So what I want to accomplish is, when the player(the ball) reaches the bottom of the interface(the screen) it gets destroyed. After it gets destroyed it would be good, if a new activity(new screen) pops up, that says "Game over". Thanks a lot for the great support. Please take a look at the interface of the application.
package com.luca.tuninga;
import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.World;
import com.badlogic.gdx.physics.box2d.Box2DDebugRenderer;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.BodyDef;
import com.badlogic.gdx.physics.box2d.CircleShape;
import com.badlogic.gdx.physics.box2d.PolygonShape;
import com.badlogic.gdx.utils.viewport.Viewport;
public class MyGdxGame extends ApplicationAdapter {
public static float APP_FPS = 60f;
public static int V_WIDTH = 480;
public static int V_HEIGHT = 640;
Box2DDebugRenderer b2dr;
World world;
Body ballBody;
OrthographicCamera camera;
float cameraMaxY;
#Override
public void create() {
world = new World(new Vector2(0, -9.8f), false);
b2dr = new Box2DDebugRenderer();
camera = new OrthographicCamera();
camera.setToOrtho(false, V_WIDTH, V_HEIGHT);
cameraMaxY = camera.position.y;
ballBody = createBall();
createWalls();
}
private void update() {
world.step(1f / APP_FPS, 6, 2);
if (Gdx.input.isTouched()) {
ballBody.setLinearVelocity(0, MathUtils.clamp(ballBody.getLinearVelocity().y, 0, 3));
ballBody.applyForceToCenter(new Vector2(0, 650f), false);
}
if (ballBody.getPosition().y * 32 > cameraMaxY) {
camera.translate(0, (ballBody.getPosition().y * 32) - cameraMaxY);
camera.update();
cameraMaxY = camera.position.y;
}
}
#Override
public void render() {
Gdx.gl.glClearColor(.25f, .25f, .25f, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
update();
b2dr.render(world, camera.combined.cpy().scl(32f));
}
#Override
public void dispose() {
super.dispose();
world.dispose();
}
private Body createBall() {
Body body;
BodyDef def = new BodyDef();
def.type = BodyDef.BodyType.DynamicBody;
def.fixedRotation = true;
def.position.set(camera.position.x/ 32 + .5f, camera.position.y/ 32);
def.position.set(camera.position.x, camera.position.y);
def.gravityScale = 3;
CircleShape shape = new CircleShape();
shape.setRadius(0.5f);
body = world.createBody(def);
body.createFixture(shape, 1.0f);
return body;
}
private void createWalls() {
Body body;
BodyDef def = new BodyDef();
def.type = BodyDef.BodyType.StaticBody;
def.fixedRotation = true;
PolygonShape shape = new PolygonShape();
shape.setAsBox(1, 200 / 32);
for(int i = 0; i < 20 ; i++) {
def.position.set(1.01f, i * (200 / 32));
body = world.createBody(def);
body.createFixture(shape, 1.0f);
def.position.set(V_WIDTH / 32 - 1, i * (200 / 32));
body = world.createBody(def);
body.createFixture(shape, 1.0f);
}
}
}
#Override
public void render() {
Gdx.gl.glClearColor(.25f, .25f, .25f, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
if (ballBody.getPosition().y < camera.position.y){
destroyBall();
} else if (ballBody.getPosition().y > camera.position.y + 300){
camera.position.set(ballBody.getPosition().y - 300);
}
update();
b2dr.render(world, camera.combined.cpy().scl(32f));
}
I hope this works. You can write destroyBall() method yourself.
Related
This is a simple android game with a bucket and raindrop. The game is about catching a raindrop into the bucket. The problem is with the bucket because the position of the bucket is not corresponding to the position of touch input.
The second problem is because I don't know how to insert a small window with raindrops counter. I need the counter with a number of raindrops I caught into the bucket.
Here is the code of my android game:
import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.audio.Music;
import com.badlogic.gdx.audio.Sound;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.TimeUtils;
import java.util.Iterator;
public class MyGdxGame extends ApplicationAdapter {
private Texture dropImage;
private Texture bucketImage;
private Sound dropSound;
private Music rainMusic;
private OrthographicCamera camera;
private SpriteBatch spriteBatch;
private Rectangle bucket;
private Array<Rectangle> raindrops;
private long lastDropTime;
#Override
public void create () {
dropImage = new Texture(Gdx.files.internal("droplet.png"));
bucketImage = new Texture(Gdx.files.internal("bucket.png"));
dropSound = Gdx.audio.newSound(Gdx.files.internal("drop.wav"));
rainMusic = Gdx.audio.newMusic(Gdx.files.internal("rain.mp3"));
rainMusic.setLooping(true);
rainMusic.play();
camera = new OrthographicCamera();
camera.setToOrtho(false, 800, 400);
spriteBatch = new SpriteBatch();
bucket = new Rectangle();
bucket.height = 64;
bucket.width = 64;
bucket.x = 800 / 2 - 64 / 2;
bucket.y = 20;
raindrops = new Array<Rectangle>();
createRainDrops();
}
#Override
public void render () {
Gdx.gl.glClearColor(0, 0, 0.2f, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
camera.update();
spriteBatch.setProjectionMatrix(camera.combined);
spriteBatch.begin();
spriteBatch.draw(bucketImage, bucket.x, bucket.y);
for (Rectangle raindrop: raindrops){
spriteBatch.draw(dropImage, raindrop.x, raindrop.y);
}
spriteBatch.end();
Touch input hendling:
if (Gdx.input.isTouched()){
bucket.x = Gdx.input.getX() - 64 / 2;
bucket.x = Gdx.input.getX();
}
I know that my solution is with Vector3 but don't know exactly how?
When I tried to play the game my touch position is not in a real position!
if (bucket.x < 0){
bucket.x = 0;
}
if (bucket.y > 800 - 64){
bucket.x = 800 - 64;
}
if (TimeUtils.nanoTime() - lastDropTime > 1000000000){
createRainDrops();
}
Iterator<Rectangle> iterator = raindrops.iterator();
while (iterator.hasNext()){
Rectangle raindrop = iterator.next();
raindrop.y -= 200 * Gdx.graphics.getDeltaTime();
if (raindrop.y + 64 < 0){
iterator.remove();
}
if (raindrop.overlaps(bucket)){
dropSound.play();
iterator.remove();
}
}
}
#Override
public void dispose () {
dropSound.dispose();
rainMusic.dispose();
bucketImage.dispose();
dropImage.dispose();
spriteBatch.dispose();
}
private void createRainDrops() {
Rectangle raindrop = new Rectangle();
raindrop.width = 64;
raindrop.height = 64;
raindrop.y = 480;
raindrop.x = MathUtils.random(0, 800 - 64);
raindrops.add(raindrop);
lastDropTime = TimeUtils.nanoTime();
}
}
You forgot about y coordinate:
if (Gdx.input.isTouched()){
bucket.x = Gdx.input.getX() - bucket.getWidth() / 2;
bucket.y = Gdx.input.getY() - bucket.getHeight() / 2;
}
For raindrops counter you can use BitmapFont
spriteBatch = new SpriteBatch();
font = new BitmapFont(Gdx.files.internal("Font.fnt"),
Gdx.files.internal("Font.png"), false);
and in render method
spriteBatch.begin();
font.draw(spriteBatch, "some string", x, y);
spriteBatch.end();
I am trying to remove created bullets when (bullet.position.y <= 0). But the game gives error. I can not remove created bullets. How can I fix it? I used one texture ( 64 x 64 ) and these are my classes:
Game1 (Main Class)
package com.outlook.anil136.game1;
import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.math.Vector3;
import java.util.ArrayList;
public class Game1 extends ApplicationAdapter {
private ShapeRenderer shapeRenderer;
private SpriteBatch batch;
private OrthographicCamera camera;
private Texture blueTexture;
private Player player1;
private ArrayList<Bullet> bullets;
private Sprite blueSprite;
#Override
public void create () {
shapeRenderer = new ShapeRenderer();
batch = new SpriteBatch();
camera = new OrthographicCamera();
camera.setToOrtho(false, 480, 800);
blueTexture = new Texture("BlueRectangle.png");
player1 = new Player(blueTexture, new Vector2(240, 600));
bullets = new ArrayList<Bullet>();
blueSprite = new Sprite(blueTexture);
}
#Override
public void render () {
Gdx.gl.glClearColor(0.1f, 0.1f, 0.1f, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
shapeRenderer.setProjectionMatrix(camera.combined);
shapeRenderer.begin(ShapeRenderer.ShapeType.Filled);
shapeRenderer.rectLine(0, 401, 480, 401, 2);
shapeRenderer.end();
batch.setProjectionMatrix(camera.combined);
batch.begin();
player1.draw(batch);
for (Bullet bullet : bullets) {
bullet.draw(batch);
bullet.update(Gdx.graphics.getDeltaTime());
if (bullet.position.y <= 0)
bullet.remove(bullets);
}
blueSprite.setPosition(416, 736);
blueSprite.setColor(1, 1, 1, 0.5f);
blueSprite.draw(batch);
batch.end();
player1.update(Gdx.graphics.getDeltaTime());
for (int i = 0; i < 20; i++) {
Vector3 touchPosition = camera.unproject(new Vector3(Gdx.input.getX(i), Gdx.input.getY(i), 0));
if (Gdx.input.isTouched(i) && touchPosition.y >= 401 && touchPosition.y > 64 && !new Rectangle(416, 736, 64, 64).contains(touchPosition.x, touchPosition.y))
player1.touchPosition = touchPosition;
if (Gdx.input.justTouched() && new Rectangle(416, 736, 64, 64).contains(touchPosition.x, touchPosition.y))
bullets.add(new Bullet(blueTexture, new Vector2(player1.position), -player1.speed));
}
if (player1.position.y + 32 > 800)
player1.position.y = 768;
else if (player1.position.y - 32 < 402)
player1.position.y = 434;
}
#Override
public void dispose () {
shapeRenderer.dispose();
batch.dispose();
blueTexture.dispose();
}
}
Player
package com.outlook.anil136.game1;
import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.math.Vector3;
import java.util.ArrayList;
import javafx.scene.input.KeyCode;
import sun.security.provider.SHA;
public class Game1 extends ApplicationAdapter {
private ShapeRenderer shapeRenderer;
private SpriteBatch batch;
private OrthographicCamera camera;
private Texture blueTexture;
private Player player1;
public static ArrayList<Bullet> bullets;
private Sprite blueSprite;
#Override
public void create () {
shapeRenderer = new ShapeRenderer();
batch = new SpriteBatch();
camera = new OrthographicCamera();
camera.setToOrtho(false, 480, 800);
blueTexture = new Texture("BlueRectangle.png");
player1 = new Player(blueTexture, new Vector2(240, 600));
bullets = new ArrayList<Bullet>();
blueSprite = new Sprite(blueTexture);
}
#Override
public void render () {
Gdx.gl.glClearColor(0.1f, 0.1f, 0.1f, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
shapeRenderer.setProjectionMatrix(camera.combined);
shapeRenderer.begin(ShapeRenderer.ShapeType.Filled);
shapeRenderer.rectLine(0, 401, 480, 401, 2);
shapeRenderer.end();
batch.setProjectionMatrix(camera.combined);
batch.begin();
player1.draw(batch);
for (Bullet bullet : bullets) {
bullet.draw(batch);
bullet.update(Gdx.graphics.getDeltaTime());
if (bullet.position.y <= 0)
bullet.remove(bullets);
}
blueSprite.setPosition(416, 736);
blueSprite.setColor(1, 1, 1, 0.5f);
blueSprite.draw(batch);
batch.end();
player1.update(Gdx.graphics.getDeltaTime());
for (int i = 0; i < 20; i++) {
Vector3 touchPosition = camera.unproject(new Vector3(Gdx.input.getX(i), Gdx.input.getY(i), 0));
if (Gdx.input.isTouched(i) && touchPosition.y >= 401 && touchPosition.y > 64 && !new Rectangle(416, 736, 64, 64).contains(touchPosition.x, touchPosition.y))
player1.touchPosition = touchPosition;
if (Gdx.input.justTouched() && new Rectangle(416, 736, 64, 64).contains(touchPosition.x, touchPosition.y))
bullets.add(new Bullet(blueTexture, new Vector2(player1.position), -player1.speed));
}
if (player1.position.y + 32 > 800)
player1.position.y = 768;
else if (player1.position.y - 32 < 402)
player1.position.y = 434;
}
#Override
public void dispose () {
shapeRenderer.dispose();
batch.dispose();
blueTexture.dispose();
}
}
Bullet
package com.outlook.anil136.game1;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.Vector2;
import java.util.ArrayList;
public class Bullet {
private Texture texture;
Vector2 position;
private int speed;
public Bullet(Texture texture, Vector2 position, int speed) {
this.texture = texture;
this.position = position;
this.speed = speed;
}
public void draw(SpriteBatch batch) {
batch.draw(texture, position.x - 16, position.y - 16, 32, 32);
}
public void update(float deltaTime) {
position.y += speed;
}
public void remove(ArrayList<Bullet> bullets) {
bullets.remove(this);
}
}
You can't remove elements from list when you are iterating it. To remove elements when iterating you need to mark bullet to remove and after iterating actually remove all marked bullets from the main list.
List<Bullet> bulletsToRemove = new ArrayList<Bullet>();
for (Bullet bullet : bullets) {
bullet.draw(batch);
bullet.update(Gdx.graphics.getDeltaTime());
if (bullet.position.y <= 0)
bulletsToRemove.add(bullet);
}
bullets.removeAll(bulletsToRemove);
I want to make a simple flappy bird clone while I'm in vacation(The firt time I try game programming since high school) so after looking at ligdx wiki and sort of adapting the code to fit my needs I had something like this:
import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL10;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.Texture.TextureFilter;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.math.Rectangle;
public class FlappyBall implements ApplicationListener {
Texture ballImage;
Texture chaoImage;
Texture canoImage;
OrthographicCamera camera;
SpriteBatch batch;
Rectangle ball;
int score = 0;
final float gravity = 9.0f;
#Override
public void create() {
ballImage = new Texture(Gdx.files.internal("crystalball_small.png"));
//chaoImage = new Texture(Gdx.files.internal("Flappy-Ground.png"));
camera = new OrthographicCamera(800,480);
camera.setToOrtho(false, 800, 480);
batch = new SpriteBatch();
ball = new Rectangle();
ball.x = 128;
ball.y = 20;
ball.width = 64;
ball.height = 64;
}
#Override
public void dispose() {
ballImage.dispose();
//chaoImage.dispose();
}
#Override
public void render() {
// cleans the screen
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
// rendenring ball
batch.setProjectionMatrix(camera.combined);
batch.begin();
batch.draw(ballImage, ball.x, ball.y);
batch.end();
// jump(not tested)
if (Gdx.input.isTouched()) {
ball.y += 10;
}
// apply gravity(not tested)
while (ball.y < 480)
ball.y -= gravity * Gdx.graphics.getDeltaTime();
}
#Override
public void resize(int width, int height) {
}
#Override
public void pause() {
}
#Override
public void resume() {
}
}
however this code ends up showing a blank screen that can't even be closed when I press the X button(in order to close it I need to terminate its process in eclipse or use the xkill command :/)
Ps.:That's my Main.java file:
import com.badlogic.gdx.backends.lwjgl.LwjglApplication;
import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration;
public class Main {
public static void main(String[] args) {
LwjglApplicationConfiguration cfg = new LwjglApplicationConfiguration();
cfg.title = "Flappy Ball";
cfg.useGL20 = false;
cfg.width = 800;
cfg.height = 480;
new LwjglApplication(new FlappyBall(), cfg);
}
}
PsĀ².:The compiler shows no errors when this code is being executed
Thanks :D
Your render method will probably never finish it's first frame. The while loop will keep going until ball.y becomes greater than or equal to 480. This will never happen because you are subtracting a positive number.
while (ball.y < 480)
ball.y -= gravity * Gdx.graphics.getDeltaTime();
I would rather change it in something like this:
float change = gravity * Gdx.graphics.getDeltaTime();
if(ball.y - change >= 0)
ball.y -= change;
I've just began to work with the Libgdx's Box2d Engine but i simply do not understand when the methods of the Contactlistener should be called. There is on the one hand "begin contact" and on the other "end contact". Where should i call them, to get the Number of of a certain fixture touching others? And how do I implement the Contactlistener?
A redirec' to a Tutorial would answer my Question. I didn't find anything while searching google.
This one helped me a lot but it is written for C++ and does not refer to the implementation into a main-gamecircle.
Thx for helping me ;)
Here's a short example for libgdx. It shows how to create a ContactListener to show which fixtures are involved when contacts are made and broken. It also shows the use of world.getContactList() which will return a list of contacts that still exist after the physics step. This may miss contacts that were made and broken during the course of the physics step. If you are interested in these then you will want to implement a ContactListener, using beginContact() to detect when contacts are made and endContact() to detect when they are broken.
package hacks;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.backends.lwjgl.LwjglApplication;
import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration;
import com.badlogic.gdx.graphics.GL10;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.BodyDef;
import com.badlogic.gdx.physics.box2d.BodyDef.BodyType;
import com.badlogic.gdx.physics.box2d.Box2DDebugRenderer;
import com.badlogic.gdx.physics.box2d.Contact;
import com.badlogic.gdx.physics.box2d.ContactImpulse;
import com.badlogic.gdx.physics.box2d.ContactListener;
import com.badlogic.gdx.physics.box2d.Fixture;
import com.badlogic.gdx.physics.box2d.FixtureDef;
import com.badlogic.gdx.physics.box2d.Manifold;
import com.badlogic.gdx.physics.box2d.PolygonShape;
import com.badlogic.gdx.physics.box2d.World;
public class Box2DDemoMain extends com.badlogic.gdx.Game {
private static final float SCALING = 0.1f;
private Box2DDebugRenderer debugRenderer;
private OrthographicCamera camera;
private World world;
#Override
public void create() {
debugRenderer = new Box2DDebugRenderer();
camera = new OrthographicCamera();
createWorld();
createCollisionListener();
createGround();
createBox();
}
private void createWorld() {
Vector2 gravity = new Vector2(0, -10);
world = new World(gravity, true);
}
private void createCollisionListener() {
world.setContactListener(new ContactListener() {
#Override
public void beginContact(Contact contact) {
Fixture fixtureA = contact.getFixtureA();
Fixture fixtureB = contact.getFixtureB();
Gdx.app.log("beginContact", "between " + fixtureA.toString() + " and " + fixtureB.toString());
}
#Override
public void endContact(Contact contact) {
Fixture fixtureA = contact.getFixtureA();
Fixture fixtureB = contact.getFixtureB();
Gdx.app.log("endContact", "between " + fixtureA.toString() + " and " + fixtureB.toString());
}
#Override
public void preSolve(Contact contact, Manifold oldManifold) {
}
#Override
public void postSolve(Contact contact, ContactImpulse impulse) {
}
});
}
private void createGround() {
PolygonShape groundShape = new PolygonShape();
groundShape.setAsBox(50, 1);
BodyDef groundBodyDef = new BodyDef();
groundBodyDef.type = BodyType.StaticBody;
groundBodyDef.position.set(0, -20);
Body groundBody = world.createBody(groundBodyDef);
FixtureDef fixtureDef = new FixtureDef();
fixtureDef.shape = groundShape;
groundBody.createFixture(fixtureDef);
groundShape.dispose();
}
private void createBox() {
PolygonShape boxShape = new PolygonShape();
boxShape.setAsBox(1, 1);
BodyDef boxBodyDef = new BodyDef();
boxBodyDef.position.set(0, 20);
boxBodyDef.angle = MathUtils.PI / 32;
boxBodyDef.type = BodyType.DynamicBody;
boxBodyDef.fixedRotation = false;
Body boxBody = world.createBody(boxBodyDef);
FixtureDef boxFixtureDef = new FixtureDef();
boxFixtureDef.shape = boxShape;
boxFixtureDef.restitution = 0.75f;
boxFixtureDef.density = 2.0f;
boxBody.createFixture(boxFixtureDef);
boxShape.dispose();
}
#Override
public void resize(int width, int height) {
super.resize(width, height);
float cameraWidth = Gdx.graphics.getWidth() * SCALING;
float cameraHeight = Gdx.graphics.getHeight() * SCALING;
camera.setToOrtho(false, cameraWidth, cameraHeight);
camera.position.set(0, 0, 0);
}
#Override
public void render() {
super.render();
world.step(Gdx.graphics.getDeltaTime(), 8, 3);
int numContacts = world.getContactCount();
if (numContacts > 0) {
Gdx.app.log("contact", "start of contact list");
for (Contact contact : world.getContactList()) {
Fixture fixtureA = contact.getFixtureA();
Fixture fixtureB = contact.getFixtureB();
Gdx.app.log("contact", "between " + fixtureA.toString() + " and " + fixtureB.toString());
}
Gdx.app.log("contact", "end of contact list");
}
Gdx.gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
camera.update();
debugRenderer.render(world, camera.combined);
}
public static void main(String[] args) {
LwjglApplicationConfiguration config = new LwjglApplicationConfiguration();
config.title = Box2DDemoMain.class.getName();
config.width = 800;
config.height = 480;
config.fullscreen = false;
config.useGL20 = true;
config.useCPUSynch = true;
config.forceExit = true;
config.vSyncEnabled = true;
new LwjglApplication(new Box2DDemoMain(), config);
}
}
you dont have to call those methods anywhere. just create a class and implement ContactListener in it. now in your code just use world.setContactListener(ContactListener listener) .
Whenever collision occur in your world, all 4 methods will be called . You will get fixtureA and fixtureB of 2 colliding bodies
I'm testing the newest Box2d Testbed using Libgdx. It appears they aren't working and need to know if anyone else is having the same issue(s). The first one is called Conveyor Belt, https://github.com/ansman/box2d/blob/master/Testbed/Tests/ConveyorBelt.h
which I converted to:
package com.badlogic.gdx.tests.box2d;
import com.badlogic.gdx.InputProcessor;
import com.badlogic.gdx.Input.Keys;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.BodyDef;
import com.badlogic.gdx.physics.box2d.BodyDef.BodyType;
import com.badlogic.gdx.physics.box2d.joints.FrictionJointDef;
import com.badlogic.gdx.physics.box2d.Box2DDebugRenderer;
import com.badlogic.gdx.physics.box2d.Contact;
import com.badlogic.gdx.physics.box2d.EdgeShape;
import com.badlogic.gdx.physics.box2d.Fixture;
import com.badlogic.gdx.physics.box2d.FixtureDef;
import com.badlogic.gdx.physics.box2d.Manifold;
import com.badlogic.gdx.physics.box2d.PolygonShape;
import com.badlogic.gdx.physics.box2d.Transform;
import com.badlogic.gdx.physics.box2d.World;
import com.badlogic.gdx.tests.utils.GdxTest;
public class ConveyorBelt extends Box2DTest {
Body m_body;
Fixture platform;
#Override
protected void createWorld (World world) {
world.setGravity(new Vector2(0, -10));
/** amount of bounce when colliding */
float k_restitution = 0.4f;
Body ground;
{ /** x,y of entire shapes */
BodyDef bd = new BodyDef();
bd.position.set(0, 20);
ground = world.createBody(bd);
PolygonShape shape = new PolygonShape();
shape.setAsEdge(new Vector2(-20.0f, 0.0f), new Vector2(20.0f, 0.0f));
ground.createFixture(shape, 0.0f);
shape.dispose();
}
// Platform
{
BodyDef bd = new BodyDef();
bd.position.set(-5.0f, 5.0f);
Body body = world.createBody(bd);
PolygonShape shape = new PolygonShape();
shape.setAsBox(10.0f, 0.5f);
FixtureDef fd = new FixtureDef();
fd.shape = shape;
fd.friction = 0.8f;
platform = body.createFixture(fd);
}
// Boxes
for (int i = 0; i < 5; ++i)
{
BodyDef bd = new BodyDef();
bd.type = BodyType.DynamicBody;
bd.position.set(-10.0f + 2.0f * i, 7.0f);
Body body = world.createBody(bd);
PolygonShape shape = new PolygonShape();
shape.setAsBox(0.5f, 0.5f);
body.createFixture(shape, 20.0f);
}
}
/* void PreSolve(Contact contact, Manifold oldManifold)
{
Test extends PreSolve(contact, oldManifold);
Fixture fixtureA = contact.getFixtureA();
Fixture fixtureB = contact.getFixtureB();
if (fixtureA == platform)
{
contact.setTangentSpeed(5.0f);
}
if (fixtureB == platform)
{
contact.setTangentSpeed(-5.0f);
}
}
void Step(Settings settings)
{
Test extends Step(settings);
}
static Test Create()
{
return new ConveyorBelt;
}
Fixture platform;*/
}
This is working by putting it in with the other Box2D tests but I noticed a few things.
Libgdx doesn't have a setTangentSpeed method in its Contact.java class
Settings has to use the org.jbox2d.common import
Test can't be resolved to a type
I also tried using Breakable, https://github.com/ansman/box2d/blob/master/Testbed/Tests/Breakable.h
Which was converted to
package com.badlogic.gdx.tests.box2d;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.BodyDef;
import com.badlogic.gdx.physics.box2d.BodyDef.BodyType;
import com.badlogic.gdx.physics.box2d.CircleShape;
import com.badlogic.gdx.physics.box2d.Contact;
import com.badlogic.gdx.physics.box2d.ContactImpulse;
import com.badlogic.gdx.physics.box2d.EdgeShape;
import com.badlogic.gdx.physics.box2d.Fixture;
import com.badlogic.gdx.physics.box2d.FixtureDef;
import com.badlogic.gdx.physics.box2d.PolygonShape;
import com.badlogic.gdx.physics.box2d.World;
import com.badlogic.gdx.physics.box2d.joints.RevoluteJointDef;
import com.badlogic.gdx.backends.gwt.*;
public class Breakable extends Box2DTest {
Body body1;
Vector2 m_velocity;
float m_angularVelocity;
PolygonShape m_shape1;
PolygonShape m_shape2;
Fixture m_piece1;
Fixture m_piece2;
boolean m_broke;
boolean m_break;
/**
* #see org.jbox2d.testbed.framework.TestbedTest#initTest()
*/
#Override
protected void createWorld (World world) {
world.setGravity(new Vector2(0, -10));
Body ground;
// Ground body
{
BodyDef bd = new BodyDef();
ground = world.createBody(bd);
PolygonShape shape = new PolygonShape();
shape.setAsEdge(new Vector2(-40.0f, 0.0f), new Vector2(40.0f, 0.0f));
ground.createFixture(shape, 0.0f);
shape.dispose();
}
// Breakable dynamic body
{
BodyDef bd = new BodyDef();
bd.type = BodyType.DynamicBody;
bd.position.set(0.0f, 40.0f);
bd.angle = 0.25f * MathUtils.PI;
body1 = world.createBody(bd);
m_shape1 = new PolygonShape();
m_shape1.setAsBox(0.5f, 0.5f, new Vector2(-0.5f, 0.0f), 0.0f);
m_piece1 = body1.createFixture(m_shape1, 1.0f);
m_shape2 = new PolygonShape();
m_shape2.setAsBox(0.5f, 0.5f, new Vector2(0.5f, 0.0f), 0.0f);
m_piece2 = body1.createFixture(m_shape2, 1.0f);
}
m_break = false;
m_broke = false;
}
void PostSolve(Contact contact, ContactImpulse impulse)
{
if (m_broke)
{
// The body already broke.
return;
}
// Should the body break?
int count = contact.getManifold().pointCount;
float maxImpulse = 0.0f;
for (int i = 0; i < count; ++i)
{
maxImpulse = MathUtils.max(maxImpulse, impulse.normalImpulses[i]);
}
if (maxImpulse > 40.0f)
{
// Flag the body for breaking.
m_break = true;
}
}
void Break()
{
// Create two bodies from one.
Body body1 = m_piece1.getBody();
Vector2 center = body1.getWorldCenter();
body1.destroyFixture(m_piece2);
m_piece2 = null;
BodyDef bd = new BodyDef();
bd.position = body1.getPosition();
bd.angle = body1.getAngle();
Body body2 = world.createBody(bd);
m_piece2 = body2.createFixture(m_shape2, 1.0f);
}
}
// Compute consistent velocities for new bodies based on
// cached velocity.
Vector2 center1 = body1.getWorldCenter();
Vector2 center2 = body2.getWorldCenter();
Vector2 velocity1 = m_velocity.add(Vector2.crs(m_angularVelocity, center1.sub(center)));
Vector2 velocity2 = m_velocity.add(Vector2.crs(m_angularVelocity, center2.sub(center)));
body1.setAngularVelocity(m_angularVelocity);
body1.setLinearVelocity(velocity1);
body2.setAngularVelocity(m_angularVelocity);
body2.setLinearVelocity(velocity2);
}
void Step(Settings settings)
{
if (m_break)
{
Break();
m_broke = true;
m_break = false;
}
// Cache velocities to improve movement on breakage.
if (m_broke == false)
{
m_velocity = body1.getLinearVelocity();
m_angularVelocity = body1.getAngularVelocity();
}
Test = Step(settings);
}
static Test Create()
{
return new Breakable;
}
Body m_body1;
}
I Noticed:
Libgdx doesn't have pointCount in Manifold.java. One quick fix was to change to getWorldManifold but didn't do any good
Vector2.java doesn't contain a crs( float x, Vector2 v) which the Vectors for m_velocity won't allow
Settings doesn't exist, unless I use the com.jbox2d.common import
How do I get these to work in Libgdx if these methods aren't included? Is Libgdx not updated anymore? I want to use these but it seems they are behind with porting. I even noticed in Contact.java he stopped just before the code for setTangentSpeed. I have added gwt jars to my tests with no benefit.
If you want the 2.2.1 version of jbox2d, you can grab a build from the trunk. It's almost ready for a release, I just need to do a bit more optimization and inlining.
edit: It looks like libgdx uses it's own wrappers to a the native C++ implementation of Box2D. This is definitely preferable performance-wise, hopefully they will update their library.