So I have 2 screens: a level select screen which uses a FitViewport with a resolution of 720 x 405 and then a game screen which uses a FillViewport with a resolution of 480 x 270 scaled by the amount of pixels per meter (/100).
After completing a certain level I want to return to the level select screen. However, upon return it seems to be fully zoomed in.
Here is how it should look, and how it looks when first launched
Here is how it looks after coming out of the game
Here is the level screen code:
public LevelScreen(CrossplatformApp game) {
this.game = game;
this.camera = new OrthographicCamera();
this.levelstage = new Stage(new FitViewport(Constants.WIDTH, Constants.HEIGHT, camera));
this.background = new Texture("Screens/LevelScreen/LevelSelection.png");
this.backbutton = new Texture("Screens/BackButton.png");
this.level1texture = new Texture("Screens/LevelScreen/Button1.png");
this.level2texture = new Texture("Screens/LevelScreen/Button2.png");
this.level3texture = new Texture("Screens/LevelScreen/Button3.png");
}
#Override
public void resize(int width, int height) {
levelstage.getViewport().update(width, height, true);
}
And the game screen:
this.game = gameFile;
this.camera = new OrthographicCamera();
this.viewport = new FillViewport(Constants.V_WIDTH / Constants.PPM, Constants.V_HEIGHT / Constants.PPM, camera);
this.levelHUD = new HUD(gameFile.batch, WorldPicker.getWorldName(playerMemory.player.worldAndLevelData.getCurrentWorld(), playerMemory.player.worldAndLevelData.getCurrentLevel()));
When changing viewports you need to apply the viewport before drawing with:
this.viewport.apply();
Related
I'm trying to get a tiledmap to render over the whole screen. The problem is that the top or right 100px, everything is just black there. My tiledmap is around 100 tiles, so it should be able to render more than what it renders.
This is how it looks right now:
1: This bar is expected as I do, currently, not have anything to render there.
2 & 3: These bars are unexpected as there are more parts of my tiledmap to render there.
I've already tried changing my Viewport from StretchViewport to FitViewport as well as FillViewport, but that doesn't change anything.
Here's my constructor in the PlayScreen class:
public Play(GameStateManager gsm) {
super(gsm);
//set up box2d
world = new World(new Vector2(0, -20.81f), true);
cl = new MyContactListener();
world.setContactListener(cl);
b2dr = new Box2DDebugRenderer();
//set up viewport
vw = new StretchViewport(1280, 720, cam);
cam.update();
//create player
createPlayer();
//create tiles
createTiles();
//setup box2D cam
b2dCam = new OrthographicCamera();
b2dCam.setToOrtho(false, Game.V_WIDTH / PPM, Game.V_HEIGHT / PPM);
}
Here's my createTiles() method:
private void createTiles(){
loader = new TmxMapLoader();
tileMap = loader.load("data/lvl1.tmx");
tmr = new OrthogonalTiledMapRenderer(tileMap);
cam.update();
//get the size of the tiles
tileSize = tileMap.getProperties().get("tilewidth", Integer.class);
//create box2d bodies for all tiledmap layers
TiledMapTileLayer layer;
layer = (TiledMapTileLayer) tileMap.getLayers().get("red");
createLayer(layer, B2DVars.BIT_RED);
layer = (TiledMapTileLayer) tileMap.getLayers().get("orange");
createLayer(layer, B2DVars.BIT_ORANGE);
layer = (TiledMapTileLayer) tileMap.getLayers().get("yellow");
createLayer(layer, B2DVars.BIT_YELLOW);
layer = (TiledMapTileLayer) tileMap.getLayers().get("green");
createLayer(layer, B2DVars.BIT_GREEN);
layer = (TiledMapTileLayer) tileMap.getLayers().get("blue");
createLayer(layer, B2DVars.BIT_BLUE);
layer = (TiledMapTileLayer) tileMap.getLayers().get("pink");
createLayer(layer, B2DVars.BIT_PINK);
}
The render() method:
public void render(float delta) {
//clear screen
Gdx.gl.glClearColor(0.619607843f, 0.79607843137f, 1, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
//set cam to follow player
cam.position.set(
player.getPosition().x * PPM + Game.V_WIDTH / 4,
Game.V_HEIGHT / 2,
0
);
//draw tile map
tmr.setView(cam);
tmr.render();
//draw player
sb.setProjectionMatrix(cam.combined);
player.render(sb);
//draw box2d world
b2dr.render(world, b2dCam.combined);
//responsive resizing
resize(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
}
And here's the create() method inside my main game class:
public void create () {
Gdx.input.setInputProcessor(new MyInputProcessor());
//asset managing
res = new Content();
res.loadTexture("data/player/player.png", "player");
sb = new SpriteBatch();
cam = new OrthographicCamera();
cam.setToOrtho(false, V_WIDTH, V_HEIGHT);
hudCam = new OrthographicCamera();
hudCam.setToOrtho(false, V_WIDTH, V_HEIGHT);
gsm = new GameStateManager(this);
}
I did not expect this game to get those black bars, I've created other games before and they have never gotten those. How can I remove them (2 & 3 on the image)?
I am using a Viewport for my libGdx landscape game like this.
public static final int WORLD_WIDTH = 1280;
public static final int WORLD_HEIGHT = 800;
camera = new OrthographicCamera();
float aspectRatio = Constants.WORLD_WIDTH / Constants.WORLD_HEIGHT;
ViewPort viewPort = new FillViewport(WORLD_WIDTH * aspectRatio,WORLD_HEIGHT, camera);
I am using all positions in terms of this width and height.
It is working fine in all devices except device that have screen resolution greater than 1300.
In device that have greater resolution than 1300,only middle part of the game is visible.I tried using stretched viewport for the greater resolution device,but it is giving all game elements stretched.
How can I make my game working in all devices fine?Do I need to change the viewport?
Finally I made it work. I am not sure whether this is the correct way to solve such problems.
I did it like this;
camera = new OrthographicCamera();
if(screenHeight>1300)
{
Constants.WORLD_WIDTH=1280;
Constants.WORLD_HEIGHT=960;
}
else{
Constants.WORLD_WIDTH=1280;
Constants.WORLD_HEIGHT=800;
}
viewPort = new FillViewport(Constants.WORLD_WIDTH, Constants.WORLD_HEIGHT, camera);
viewPort.apply();
I used a viewPort width of 1280x960 for all greater resolution devices while keeping 1280x800 resolution for all other devices that has screen width less than 1300.
While drawing background I used viewport width and height to set the size like this.
bgSprite=new Sprite(bgTexture);
bgSprite.setPosition(Constants.BG_X,Constants.BG_Y);
bgSprite.setSize(game.viewPort.getWorldWidth(),game.viewPort.getWorldHeight());
Not sure this the right way,but doing this solved my problem.
I'll recommend ExtendViewprot to use, because it keeps the world aspect ratio without black bars by extending the world in one direction. Use all positions in terms of world width and height not screen width and height and resize viewport in resize method according to your device width and height.
Your resources size should be in the respect of world width and height.
public class MyGdxGame extends ApplicationAdapter {
Stage stage;
public static final int WORLD_WIDTH = 800;
public static final int WORLD_HEIGHT = 480;
#Override
public void create() {
ExtendViewport extendViewport=new ExtendViewport(WORLD_WIDTH,WORLD_HEIGHT);
stage=new Stage(extendViewport);
//logical pixels of your current device, device specific
//float w=Gdx.graphics.getWidth(); //screen width
//float h=Gdx.graphics.getHeight();// screen height
Image image=new Image(new Texture("badlogic.jpg"));
image.setPosition(WORLD_WIDTH/2,WORLD_HEIGHT/2, Align.center); //consider world width and height instead of screen width and height
stage.addActor(image);
stage.setDebugAll(true);
}
#Override
public void render() {
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
Gdx.gl.glClearColor(0,0,0,1);
stage.act();
stage.draw();
}
#Override
public void resize(int width, int height) {
stage.getViewport().update(width,height);
stage.getCamera().position.set(WORLD_WIDTH/2,WORLD_HEIGHT/2,0);
stage.getCamera().update();
}
#Override
public void dispose() {
stage.dispose();
}
}
Am trying to reduce number of calls being made everytime a Screen is called on my game in a bid to make my game faster and I noticed I do alot the same calculation on every screen..how can i avoid this?
I do this in practically every screen
public class ****Screen implements Screen {
#Override
public void show() {
float screenWidth = Gdx.graphics.getWidth();
float screenHeight = Gdx.graphics.getHeight();
float gameWidth = 360;
float gameHeight = screenHeight / (screenWidth / gameWidth);
midPointY = (int) (gameHeight / 2);
cam = new OrthographicCamera();
cam.setToOrtho(true, gameWidth, gameHeight);
viewport = new FitViewport(gameWidth, gameHeight, cam);
viewport.apply();
stage = new Stage(viewport);
Gdx.input.setInputProcessor(stage);
yet I have a GameClass..How can I implement the above in my gameclass(below) and only have to call it once?...
public class Start extends Game {
#Override
public void create() {
float screenWidth = Gdx.graphics.getWidth();
float screenHeight = Gdx.graphics.getHeight();
float gameWidth = 360;
float gameHeight = screenHeight / (screenWidth / gameWidth);
assets = new AssetLoader();
assetManager = new AssetManager();
camera = new OrthographicCamera();
camera.setToOrtho(true, gameWidth, gameHeight);
//initialize screens here
mainMenu = new MenuScreen(this);
loadingScreen = new LoadingScreen(this);
gameScreen = new GameScreen(this);
.......
//call assets
AssetLoader.load();
//start mainmenu...
this.setScreen(mainMenu);
}
First i have to tell you actualy this wont speed up your game.
If you change screen every 20 seconds then that means game does calculations 1 frame per 1200 frames.
However i am same like you and really looking for most optimize ways while doing game.
I found a solution for this case.
You can pass objects that you use in all screens, from game class to screen class.
Screen class
public class MainMenuScreen implements Screen {
public MainMenuScreen(OrthographicCamera camera) {
this.camera=camera;
}
//...Rest of class omitted for succinctness.
}
Game class
public class Starts extends Game {
OrthographicCamera camera;
public void create() {
camera=new OrthographicCamera();
camera.setToOrtho(false, 800, 480);
this.setScreen(new MainMenuScreen(camera));// change screen and pass camera to new screen.
}
}
Or you can even pass the whole game class like this.
public class MainMenuScreen implements Screen {
final Starts game;
public MainMenuScreen(final Starts game) {
this.game = game;
}
#Override
public void render(float delta) {
Gdx.gl.glClearColor(0, 0, 0.2f, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
game.camera.update();
game.batch.setProjectionMatrix(game.camera.combined);
game.batch.begin();
game.font.draw(...);
game.font.draw(...);
game.batch.end();
if (Gdx.input.isTouched()) {
game.setScreen(new AnotherScreen(game));
dispose();
}
}
}
just need to call like this in game class. So you can use stage batches fonts etc. of game in all screens.
this.setScreen(new MainMenuScreen(this));
I assume you mean you want to shorten the little hiccup you get when switching screens. (Your game's frame rate is not affected by this.)
Easy way: move that code from show to the constructor of each screen class.
However, it is wasteful to be creating a new Stage for each Screen without passing it a SpriteBatch, because you are essentially instantiating three separate SpriteBatches, which are heavy objects (they have a big array for the mesh data, a big mesh on the GPU, and have to compile a shader).
You can instantiate shared objects in your Game class and pass them into the constructors of your Screens like this:
public class Start extends Game {
SpriteBatch spriteBatch;
#Override
public void create() {
//...
//initialize screens here
spriteBatch = new SpriteBatch(); //must be disposed in dispose()
mainMenu = new MenuScreen(this, spriteBatch);
loadingScreen = new LoadingScreen(this, spriteBatch);
gameScreen = new GameScreen(this, spriteBatch);
//...
}
}
Update your Screens' constructors accordingly and pass the sprite batch into the stage constructors. Viewports and cameras are lightweight, so I wouldn't bother with moving those up to the Game class unless it helps make your code more maintainable.
By the way, you're kind of abusing FitViewport by pre-calculating the aspect ratio. The point of Viewports is that you don't need to calculate anything when setting up. Use new ExtendViewport(360, 1, cam) to get the same thing you're doing without the calculations. And make sure you're updating it in resize().
Is it possible to set a minimum and maximum aspect ratio?
Lets say from 1:1 to 2.5:1. Or at least set min and max for width and height?
You can use a FitViewport to maintain a fixed width and height:
FitViewport viewport = new FitViewport(SCREEN_WIDTH, SCREEN_HEIGHT, camera);
If you are using a Stage to draw all your actors then all you need to do is set the viewport on the stage like this:
stage.setViewport(viewport);
However if you are not using a Stage then you need to do the following. If you are drawing directly with a SpriteBatch you will need to set up a Camera too:
SpriteBatch batch = new SpriteBatch();
OrthographicCamera camera = new OrthographicCamera(SCREEN_WIDTH, SCREEN_HEIGHT);
camera.setToOrtho(true);
//center the camera in the center of the screen
camera.position.set(SCREEN_WIDTH / 2f, SCREEN_HEIGHT / 2f, 0f);
//pass the camera to the third argument of the viewport
FitViewport viewport = new FitViewport(SCREEN_WIDTH, SCREEN_HEIGHT, camera);
Then you will need to set up the projection matrix on the Camera and SpriteBatch when rendering:
#Override
public void render(float deltaTime) {
camera.update();
batch.setProjectionMatrix(camera.combined);
// do all the rendering of textures and stuff
}
Also you need to update the viewport every time the screen is resized:
#Override
public void resize(int width, int height) {
viewport.update(width, height);
}
I make simply aplication in LibGDX. I have got two textures (background and sprite). The background is diplayed ok but I don't see the sprite. I have tried many solutions but nothing works. I don't know what is going on. Thanks for help.
Here is my code:
public void create() {
float w = Gdx.graphics.getWidth();
float h = Gdx.graphics.getHeight();
Texture.setEnforcePotImages(false);
camera = new OrthographicCamera(1, h/w);
batch = new SpriteBatch();
texture = new Texture(Gdx.files.internal("graphic/bg1.png"));
bad = new Texture(Gdx.files.internal("graphic/b.png"));
layerOne = new TextureRegion(texture);
spriteb = new Sprite(bad);
rbg = new ParallaxBackground(new ParallaxLayer[]{
new ParallaxLayer(layerOne, new Vector2(),new Vector2()),
}, w, h,new Vector2());
}
public void render() {
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
rbg.render();
camera.update();
batch.setProjectionMatrix(camera.combined);
batch.begin();
spriteb.setPosition(400, 200);
spriteb.draw(batch);
batch.end();
}
Your camera viewport is too small for the Sprite position
camera = new OrthographicCamera(1, h/w);
...
spriteb.setPosition(400, 200);
The sprite is being rendered far outside of the viewport.
Try setting your camera like this:
camera = new OrthographicCamera(w, (h/w)*h);