I am trying to make a space look to my game and wanted to add stars to the background. I decided to make a float[] points and make it randomized. I then use the canvas.drawPoints(points, white);. This works very well on my emulator. On a phone, you can barely see the points. I am wondering if I can have points bigger than a pixel (I know that makes no sense) or use a method like drawRects(points, size, paint);. Using a for loop is not efficient and makes the game laggy. Is there another way or do I have to live with the lag.
Thanks!
It is related to different densities of your emulator and phone.
1 px on different screens have different physical size. You should use dp (dip or density independent pixels) and then convert it to the pixels.
So your code should look like:
ind dpRadius = 1;
Resources r = getResources();
float pxRadius = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpRadius, r.getDisplayMetrics());
Paint paint = new Paint();
paint.setColor(Color.BLUE);
paint.setStrokeWidth(pxRadius);
paint.setStyle(Paint.Style.STROKE);
// your drawPoints code ...
Related
first of all I have scoured Google and SO for this answer, finding only how to change the actual pixels to be of a certain alpha value, which would be incredibly slow or actually making a part of the BufferedImage completely transparent via the use of lwg2.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR)). This is the exact functionality I need, however, I need to have the value to be less than 1f, which you cannot do with this specific instance of AlphaComposite.CLEAR.
What I want this implementation for is to make a wall inside my 2.5d game become transparent when the player goes behind it, like so:
The logic behind my game is that the terrain is one BufferedImage which is only updated when called, and then having the rest of the walls, etc, being drawn onto another BufferedImage where entities are also drawn, so the opacity transformation would only affect the trees (or walls).
This is the code I am using atm, but as I said I don't want the circle that I am drawing to make a part of the image completely transparent, but only slightly (about 50%):
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR, 0.5f));
g2.fillOval(x - (int) (TILE_WIDTH * 1), y - (int) (TILE_HEIGHT * 1.5), TILE_WIDTH * 2, TILE_HEIGHT * 3);
(The 0.5f in the AlphaComposite constructor does nothing).
The reason I need this to be efficient is because I am updating this image 30 times a second, so efficiency > quality.
So, I ended up solving the issue by not manipulating the image directly via making a part of the image translucent, but manipulating the opacity of the images I am drawing with. As #user343760 and #NESPowerGlove mentioned, I could just make the assets I am using translucent when the player is behind it. Since I am using a underlying grid array to back my game, I could do this by working out if the tile.x - 1 == (int) player.x and tile.y - 1== (int) player.y. In isometry, this meant that the player was on the tile directly above it in our perspective. Then I had to solve the issue if the wall.z is bigger than 0 or 1, hence having the problem where a tile 5 blocks "bellow" the player could obstruct him if the walls extended z = 5 above the tile. For this problem, I implemented the following solution:
for(int i = 0; i < wall.getAsset(1f).getHeight()/TILE_HEIGHT; i++) {
if((tile.x - i - wall.z == (int) world.player.getX() && tile.y - i -wall.z == (int) world.player.getY())) {
lwg2.drawImage(wall.getAsset(0.5f), x, y, this);
}
}
This also ensures that the image is transparent even if the player is "above" the tile "above" the tile where the wall is situated, in terms of the image extending above that limit. I have fixed this via using the for loop which looks above for i number of times, depending on the image.height/tile_height, which is an universal constant.
If you require to make a part of the image transparent, I have not found solutions which would work fault free, except for manipulating the pixels in the low-levels of BufferedImage. If you also want to erase a part of an image directly, use the code g2.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR)); and draw as you would normally. Remember to switch back to a normal composite via g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER));.
You could also draw with a certain opacity in the first place using the Composite g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, opacity));, where opacity is a float with values from 0f to 1f, 0f being completely transparent and 1f being completely opaque.
I hope this helped anyone out there. If you find a better way of doing this, please leave a comment for future readers.
This is what my solution looks like :):
I am trying to follow along with the guide on here and learn LibGdx.
http://www.kilobolt.com/day-4-gameworld-and-gamerenderer-and-the-orthographic-camera.html
Here's the author's code for setting the width and height of the orthographic camera(camera used to project the 3d stuff all evenly into 2d?
private OrthographicCamera cam;
and later in a constructor
cam = new OrthographicCamera();
cam.setToOrtho(true, 136, 204);
Is there a reason why he choose to hardcode the width and height and not retrieve the height and width of the screen the game is being run on via Gdx.graphics.getWidth/getHeight?
(-from Changing the Coordinate System in LibGDX (Java))
You didn't understand how camera behaves. It doesn't matter if screen is 320x480 or 1080*1920 for camera. Camera uses own coordinate system. For example we have 1920*1080 screen. We DON'T wanna use pixels because it's bad practice. What we really want is to have own coordinate system of our world. If you have world 16*9 m then you can calculate that 1 m = 120 pixels. But your friend can have 800*450 screen and for him 1 m = 50 pixels. That's why we hardcode camera's width and height. But there is another problem here, the ratio. We considered that our ratio is 16/9 but some devices can have 4/3 ratio. Supporting a lot of ratios is very complex theme so i don't wanna mention it here.
Screenshots on different ratios of my game
If you want i can share with you my code. But note it isn't perfect and it's not complete game. And as you can see from screenshots i didn't hardcode height, only width. So i have empty space up and down.
If anyone is still struggling with this, I suggest reading into part 5, where the author explains how
"we are going to assume that the width of the game is always 136. The height will be dynamically determined! We will calculate our device's screen resolution and determine how tall the game should be."
I know this question has been accessed before (like here), but I was wondering how to do the following. In my game, I have a scrolling background. There is for example a blue sky that is light blue at the bottom and gets darker the higher you go. This is not really possible with the suggested solution:
shapeRenderer.filledRect(x, y, width, height,
lightBlue, lightBlue, darkBlue, darkBlue);
since you can only give the colors that really will be shown. I would like to have a gradientPaint with at the top darkblue and the bottom lightblue that stretches out over for example 500 pixels. This, while I only draw only 200 pixels of it. With this, the color would still get darker when the background scrolls. Does anybody know how to do this with libgdx?
What you want is to see a smaller (say 200 pixel) window onto a larger (say 500 pixel) gradient. To do that you just need to compute the colors of four corners colors based on the location of your window in the overall gradient, and then draw just that. (So don't think about drawing the entire background, but about figuring out how to draw just the part that you need.)
Since you're just moving smoothly between the two colors (between 0 and 500), you're doing a "linear interpolation" (that is a straight-line estimation) between the colors based on where the Window is. Libgdx supports this via the lerp() methods on Color.
Assuming the window is travelling along the Y axis, something like this should give what you want:
Color baseColor = lightBlue;
Color topColor = darkBlue;
int skyHeight = 500;
int windowHeight = 200;
int windowLocation = ...; // something betweeen 0 and skyHeight - windowHeight;
Color windowBottomColor = baseColor.copy().lerp(topColor, windowLocation / skyHeight);
Color windowTopColor = baseColor.copy().lerp(topColor, (windowLocation + windowHeight) / skyHeight);
Now windowBottomColor and windowTopColor should be suitable for calling filledRect:
shapeRenderer.filledRect(x, y, width, height,
windowBottomColor, windowBottomColor, windowTopColor, windowTopColor);
Note that the "copy()" calls create a new Color object for each invocation, so you might want to optimize that to avoid the allocation.
Disclaimer: I haven't tried this code, so it probably has some stupid bugs in it, but hopefully it gives you the right idea.
is there a way to combine a number of textures into one texture with libgdx API?
For example, consider having these 3 textures:
Texture texture1 = new Texture("texture1.png");
Texture texture2 = new Texture("texture2.png");
Texture texture3 = new Texture("texture3.png");
The goal is to combine them into one usable texture, is there a way to do it?
I wanted to get the same result, but I did not find the previous instructions given to be of any help. Neither I was able to find any other clear solution for this issue, so here's what I managed to get working after I read a bit of api-docs and did some testing of my own.
Texture splashTexture = new Texture("texture1.png"); // Remember to dispose
splashTexture.getTextureData().prepare(); // The api-doc says this is needed
Pixmap splashpixmap = splashTexture.getTextureData().consumePixmap(); // Strange name, but gives the pixmap of the texture. Remember to dispose this also
Pixmap pixmap = new Pixmap(splashTexture.getWidth(), splashTexture.getHeight(), Format.RGBA8888); // Remember to dispose
// We want the center point coordinates of the image region as the circle origo is at the center and drawn by the radius
int x = (int) (splashTexture.getWidth() / 2f);
int y = (int) (splashTexture.getHeight() / 2f);
int radius = (int) (splashTexture.getWidth() / 2f - 5); // -5 just to leave a small margin in my picture
pixmap.setColor(Color.ORANGE);
pixmap.fillCircle(x, y, radius);
// Draws the texture on the background shape (orange circle)
pixmap.drawPixmap(splashpixmap, 0, 0);
// TADA! New combined texture
this.splashImage = new Texture(pixmap); // Not sure if needed, but may be needed to get disposed as well when it's no longer needed
// These are not needed anymore
pixmap.dispose();
splashpixmap.dispose();
splashTexture.dispose();
Then use the splashImage (which is a class variable of type Texture in my case) to render the combined image where you want it. The resulting image has the given background and the foreground is a png image which has transparent parts to be filled by the background color.
#Ville Myrskyneva's answer works, but it doesn't entirely show how to combine 2 or more textures. I made a Utility method that takes 2 textures as input and returns a combined texture. Note that the second texture will always be drawn on top of the first one.
public static Texture combineTextures(Texture texture1, Texture texture2) {
texture1.getTextureData().prepare();
Pixmap pixmap1 = texture1.getTextureData().consumePixmap();
texture2.getTextureData().prepare();
Pixmap pixmap2 = texture2.getTextureData().consumePixmap();
pixmap1.drawPixmap(pixmap2, 0, 0);
Texture textureResult = new Texture(pixmap1);
pixmap1.dispose();
pixmap2.dispose();
return textureResult;
}
You should use the TexturePacker for creating one big Texture from lots of small one. https://github.com/libgdx/libgdx/wiki/Texture-packer .
And here is GUI version (jar) whcih will help you to pack all your textures in one before putting them to your project: https://code.google.com/p/libgdx-texturepacker-gui/.
You should also remember that maximum size of one texture for most Android and IOS devices is: 2048x2048.
In case you want to use combined texture as atlas for performance benefits, you better use #Alon Zilberman answer.
But I think that your question is about another problem. If you want to get some custom texture from these three textures (e.g. merge them by drawing one at one), then your best solution is to draw to FrameBuffer. Here you can find nice example of how to do it https://stackoverflow.com/a/7632680/3802890
I am using the animation class to make a simple animation, with only 2 frames.
With animation, i can get the index, or texture region at the current time.
if (!animation.isAnimationFinished(time))
time += Gdx.graphics.getDeltaTime();
else
time = 0;
But the problem is, that I can't load any texture, its width and height must be a power of 2, so i got a big 1024x1024 texture, that has the 2 images.
With sprite.setTexture() i can only put a Texture, but animation.getframe returns a texture region.
Is there a way to change the sprite texture with an animation?
Also
sprite.setTexture(animation.getKeyFrame(time).getTexture());
Does not work.
This works
sprite = new Sprite(animation.getKeyFrame(time));
But I don't think is the best idea... I think is slow can can make bugs.
You usually use TextureRegion for sprites. The method that you are looking for is TextureRegion#setRegion (Sprite extends TextureRegion).
Like this:
sprite.setRegion(animation.getKeyFrame(time));