Физические безумства

в 15:30, , рубрики: box2d, eclipse, java, libgdx, физика, физичекий движок

Добрый день, уважаемый читатель! Я, начинающий Java-программист, долгое время не мог освоиться с библиотекой Box2D. Во-первых, из-за того, что она написана для C++, и по ней нет документации, а синтаксис Си я не знаю. Во-вторых, из-за того, что подробные уроки по этой библиотеке есть только в качестве расширения libGDX. Спустя пару недель упорной борьбы, я наконец смог понять, как надо работать с этой библиотекой, и в этой статье я расскажу об этом (и покажу это).

Работаю в Eclipse, статья будет связана с этой средой разработки. Для начала скачайте сборщик libGDX и сделайте стандартную сборку. Нам понадобится Desktop’ное приложение с расширением Box2D. Потом заходите в Eclipse, нажимаете File → Import → Gradle → Gradle Project и указываете путь к вашей сборке.

Вот изображение с демонстрацией того, как выглядит моя. Я добавил в папку Core пакет Utils с классом Constants, в котором содержится только одна константа – к-во пикселей в метре. Это для того, чтобы мир не был гигантским.

image

Вот код для класса DesktopLauncher из пакета com.mygdx.game.desktop:

Вставьте этот код в класс и забудьте про него

package com.mygdx.game.desktop;

import com.badlogic.gdx.backends.lwjgl.LwjglApplication;
import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration;
import com.mygdx.game.MyGdxGame;

public class DesktopLauncher {
	public static void main(String[] arg) {
		LwjglApplicationConfiguration config = new LwjglApplicationConfiguration();
		// ширина окна
		config.width = 720;
		// высота окна
		config.height = 480;
		config.backgroundFPS = 60;
		config.foregroundFPS = 60;
		new LwjglApplication(new MyGdxGame(), config);
	}
}

Кода будет много, поэтому я заключу его в спойлеры. Изменяется только класс MyGdxGame из пакета com.mygdx.game.

Итак, попробуем сделать довольно простую вещь в нашем приложении. Путь мячик врезается в стену из дощечек, и они разлетаются. Что-то подобное:

image
Идея 1. Боулинг

package com.mygdx.game;

import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input.Keys;
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.Vector2;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.BodyDef;
import com.badlogic.gdx.physics.box2d.Box2DDebugRenderer;
import com.badlogic.gdx.physics.box2d.CircleShape;
import com.badlogic.gdx.physics.box2d.PolygonShape;
import com.badlogic.gdx.physics.box2d.World;
import utils.Constants;

public class MyGdxGame extends ApplicationAdapter {
	SpriteBatch batch;
	Texture img;
	private OrthographicCamera camera;
	private boolean DEBUG = false;
	private World world;
	private Body ball;
	private Body floor;
	private Body wall;
	private Body verticals;
	private Body horizontals;
	private Box2DDebugRenderer b2dr;

	// здесь происходит создание мира и его наполнение
	public void create() {
		float w = Gdx.graphics.getWidth();
		float h = Gdx.graphics.getHeight();
		camera = new OrthographicCamera();
		camera.setToOrtho(false, w / 2, h / 2);
		world = new World(new Vector2(0, -9.8f), false);
		// мир со стандартной силой тяжести
		b2dr = new Box2DDebugRenderer();
		// здесь создается мячик
		ball = createPlayer();
		// здесь создается "пол", чтобы все не проваливалось
		floor = createfloor();
		// здесь создаются дощечки
		verticals = createverticals(80, 80);
		verticals = createverticals(100, 80);
		verticals = createverticals(120, 80);
		verticals = createverticals(90, 111);
		verticals = createverticals(110, 111);
		verticals = createverticals(100, 141);
		horizontals = createhorizontals(85, 95);
		horizontals = createhorizontals(115, 95);
		horizontals = createhorizontals(100, 126);
		// здесь создаются стены-ограничители
		wall = createwall(430, 170);
		wall = createwall(-430, 170);
	}

