Precise position of widgets for libGDX scene2d - android

I want to layout a set off press-able piano keys in my libGDX app, something like the following:
When a key is pressed, I need to change it from the up to down position (this is easy using an image button).
What I'm struggling with is how to layout all of the buttons such that they for something that resembles a piano keyboard. The white piano key images are rectangular, but a black piano key needs to be placed on top of it. Below shows what one of my white piano key images looks like, there is dead space in the top corner where I intend to put a black note.
Using a Table won't work, as tables layout everything side-by-side, which would leave me with gaps. I've seen you can use a Stack, but that just lays every child directly on top of the last, so that doesn't seem to help either.
If it helps, my code is something like this:
Skin skin;
Stage stage;
SpriteBatch batch;
private TextButton button1;
private TextButton button2;
#Override
public void create () {
batch = new SpriteBatch();
stage = new Stage();
Gdx.input.setInputProcessor(stage);
createSkin();
Table table = new Table();
table.setFillParent(true);
stage.addActor(table);
// Create a button with the "default" TextButtonStyle. A 3rd parameter can be used to specify a name other than "default".
button1 = new TextButton("First note", skin);
button1.getLabel().setFontScale(5);
button2 = new TextButton("Second note", skin);
button2.getLabel().setFontScale(5);
table.add(button1).width(500).height(500);
table.add(button2).width(500).height(200);
}
#Override
public void render () {
super.render();
Gdx.gl.glClearColor(0.2f, 0.2f, 0.2f, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
stage.act(Gdx.graphics.getDeltaTime());
stage.draw();
}
#Override
public void resize (int width, int height) {
stage.getViewport().update(width, height, true);
}
#Override
public void dispose () {
stage.dispose();
skin.dispose();
}
private void createSkin() {
skin = new Skin();
Pixmap pixmap = new Pixmap(1, 1, Pixmap.Format.RGBA8888);
pixmap.setColor(Color.WHITE);
pixmap.fill();
skin.add("white", new Texture(pixmap));
skin.add("default", new BitmapFont());
TextButton.TextButtonStyle textButtonStyle = new TextButton.TextButtonStyle();
textButtonStyle.up = skin.newDrawable("white", Color.DARK_GRAY);
textButtonStyle.down = skin.newDrawable("white", Color.BLUE);
textButtonStyle.checked = skin.newDrawable("white", Color.DARK_GRAY);
textButtonStyle.over = skin.newDrawable("white", Color.DARK_GRAY);
textButtonStyle.font = skin.getFont("default");
skin.add("default", textButtonStyle);
}
Which renders this:
There's no way to overlap things as far as I can tell using table, but I can't find another way of doing it. Is doing this possible using scene2d?

The simpliest solution seems to be to create second Stage with same viewport (stages needs to behave in the same way in case of resizing) and place it over your current one. You need to create same table but fullfill it only with black notes (your current stage would contains only white ones of course).
Notice that you will need to use InputMultiplexer to get event from both stages - you can read here about how to use it.

Add all the Buttons that represent keys to the stage directly without putting them in a Table. Set their positions manually. Should be pretty easy to do manually since piano keys have a clear pattern. Add the black keys after adding the white keys. Then you don't have to worry about the white keys being non-rectangular because the black keys will get prioritized for receiving input.

Related

Libgdx, Stage doesnt fit into the screen and the button are not centered within the Table

I am currently working on a StartMenu for my very first android game and there are 3 Problems that I am currently encountering:
1) the stage doesn't fit perfectly into the screen. I already tried to pass the different viewport types (stretch-, fit, extendviewport) to the stage Constructor, but none of them really worked out as I intended. I also tried different parameters for the viewport (e.g. numbers like 480, 800 but also Gdx.graphics.getWidth()), but I am unable to make the Menu resolution independent (tried on s3 mini and on Huawei P8), it either turns out too small or too big.
2) the settings buttons is not centered within the table cell.
3) the buttons change size. when pressed, they fill the cell in which they are in, how do I disable this feature? (i defined the button skin with a JSON-file, by the way, but I doubt this is the cause)
#Override
public void resize(int width, int height) {
stage.getViewport().update(width, height, true);
}
#Override
public void show() {
stage = new Stage(new ExtendViewport(Constants.VIEWPORT_GUI_WIDTH, Constants.VIEWPORT_GUI_HEIGHT));
Gdx.input.setInputProcessor(stage);
rebuildStage();
}
private void rebuildStage() {
skinStartMenu = new Skin(
Gdx.files.internal(Constants.SKIN_Start_Menu_UI),
new TextureAtlas(Constants.Start_Menu_Texture_Atlas));
Table layerControls = buildControlsLayer();
stage.clear();
Stack stack = new Stack();
stage.addActor(stack);
stack.setSize(Constants.VIEWPORT_GUI_WIDTH, Constants.VIEWPORT_GUI_HEIGHT);
stack.add(layerControls);
}
private Table buildControlsLayer() {
Table layer = new Table();
// + Play Button
btnMenuPlay = new Button(skinStartMenu, "play");
layer.add(btnMenuPlay);
btnMenuPlay.addListener(new ChangeListener() {
#Override
public void changed(ChangeEvent event, Actor actor) {
onPlayClicked();
}
});
layer.row();
// + Options Button
btnMenuOptions = new Button(skinStartMenu, "options");
layer.add(btnMenuOptions);
btnMenuOptions.addListener(new ChangeListener() {
#Override
public void changed(ChangeEvent event, Actor actor) {
onOptionsClicked();
}
});
if (debugEnabled) layer.debug();
return layer;
}
No Button Pressed;
Button Pressed
Edit: I solved the first problem by resizing the cells of the table, however i still do not have a workaround for problem 2) and 3).
Okay, I found the root of my problems. stupid me exported the png-files of the button in different sizes. thats why the buttons got taller when pressed. i thought this was a feature of the button-widget, which was enabled by default x). The problem with the stage size was solved, by simply changing the size of the table-cells in which the buttons where contained via " layer.add(btnMenuPlay).size(273, 150);".
The StartMenu looks like this now:

