Кустарная Колыбель Ньютона

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!

Здравствуй, дорогой читатель! Я уже написал первую статью с самыми основами Box2D в Eclipse на Java. Сегодня на примере Колыбели Ньютона покажу, как настроить связь объектов в этой чудесной физической библиотеке.

Что же мы ожидаем увидеть?

image

Рисунок 1. Слишком хорошо!

Определенно, что-то, абсолютно не похожее на это!

По подключению libGDX смотрите первую статью.

Состав проекта не изменился:

image

Рисунок 2. Проект. Папки и пакеты.

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

Вот код для класса 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);
	}
}


В нашей физической модели первостепенное значение будет иметь коэффициент упругости. Чем он выше, тем больше колебаний совершит маятник. В Box2D параметр restitution у FixtureDef может принимать значения от 0 до 1.0f, где 0 — абсолютно не упругое тело, а 1.0f — абсолютно упругое. Лучшая модель Колыбели Ньютона у меня получилось при restitution = 0.8f:

image

Рисунок 3. Коэффициент упругости = 0.8f, для большей наглядности замедленная съемка.

Код реализации:
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.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 com.badlogic.gdx.physics.box2d.joints.RevoluteJointDef;

import utils.Constants;

public class MyGdxGame extends ApplicationAdapter {
	private OrthographicCamera camera;
	private boolean DEBUG = false;
	private World world;
	private Body plos;
	private Body plos2;
	private Body plos3;
	private Body plos1;
	private Body plos4;
	private Box2DDebugRenderer b2dr;
	private Body ball;
	private Body ball1;
	private Body ball2;
	private Body ball3;
	private Body ball4;

	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();
		// создаем крепления для шариков
		plos = createplos(20 / Constants.PPM);
		plos1 = createplos(0 / Constants.PPM);
		plos2 = createplos(40 / Constants.PPM);
		plos3 = createplos(80 / Constants.PPM);
		plos4 = createplos(60 / Constants.PPM);
		// создаем шарики
		ball = createball(20 / Constants.PPM);
		ball1 = createball(40 / Constants.PPM);
		ball2 = createball(60 / Constants.PPM);
		ball3 = createball(0 / Constants.PPM);
		ball4 = createball(80 / Constants.PPM);
		// связываем крепление с соответствующим ему шариком
		rotation(plos, ball);
		rotation(plos2, ball1);
		rotation(plos1, ball3);
		rotation(plos4, ball2);
		rotation(plos3, ball4);
	}
	// здесь описывается связь шарика и крепления
	public void rotation(Body body1, Body body2) {
		RevoluteJointDef rjd = new RevoluteJointDef();
		rjd.bodyA = body1;
		rjd.bodyB = body2;
		rjd.collideConnected = false;
		// центр крепления для первого тела
		rjd.localAnchorB.set((plos.getPosition().x) / Constants.PPM, plos.getPosition().y / Constants.PPM + 2);
		// центр крепления для второго тела
		rjd.localAnchorA.set((plos.getPosition().y - 6.8f) / Constants.PPM, plos.getPosition().x / Constants.PPM);
		world.createJoint(rjd);
	}

	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);
		inputUpdate(delta);
	}

	public void inputUpdate(float delta) {
	// по нажатию на пробел, крайнему левому шарику сообщается скорость -7 м/с по x, -7 м/с по y
		if (Gdx.input.isKeyPressed(Keys.SPACE)) {
			ball3.setLinearVelocity(-7, -7);
		}
	}

	// камера следует за центральным шариком
	public void cameraUpdate(float delta) {
		Vector3 position = camera.position;
		position.x = ball1.getPosition().x * Constants.PPM;
		position.y = ball1.getPosition().y * Constants.PPM;
		camera.position.set(position);
		camera.update();
	}

	// создание крепления
	public Body createplos(float xo) {
		PolygonShape shape = new PolygonShape();
		Body fBody;
		BodyDef def = new BodyDef();
		def.type = BodyDef.BodyType.StaticBody;
		def.position.set(xo, 200 / Constants.PPM);
		def.fixedRotation = true;
		fBody = world.createBody(def);
		shape.setAsBox(10 / Constants.PPM, 10 / Constants.PPM);
		fBody.createFixture(shape, 0.001f);
		shape.dispose();
		return fBody;
	}

	// создание шарика
	public Body createball(float xo) {
		Body pBody;
		BodyDef def = new BodyDef();
		def.type = BodyDef.BodyType.DynamicBody;
		def.position.set(xo, 100 / Constants.PPM);
		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 = 0.8f;
		// плотность
		fd.density = 10.0f;
		// коэффициент трения
		fd.friction = 0f;
		fd.shape = shape;
		pBody.createFixture(fd);
		shape.dispose();
		return pBody;
	}
}


Вы можете самостоятельно изменять коэффициенты и получать различные результаты. Кроме того, на примитивы можно наложить текстуры для достижения большей реалистичности.

Далее будут представлены gif-изображения для различных значений коэффициента упругости.

image

Рисунок 4. Коэффициент упругости, равный 1f.

image

Рисунок 5. Коэффициент упругости, равный 0.5f.

image

Рисунок 6. Коэффициент упругости, равный 0.2f.

image

Рисунок 7. Коэффициент упругости, равный 0.

Идей много, стараюсь выкладывать результаты по мере возможности! Спасибо, что прочли до конца, надеюсь, статья была полезной для вас! Давайте вместе устроим настоящий хаос в игровом мире благодаря библиотеке Box2D!

P.S. Отвечу на все вопросы в комментариях.
Источник: https://habr.com/ru/post/450346/


Интересные статьи

Интересные статьи

Если у Вас нет математического образования, если Вы хотите по-настоящему разобраться в том, что из себя представляет интеграл и интегрирование, зачем всё это надо, как ма...
Всем привет. Если вы когда-либо работали с универсальными списками в Битрикс24, то, наверное, в курсе, что страница детального просмотра элемента полностью идентична странице редак...
Всем привет! Не так давно на работе в рамках тестирования нового бизнес-процесса мне понадобилась возможность авторизации под разными пользователями. Переход в соответствующий р...
Если в вашей компании хотя бы два сотрудника, отвечающих за работу со сделками в Битрикс24, рано или поздно возникает вопрос распределения лидов между ними.
Компании растут и меняются. Если для небольшого бизнеса легко прогнозировать последствия любых изменений, то у крупного для такого предвидения — необходимо изучение деталей.