	public void render() {
		update(Gdx.graphics.getDeltaTime());
		// просто черный экран
		Gdx.gl.glClearColor(0, 0, 0, 1);
		Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
		b2dr.render(world, camera.combined.scl(Constants.PPM));
	}

	public void resize(int width, int height) {
		camera.setToOrtho(false, width / 2, height / 2);
	}

	public void dispose() {
		world.dispose();
		b2dr.dispose();
	}

	// обновление мира и камеры
	public void update(float delta) {
		world.step(1 / 60f, 6, 2);
		inputUpdate(delta);
		cameraUpdate(delta);

	}

	// обработка нажатия клавиши пробел
	public void inputUpdate(float delta) {
		int HF = 0;
		if (Gdx.input.isKeyPressed(Keys.SPACE)) {
			HF = 5;
		}
		ball.setLinearVelocity(HF * 5, ball.getLinearVelocity().y);
	}

	// камера повсюду следует за мячиком
	public void cameraUpdate(float delta) {
		Vector3 position = camera.position;
		position.x = ball.getPosition().x * Constants.PPM;
		position.y = ball.getPosition().y * Constants.PPM;
		camera.position.set(position);
		camera.update();
	}

	// обратите внимание, что не заданы такие параметры, как коэффициент трения,
	// масса, коэффициент упругости.
	// мячик и его параметры
	public Body createPlayer() {
		Body pBody;
		BodyDef def = new BodyDef();
		def.type = BodyDef.BodyType.DynamicBody;
		def.position.set(20 / Constants.PPM, 90 / Constants.PPM);
		def.fixedRotation = false;
		pBody = world.createBody(def);
		CircleShape shape = new CircleShape();
		shape.setRadius(10 / Constants.PPM);
		pBody.createFixture(shape, 1.0f);
		def.bullet = true;
		shape.dispose();
		return pBody;
	}

	// пол и его параметры
	public Body createfloor() {
		Body fBody;
		BodyDef def = new BodyDef();
		// тип тела
		def.type = BodyDef.BodyType.StaticBody;
		// координата
		def.position.set(0, 0);
		// будет вращаться
		def.fixedRotation = true;
		fBody = world.createBody(def);
		PolygonShape shape = new PolygonShape();
		// его размеры
		shape.setAsBox(480 / Constants.PPM, 70 / Constants.PPM);
		fBody.createFixture(shape, 0.001f);
		shape.dispose();
		return fBody;
	}

	// стены и их параметры
	public Body createwall(int xo, int yo) {
		Body fBody;
		BodyDef def = new BodyDef();
		def.type = BodyDef.BodyType.StaticBody;
		def.position.set(xo / Constants.PPM, yo / Constants.PPM);
		def.fixedRotation = true;
		fBody = world.createBody(def);
		PolygonShape shape = new PolygonShape();
		shape.setAsBox(50 / Constants.PPM, 100 / Constants.PPM);
		fBody.createFixture(shape, 0.001f);
		shape.dispose();
		return fBody;
	}

	// вертикальные дощечки
	public Body createverticals(int xo, int xy) {
		Body fBody;
		BodyDef def = new BodyDef();
		def.type = BodyDef.BodyType.DynamicBody;
		def.position.set(xo / Constants.PPM, xy / Constants.PPM);
		def.fixedRotation = false;
		fBody = world.createBody(def);
		PolygonShape shape = new PolygonShape();
		shape.setAsBox(5 / Constants.PPM, 10 / Constants.PPM);
		fBody.createFixture(shape, 1.0f);
		def.bullet = true;
		shape.dispose();
		return fBody;
	}

	// горизонтальные дощечки
	public Body createhorizontals(int xo, int xy) {
		Body fBody;
		BodyDef def = new BodyDef();
		def.type = BodyDef.BodyType.DynamicBody;
		def.position.set(xo / Constants.PPM, xy / Constants.PPM);
		def.fixedRotation = false;
		fBody = world.createBody(def);
		PolygonShape shape = new PolygonShape();
		shape.setAsBox(13 / Constants.PPM, 5 / Constants.PPM);
		fBody.createFixture(shape, 1.0f);
		def.bullet = true;
		shape.dispose();
		return fBody;
	}
}