LibGDX - How do I get my screen to display "LEVEL COMPLETE"?

I want the game screen on the Android device to change to a screen that displays "LEVEL COMPLETE". I made a .png file with this message in the middle and want to basically load it on top of the current screen (like a Fragment i guess?) when Player collides with Flag (both are modelled as rectangles for the sake of collision detection). This is my Flag class
public class Flag extends GameObject {
private Sprite spr;
private Rectangle playerRect;
private boolean isOverlapping;
Player player;
private Rectangle flagRect;
public Flag(Sprite spr, float xPos, float yPos) {
super(spr, xPos, yPos);
player = Player.getInstance(null);
setxPos(xPos);
setyPos(yPos);
flagRect = new Rectangle(getxPos(), getyPos(), getSprite().getWidth(),
getSprite().getHeight());
}
public void update() {
playerRect = new Rectangle(player.getxPos(), player.getyPos(), player
.getSprite().getWidth(), player.getSprite().getHeight());
isOverlapping = playerRect.overlaps(flagRect);
if(isOverlapping) {
...
}
}
}
I put levelComplete.png in my assets folder and am a little unsure where to go from here. Any suggestions? Would be highly appreciated
All you need to do is make a Texture from your image and draw it on your screen using SpriteBatch. This can be achieved with something like this:
public Texture levelComplete = new Texture(Gdx.files.internal("assets/imageName.png"));
public SpriteBatch batch = new SpriteBatch();
public render(){
batch.begin();
if(isOverlapping){
batch.draw(levelComplete, x, y);
}else{
// render game
}
batch.end();
}
Note that you might want to put some timer and stop drawing the Texture after like 5 seconds or put some sort of "ok" button. Otherwise you will be stuck with the same Texture.
Instead of creating an image that contain your text "Level Complete " you can use BitmapFont to write it down on your screen with any font you like
first choose your font (you can generate any font you want using tools like Hiero)
put them on assets file and load them using this line of code
textFont = new BitmapFont(Gdx.files.internal("nameFont.fnt"), gdx.files.internal("nameFont.png"), false);
then you have just to write your text in the position you want
textFont.draw(spritebatch, "Level Complete", x, y)
hope it will help !

LibGDX - ImageButton - Setting Image With Background

