I use libgdx's scene2d built-in UI library to make an UI in my game. I'm interesting how can I draw 2 images(or actors) in a table one on another? I'm looking to the similar like LayerDrawable in Android. Is there any exists stuff to make it?
There is a Stack widget in libGDX UI library for these purposes.
UPDATE: if you want to place one widget on top of another widget and these widgets have different size then you should wrap the smaller widget. Something like:
//First add actual content
stack.add(content);
//Second add wrapped overlay object
Table overlay = new Table();
overlay.add(overlayWidget).expand().fillX().bottom().left();
stack.add(overlay);
stack variable is a Stack instance
It's an actual excerpt from my project. You should tune it for your case.
You can use somethings like this :
//create stage
stage = new Stage(new StretchViewport(game.width, game.height));
//create table
Table table = new Table();
table.setSize(game.width,game.height); //fullscreen
//add Image 1
table.add(new Image(game.skin.getDrawable("image1")));
//add Image 2 (create new col)
table.add(new Image(game.skin.getDrawable("image2"))).width(xx).height(xx);
//add new row
table.row();
//add Image 3 - padding to draw over image1/2 && colspan
table.add(new Image(game.skin.getDrawable("image3"))).width(xx).height(xx).padTop(-50f).colspan(2);
//add table to stage
stage.addActor(table);
/*
* Add action
*
*/
#Override
public void render(float delta) {
...
//don't forget to draw ur stage
stage.act(delta); // or stage.act(Gdx.graphics.getDeltaTime())
stage.draw();
}
Also you can add action to stage/table or image etc ... :
stage.addAction(Actions.sequence(
Actions.fadeOut(0.0001f),
Actions.fadeIn(0.5f),
Actions.delay(0.1f),
Actions.run(new Runnable() {
#Override
public void run() {
//mmmm new screen
dispose();
game.setScreen(new BoobsScreen(game));
}
})));
Of course you can draw more than image : button, textbutton, label etc or add scrollPane for Table but before take a look at Skin on libgdx
For exemple a programmatically ninepatch textbutton :
private NinePatch processNinePatchFile(String fname) {
final Texture t = new Texture(Gdx.files.internal(fname));
final int width = t.getWidth() - 2;
final int height = t.getHeight() - 2;
return new NinePatch(new TextureRegion(t, 1, 1, width, height), 3, 3, 3, 3);
}
//create skin
skin = new Skin();
...
//create font
...
//create ninepatch button from android/assets/style/button
NinePatch ninepatch = processNinePatchFile("style/button.9.png");
skin.add("button.9", ninepatch);
//create textbuttonstyle
TextButton.TextButtonStyle textButtonStyle = new TextButton.TextButtonStyle();
textButtonStyle.font = skin.getFont("font_black_38");
textButtonStyle.fontColor = Color.DARK_GRAY;
textButtonStyle.up = skin.getDrawable("button.9");
skin.add("buttonTextStyle", textButtonStyle);
//now you can create textbutton
TextButton btn = new TextButton("Hello", game.skin.get("buttonTextStyle", TextButton.TextButtonStyle.class));
//add a clicklistener
btn.addListener(new ClickListener(){
#Override
public void clicked(InputEvent event, float x, float y) {
//mmmmmm add action for exemple
stage.addAction(Actions.sequence(Actions.fadeOut(0.5f), Actions.run(new Runnable() {
#Override
public void run() {
//dispose and load screen
dispose();
game.setScreen(new MoreBoobsScreen(game));
}
})));
}
});
table.add(btn);
To create bitmapfont take a look at Gdx freetype, it's really easy to use.
Related
I want to display many text input fields with libgdx (like for example
Name, Surname, email) where the user has to input those info.
I've tried following this https://github.com/libgdx/libgdx/wiki/Simple-text-input but it's not the best option in my case both because I want it to be included in the main window instead of opening a new little one and because it displays only one text input field.
Moreover i want to be able to make those fields appear at random position on the main window.
You can use scene2d widget for your requirement, Create Label and TextField and add to stage. You can use Table for arrangement of your Actors.
public class Splash extends Game {
private Stage stage;
#Override
public void create() {
ExtendViewport extendViewport=new ExtendViewport(700,1200,new OrthographicCamera());
stage=new Stage(extendViewport);
Skin skin=new Skin(Gdx.files.internal("skin/uiskin.json"));
skin.get("font-label", BitmapFont.class).getRegion().getTexture().setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear);
Table table=new Table();
table.defaults().pad(10);
table.setFillParent(true);
Label userName=new Label("USER ID : ",skin);
TextField userNameField=new TextField("",skin);
Label name =new Label("NAME : ",skin);
TextField nameField=new TextField("",skin);
Label email=new Label("EMAIL : ",skin);
TextField emailField=new TextField("",skin);
table.add(userName);
table.add(userNameField).width(300);
table.row();
table.add(name).left();
table.add(nameField).width(300);
table.row();
table.add(email).left();
table.add(emailField).width(300);
stage.addActor(table);
Gdx.input.setInputProcessor(stage);
}
#Override
public void render() {
super.render();
Gdx.gl.glClearColor(0,1,1,1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
stage.draw();
stage.act();
}
#Override
public void resize(int width, int height) {
super.resize(width,height);
stage.getViewport().update(width,height);
}
#Override
public void dispose() {
stage.dispose();
}
Output looks :
I have implemented the loading screen from this example on my Loading Screen that is a child of Game. This is how my asset init method and Screen class looks like. My init method in assets loads classes that contain my AtlasRegion. I have tested that this method is what makes my screen load a black screen as it loads a lot of resources.
public void init (AssetManager assetManager) {
this.assetManager = assetManager;
// set asset manager error handler
assetManager.setErrorListener(this);
assetManager.load(Constants.TEXTURE_ATLAS_OBJECTS, TextureAtlas.class);
assetManager.load(Constants.TEXTURE_ATLAS_UI, TextureAtlas.class);
assetManager.finishLoading();
TextureAtlas atlas = assetManager.get(Constants.TEXTURE_ATLAS_OBJECTS);
TextureAtlas atlasUi = assetManager.get(Constants.TEXTURE_ATLAS_UI);
//font = new BitmapFont(Gdx.files.internal("data/font.fnt"), Gdx.files.internal("data/font.png"), false);
clickSound = Gdx.audio.newSound(Gdx.files.internal("data/sounds/click.wav"));
// create game resource objects
fonts = new AssetFonts(assetManager);
skins = new AssetSkins();
background = new AssetBackgroundImage();
cards = new AssetCards(atlas);
cardimages = new AssetImages(atlas);
cardsjson = new AssetList();
suitimages = new AssetSuitImages(atlas);
}
This is my Loading Screen class:
public class LoadingScreen extends AbstractGameScreen implements Disposable {
private Stage stage;
private Image logo;
private Image loadingFrame;
private Image loadingBarHidden;
private Image screenBg;
private Image loadingBg;
private float startX, endX;
private float percent;
private Actor loadingBar;
public LoadingScreen(CardGame game) {
super(game);
}
public InputProcessor getInputProcessor () {
return (null);
}
#Override
public void show() {
// Tell the manager to load assets for the loading screen
game.manager.load("data/images-ui/loading/loading.pack", TextureAtlas.class);
// Wait until they are finished loading
game.manager.finishLoading();
// Initialize the stage where we will place everything
stage = new Stage();
// Get our textureatlas from the manager
TextureAtlas atlas = game.manager.get("data/images-ui/loading/loading.pack", TextureAtlas.class);
// Grab the regions from the atlas and create some images
logo = new Image(atlas.findRegion("libgdx-logo"));
loadingFrame = new Image(atlas.findRegion("loading-frame"));
loadingBarHidden = new Image(atlas.findRegion("loading-bar-hidden"));
screenBg = new Image(atlas.findRegion("screen-bg"));
loadingBg = new Image(atlas.findRegion("loading-frame-bg"));
// Add the loading bar animation
Animation anim = new Animation(0.05f, atlas.findRegions("loading-bar-anim") );
anim.setPlayMode(Animation.PlayMode.LOOP_REVERSED);
loadingBar = new LoadingBar(anim);
// Or if you only need a static bar, you can do
// loadingBar = new Image(atlas.findRegion("loading-bar1"));
// Add all the actors to the stage
stage.addActor(screenBg);
stage.addActor(loadingBar);
stage.addActor(loadingBg);
stage.addActor(loadingBarHidden);
stage.addActor(loadingFrame);
stage.addActor(logo);
// Add everything to be loaded, for instance:
Assets.instance.init(game.manager);
}
#Override
public void resize(int width, int height) {
// Set our screen to always be XXX x 480 in size
//width = 480 * width / height;
//height = 480;
stage.getViewport().update(width, height, false);
// Make the background fill the screen
screenBg.setSize(width, height);
// Place the logo in the middle of the screen and 100 px up
logo.setX((width - logo.getWidth()) / 2);
logo.setY((height - logo.getHeight()) / 2 + 100);
// Place the loading frame in the middle of the screen
loadingFrame.setX((stage.getWidth() - loadingFrame.getWidth()) / 2);
loadingFrame.setY((stage.getHeight() - loadingFrame.getHeight()) / 2);
// Place the loading bar at the same spot as the frame, adjusted a few px
loadingBar.setX(loadingFrame.getX() + 15);
loadingBar.setY(loadingFrame.getY() + 5);
// Place the image that will hide the bar on top of the bar, adjusted a few px
loadingBarHidden.setX(loadingBar.getX() + 35);
loadingBarHidden.setY(loadingBar.getY() - 3);
// The start position and how far to move the hidden loading bar
startX = loadingBarHidden.getX();
endX = 440;
// The rest of the hidden bar
loadingBg.setSize(450, 50);
loadingBg.setX(loadingBarHidden.getX() + 30);
loadingBg.setY(loadingBarHidden.getY() + 3);
}
#Override
public void render(float delta) {
// Clear the screen
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
if (game.manager.update()) { // Load some, will return true if done loading
if (Gdx.input.isTouched()) { // If the screen is touched after the game is done loading, go to the main menu screen
game.setScreen(new MainMenuScreen(game));
}
}
// Interpolate the percentage to make it more smooth
percent = Interpolation.linear.apply(percent, game.manager.getProgress(), 0.1f);
// Update positions (and size) to match the percentage
loadingBarHidden.setX(startX + endX * percent);
loadingBg.setX(loadingBarHidden.getX() + 30);
loadingBg.setWidth(450 - 450 * percent);
loadingBg.invalidate();
// Show the loading screen
stage.act();
stage.draw();
}
#Override
public void pause () {}
#Override
public void resume () {}
#Override
public void hide() {
// Dispose the loading assets as we no longer need them
game.manager.unload("data/images-ui/loading/loading.pack");
}
}
I need to load the screen then load my assets on this Assets.instance.init(new AssetManager()) since it is what is causing a black screen. The problem is my screen loads after loading the assets hence this makes my loading screen to be of no use. How can I load this method after the screen has rendered?
Remove the finishLoading call from your init method. That should do it. finishLoading forces the assets to finish loading immediately which is not what you want here. Calling update on it repeatedly, which you are already doing is the way to load assets asynchronously.
Here's a general structure for how it could be done. Call all the load methods on the asset manager before it ever gets to the render method. Then call update repeatedly until everything is loaded. Then get references to the assets before continuing.
private boolean loadComplete;
public void show(){
//...
loadComplete = false;
}
private void init(AssetManager assetManager){
this.assetManager = assetManager;
assetManager.load(/*whatever*/);
assetManager.load(/*whatever*/);
assetManager.load(/*whatever*/);
}
private void onAssetsLoaded(){
loadComplete = true;
myAtlas = assetManager.get("myAtlas.json", TextureAtlas.class);
//and so on
}
public void render(float delta){
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
//load one asset at a time per frame until loading is complete
if (assetManager == null || !assetManager.update()){
//maybe draw a load screen image that's not a texture that's being managed
//by the assetManager. You could even play an animation. Otherwise,
//you can leave the screen blank.
return;
}
//will only get here when asset manager is done. The first time, you still
//need to get references to its assets
if (!loadComplete)
onAssetsLoaded();
//the rest of you render method. Everything below here only happens after assets are loaded and asset references have been aquired
}
After trying so many recommended solutions, I finally managed to fix this problem thanks to this blog post
I used a callback which displays an android framelayout with an image as the assets load asynchronously.
I have implemented a custom view in my Eclipse plugin project, where I want to display different graphs, which are selected by the user. I have no problem with creating a custom view, using org.eclipse.swt.graphics.GC and drawing the required parts but I would like to implement the following:
Inside the custom view I want to have some fixed area on the bounds of the view, where I can display the coordinate system (x- and y-axis with the corresponding labeling), which is fixed. Between these bounds I would like to display the graph, which is changing dynamically, depending on user selection.
So what I need is a custom view, that is built like the following:
Inside the grey area on the left and on the bottom I want to have the coordinate system axes (shown red) and inside the white area I want to draw the graph.
How do I create such an area inside my view? It should just be a filed, without any translations or scales, just a independend area, like a view inside a view...
#Override
public void init(IViewSite site) throws PartInitException {
super.init(site);
}
#Override
public void createPartControl(Composite parent) {
canvas = new Canvas(parent, SWT.NONE);
canvas.addPaintListener(new PaintListener() {
public void paintControl(PaintEvent e) {
drawCoordinateSystem(e);
drawGraph(e);
});
public void drawCoordinateSystem(PaintEvent e) {
// 1. create area inside view
// 2. draw coordinate system
}
public void drawGraph() {
// 3. draw graph
}
I know how to solve point 2 and 3. But I don't know, how to create such an area inside my view.
I would appreciate any help!
I would suggest that you add multiple controls and handle drawing for different cases in a different way.
For example, instead of having just one monolithic Canvas that draws everything from graph to coordinates, to helpful labels. Add a bunch of label controls on top for showing coordinates, add a parent, or labels for coordinate systems etc.
Your createPartControl should look something like below:
Composite topBar = new Composite(parent, SWT.None);
topBar.setLayout(new GridLayout(3, false));
Label title = new Label(topBar, SWT.NONE);
title.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, true, false));
Label x = new Label(topBar, SWT.NONE);
Label y = new Label(topBar, SWT.NONE);
Composite graphArea = new Composite(parent, SWT.NONE);
graphArea.setLayout(new GridLayout(2, false));
Canvas xAxis = new Canvas(graphArea, SWT.NONE);
GridData gd = new GridData(GridData.CENTER, GridData.FILL, false, true);
gd.widthHint = 10;
xAxis.setLayoutData(gd);
xAxis.addPaintListener(new PaintListener() {
#Override
public void paintControl(PaintEvent e) {
drawXAxis();
}
});
Canvas graph = new Canvas(graphArea, SWT.NONE);
graph.addPaintListener(new PaintListener() {
public void paintControl(PaintEvent e) {
drawGraph(e);
}
});
Label emptySpace = new Label(graphArea, SWT.NONE);
Canvas yAxis = new Canvas(graphArea, SWT.NONE);
GridData gd = new GridData(GridData.FILL, GridData.CENTER, true, false);
gd.heightHint = 10;
xAxis.setLayoutData(gd);
yAxis.addPaintListener(new PaintListener() {
#Override
public void paintControl(PaintEvent e) {
drawYAxis();
}
});
You should draw everything in Your paintListener, if Your graph changes just redraw area of graph for example:
Rectangle rect = getGraphBoundries(); //you must implement this method
canvas.redraw(rect.x, rect.y, rect.width, rect.height, true);
this will redraw graph area. To avoid unnecessary computing of axes area in in paintListener paintEvent's gc has area that need to be redrawn called clipping. You can write condition like this:
public void paintControl(PaintEvent e) {
...
if(drawGraph(e.gc.getClipping().intersects(getGraphBoundries())) {
drawGraph(e);
}
...
}
as the title says i have a small problem with fot-size in eclipse.
i created a font using "BMfont", and i implemented it in my game, but when i tested it on a smaller device it was way too big, is there a code i can use to make it adjust automatically.
im using Libgdx ,any help is appreciated.
my code
#Override
public void show() {
stage = new Stage();
Gdx.input.setInputProcessor(stage);
atlas = new TextureAtlas("ui/button.pack");
skin = new Skin(atlas);
table = new Table(skin);
table.setBounds(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
white = new BitmapFont(Gdx.files.internal("font/white.fnt"), false);
black = new BitmapFont(Gdx.files.internal("font/black.fnt"), false);
//maakt buttons
TextButtonStyle textButtonStyle = new TextButtonStyle();
textButtonStyle.up = skin.getDrawable("button.up");
textButtonStyle.down = skin.getDrawable("button.down");
textButtonStyle.pressedOffsetX = 1;
textButtonStyle.pressedOffsetY = -1;
textButtonStyle.font = black;
buttonExit = new TextButton("EXIT", textButtonStyle);
buttonExit.addListener(new ClickListener() {
#Override
public void clicked(InputEvent event, float x, float y) {
Gdx.app.exit();
}
});
buttonExit.pad(20);
//maakt header
LabelStyle headingStyle = new LabelStyle(white, Color.WHITE);
heading = new Label(Papermadness.TITLE, headingStyle);
heading.setFontScale(3);
table.add(heading);
table.row();
table.add(buttonExit);
//table.debug();
stage.addActor(table);
}
You have to check the display's density and multiply by the desired font size, so that the font is the same size across all devices.
See the link below:
https://gamedev.stackexchange.com/questions/24638/resolution-independence-in-libgdx
I think you should use youeBitmapFont.setScale() and you should get screen size Gdx.graphics.getWidth() and multiple with some number
Trying to add multiple items to a scrollpane I quickly found that all "addActor" functions are Unsupported. So, I went with adding a table with all the items I wanted (this code misses a image that I still want to add) to make a scrollable credits screen... but this approach (currently) doesn't allow for overflow, rendering the ScrollPane useless. (My text is only shown up to what the screen's height allows, and isn't scrollable).
What's the way to make a scrollable pane with multiple widgets in LibGDX? (I only care about Android and Win/Lin/Mac platforms at the moment.
pane = new ScrollPane(null, skin);
pane.setFillParent(true);
paneContent = new Table(skin);
paneContent.setFillParent(true);
Label temp = new Label("", skin);
temp.setAlignment(Align.left, Align.center);
temp.setText( Gdx.files.internal("licenses/credits.txt").readString("UTF-8") );
paneContent.addActor(temp);
pane.setWidget(paneContent);
stage.addActor(pane);
If you want to put multiple items into the ScrollPane you simply need to put a table into it and call add() for each widget you want to put into the ScrollPane.
Below is an example of how to make your credits scrollable:
public class ScrollTest implements ApplicationListener {
private Stage stage;
private static final String reallyLongString = "This\nIs\nA\nReally\nLong\nString\nThat\nHas\nLots\nOf\nLines\nAnd\nRepeats.\n"
+ "This\nIs\nA\nReally\nLong\nString\nThat\nHas\nLots\nOf\nLines\nAnd\nRepeats.\n"
+ "This\nIs\nA\nReally\nLong\nString\nThat\nHas\nLots\nOf\nLines\nAnd\nRepeats.\n";
#Override public void create() {
this.stage = new Stage();
Gdx.input.setInputProcessor(this.stage);
final Skin skin = new Skin(Gdx.files.internal("skin/uiskin.json"));
final Label text = new Label(reallyLongString, skin);
text.setAlignment(Align.center);
text.setWrap(true);
final Label text2 = new Label("This is a short string!", skin);
text2.setAlignment(Align.center);
text2.setWrap(true);
final Label text3 = new Label(reallyLongString, skin);
text3.setAlignment(Align.center);
text3.setWrap(true);
final Table scrollTable = new Table();
scrollTable.add(text);
scrollTable.row();
scrollTable.add(text2);
scrollTable.row();
scrollTable.add(text3);
final ScrollPane scroller = new ScrollPane(scrollTable);
final Table table = new Table();
table.setFillParent(true);
table.add(scroller).fill().expand();
this.stage.addActor(table);
}
#Override public void render() {
this.stage.act();
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
this.stage.draw();
}
#Override public void resize(final int width, final int height) {}
#Override public void pause() {}
#Override public void resume() {}
#Override public void dispose() {}
}
Edit: Added code on setting up a table inside of a ScrollPane.