Замечательно получилось, не так ли? Изменив несколько параметров, вы можете добиться именно того, что нужно вам! И не надо писать так много строк кода.

Но теперь хочется увидеть упругий удар. И пусть объектов на сцене будет побольше. Получим такой результат:

image

А вот и код:

package com.mygdx.game;

import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.physics.box2d.FixtureDef;
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.Vector2;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.BodyDef;
import com.badlogic.gdx.physics.box2d.Box2DDebugRenderer;
import com.badlogic.gdx.physics.box2d.CircleShape;
import com.badlogic.gdx.physics.box2d.PolygonShape;
import com.badlogic.gdx.physics.box2d.World;
import utils.Constants;

public class MyGdxGame extends ApplicationAdapter {
	SpriteBatch batch;
	Texture img;
	private OrthographicCamera camera;
	private boolean DEBUG = false;
	private World world;
	private Body ball;
	private Body floor;
	private Body wall;
	private Body verticals;
	private Body horizontals;
	private Box2DDebugRenderer b2dr;

	public void create() {
		float w = Gdx.graphics.getWidth();
		float h = Gdx.graphics.getHeight();
		camera = new OrthographicCamera();
		camera.setToOrtho(false, w / 2, h / 2);
		world = new World(new Vector2(0, -9.8f), false);
		b2dr = new Box2DDebugRenderer();
		// наш мячик
		ball = createPlayer();
		// границы мира
		floor = createfloor();
		wall = createwall(100, 170);
		wall = createwall(-60, 170);

		// создаем мячики снизу. Через цикл пробовал, не работает
		verticals = createverticals(5, 50);
		verticals = createverticals(10, 50);
		verticals = createverticals(15, 50);
		verticals = createverticals(20, 50);
		verticals = createverticals(25, 50);
		verticals = createverticals(30, 50);
		verticals = createverticals(35, 50);

		verticals = createverticals(5, 55);
		verticals = createverticals(10, 55);
		verticals = createverticals(15, 55);
		verticals = createverticals(20, 55);
		verticals = createverticals(25, 55);
		verticals = createverticals(30, 55);
		verticals = createverticals(35, 55);

		verticals = createverticals(5, 60);
		verticals = createverticals(10, 60);
		verticals = createverticals(15, 60);
		verticals = createverticals(20, 60);
		verticals = createverticals(25, 60);
		verticals = createverticals(30, 60);
		verticals = createverticals(35, 60);

		verticals = createverticals(5, 70);
		verticals = createverticals(10, 70);
		verticals = createverticals(15, 70);
		verticals = createverticals(20, 70);
		verticals = createverticals(25, 70);
		verticals = createverticals(30, 70);
		verticals = createverticals(35, 70);

		verticals = createverticals(5, 80);
		verticals = createverticals(10, 80);
		verticals = createverticals(15, 80);
		verticals = createverticals(20, 80);
		verticals = createverticals(25, 80);
		verticals = createverticals(30, 80);
		verticals = createverticals(35, 80);
	}

	public void render() {
		update(Gdx.graphics.getDeltaTime());
		Gdx.gl.glClearColor(0, 0, 0, 1);
		Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
		b2dr.render(world, camera.combined.scl(Constants.PPM));
	}

	public void resize(int width, int height) {
		camera.setToOrtho(false, width / 2, height / 2);
	}

	public void dispose() {
		world.dispose();
		b2dr.dispose();
	}

	public void update(float delta) {
		world.step(1 / 60f, 6, 2);
		inputUpdate(delta);
		cameraUpdate(delta);

	}

	// чтобы мяч вращался
	public void inputUpdate(float delta) {
		ball.setAngularVelocity(3.0f);
	}

	public void cameraUpdate(float delta) {
		Vector3 position = camera.position;
		position.x = ball.getPosition().x * Constants.PPM;
		position.y = ball.getPosition().y * Constants.PPM;
		camera.position.set(position);
		camera.update();
	}