From my understanding, the ImageButton within LibGDX is a frame containing an image. Is it possible to set the background of the frame?
For example, I would like to use a Button background, and apply an Icon on top of that image.
Current Code
Skin with the background:
"com.badlogic.gdx.scenes.scene2d.ui.ImageButton$ImageButtonStyle": {
"default": {
"imageDown": "button-down",
"imageUp": "button-up"
}
}
Creating the ImageButton:
// Getting imageButtonStyle with "default" style, as it just has the background.
ImageButton.ImageButtonStyle imageButtonStyle = skin.get( "default", ImageButton.ImageButtonStyle.class );
ImageButton button = new ImageButton( imageButtonStyle );
// Set the image on the button to something.
Background image.
Background image with icon overlayed.
Thank you for your help.
The trick is using the 2 different Styles available. ImageButtonStyle to set the icon attributes, but since ImageButtonStyle extends ButtonStyle, the background attributes are set in ButtonStyle. Something like:
ImageButtonStyle style = new ImageButtonStyle();
style.up = background;
style.down = background;
style.checked = background;
style.imageUp = icon_up;
style.imageDown = icon_down;
style.imageChecked = icon_checked;
style.unpressedOffsetY = -20; // to "not" center the icon
style.unpressedOffsetX = -30; // to "not" center the icon
ImageButton heartButton = new ImageButton(style);
ImageButton envelopeButton = new ImageButton(envelopeStyle);
Something like that (for me, backround, icon_* are Drawable). But that's the basics and worked like a charm for me.
You could implement your own button class that extends ImageButton.
Then, if you overload the constructor, you can pass either Drawables or Textures for imageUp, imageDown and background to it:
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.scenes.scene2d.ui.ImageButton;
import com.badlogic.gdx.scenes.scene2d.utils.Drawable;
import com.badlogic.gdx.scenes.scene2d.utils.SpriteDrawable;
public class myButton extends ImageButton
{
public myButton(Texture texture_up, Texture texture_down, Texture background)
{
super(new SpriteDrawable(new Sprite(texture_up)),
new SpriteDrawable(new Sprite(texture_down)));
this.setBackground(new SpriteDrawable(new Sprite(background));
}
}
Now, you can use your own Button class and instantiate it as follows:
Texture textureUp = new Texture(Gdx.files.internal("data/image_up.png"));
Texture textureDown = new Texture(Gdx.files.internal("data/image_down.png"));
Texture background = new Texture(Gdx.files.internal("data/background.png"));
MyButton myButton = new MyButton(textureUp, textureDown, background);
Maybe play around with it a little and you'll find out what else you can do with it. Just make sure that you have the images in the correct resolution. Background doesn't have to be an image.
A button by definition will have three states:
imageDown - When the mouse is clicked on the button
imageUp - When the mouse is released on the button
imageChecked - When the mouse is hovering on the button
In the scene2d api there isn't a way yet of manually setting the imageButton's background image but if you do want something like that its best to have an array of images and an index as to what image you want, and render using a sprite batch e.g:
Texture[] images;
int currentImage;

How to use native Textview (View) in Andengine Game Activity

I want to know is there any way to use native TextView or any other layout of android inside BaseAndEngine Activity.
My application is using Andengine for one of its whole screen. This screen is extended from BaseAndEngine and I need to use some native view like textview inside that screen. Because Andengine does not work fine for Arabic text and I need to show some Arabic text on gaming screen.
OR if possible how to show Arabic text in changeable text in Andengine. As changeable text write Arabic from left to right in reverse order.
Of course you can.
Check this code out - basically you override onSetContentView, then you can set whatever you want.
#Override
protected void onSetContentView() {
final FrameLayout frameLayout = new FrameLayout(this);
final FrameLayout.LayoutParams frameLayoutLayoutParams = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.FILL_PARENT, FrameLayout.LayoutParams.FILL_PARENT);
this.mRenderSurfaceView = new RenderSurfaceView(this);
mRenderSurfaceView.setRenderer(mEngine);
final FrameLayout.LayoutParams surfaceViewLayoutParams = new FrameLayout.LayoutParams(super.createSurfaceViewLayoutParams());
frameLayout.addView(this.mRenderSurfaceView, surfaceViewLayoutParams);
//Create any other views you want here, and add them to the frameLayout.
this.setContentView(frameLayout, frameLayoutLayoutParams);
}
(This method goes to your subclass of BaseGameActivity.)
You could also do it through xml, but I think this method is more clear.
You can use Andengine for Arabic and Persian fonts too. But in a different manner. to do that you need to create a Sprite and add a bitmap to it. before that you draw your text on that bitmap.
the following code is an example that draw the Persian/Arabians text and attach it to a sprite. so we can attach the sprite to our scene.
this is an example to show how we can do that, so you can adjust the bitmap and text size by yourself.
if your device support Persian/Arabians, this code will work properly. if the text does not appear in your scene, change its position, it is out of screen
the example code function will print the "Persian Golf" in Persian/Arabians.
private void persianGolfPrinter(){
BitmapTextureAtlas mBitmapTextureAtlas = new BitmapTextureAtlas(ResourceManager.getInstance().gameActivity.getTextureManager(), 400, 800, TextureOptions.BILINEAR);
ITextureRegion mDecoratedBalloonTextureRegion;
final IBitmapTextureAtlasSource baseTextureSource = new EmptyBitmapTextureAtlasSource(400, 800);
final IBitmapTextureAtlasSource decoratedTextureAtlasSource = new BaseBitmapTextureAtlasSourceDecorator(baseTextureSource) {
#Override
protected void onDecorateBitmap(Canvas pCanvas) throws Exception {
this.mPaint.setColor(Color.BLACK);
this.mPaint.setStyle(Style.FILL);
this.mPaint.setTextSize(32f);
this.mPaint.setTextAlign(Align.CENTER);
pCanvas.drawText("خلیج فارس", 150, 150, this.mPaint);
}
#Override
public BaseBitmapTextureAtlasSourceDecorator deepCopy() {
throw new DeepCopyNotSupportedException();
}
};
mDecoratedBalloonTextureRegion = BitmapTextureAtlasTextureRegionFactory.createFromSource(mBitmapTextureAtlas, decoratedTextureAtlasSource, 0, 0);
mBitmapTextureAtlas.load();
Sprite test = new Sprite(0,0,mDecoratedBalloonTextureRegion,ResourceManager.getInstance().engine.getVertexBufferObjectManager());
this.attachChild(test);
}
don't use android textview... it makes your game ugly ....
You cannot use them directly in AndEngine, because the objects in Andengine are OpenGL objects. But you can use android OS to draw a bitmap of any standard view, and then create a texture and a sprite from that view. This is less than optimum for a case such as arabic text, but it will work. Be careful about memory leaks as you create the bitmaps of your views.

