How to always print String at the center of the screen? - java

I am using libgdx for my game and I have a viewport of 360x630, the problem is that I am using FreetypeFont for my fonts and the size is set to 24, I don't know how many pixels is 24. So what I did is
width = Gdx.graphics.getWidth();
height = Gdx.graphics.getHeight();
font.draw(batch, wc.string, width / 2 - string.length / 2, height / 2 - string.length / 2);
but the string length is always changed because the string is always changed too.

bellow A work around I always use to center any text with changing size, I don't know if it's a good practice to add useless sciene2D table for the purpose, anyway here is the solution :
Create a table :
private Table table;
In your show/create methode ( depend on your libgdx version ... ) add the following :
table = new Table(skin); // if you have a skin or you leave it empty
table.setFillParent(true);
YourText = new Label("YourText", skin, "YourFont");
table.add(YourText).colspan(3).expandX().spaceBottom(50).row(); // you change 50 depend on your screen resolution till you get to the center
This will put your text in a cell/row and center it H/V depend on the screen of course.
In the create/show method dont forget to add the table to the stage :
stage.addActor(table);
Now in your render method your add the following:
stage.act(delta);
stage.draw();
Finally you have to dispose the stage because the GC don't do it for you ( a libgdx way to do GC stuff ), in your dispose method you add this :
stage.dispose();

Related

LibGdx Label text wrap bug?

I use a Label with text wrap enabled. In this case, the text wraps wrong. The text wraps into 3 lines, when it should be only 2 and the Label size only reflects the 2 lines. I debugged through the code and found the reason for this to be in the Label.layout() method. Not sure if this is a bug or if I am doing something wrong.
In the code below you can see that the text is set twice to the GlyphLayout. The first time it wraps correct, the second time we use the reduced width and it wraps into more lines as before. I think the second time we set the text into the GlyphLayout, the same width should be used.
public class Label extends Widget {
public void layout () {
...
float width = getWidth(), height = getHeight();
...
GlyphLayout layout = this.layout;
float textWidth, textHeight;
if (wrap || text.indexOf("\n") != -1) {
// Set the text into the GlyphLayout. The text is wrapped correctly here
layout.setText(font, text, 0, text.length, Color.WHITE, width, lineAlign, wrap, ellipsis);
textWidth = layout.width;
textHeight = layout.height;
...
} else {
textWidth = width;
textHeight = font.getData().capHeight;
}
...
// Set the text again into the GlyphLayout. This time with the width that we got when we set it the first time
// This time the text is wrapped wrong as it uses less width as it should
layout.setText(font, text, 0, text.length, Color.WHITE, textWidth, lineAlign, wrap, ellipsis);
...
}
}
Make sure to invalidate() the label and then pack() the label so it calculates any new preferred sizes; this may or may not fix the problem.
Looking at the source code of Label then you can see that the last invocation of layout.setText() is always invoked regardless of text wrapping or not.
The previous layout.setText() invocation is used to set the textWidth and textHeight for the later call where those values are actually used.
If wrapping is on or there is a newline character then the width and height is set to that of the label and if it is off then the width is set to the actual text width and the height set to the font data height.
From the above, another problem that may be causing this to happen is if you have scaled the font and/or label. The scaling factor is not being applied from within Label.layout() which may cause the label size to be that of 2 lines whilst the actual text is 3 lines as the width doesn't allow for overflow with wrapping set to on.
If all else fails, I would ensure that your font files are correct and that there are not any characters or data in your text that may cause a new line to occur.
I would also suggest to use another font of the same glyph width and height and see if the problem persists. If it does not then at least you know it is a problem relating to the font and not the label.
Hope this helped you.
This issue has been solved in libgdx 1.9.12

screenshot image from vtkRenderWindow without borders

I tried everything I found to save just my image without borders without success.
My image is 124x126, so when the image is saved it's always with borders and new size 300x300, If I use another program to select only my image it's 208x209.
so I don't know why my image is scaled and why it's always 300x300, If I change the size of vtkRenderWindow to 124x126 the borders are still there and my image is shrunk.
My question is how I can save my image of 124x126 without borders?
mapper.SetInputConnection(polyDataReader.GetOutputPort());
vtkActor actor = new vtkActor();
actor.SetMapper(mapper);
actor.GetBounds(bounds);
System.out.println("actor: " + bounds[1] + " x " + bounds[3]); // 124x126 (everything's ok)
//Create a renderer, render window, and interactor
vtkRenderer renderer = new vtkRenderer();
vtkRenderWindow renderWindow = new vtkRenderWindow();
renderWindow.BordersOff(); // the borders are still there
renderWindow.AddRenderer(renderer);
vtkRenderWindowInteractor renderWindowInteractor = new vtkRenderWindowInteractor();
renderWindowInteractor.SetRenderWindow(renderWindow);
//Add the actor to the scene
renderer.AddActor(actor);
renderer.SetBackground(0, 0, 0);
//Render and interact
renderWindow.Render();
//screenshot code:
vtkWindowToImageFilter w2if = new vtkWindowToImageFilter();
w2if.SetInput(renderWindow);
w2if.Update();
vtkPNGWriter writer = new vtkPNGWriter();
writer.SetFileName("out.png"); //my image with borders 300x300 !!!!??
writer.SetInputData(w2if.GetOutput());
writer.Write();
ps: sorry for my English
It is because your renderwindow has the default size of 300x300.
What you have to realize is that the polydata is rendered in a 3D scene, and what you call "borders" is the background, the amount of which depends on the zoom level, i.e. on your camera's position. To get what you want, you need to do two things:
Resize renderwindow to desired image size:
renderWindow.SetSize(bounds[1], bounds[3]);
Reposition camera so that the actor fills the viewport completely. Try
renderer.GetActiveCamera().SetParallelScale(1); // we want parallel projection
renderer.GetActiveCamera().SetParallelScale(0.5 * (bounds[3] - bounds[2])); // zoom
The bounds in zoom may be 0.5 * (bounds[1] - bounds[0]), not exactly sure which side of the rectangle it should be.
Hope this helps,
Miro