	// создаем мячик
	public Body createPlayer() {
		Body pBody;
		BodyDef def = new BodyDef();
		def.type = BodyDef.BodyType.DynamicBody;
		def.position.set(20 / Constants.PPM, 800 / Constants.PPM);
		def.fixedRotation = false;
		pBody = world.createBody(def);
		CircleShape shape = new CircleShape();
		shape.setRadius(10 / Constants.PPM);
		pBody.createFixture(shape, 1.0f);
		def.bullet = true;
		shape.dispose();
		return pBody;
	}

	// создаем пол
	public Body createfloor() {
		Body fBody;
		BodyDef def = new BodyDef();
		def.type = BodyDef.BodyType.StaticBody;
		def.position.set(0, 0);
		def.fixedRotation = true;
		fBody = world.createBody(def);
		PolygonShape shape = new PolygonShape();
		shape.setAsBox(480 / Constants.PPM, 70 / Constants.PPM);
		fBody.createFixture(shape, 0.001f);
		shape.dispose();
		return fBody;
	}

	// создаем стены
	public Body createwall(int xo, int yo) {
		Body fBody;
		BodyDef def = new BodyDef();
		def.type = BodyDef.BodyType.StaticBody;
		def.position.set(xo / Constants.PPM, yo / Constants.PPM);
		def.fixedRotation = true;
		fBody = world.createBody(def);
		PolygonShape shape = new PolygonShape();
		shape.setAsBox(50 / Constants.PPM, 100 / Constants.PPM);
		fBody.createFixture(shape, 0.001f);
		shape.dispose();
		return fBody;
	}

	// обратите здесь внимание на параметры
	public Body createverticals(int xo, int yo) {
		Body pBody;
		BodyDef def = new BodyDef();
		def.type = BodyDef.BodyType.DynamicBody;
		def.position.set(xo / Constants.PPM, yo / Constants.PPM);
		def.fixedRotation = false;
		pBody = world.createBody(def);
		CircleShape shape = new CircleShape();
		shape.setRadius(2 / Constants.PPM);
		// здесь заключена вся магия
		FixtureDef fd = new FixtureDef();
		// упругость
		fd.restitution = 1.0f;
		// плотность
		fd.density = 5.0f;
		// трение
		fd.friction = 0.01f;
		fd.shape = shape;
		pBody.createFixture(fd);
		def.bullet = true;
		shape.dispose();
		return pBody;
	}
}

Создать тележку в Box2D непросто. Нужно связывать тела, чтобы они двигались, как единое целое. Следующая гифка демонстрирует только суть.

image
Как это получилось?

package com.mygdx.game;

import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
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.Vector2;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.BodyDef;
import com.badlogic.gdx.physics.box2d.Box2DDebugRenderer;
import com.badlogic.gdx.physics.box2d.CircleShape;
import com.badlogic.gdx.physics.box2d.PolygonShape;
import com.badlogic.gdx.physics.box2d.World;
import utils.Constants;

public class MyGdxGame extends ApplicationAdapter {
	SpriteBatch batch;
	Texture img;
	private OrthographicCamera camera;
	private boolean DEBUG = false;
	private World world;
	private Body ball;
	private Body ball1;
	private Body floor;
	private Body wall;
	private Body verticals;
	private Body horizontals;
	private Box2DDebugRenderer b2dr;

	public void create() {
		float w = Gdx.graphics.getWidth();
		float h = Gdx.graphics.getHeight();
		camera = new OrthographicCamera();
		camera.setToOrtho(false, w / 2, h / 2);
		world = new World(new Vector2(0, -9.8f), false);
		b2dr = new Box2DDebugRenderer();
		// создаем колеса
		ball = createPlayer(20 / Constants.PPM, 70 / Constants.PPM);
		ball1 = createPlayer(50 / Constants.PPM, 70 / Constants.PPM);
		floor = createfloor();
		wall = createwall(430, 170);
		wall = createwall(-430, 170);
		verticals = createverticals();

	}

	public void render() {
		update(Gdx.graphics.getDeltaTime());
		Gdx.gl.glClearColor(0, 0, 0, 1);
		Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
		b2dr.render(world, camera.combined.scl(Constants.PPM));
	}

