Box2d Освещение разного поведения с разным размером экрана

Я попытался немного поиграть с освещением, но очень быстро наткнулся на странное поведение, которое я не понимаю. Может ли кто-нибудь объяснить мне, почему это происходит, если это нарочно, или я делаю что-то не так.

На первом изображении свет проходит через препятствие (что тоже странно).

Экран игры шире

Когда размер экрана изменяется на меньшую ширину, свет проходит еще больше через препятствие.

Красный фон - "черная полоса", так как я использую FitViewport. "Реальный" мир имеет badlogic.jpg повсюду.

Игровой экран узкий

На следующих рисунках вы можете увидеть, как это работает без рендеринга света - экран отображает один и тот же мир независимо от размера экрана (только масштабированный). Вот как я ожидал бы, что это будет работать даже с освещением.

Проект стандартный, сгенерированный генератором проекта libgdx. Весь мой код только один класс, поэтому я могу загрузить его здесь:

package com.gobanit.sandbox.main;

import com.badlogic.ashley.core.Engine;
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.BodyDef.BodyType;
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.utils.viewport.FitViewport;
import com.badlogic.gdx.utils.viewport.Viewport;

import box2dLight.PointLight;
import box2dLight.RayHandler;

public class SandboxTestGame extends ApplicationAdapter {
    SpriteBatch batch;
    World world;
    Engine engine;
    Viewport viewport;
    Box2DDebugRenderer debugRenderer;
    Texture texture;
    RayHandler rayHandler;

    Body playerBody;

    @Override
    public void create () {
        batch = new SpriteBatch();
        texture = new Texture(Gdx.files.internal("badlogic.jpg"));
        engine = new Engine();
        world = new World(new Vector2(0, 0), true);
        viewport = new FitViewport(1000, 500);
        viewport.getCamera().position.set(new Vector3(0, 0, 0));
        debugRenderer = new Box2DDebugRenderer();   
        rayHandler = new RayHandler(world);
        rayHandler.setShadows(true);

        createPlayerBody();
        createObstacleBody();       

        PointLight l1 = new PointLight(rayHandler, 100, null, 500, 0, 0);
        l1.attachToBody(playerBody);
        //l1.setSoft(true);

        //new PointLight(rayHandler, 100, null, 500, 0, 200);

    }

    private void createObstacleBody() {
        BodyDef bodyDef = new BodyDef();
        bodyDef.position.add(new Vector2(-10000, 100));
        bodyDef.type = BodyType.StaticBody;

        Body body = world.createBody(bodyDef);

        FixtureDef fixDef = new FixtureDef();
        PolygonShape shape = new PolygonShape();
        shape.set(new float[] {0f,0f,0f,40f,20000f,40f,20000f,0f});
        fixDef.shape = shape;

        body.createFixture(fixDef);

        body.setActive(true);       
    }

    private void createPlayerBody() {
        BodyDef bodyDef = new BodyDef();
        bodyDef.position.add(new Vector2(100, 50));
        bodyDef.type = BodyType.DynamicBody;

        Body body = world.createBody(bodyDef);

        FixtureDef fixDef = new FixtureDef();
        CircleShape circle = new CircleShape();
        circle.setRadius(20);
        fixDef.shape = circle;

        body.createFixture(fixDef);

        body.setActive(true);

        playerBody = body;      
    }



    @Override
    public void render () {
        update();
        draw();
    }

    private void draw() {
        Gdx.gl.glClearColor(100, 0, 0, 1);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

        viewport.update(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());

        batch.setProjectionMatrix(viewport.getCamera().combined);
        batch.begin();
        batch.draw(texture, -1000, -1000, 2000, 2000);
        batch.end();

        debugRenderer.render(world, viewport.getCamera().combined);

        rayHandler.setCombinedMatrix((OrthographicCamera) viewport.getCamera());
        rayHandler.render();    
    }

    private void update() {
        world.step(1f/60f, 8, 3);
        rayHandler.update();

        if(Gdx.input.isKeyPressed(Keys.D)) {
            //viewport.getCamera().position.add(new Vector3(1,0,0));
            playerBody.applyForceToCenter(100, 0, true);
        }
        if(Gdx.input.isKeyPressed(Keys.A)) {
            //viewport.getCamera().position.add(new Vector3(-1,0,0));
            playerBody.applyForceToCenter(-100, 0, true);
        }
        if(Gdx.input.isKeyPressed(Keys.W)) {
            //viewport.getCamera().position.add(new Vector3(0,1,0));
            playerBody.applyForceToCenter(0, 100, true);
        }
        if(Gdx.input.isKeyPressed(Keys.S)) {
            //viewport.getCamera().position.add(new Vector3(0,-1,0));
            playerBody.applyForceToCenter(0, -100, true);
        }   

        viewport.getCamera().position.set(new Vector3(playerBody.getPosition().x, playerBody.getPosition().y, 0));
    }

    @Override
    public void dispose () {
        batch.dispose();
        texture.dispose();
        world.dispose();
        debugRenderer.dispose();
        rayHandler.dispose();
    }
}

Большое спасибо. Если потребуется дополнительная информация, скажите мне, и я отредактирую вопрос.

1 ответ

чтобы подтвердить то, что сказал @Михаил Чурбанов, и привлечь больше внимания. В документации упоминается, что мы несем ответственность за обновление области просмотра при изменении размера. Я думал, что это точка подходящего видового экрана. Я смущен.

В любом случае, я использовал эту функцию в своем resize() следующим образом:

          if(viewport.getRightGutterWidth() > 0){
        rayHandler.useCustomViewport(viewport.getRightGutterWidth()-5,viewport.getBottomGutterHeight()-5, (int)(height*SCREEN_RATIO)+10,height+10);
    }else{
        rayHandler.useCustomViewport(viewport.getRightGutterWidth()-5,viewport.getBottomGutterHeight()-5, width+10,(int)(width/SCREEN_RATIO)+10);
    }
  • Первое условие позволяет отличить вертикальное/горизонтальное изменение размера.
  • использование getRightGutterWidth и getBottomGutterHeight для позиционирования области просмотра
  • Использование коэффициента постоянной экрана для определения ширины или высоты в зависимости от случая
  • И последнее, но не последнее: к сожалению, пришлось добавить крошечные отступы (5 и 10), иначе вы когда-нибудь увидите линию в 1 пиксель на випорте без включенного света.

Это вызывает у меня смешанные чувства. Я не особо верю, что это так, эй, это работает!

Другие вопросы по тегам