How to center actors in a group with Scene2d and LibGDX?

I'm using LibGDX and Scene2d and I want to create a pop-up that looks like the one shown in the image below.
So far, I created a table and set the background to a semitransparent color. Then I created an image with a white background. This image expands x, so it is centered. Now I want to have a label centered inside the image. To overlay these two actors, I created a group, but I couldn't find out how to center something in a group. How can I do this?
Here is my code:
Table table = new Table();
table.top();
table.setFillParent(true);
table.setBackground(getColoredBackground(color));
labelStyle = new Label.LabelStyle(font, fontColor);
label = new Label(message, labelStyle);
Image image = new Image(whiteBackground);
image.setSize(table.getWidth() - padding, label.getHeight() + extraHeight);
Group group = new Group();
group.setSize(image.getWidth(), image.getHeight());
group.addActor(image);
group.addActor(label);
table.add(group).expandX().padTop(padTop);
The group has it own coordinates system. It means that when you are setting actor position to (0,0) for example and then adding it to group which is actually at (100, 100) position then the object will be at (100, 100) position relative to the stage.
All you need to do is just to set:
label.setPosition( group.getWidth() / 2f - label.getWidth() / 2f, group.getHeight() / 2f - label.getHeight() / 2f );
after setting Group size. Remember that setting actor's position we are defining its left bottom corner position and that's why you need to also subtract the half of label width/height.
Of course you can modify the y position it doesn't have to be centered vertically also

LibGdx How to repeat background?