	public void resize(int width, int height) {
		camera.setToOrtho(false, width / 2, height / 2);
	}

	public void dispose() {
		world.dispose();
		b2dr.dispose();
	}

	public void update(float delta) {
		world.step(1 / 60f, 6, 2);
		inputUpdate(delta);
		cameraUpdate(delta);

	}

	public void inputUpdate(float delta) {
		// задаем вращение колесам. А верхняя планка пусть двигается вместе с ними
		ball.setLinearVelocity(3.0f, ball.getLinearVelocity().y);
		ball1.setLinearVelocity(3.0f, ball.getLinearVelocity().y);
		verticals.setLinearVelocity(3.0f, verticals.getLinearVelocity().y);
	}

	public void cameraUpdate(float delta) {
		Vector3 position = camera.position;
		position.x = ball.getPosition().x * Constants.PPM;
		position.y = ball.getPosition().y * Constants.PPM;
		camera.position.set(position);
		camera.update();
	}

	// два колеса
	public Body createPlayer(float xo, float yo) {
		Body pBody;
		BodyDef def = new BodyDef();
		def.type = BodyDef.BodyType.DynamicBody;
		def.position.set(xo, yo);
		def.fixedRotation = false;
		pBody = world.createBody(def);
		CircleShape shape = new CircleShape();
		shape.setRadius(10 / Constants.PPM);
		pBody.createFixture(shape, 1.0f);
		def.bullet = true;
		shape.dispose();
		return pBody;
	}

	public Body createfloor() {
		Body fBody;
		BodyDef def = new BodyDef();
		def.type = BodyDef.BodyType.StaticBody;
		def.position.set(0, 0);
		def.fixedRotation = true;
		fBody = world.createBody(def);
		PolygonShape shape = new PolygonShape();
		shape.setAsBox(480 / Constants.PPM, 70 / Constants.PPM);
		fBody.createFixture(shape, 0.001f);
		shape.dispose();
		return fBody;
	}

	public Body createwall(int xo, int yo) {
		Body fBody;
		BodyDef def = new BodyDef();
		def.type = BodyDef.BodyType.StaticBody;
		def.position.set(xo / Constants.PPM, yo / Constants.PPM);
		def.fixedRotation = true;
		fBody = world.createBody(def);
		PolygonShape shape = new PolygonShape();
		shape.setAsBox(50 / Constants.PPM, 100 / Constants.PPM);
		fBody.createFixture(shape, 0.001f);
		shape.dispose();
		return fBody;
	}

	// вертикальная планка
	public Body createverticals() {
		Body fBody;
		BodyDef def = new BodyDef();
		def.type = BodyDef.BodyType.DynamicBody;
		def.position.set(30 / Constants.PPM, 90 / Constants.PPM);
		def.fixedRotation = true;
		fBody = world.createBody(def);
		PolygonShape shape = new PolygonShape();
		shape.setAsBox(30 / Constants.PPM, 3 / Constants.PPM);
		fBody.createFixture(shape, 0.001f);
		shape.dispose();
		return fBody;
	}
}

Если вы присмотритесь к коду, то заметите, что это не настоящая тележка, а, скорее, палочка на колесиках. Вперед, энтузиасты! На Youtube есть видео, где в Box2D сделали четырехтактный ДВС. Разве мы хуже? Жду в комментариях Ваши успехи!

image
Больше столкновений!
package com.mygdx.game;

import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
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.Vector2;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.BodyDef;
import com.badlogic.gdx.physics.box2d.Box2DDebugRenderer;
import com.badlogic.gdx.physics.box2d.CircleShape;
import com.badlogic.gdx.physics.box2d.FixtureDef;
import com.badlogic.gdx.physics.box2d.PolygonShape;
import com.badlogic.gdx.physics.box2d.World;
import utils.Constants;

public class MyGdxGame extends ApplicationAdapter {
	SpriteBatch batch;
	Texture img;
	private OrthographicCamera camera;
	private boolean DEBUG = false;
	private World world;
	private Body ball;
	private Body ball1;
	private Body ball2;
	private Body ball3;
	private Body ball4;
	private Body ball5;
	private Body floor;
	private Body wall;
	private Body verticals;
	private Body horizontals;
	private Box2DDebugRenderer b2dr;

