Can I tint texture inside an actor? - java

I need to tint an item in my ShopCell (it should be black at first, and after purchase it becomes normal).
public class ShopCell extends Group {
private final float WIDTH = 100;
private final float HEIGHT = 150;
private Label label;
public ShopCell(TextureRegion itemTxt, int price) {
this.setSize(WIDTH, HEIGHT);
Image cellBg = new Image(Resource.cellBg);
cellBg.setSize(WIDTH, HEIGHT);
Image item = new Image(itemTxt);
float aspectRatio = item.getWidth()/item.getHeight();
item.setBounds(cellBg.getX() + WIDTH/2-(HEIGHT*0.3f*aspectRatio), cellBg.getY() + HEIGHT/3, HEIGHT*0.6f*aspectRatio, HEIGHT*0.6f);
label = new Label(String.valueOf(price), new Label.LabelStyle(Resource.font, Color.YELLOW));
label.setPosition(cellBg.getX() + WIDTH/2 - label.getWidth()/2, cellBg.getY() + HEIGHT/15);
this.addActor(cellBg);
this.addActor(item);
this.addActor(label);
}
I've tried to make Sprite at first, tint it like this and add it to Image:
Sprite sprite = new Sprite(itemTxt);
sprite.setColor(Color.BLACK);
Image item = new Image(sprite);
But when I do so, my texture doesn't tint.
How can I tint it and add it to the Group? And can I return its normal appearence then (for purchased items)?

Sprite class having own color so that can be tint but when you create Image from that Sprite, only TextureRegion of Sprite used for construction of new Image object.
Set color of Image instead of tinted Sprite :
Image item = new Image(itemTxt);
item.setColor(Color.BLACK);
You can also try fadeIn/Out Action on your object
image.addAction(Actions.fadeOut(2));

Related

libGDX camera zoom is different on different devices:

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.

What is the best way to read pixels of a JavaFX Canvas?

I want to get the color for specific coordinates inside a Canvas. I already tried getting a snapshot using this code:
WritableImage snap = gc.getCanvas().snapshot(null, null);
snap.getPixelReader().getArgb(x, y); //This just gets the color without assigning it.
But it just takes too much time for my application. I was wondering if there is any other way to access the color of a pixel for which I know the coordinates.
A Canvas buffers the drawing instructions prescribed by invoking the methods of a GraphicsContext. There are no pixels to read until the Canvas is rendered in a later pulse, and the internal format of the instruction buffer is not exposed in the API.
If a snapshot() of the Canvas is feasible, a rendered pixel may be examined using the resulting image's PixelReader.
int aRGB = image.getPixelReader().getArgb(x, y);
This example focuses on a single pixel. This example displays the ARGB BlendMode result in a TextField and a Tooltip as the mouse moves on the Canvas. More examples may be found here.
As an alternative, consider drawing into a BufferedImage, illustrated here, which allows access to the image's pixels directly and via its WritableRaster. Adding the following line to this complete example outputs the expected value for opaque red in ARGB order: ffff0000.
System.out.println(Integer.toHexString(bi.getRGB(50, 550)));
public class Pixel
{
private static final SnapshotParameters SP = new SnapshotParameters();
private static final WritableImage WI = new WritableImage(1, 1);
private static final PixelReader PR = WI.getPixelReader();
private Pixel()
{
}
public static int getArgb(Node n, double x, double y)
{
synchronized (WI)
{
Rectangle2D r = new Rectangle2D(x, y, 1, 1);
SP.setViewport(r);
n.snapshot(SP, WI);
return PR.getArgb(0, 0);
}
}
public static Color getColor(Node n, double x, double y)
{
synchronized (WI)
{
Rectangle2D r = new Rectangle2D(x, y, 1, 1);
SP.setViewport(r);
n.snapshot(SP, WI);
return PR.getColor(0, 0);
}
}
}

Creating a 3D shadow effect on images with itextpdf

I want to create a 3D shadow effect on images that I place in a pdf. I am using itextpdf.
The question is similar to :
Adding shadow effect on iText elements
but with images and not texts.
My images are placed in table cells. As long as the table is not completed, no way to get the actual size of the image nor its coordinates in the page, this makes it tricky.
Any brilliant id ?
Thanks and regards,
Sylvain
4 hours later, I found a way to do it using PdfCellEvent and drawing what I need inside the cell's padding.
static class ShadowRectangle implements PdfPCellEvent {
public void cellLayout(PdfPCell cell, Rectangle rect,
PdfContentByte[] canvas) {
PdfContentByte lCb = canvas[PdfPTable.LINECANVAS];
// Paddings for the border
int paddingHorizontal = 8;
int paddingVertical = 8;
// Width of the shadow
int shadowwidth = 7;
// Calculate border location and size
float left = rect.getLeft() + paddingHorizontal;
float bottom = rect.getBottom() + paddingVertical;
float width = rect.getWidth() - 2 * paddingHorizontal;
float height = rect.getHeight() - 2 * paddingVertical;
lCb.saveState();
lCb.setColorFill(BaseColor.GRAY);
// Draw the shadow at the bottom
lCb.rectangle(left + shadowwidth, bottom - shadowwidth, width, shadowwidth);
lCb.fill();
// Draw the shadow at the right
lCb.rectangle(left + width, bottom - shadowwidth, shadowwidth, height);
lCb.fill();
//lCb.setColorStroke(BaseColor.RED);
// Draw the border
//lCb.rectangle(left, bottom, width, height);
lCb.stroke();
lCb.restoreState();
}
}
// And I fill the PdfPTable this way
PdfPTable lImages = new PdfPTable(NB_PICTURE_PER_ROW);
lImages.getDefaultCell().setBorder(Rectangle.NO_BORDER);
// ... in a loop
lImageBoucle = Image.getInstance(lFile.getCanonicalPath() + File.separator + lTabPhotos[i]);
PdfPCell lCell = new PdfPCell();
lCell.setImage(lImageBoucle);
lCell.setBorder(Rectangle.NO_BORDER);
lCell.setPadding(8);
PdfPCellEvent lShadowRectangle = new ShadowRectangle();
lCell.setCellEvent(lShadowRectangle);
lImages.addCell(lCell);

Specify Animation sprites size in world units ALL AT ONCE

If I use sprites I can setup thie size and position of the sprite with reference to my game WORLD UNITS:
AtlasRegion region = textureAtlas.findRegion("0001");
sprite = new Sprite(region);
sprite.setPosition(11.5f, 5f);
sprite.setSize(7f, 7f * region.getRegionHeight() / region.getRegionWidth());
How can I achieve that with an Animation. How can I set the size of each keyframe sprite?
textureAtlas = new TextureAtlas(Gdx.files.internal("data/bycicle.atlas"));
TextureRegion[] rotateUpFrames = new TextureRegion[4];
// Create an array of TextureRegions
rotateUpFrames[0] = (textureAtlas.findRegion("0001"));
rotateUpFrames[1] = (textureAtlas.findRegion("0002"));
rotateUpFrames[2] = (textureAtlas.findRegion("0003"));
rotateUpFrames[3] = (textureAtlas.findRegion("0004"));
rotateUpAnimation = new Animation(0.1f,rotateUpFrames);
I set up an Animation subclass so I can have convenience methods to apply the scale each time the sprite is updated with a new region. For example:
public class AnimationPlus extends Animation {
float scale;
public AnimationPlus (float frameDuration,
Array<? extends TextureRegion> keyFrames, PlayMode playMode, float scale)
{
super(frameDuration, keyFrames, playMode);
this.scale = scale;
}
public void applyKeyFrameToSprite (float stateTime, Sprite sprite)
{
TextureRegion region = getKeyFrame(stateTime);
sprite.setSize(scale,
scale * region.getRegionHeight() / region.getRegionWidth());
}
}
By the way, if you name your frames of animation with underscore number suffixes (such as "bike_0", "bike_1", "bike_2", etc), then you can conveniently get the array of regions like this:
Array<TextureRegion> bikeRegions = textureAtlas.findRegions("bike");
AnimationPlus animation = new AnimationPlus(0.1f, bikeRegions, PlayMode.LOOP, 7f);

How to change the color of the background in libgdx labels?

I can change the color of the font like this
LabelStyle style1 = new LabelStyle(..some font...,
Color.valueOf("FF4500")
);
label.setStyle(style1);
but how do I change the background?
right now the background is the same as the background of whole screen which is set in
render method lke this
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
Gdx.gl.glClearColor(
1.000f, 0.980f, 0.941f
,1);
Label label = new Label(labelText, skin);
Pixmap labelColor = new Pixmap(labelWidth, labelHeight, Pixmap.Format.RGB888);
labelColor.setColor(<your-color-goes-here>);
labelColor.fill();
label.getStyle().background = new Image(new Texture(labelColor)).getDrawable();
Basically, use the getDrawable() function of the Image class to assign the color of your Label's LabelStyles' background Drawable.
This is the simplest workaround I've been able to come up with and, frankly, it's just silly that there is no setBackground() in the Label class.
Actually, maybe the easiest fix is to hack the Label class and add a setBackground() method to it.
[Edit] Be sure to dispose of Pixmaps when you are done with them; i.e. labelColor.dispose();
[Update] #Mitrakov Artem made a good point: The above solution will affect all instances of this LabelStyle. If that's not what you want you can create a new LabelStyle, use the above method on it, then save it to the Label. Quoting Artem: "So I would recommend to create a new style (LabelStyle style = new LabelStyle(label.getStyle());), change its background and then apply it to the label (label.setStyle(style);)"
Actually you do not change the background of the Lable like that. You did just change the clearcolour. Guess you know that.
To change the background you need to change the background at the style of the label. To do so i'd recommend to use a simple NinePatch as background, (can be a square! if its white you can change the colour of the ninepatch and the background colour changes!)
NinePatch temp = new NinePatch(new Texture(....), 10, 10, 10, 10); //edges
For more information about ninepatch take a look here libgdx wiki ninepatch
You need to add that ninepatch to an Skin objekt. For example like this
Skin skin = new Skin();
skin.add("background",temp)
After that you can get a drawable from the skin that you can set as background of the LabelStyle.
style1.background = skin.getDrawable("background");
see libgdx API LabelStyle
You can also use a simple bitmap but that does get scaled to the label size which causes in most of the cases deformation. A Ninepatch can be scaled without having deformation.
If you need a quick and easy solution, you can use the snippet below. It doesn't work well with multiline text because it doesn't take the text width per line into account.
Anyway, the background is automatically adjusted to the width and height of the label widget (i.e. if your text changes).
private Label label = new Label("text", createLabelStyleWithBackground());
private LabelStyle createLabelStyleWithBackground() {
LabelStyle labelStyle = new LabelStyle();
labelStyle.font = new BitmapFont();
labelStyle.fontColor = Color.WHITE;
labelStyle.background = createBackground();
return labelStyle;
}
private Drawable createBackground() {
Pixmap labelColor = new Pixmap(1, 1, Pixmap.Format.RGBA8888);
Color color = new Color(Color.GRAY);
color.a = 0.75f;
labelColor.setColor(color);
labelColor.fill();
Texture texture = new Texture(labelColor);
return new BaseDrawable() {
#Override
public void draw(Batch batch, float x, float y, float width, float height) {
GlyphLayout layout = label.getGlyphLayout();
x = label.getX();
y = label.getY() - (layout.height + 15) / 2; // +15 is some space
batch.draw(texture, x, y, layout.width, layout.height + 15);
}
};
}
here is an example with a multiline label

Categories