Few days ago I figured out how to do some scrolling in LibGdx. Now I'm triying to do something related. I want to repeat the background. My scrolling follows a ship (Is an s[ace ship game). In the background there is a space photo loaded as a Texture. When the ship reach the end of the backgorund, It keeps going and there's no background anymore. I have read about wrap but I don't really understand How It works. I did that:
px=new Pixmap(Gdx.files.internal("fondo.jpg"));
background=new Texture(px);
background.setWrap(TextureWrap.Repeat, TextureWrap.Repeat);
And then, in my render method
spriteBatch.begin();
spriteBatch.draw(background,0,0,500,50);
drawShip();
spriteBatch.end();
Of course It doesn't work, It only draws the background once. I don't know how make this wrap method work. Any help?
SOLUTION
I figured It out. It's not a nice code but It works.
First I declare two Textures with the same image
bck1=new Texture(Gdx.files.internal("fondo.jpg"));
bck2=new Texture(Gdx.files.internal("fondo.jpg"));
Also I declare two variables like this to specify the X value of the position of each bck
int posXBck1=0,posXBck2=0;
Then I use that in Render()
public void calculoPosicionFondos(){
posXBck2=posXBck1+ANCHODEFONDO;
if(cam.position.x>=posXBck2+cam.viewportWidth/2){
posXBck1=posXBck2;
}
}
Where:
ANCHODEFONDO is the width of my background
Cam is an OtrhoCam.
So I said that if the cam is in bck2 (wich means that you can't see bck1 anymore) It change positions, giving bck1 de position of bck2 and, in the next render loop, recalculating bck2
Then just paint both bck in your render mode.
Like Teitus said, do not load your texture multiple times, ever! Anyway, you where on the right track with the wrapper:
texture.setWrap(TextureWrap.Repeat, TextureWrap.Repeat);
Now you can just use the draw method with the source location. The source location is the area you choose to draw on the texture.
batch.draw(texture, x, y, srcX, srcY, srcWidth, srcHeight)
To scroll your texture from right to left all you have to do is increase srcX incrementally. So create a int that increments in the update/render method.
int sourceX = 0;
//render() method
//Increment the variable where to draw from on the image.
sourceX += 10;
//Simply draw it using that variable in the srcX.
batch.draw(YourTexture, 0, 0, sourceX, 0, screenWidth, screenHeight);
Because you are wrapping the texture it will wrap/loop and scroll indefinitely. There might be a issue with the sourceX int if the game runs for a very long time because a int can only hold 2147483647. It takes a while but you can fix it by subtracting the image width each time the number goes over the total image width.
Don't to this, please:
bck1=new Texture(Gdx.files.internal("fondo.jpg"));
bck2=new Texture(Gdx.files.internal("fondo.jpg"));
That will load your big background texture twice. That's a complete waste. If you want to keep your solution at least do:
bck1=new Texture(Gdx.files.internal("fondo.jpg"));
bck2=bkg1;
Regarding the texture Wrapping. If your texture is 500px wide, and you draw a 500px sprite, you won't see any repetition. If you want it repeated 2 times, draw it 1000px wide with 0-2 texture coordinates.
I'm not sure how spriteBatch handles the call you posted, you could try that one, or may be use the overload that uses a texture region and set your region manually.
I see this is a pretty old question, but I think there is an easier way to accomplish background scrolling. Just use the Sprite class. Here is a snippet I use for layered background images that scroll from right to left.
public class LevelLayer
{
public float speedScalar = 1;
private List<Sprite> backgroundSprites = new ArrayList<Sprite>();
public LevelLayer()
{
}
public void addSpriteLayer(Texture texture, float startingPointX, float y, int repeats)
{
for (int k = 0; k < repeats; k++)
{
Sprite s = new Sprite(texture);
s.setX(startingPointX + (k*texture.getWidth()));
s.setY(y);
backgroundSprites.add(s);
}
}
public void render(SpriteBatch spriteBatch, float speed)
{
for (Sprite s : backgroundSprites)
{
float delta = s.getX() - (speed * speedScalar);
s.setX(delta);
s.draw(spriteBatch);
}
}
}
Then you can use the same texture or series of textures like so:
someLayer.addSpriteLayer(sideWalkTexture1, 0, 0, 15);
someLayer.addSpriteLayer(sideWalkTexture2, 15 * sideWalkTexture1.getWidth(), 0, 7);
I change background repeating sections randomly in code and make new ones or reset existing sets when they go off screen. All the layers go to a pool and get pulled randomly when a new one is needed.
SOLUTION
I figured It out. It's not a nice code but It works.
First I declare two Textures with the same image
bck1=new Texture(Gdx.files.internal("fondo.jpg"));
bck2=new Texture(Gdx.files.internal("fondo.jpg"));
Also I declare two variables like this to specify the X value of the position of each bck
int posXBck1=0,posXBck2=0;
Then I use that in Render()
public void calculoPosicionFondos(){
posXBck2=posXBck1+ANCHODEFONDO;
if(cam.position.x>=posXBck2+cam.viewportWidth/2){
posXBck1=posXBck2;
}
}
Where:
ANCHODEFONDO is the width of my background
Cam is an OtrhoCam.
So I said that if the cam is in bck2 (wich means that you can't see bck1 anymore) It change positions, giving bck1 de position of bck2 and, in the next render loop, recalculating bck2
Then just draw both bck in your render()

Create a margins editor component like the one in Microsoft word

I have a Java Swing application that i want to create a nice component in it like a component in Microsoft word. In Microsoft word you can change the margins of your document like in here :
The trick here is that if you change the Top margins to (Let's say) 1.5" then the Preview image will change to show this, so the lines will move down a bit in the image to show that change in the margins so the user can feel how much his document will be affected by this change. So for example if i change the left margin to (4.0") the image will look like this :
What i did is create 2 images a blank page image + another image that contains lines only(Lines image), like these 2 images :
I inserted each image in a JLabel above each other, and now when i change the JSpinner top margin value, i keep the "blank page" image fixed, but i change the border of the "lines image" to move it down a bit. The trick worked fine for the top margin, but the behavior goes totally wrong if i change the bottom/right/left margins.
Here is my code that i apply when changing any JSpinner value :
private void marginSpinnerStateChanged() {
//1. Get the approximate values of all margins :
int topMargin = (int)( Float.valueOf( topSpinner.getValue().toString() ) * 8 );
int bottomMargin = (int)( Float.valueOf( bottomSpinner.getValue().toString() ) * 8 );
int leftMargin = (int)( Float.valueOf( leftSpinner.getValue().toString() ) * 8 );
int rightMargin = (int)( Float.valueOf( rightSpinner.getValue().toString() ) * 8 );
//2. Apply all specified margins to the lines label :
linesLabel.setBorder( new EmptyBorder( topMargin, leftMargin, bottomMargin, rightMargin ) );
}
Can you help me continue this to work right ?
You could just draw the image on top of the paper and scale the image as you go. So you would override the paintComponent() method of a JComponent to do something like:
g.drawImage(image, x, y, width, height, null);
x - would be the left margin
y - would be the top margin
width - would be (maxWidth - leftMargin - rightMargin)
height - would be (maxHeight - topMargin - bottomMargin)
If you don't like scaling the image you can always use a BufferedImage and then use the getSubImage(...) method to get an image the desired size to be painted.
If you notice, they don't shift the textual image. Instead, they only show half of it. This is simple image manipulation. For a good example, see this.

Categories

Resources