	public void create() {
		float w = Gdx.graphics.getWidth();
		float h = Gdx.graphics.getHeight();
		camera = new OrthographicCamera();
		camera.setToOrtho(false, w / 2, h / 2);
		world = new World(new Vector2(0, -9.8f), false);
		b2dr = new Box2DDebugRenderer();
		// создадим шесть больших упругих мячиков
		ball = createPlayer(20 / Constants.PPM, 150 / Constants.PPM);
		ball1 = createPlayer(35 / Constants.PPM, 200 / Constants.PPM);
		ball2 = createPlayer(35 / Constants.PPM, 300 / Constants.PPM);
		ball3 = createPlayer(20 / Constants.PPM, 400 / Constants.PPM);
		ball4 = createPlayer(35 / Constants.PPM, 200 / Constants.PPM);
		ball5 = createPlayer(45 / Constants.PPM, 500 / Constants.PPM);
		floor = createfloor();
		wall = createwall(100, 170);
		wall = createwall(-60, 170);
	}

	public void render() {
		update(Gdx.graphics.getDeltaTime());
		Gdx.gl.glClearColor(0, 0, 0, 1);
		Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
		b2dr.render(world, camera.combined.scl(Constants.PPM));
	}

	public void resize(int width, int height) {
		camera.setToOrtho(false, width / 2, height / 2);
	}

	public void dispose() {
		world.dispose();
		b2dr.dispose();
	}

	public void update(float delta) {
		world.step(1 / 60f, 6, 2);
		cameraUpdate(delta);

	}

	public void cameraUpdate(float delta) {
		Vector3 position = camera.position;
		position.x = ball.getPosition().x * Constants.PPM;
		position.y = ball.getPosition().y * Constants.PPM;
		camera.position.set(position);
		camera.update();
	}

	public Body createPlayer(float xo, float yo) {
		Body pBody;
		BodyDef def = new BodyDef();
		def.type = BodyDef.BodyType.DynamicBody;
		def.position.set(xo, yo);
		def.fixedRotation = false;
		pBody = world.createBody(def);
		CircleShape shape = new CircleShape();
		shape.setRadius(10 / Constants.PPM);
		pBody.createFixture(shape, 0.0001f);
		def.bullet = true;
		// параметры, благодаря которым они такие упругие
		FixtureDef fd = new FixtureDef();
		fd.restitution = 1.0f;
		fd.density = 5.0f;
		fd.friction = 0.01f;
		fd.shape = shape;
		pBody.createFixture(fd);
		shape.dispose();
		return pBody;
	}

	public Body createfloor() {
		Body fBody;
		BodyDef def = new BodyDef();
		def.type = BodyDef.BodyType.StaticBody;
		def.position.set(0, 0);
		def.fixedRotation = true;
		fBody = world.createBody(def);
		PolygonShape shape = new PolygonShape();
		shape.setAsBox(480 / Constants.PPM, 70 / Constants.PPM);
		fBody.createFixture(shape, 0.001f);
		shape.dispose();
		return fBody;
	}

	public Body createwall(int xo, int yo) {
		Body fBody;
		BodyDef def = new BodyDef();
		def.type = BodyDef.BodyType.StaticBody;
		def.position.set(xo / Constants.PPM, yo / Constants.PPM);
		def.fixedRotation = true;
		fBody = world.createBody(def);
		PolygonShape shape = new PolygonShape();
		shape.setAsBox(50 / Constants.PPM, 100 / Constants.PPM);
		fBody.createFixture(shape, 0.001f);
		shape.dispose();
		return fBody;
	}
}

И последняя гифка на сегодня. Наклонная плоскость знакома нам с уроков физики. В данном коде представлено, как можно получить более сложную форму (теоретически произвольную), чтобы открылись безграничные возможности для игровой физики.

image

Наклонная плоскость

