I have trouble with my app. On iPhone (tested on 5c, 5s, 6) i have two black stripes on both sides (on android all looks well).
How i can dispose of them?
This is my code for drawing
#Override
public void create () {
mWidth = Gdx.graphics.getWidth();
mHeight = Gdx.graphics.getHeight();
mScale = Math.max(mWidth, mHeight) / 20f;
backgroundTexture = new Texture(Gdx.files.internal("backBlue.png"));
ShaderProgram.pedantic = false;
backgroundShader = new ShaderProgram(VERT, FRAG);
if (!backgroundShader.isCompiled()) {
System.err.println(backgroundShader.getLog());
System.exit(0);
}
if (backgroundShader.getLog().length()!=0)
System.out.println(backgroundShader.getLog());
backgroundBatch = new SpriteBatch(5, backgroundShader);
}
#Override
public void render () {
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
backgroundBatch.begin();
backgroundBatch.draw(backgroundTexture, 0, 0, mWidth, mHeight);
backgroundBatch.end();
...
}
#Override
public void resize (int width, int height) {
mWidth = width;
mHeight = height;
mScale = Math.max(width, height) / 20f;
backgroundShader.begin();
backgroundShader.setUniformf("resolution", width, height);
backgroundShader.end();
}
This is probably happening because the viewport you are using, which is usually set in the constructor or the create method.
What is a viewport?
Basically, a viewport is an object that is created to define the policy of how the game will be drawn on different screens. E.g., say your camera is set to be 480 x 800 (pixels). What happens if your game is running on a screen that has a different ratio, for instance, the iPhone 5 that has a screen of 1,136 × 640 pixels? Should the game be stretched? Should the image be cropped? Or should libgdx add black bars on either side to fit the camera size you are using? This decision is made by the viewport your camera is using.
This is it in a nutshell. It is highly recommended to read more on this on the wiki.
Additionally, a good tutorial on this subject can be found here.
Related
I'm making a game on both desktop and android and the same code results in two different screens (cam.zoom is the same in both):
The desired result is the left screen and the code used to render is like so: (the image is 8000x4000 and is a place holder for my map)
public class MainMenuScreen implements Screen {
private final Application application;
private SpriteBatch batch;
private ShapeRenderer sr;
private OrthographicCamera cam;
private Viewport viewport;
private Button startGame;
private Texture background = new Texture(Gdx.files.internal("background.jpg"));
public MainMenuScreen(final Application application) {
this.application = application;
cam = new OrthographicCamera(WIDTH, HEIGHT);
viewport = new FitViewport(WIDTH, HEIGHT, cam);
batch = this.application.batch;
sr = this.application.sr;
startGame = new Button(-50, -25, 100, 50);
startGame.setColour(new Color(0.01f, 0.35f, 0.47f, 1));
startGame.setText("Start game", this.application.font);
startGame.setHasBorder(true);
startGame.setBorderThickness(3);
startGame.setBorderColour(new Color(0.02f, 0.62f, 0.79f, 1));
startGame.setTextColour(new Color(0.02f, 0.62f, 0.79f, 1));
}
public void update() {
Vector2 mousePos = Extras.getMousePos(viewport);
if (startGame.isClickedOn(mousePos)) {
}
}
#Override
public void render(float delta) {
ScreenUtils.clear(0, 0, 0, 1);
batch.setProjectionMatrix(cam.combined);
sr.setProjectionMatrix(cam.combined);
update();
batch.begin();
batch.draw(background, -background.getWidth() / 2, -background.getHeight() / 2);
batch.end();
startGame.render(this.sr, this.batch);
}
How do I make sure all different devices have the same zoom in the camera?
A possible solution I don't know how to implement yet could be setting cam.zoom to a value dependent on the screen size somehow but there has to be a better way for this using libGDX itself.
First, are you trying to make the button size's same on all device's screen resolution? or you want to make camera zooming have same value?
Ok, How the variable WIDTH and HEIGHT was declared?if you have declared both with one spesific size. Its will be not same if you're trying in another resolutions.
EXAMPLE:
//Constant Spesific Value of WIDTH and HEIGHT Size.
public static final int WIDTH = 1280, HEIGHT = 720;
///////////////////////////////////////////////////
//Non-Constant Value of WIDTH and HEIGHT Size.
public static int WIDTH, HEIGHT;
...
//Define Both In Main.class
public MainGameScreen(){
WIDTH = Gdx.graphics.getWidth();
HEIGHT = Gdx.graphics.getHeight();
}
However, LibGDX's screen resolution can be calculated. Some object size in your game must be spesific, when calculating the size between both WIDTH and HEIGHT you need to know, how the size will be same in all device with one spesific calculation.
EXAMPLE:
/* Button (256x72) in Screen Resolution (1280x720)
Button (160x48) in Screen Resolution (800x480) */
startGame = new Button(0,0, WIDTH/5, HEIGHT/10);
//Button (400x100) in All Screen (Constant Value)
startGame = new Button(0,0, 400, 100);
So, i suggest you to make a calculation to sizing some objects in your game. Because its will be different if you trying to make value in constant.
Ok, the next is, OrthographicCamera Which you want to make same value of zoom right? the cam.zoom is a floating value. Its not a constant value, but it was a variable value that can be changed in all time.
You can trying this code, if you want to zoom camera directly on game
if(Gdx.input.isTouched()){
//Zoom Out
cam.zoom += Gdx.graphics.getDeltaTime();
//Zoom In
cam.zoom -= Gdx.graphics.getDeltaTime();
}
Or if you talking about static-zoom, in a spesific value (not directly changed)
cam.zoom = 1f; //for 1 value of Zoom Out
I hope you understand what i means and im sorry if my answers can't be helpful for you, cause im still learning too, all about LibGDX.
#Alf Equilfe was the one who helped me get to it with his answer and here is the actual solution:
Set WIDTH, HEIGHT to a constant value independent of device size (make it so that any device can handle the size, in my case i chose 1024, 512) and make the aspect ratio the scale so it looks same on all devices.
I have been working on this for 2 days and still cant figure out what is going on. I am working on a Game Framework and i have migrated from Slick2D to LibGDX and would like to render once to a texture as to save CPU/GPU cycles and improve performance. I have created a class called DrawSurface and its main goal is to allow me to draw to a offscreen texture and then just draw that using LibGDXs Built in Image class.
public final class DrawSurface {
public static interface DrawCall{
void draw(SpriteBatch b, int width, int height);
}
public static Texture offscreenDraw(DrawCall c, int canvasWidth, int canvasHeight){
FrameBuffer fbo = new FrameBuffer(Pixmap.Format.RGBA8888,(canvasWidth),(canvasHeight),true);
SpriteBatch batch = new SpriteBatch();
batch.setProjectionMatrix(new Matrix4().setToOrtho2D(0,0,fbo.getWidth(),fbo.getHeight()));
fbo.begin();
batch.begin();
c.draw(batch,fbo.getWidth(),fbo.getHeight());
batch.end();
Pixmap map = ScreenUtils.getFrameBufferPixmap(0,0,fbo.getWidth(),fbo.getHeight());
fbo.end();
Texture t = new Texture(map);
map.dispose();
return t;
}
}
Which Gives me This Result When Drawing Images:
The "DrawCall" that is used to get this image is:
Texture t = DrawSurface.offscreenDraw(new DrawSurface.DrawCall() {
#Override
public void draw(SpriteBatch b, int w, int h) {
Image img = new Image(0x0000FF,w,h);
img.setLocation(0,0);
img.draw(b);
for(int i = 0; i < w; i += 64){
for(int j = 0; j < h; j += 64){
Blocks.GRASS_BLOCK.setLocation(i,j);
Blocks.GRASS_BLOCK.draw(b);
}
}
}
},512,512);
The Image should Render as a blue Square 512x512 pixels in size, with small "Grass" block images that should also be square. Sized 16x16. Unfortunately i get a warped result, and i do not understand why. As the Large White thing (a software JoyStick i created) is not stretched while the "DrawsSurface" is. If you would like a look at my camera code:
// Constructor Above.
this.gameWidth = gameWidth;
this.gameHeight = gameHeight;
this.camera = new OrthographicCamera();
FlatPixelGame.gameCamera = this.camera;
this.viewport = new StretchViewport(gameWidth,gameHeight,camera);
this.viewport.apply();
LogBot.log("Game Instance Created Size [%s,%s]",gameWidth,gameHeight);
InputManager.getInstance().addListener(this);
this.camera.position.set(camera.viewportWidth / 2, camera.viewportHeight / 2, 0);
Any Help Would Be Appreciated, i have scoured Forums, StackOverflow and LibGDX Documentation and still cannot seem to fix this issue.
Again, Thank you in Advance :)
After a little work under the hood with LibGDX source code from BadLogic, as well as reading bug threads it seems there is an issue when converting a PixMap to a texture. Rendering a image derived from a file works fine, but generated images that come from a Pixmap can show warping due to the off-screen view-port not being the same as the current rendering view-port.
A quick way around this is using TextureRegions and Sprites.
public static Image offscreenDraw(DrawCall c, int canvasWidth, int canvasHeight){
FrameBuffer fbo = new FrameBuffer(Pixmap.Format.RGBA8888,canvasWidth,canvasHeight,true);
SpriteBatch batch = new SpriteBatch();
Matrix4 matrix = new Matrix4();
matrix.setToOrtho2D(0, 0, canvasWidth,canvasHeight);
batch.setProjectionMatrix(matrix);
fbo.begin();
batch.begin();
c.draw(batch,canvasWidth,canvasHeight);
batch.end();
Texture t = fbo.getColorBufferTexture();
t.setFilter(Texture.TextureFilter.Nearest, Texture.TextureFilter.Nearest);
if(!t.getTextureData().isPrepared()){
t.getTextureData().prepare();
}
fbo.end();
TextureRegion r = new TextureRegion(t,0,0,canvasWidth,canvasHeight);
return new Image(new com.badlogic.gdx.scenes.scene2d.ui.Image(new Sprite(r)));
}
I am developing a game which has 480x800 VIRTUAL screen sizes. Also I render my map using TiledMapRenderer. My problem is fitting background and HUD elements into the screen which has different ratio than 480/800 (Mostly taller devices). Some devices show blank area at the bottom of screen.
//my viewport (WIDTH = 480, HEIGHT = 800)
viewport = new ScalingViewport(Scaling.fillX,MyGdxGame.WIDTH,MyGdxGame.HEIGHT,camera);
#Override
public void resize(int width, int height) {
viewport.update(width, height, true);
camera.position.set(camera.viewportWidth / 2, camera.viewportHeight / 2, 0);
barriers.getRenderer().setProjectionMatrix(viewport.getCamera().combined);
shapeRenderer.setProjectionMatrix(viewport.getCamera().combined);
}
My screen should fit the X, but background image should fit X and Y without changing the aspect ratio. In this case ScalingViewport does not solve my problem, and if I change the viewport, I have to code everything from beginning.
#Override
public void render(float delta) {
update(delta);
SpriteBatch sb = game.batch;
Gdx.gl.glClearColor(46f/255,46f/255,46f/255,1f);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
sb.setProjectionMatrix(camera.combined);
sb.begin();
//this has to change in somehow
sb.draw(AssetManager.backgroundMenu,0,0,MyGdxGame.WIDTH,MyGdxGame.HEIGHT);
sb.end();
}
Should I use multiple viewport? Or is there any way to fit my background into the screen? By the way I do not want to change my camera if there is a way.
Yes, you should use second viewport for your HUD elements.
I would recommend using ExtendViewport
ExtendViewport viewport = new ExtendViewport(MyGdxGame.WIDTH,MyGdxGame.HEIGHT);
It fills all screen (without black bars) and keeps aspect ratio for all resolutions.
I want to be able to scale my image based on the screen size. In a normal java applet I would do something like the following....
int windowWidth = 1280;
int windowHeight = 720;
Image image;
public void paint(Graphics g)
{
g.drawImage(image, x, y, windowWidth / 4, windowHeight / 16, null);
}
I've been searching for an answer for a while and everything I find seems to turn up some weird result. From what I read I might need to do something with Resolution Independent Pixels but I'm not %100 sure.
The thing I am trying to avoid is having to create a whole new set of images and icons just for different screen densities. The method I showed above works for resizing desktop apps without a problem.
Edit:
This is what I have been using to draw an image in android.
Matrix matrix = new Matrix();
Bitmap image;
Constuctor....()
{
image = BitmapFactory.decodeResource(context.getResources(), R.drawable.play);
}
public void render(Canvas c)
{
c.drawBitmap(image, matrix, null);
}
Hi see thsi question I have posted scale bitmap
If you are using canvas get the width and height of the canvas. or if you want to have it formal normal layouts then get the width and height by using
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
dispWidth=metrics.widthPixels;
dispheight=metrics.heightPixels;
and then scale our bitmap according to your requirement like this. In this I Have to have 8 bricks so I have taken the width by dividing with the Number of columns
String strwidth=String.valueOf(((float)(bmp.getWidth())/NO_COLUMNS));
if(strwidth.contains("."))
{
scalebit=Bitmap.createScaledBitmap(bmp, (int)(Math.ceil(((float)bmp.getWidth())/NO_COLUMNS))*NO_COLUMNS, bmp.getHeight(), true);
}
else
{
scalebit=bmp;
}
I'm having performance oddities with Java2D. I know of the sun.java2d.opengl VM parameter to enable 3D acceleration for 2D, but even using that has some weird issues.
Here are results of tests I ran:
Drawing a 25x18 map with 32x32 pixel tiles on a JComponent
Image 1 = .bmp format, Image 2 = A .png format
Without -Dsun.java2d.opengl=true
120 FPS using .BMP image 1
13 FPS using .PNG image 2
With -Dsun.java2d.opengl=true
12 FPS using .BMP image 1
700 FPS using .PNG image 2
Without acceleration, I'm assuming some kind of transformation is taking place with every drawImage() I do in software, and is pulling down the FPS considerably in the case of .PNG. Why though, with acceleration, would the results switch (and PNG actually performs incredibly faster)?! Craziness!
.BMP Image 1 is translated to an image type of TYPE_INT_RGB. .PNG Image 2 is translated to an image type of TYPE_CUSTOM. In order to get consistent speed with and without opengl acceleration, I have to create a new BufferedImage with an image type of TYPE_INT_ARGB, and draw Image 1 or Image 2 to this new image.
Here are the results running with that:
Without -Dsun.java2d.opengl=true
120 FPS using .BMP image 1
120 FPS using .PNG image 2
With -Dsun.java2d.opengl=true
700 FPS using .BMP image 1
700 FPS using .PNG image 2
My real question is, can I assume that TYPE_INT_ARGB will be the native image type for all systems and platforms? I'm assuming this value could be different. Is there some way for me to get the native value so that I can always create new BufferedImages for maximum performance?
Thanks in advance...
I think I found a solution by researching and putting bits and pieces together from too many Google searches.
Here it is, comments and all:
private BufferedImage toCompatibleImage(BufferedImage image)
{
// obtain the current system graphical settings
GraphicsConfiguration gfxConfig = GraphicsEnvironment.
getLocalGraphicsEnvironment().getDefaultScreenDevice().
getDefaultConfiguration();
/*
* if image is already compatible and optimized for current system
* settings, simply return it
*/
if (image.getColorModel().equals(gfxConfig.getColorModel()))
return image;
// image is not optimized, so create a new image that is
BufferedImage newImage = gfxConfig.createCompatibleImage(
image.getWidth(), image.getHeight(), image.getTransparency());
// get the graphics context of the new image to draw the old image on
Graphics2D g2d = newImage.createGraphics();
// actually draw the image and dispose of context no longer needed
g2d.drawImage(image, 0, 0, null);
g2d.dispose();
// return the new optimized image
return newImage;
}
In my previous post, GraphicsConfiguration was what held the information needed to create optimized images on a system. It seems to work pretty well, but I would have thought Java would automatically do this for you. Obviously you can't get too comfortable with Java. :) I guess I ended up answering my own question. Oh well, hopefully it'll help some of you I've seen trying to make use of Java for 2D games.
Well, this is old post but I'd like to share my findings about direct drawing with Swing/AWT, without BufferedImage.
Some kind of drawing, as 3D, are better done when painting directly to a int[] buffer. Once done the images, you can use an ImageProducer instance, like MemoryImageSource, to produce images. I'm assuming you know how to perform your drawings directly, without help of Graphics/Graphics2.
/**
* How to use MemoryImageSource to render images on JPanel
* Example by A.Borges (2015)
*/
public class MyCanvas extends JPanel implements Runnable {
public int pixel[];
public int width;
public int height;
private Image imageBuffer;
private MemoryImageSource mImageProducer;
private ColorModel cm;
private Thread thread;
public MyCanvas() {
super(true);
thread = new Thread(this, "MyCanvas Thread");
}
/**
* Call it after been visible and after resizes.
*/
public void init(){
cm = getCompatibleColorModel();
width = getWidth();
height = getHeight();
int screenSize = width * height;
if(pixel == null || pixel.length < screenSize){
pixel = new int[screenSize];
}
mImageProducer = new MemoryImageSource(width, height, cm, pixel,0, width);
mImageProducer.setAnimated(true);
mImageProducer.setFullBufferUpdates(true);
imageBuffer = Toolkit.getDefaultToolkit().createImage(mImageProducer);
if(thread.isInterrupted() || !thread.isAlive()){
thread.start();
}
}
/**
* Do your draws in here !!
* pixel is your canvas!
*/
public /* abstract */ void render(){
// rubisch draw
int[] p = pixel; // this avoid crash when resizing
if(p.length != width * height) return;
for(int x=0; x < width; x++){
for(int y=0; y<height; y++){
int color = (((x + i) % 255) & 0xFF) << 16; //red
color |= (((y + j) % 255) & 0xFF) << 8; //green
color |= (((y/2 + x/2 - j) % 255) & 0xFF) ; //blue
p[ x + y * width] = color;
}
}
i += 1;
j += 1;
}
private int i=1,j=256;
#Override
public void run() {
while (true) {
// request a JPanel re-drawing
repaint();
try {Thread.sleep(5);} catch (InterruptedException e) {}
}
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
// perform draws on pixels
render();
// ask ImageProducer to update image
mImageProducer.newPixels();
// draw it on panel
g.drawImage(this.imageBuffer, 0, 0, this);
}
/**
* Overrides ImageObserver.imageUpdate.
* Always return true, assuming that imageBuffer is ready to go when called
*/
#Override
public boolean imageUpdate(Image image, int a, int b, int c, int d, int e) {
return true;
}
}// end class
Note we need unique instance of MemoryImageSource and Image. Do not create new Image or new ImageProducer for each frames, unless you have resized your JPanel. See init() method above.
In a rendering thread, ask a repaint(). On Swing, repaint() will call the overridden paintComponent(), where it call your render() method and then ask your imageProducer to update image.
With Image done, draw it with Graphics.drawImage().
To have a compatible Image, use proper ColorModel when you create your Image. I use GraphicsConfiguration.getColorModel():
/**
* Get Best Color model available for current screen.
* #return color model
*/
protected static ColorModel getCompatibleColorModel(){
GraphicsConfiguration gfx_config = GraphicsEnvironment.
getLocalGraphicsEnvironment().getDefaultScreenDevice().
getDefaultConfiguration();
return gfx_config.getColorModel();
}
From what I remember when I was thinking about doing graphics programming in Java, the built in libraries are slow. I was advised on GameDev.Net that anyone doing anything serious would have to use something like jogl