UI API for libgdx

Android and libgdx noob here.
Does anyone know anything about the recent UI API that was released for libgdx?
See blog post here: http://www.badlogicgames.com/wordpress/?p=2058
I am looking to create a basic menu system, and I was wondering if this UI API would make it easier.
Updated to reflect changes to the LibGDX
I am in a similar position, the following code worked for me to create a basic menu (A container of buttons). The code won't work as is, because it uses some of my classes, but what really matter is the content of the create method. This creates a centered title, then some buttons in a container that gets centered, then fps label in the lower left and an image in the lower right corner. The theme files and some of the images are from the LibGDX tests assets.
I've gotten this to work with the JOGL, LWJGL, and android application classes. I've run it on a Droid 2 and got it to run as it did on my desktop. Hopefully this should get you started.
public class MenuScreen extends Screen{
private Stage ui;
private Table window;
#Override
public void create(final Game game) {
super.create(game);
TextureRegion image = new TextureRegion(new Texture(Gdx.files.internal(Art.badlogicSmall)));
Label fps = new Label("fps: ", Art.sSkin.getStyle(LabelStyle.class),"fps");
ui = new Stage(Gdx.graphics.getWidth(),Gdx.graphics.getHeight(), true);
Gdx.input.setInputProcessor(ui);
window = new Table("window");
window.width = ui.width();
window.height = ui.height();
window.x = 0;
window.y = 0;
window.debug();
Label title = new Label("Title",Art.sSkin.getStyle(LabelStyle.class),"title");
Button newGame = new Button("New Game",Art.sSkin.getStyle(ButtonStyle.class),"new");
newGame.setClickListener(new ClickListener() {
#Override
public void click(Actor actor) {
game.setScreen(GameScreen.class);
}
});
Button optionMenu = new Button("Option",Art.sSkin.getStyle(ButtonStyle.class),"Options");
Button helpMenu = new Button("Help",Art.sSkin.getStyle(ButtonStyle.class),"Help");
Image libgdx = new Image("libgdx", image);
window.row().fill(false,false).expand(true,false).padTop(50).padBottom(50);
window.add(title);
Table container = new Table("menu");
container.row().fill(true, true).expand(true, true).pad(10, 0, 10, 0);
container.add(newGame);
container.row().fill(true, true).expand(true, true).pad(10, 0, 10, 0);
container.add(optionMenu);
container.row().fill(true, true).expand(true, true).pad(10, 0, 10, 0);
container.add(helpMenu);
window.row().fill(0.5f,1f).expand(true,false);
window.add(container);
Table extras = new Table("extras");
extras.row().fill(false,false).expand(true,true);
extras.add(fps).left().center().pad(0,25,25,0);
extras.add(libgdx).right().center().pad(0,0,25,25);
window.row().fill(true,false).expand(true,true);
window.add(extras).bottom();
ui.addActor(window);
}
#Override
public void render(float arg0) {
Gdx.gl.glClearColor(0.2f, 0.2f, 0.2f, 1);
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
((Label)ui.findActor("fps")).setText("fps: " + Gdx.graphics.getFramesPerSecond());
ui.act(Math.min(Gdx.graphics.getDeltaTime(), 1 / 30f));
ui.draw();
Table.drawDebug(ui);
}
#Override
public void resize(int width, int height) {
ui.setViewport(width, height, true);
Log.d("Resize: "+width+", "+height);
}
Yes, the the new UI api is very easy to use. You can use the Skin object to create some Actor object, and then join them to the Stage object.
You can reference the UITest.java file in the libgdx source. It demonstrates how to use the basic UI elements.
From low level to see the libgdx new UI, it only include the following element:
NinePatch: the basic shape object for create the element could stretch up;
Region: the shape object for the fixed size element;
Font: the bitmapfont object for display text;
The high level element is composed by them, such as the Button object, include: ninepatch and font ojbect, and so on.
So, you can very easy to create the 2D UI use them. :)

Categories

Resources