public class MyGdxGame extends ApplicationAdapter {
	SpriteBatch batch;
	Texture img;
	private OrthographicCamera camera;
	private boolean DEBUG = false;
	private World world;
	private Body ball;
	private Body floor;
	private Body wall;
	private Body plos;
	private Body verticals;
	private Body horizontals;
	private Box2DDebugRenderer b2dr;

	public void create() {
		float w = Gdx.graphics.getWidth();
		float h = Gdx.graphics.getHeight();
		camera = new OrthographicCamera();
		camera.setToOrtho(false, w / 2, h / 2);
		world = new World(new Vector2(0, -9.8f), false);
		b2dr = new Box2DDebugRenderer();
		ball = createPlayer();
		floor = createfloor();
		wall = createwall(430, 170);
		wall = createwall(-430, 170);
		plos = createplos();
	}

	public void render() {
		update(Gdx.graphics.getDeltaTime());
		Gdx.gl.glClearColor(0, 0, 0, 1);
		Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
		b2dr.render(world, camera.combined.scl(Constants.PPM));
	}

	public void resize(int width, int height) {
		camera.setToOrtho(false, width / 2, height / 2);
	}

	public void dispose() {
		world.dispose();
		b2dr.dispose();
	}

	public void update(float delta) {
		world.step(1 / 60f, 6, 2);
		cameraUpdate(delta);

	}
	
	public void cameraUpdate(float delta) {
		Vector3 position = camera.position;
		position.x = ball.getPosition().x * Constants.PPM;
		position.y = ball.getPosition().y * Constants.PPM;
		camera.position.set(position);
		camera.update();
	}

	public Body createPlayer() {
		Body pBody;
		BodyDef def = new BodyDef();
		def.type = BodyDef.BodyType.DynamicBody;
		def.position.set(30 / Constants.PPM, 190 / Constants.PPM);
		def.fixedRotation = false;
		pBody = world.createBody(def);
		CircleShape shape = new CircleShape();
		shape.setRadius(10 / Constants.PPM);
		pBody.createFixture(shape, 1.0f);		
		def.bullet = true;
		shape.dispose();
		return pBody;
	}

	public Body createfloor() {
		Body fBody;
		BodyDef def = new BodyDef();
		def.type = BodyDef.BodyType.StaticBody;
		def.position.set(0, 0);
		def.fixedRotation = true;
		fBody = world.createBody(def);
		PolygonShape shape = new PolygonShape();
		shape.setAsBox(480 / Constants.PPM, 70 / Constants.PPM);
		fBody.createFixture(shape, 0.001f);
		shape.dispose();
		return fBody;
	}

	public Body createwall(int xo, int yo) {
		Body fBody;
		BodyDef def = new BodyDef();
		def.type = BodyDef.BodyType.StaticBody;
		def.position.set(xo / Constants.PPM, yo / Constants.PPM);
		def.fixedRotation = true;
		fBody = world.createBody(def);
		PolygonShape shape = new PolygonShape();
		shape.setAsBox(50 / Constants.PPM, 100 / Constants.PPM);
		fBody.createFixture(shape, 0.001f);
		shape.dispose();
		return fBody;
	}
	
	public Body createplos() {
		Vector2[] vertices = new Vector2[3];
	    vertices[0] = new Vector2(0f  , -0.6f  );
	    vertices[1] = new Vector2(1f , -0.6f  );
	    vertices[2] = new Vector2(1f , 1f);
	    PolygonShape shape = new PolygonShape();
		Body fBody;
		BodyDef def = new BodyDef();
		def.type = BodyDef.BodyType.StaticBody;
		def.position.set(20 / Constants.PPM, 90 / Constants.PPM);
		def.fixedRotation = true;
		fBody = world.createBody(def);
		shape.set(vertices);
		fBody.createFixture(shape, 0.001f);
		shape.dispose();
		return fBody;
	}
}

Надеюсь, благодаря этому коду Вам удастся разобраться с основами Box2D, и на свет появятся исключительно превосходные приложения! Спасибо, что прочли до конца! Постараюсь ответить на все вопросы в комментариях!

Автор: Васильев Алексей

Источник


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js