Libgdx Box2D преобразования пикселей в метр?
При попытке запрограммировать игру с помощью Box2D я столкнулся с проблемой с Box2D. Я заполнил номера пикселей для длин текстур и спрайтов, чтобы создать рамку вокруг него. Все было в нужном месте, но почему-то все шло очень медленно. Посмотрев в интернете, я обнаружил, что если вы не конвертируете пиксели в метры, box2d может обрабатывать фигуры как очень большие объекты. это казалось логичной причиной того, что все движется медленно.
Я нашел похожие вопросы на этом сайте, но ответы, похоже, не помогли. В большинстве случаев решение состояло в том, чтобы создать методы для преобразования чисел пикселей в метры с использованием масштабного коэффициента. Я попробовал это, но все стало неуместным и имело неправильные размеры. это казалось мне логичным, поскольку числа менялись, но имели одинаковое значение.
Мне было интересно, есть ли способ, чтобы пиксели означали меньше метров, чтобы все было в одном месте с тем же (пиксельным) размером, но означало бы меньше метров. Если у вас есть другой способ, который, по вашему мнению, может помочь, я также хотел бы услышать это...
Вот код, который я использую для создания камеры
width = Gdx.graphics.getWidth() / 5;
height = Gdx.graphics.getHeight() / 5;
camera = new OrthographicCamera(width, height);
camera.setToOrtho(false, 1628, 440);
camera.update();
Это метод, который я использую для создания объекта:
public void Create(float X, float Y, float Width, float Height, float density, float friction, float restitution, World world){
//Method to create an item
width = Width;
height = Height;
polygonDef = new BodyDef();
polygonDef.type = BodyType.DynamicBody;
polygonDef.position.set(X + (Width / 2f), Y + (Height / 2f));
polygonBody = world.createBody(polygonDef);
polygonShape = new PolygonShape();
polygonShape.setAsBox(Width / 2f, Height / 2f);
polygonFixture = new FixtureDef();
polygonFixture.shape = polygonShape;
polygonFixture.density = density;
polygonFixture.friction = friction;
polygonFixture.restitution = restitution;
polygonBody.createFixture(polygonFixture);
}
Для создания элемента, в данном случае таблицы, я использую следующее:
Table = new Item();
Table.Create(372f, 60f, 152f, 96f, 1.0f, 0.2f, 0.2f, world);
Спрайты нарисованы на элементе с помощью следующего метода:
public void drawSprite(Sprite sprite){
polygonBody.setUserData(sprite);
Utils.batch.begin();
if(polygonBody.getUserData() instanceof Sprite){
Sprite Sprite = (Sprite) polygonBody.getUserData();
Sprite.setPosition(polygonBody.getPosition().x - Sprite.getWidth() / 2, polygonBody.getPosition().y - Sprite.getHeight() / 2);
Sprite.setRotation(polygonBody.getAngle() * MathUtils.radiansToDegrees);
Sprite.draw(Utils.batch);
}
Utils.batch.end();
}
Спрайты также имеют размеры в пикселях.
Используя эти методы, он отображает изображения в нужных местах, но все движется медленно. Мне было интересно, как или если я должен был бы изменить это, чтобы заставить объекты двигаться правильно, и / или значить меньше. Заранее спасибо.
1 ответ
Box2D полностью независим от используемой вами графической библиотеки. Здесь нет понятия спрайтов и текстур. То, что вы читаете онлайн, правильно, вам придется конвертировать пиксели в метры, так как Box2D работает с метрами (стандартная единица измерения расстояния).
Например, если вы нарисовали спрайт размером 100x100 пикселей, это размер спрайта, который вы хотите, чтобы пользователь видел на экране. В реальном мире размер объекта должен быть в метрах, а не в пикселях - поэтому, если вы скажете 1px = 1m, тогда это отобразит спрайт в гигантский объект размером 100x100 метров. В Box2D большие объекты мира замедляют вычисления. Итак, вам нужно сопоставить 100 пикселей с меньшим количеством метров, скажем, 1 метр - таким образом, спрайт 100x100px будет представлен в мире Box2D объектом 1x1 метр.
Box2D не очень хорошо работает с очень маленькими и очень большими числами. Так что держите его между, скажем, между 0,5 и 100, чтобы иметь хорошую производительность.
РЕДАКТИРОВАТЬ: Хорошо. Теперь я понимаю ваш вопрос. Не кодируйте в пиксели. Это так просто. Я знаю, что потребуется некоторое время, чтобы понять это (это заняло у меня). Но как только вы поймете это, это прямо вперед. Вместо пикселей, используйте единицу, скажем, вы называете это метр. Таким образом, мы решили, что наш видовой экран должен быть 6mx5m.
Итак, инициализация
Constants.VIEWPORT_WIDTH = 6;
Constants.VIEWPORT_HEIGHT = 5;
...
void init() {
camera = new OrthographicCamera(Constants.VIEWPORT_WIDTH, Constants.VIEWPORT_HEIGHT);
camera.position.set(Constants.VIEWPORT_WIDTH/2, Constants.VIEWPORT_HEIGHT/2, 0);
camera.update();
}
Как только вы узнаете фактическую ширину и высоту, вы вызываете следующую функцию, чтобы сохранить соотношение сторон:
public void resize(int width, int height) {
camera.viewportHeight = (Constants.VIEWPORT_WIDTH / width) * height;
camera.update();
}
resize()
может вызываться в любое время при изменении размера экрана (например, при изменении ориентации экрана). resize()
принимает фактическую ширину и высоту (320x480 и т. д.), то есть значение в пикселях.
Теперь вы указываете размеры спрайтов, их позиции и т. Д. В этом новом мире размером 6х5. Вы можете забыть пиксели. Минимальный размер спрайта, который будет заполнять экран, будет 6x5.
Теперь вы можете использовать то же устройство с Box2D. Поскольку новые размеры будут меньше, для Box2D это не будет проблемой. Если я правильно помню, Box2D не имеет никакого устройства. Мы просто называем это метр для удобства.
Теперь вы можете спросить, где вы указываете размеры окна. Это зависит от платформы. В следующем коде показана оконная настольная игра размером 320x480:
public class Main {
public static void main(String[] args) {
LwjglApplicationConfiguration cfg = new LwjglApplicationConfiguration();
cfg.title = "my-game";
cfg.useGL20 = false;
cfg.width = 480;
cfg.height = 320;
new LwjglApplication(new MyGame(), cfg);
}
}
Наша камера будет интеллектуально отображать область просмотра 6x5 на 480x320.