I've read about libgdx's scene2d features, including the UI elements, but I can't get them to work. They all seem to use a skin object, how do I create one?
I've gone through the nice tutorial that creates a simple libgdx game catching raindrops in a bucket, and I've created a simple board game app by loading images with a texture atlas. However, scene2d sounds like a better way to control the moving pieces in a board game app, as well as any buttons and menus.
To load a skin, you can start with the sample skin files used in the libgdx test project.
Atlaspack File
Json File
Atlaspack Image
Font File
There's a bit more detail in this question, and I found that I had to move the files into a subdirectory of assets to avoid a bug in the HTML version. (If I leave files in the assets folder, I see an error message like, "GwtApplication: exception: Error reading file data/uiskin.json.")
I posted a complete example that displays a single button, and the interesting code is all in the game class. The example is so simple that you only need two member variables to hold the scene and the button.
private Stage stage;
private TextButton button;
To create the skin, you just load the data file.
Skin skin = new Skin(Gdx.files.internal("data/uiskin.json"));
Wire the button into the stage.
stage = new Stage();
button = new TextButton("Click Me!", skin);
stage.addActor(button);
Wire a listener into the button, and register the stage to receive events.
button.addListener(new ClickListener() {
#Override
public void clicked(InputEvent event, float x, float y) {
button.setText("Clicked!");
}
});
Gdx.input.setInputProcessor(stage);
The render() method is basically a call to stage.draw().
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
stage.act(Math.min(Gdx.graphics.getDeltaTime(), 1 / 30f));
stage.draw();
Then you just need to layout the screen when it resizes.
button.setPosition(
(width-button.getWidth())/2,
(height-button.getHeight())/2);
If your screen is more complicated, consider using a Table.
If you want to use a different font, you can generate the font file and image file using Hiero. After you've done that, you'll have to take the new font image and use the TexturePacker to repack it with the other skin assets.
Now Libgdx provide Git repository to get skin, you can download it from: https://github.com/libgdx/libgdx-skins, copy assets:https://github.com/libgdx/libgdx-skins/tree/master/skins/visui/assets to your project
Related
I'm trying to make my first game in JavaFX, where a player object (not a Node) will move inside a level. However, the full level shouldn't be visible inside the window, only a part of it surrounding the player should be. I've searched quite a bit for a solution to this that works with the way I've done my project, but haven't been successful. The following code describes how I've set up my GUI:
private VBox appRoot;
private Pane gameRoot;
private Canvas canvas;
private GraphicsContext gc;
private HBox uiRoot;
This is the different panes I use. The appRoot contains both the gameRoot and the uiRoot, in that order. The gameRoot contains the canvas. Everything inside the level, including the level itself, is drawn onto the canvas, like this:
canvas = new Canvas(ROOM_WIDTH, ROOM_HEIGHT);
gc = canvas.getGraphicsContext2D();
createLevel(ROOM_WIDTH, ROOM_HEIGHT, CELL_WIDTH, CELL_HEIGHT);
gc.scale(2, 2);
drawLevel(gc, ROOM_WIDTH, ROOM_HEIGHT, CELL_WIDTH, CELL_HEIGHT);
player.render(gc);
createLevel and drawLevel just creates a level and draws squares where different blocks should be. The player object's render method draws the player at its x- and y-coordinates. As you can see I've scaled the canvas, so as of now the entire level isn't shown when the game is started.
The problem is that I can't make it so that what is shown in the window is the things surrounding the player object. I've seen some code utilizing the methods setLayoutX and setLayoutY, but I've been unable to reproduce this so that it works.
I would be very grateful if anybody could help me out with this, and hopefully without changing too much of how the drawing is done.
Thanks! :)
Also, here are two pictures showing how it looks; the first is when the player is not inside the current view, and the second is with the player in the view.
Image without player in view
Image with player in view
Do not us the Canvas directly to display the level. Instead you can use an image that represents your level and then have the image in an ImageView. On that ImageView you can define a viewport of the area of the image that is visible.
To get the image you can either use your Canvas node and take a snapshot (See this question). This is probably the easiest way with what you have. Or you can forego the Canvas altogether and draw the image. If the levels are predefined (and not generated at runtime), this seems the best approach, then you can supply the images as resources along with the code.
I am trying to do a project with javafx but I can't create the figures to a puzzle game with tiles, in order to push them with the click of a button. How can an Image be cropped and saved as an individual tile ?
The ImageView class is used to display an image. It has a viewport property that represents the portion of the image it is viewing. So you can create multiple image views from the same image, each with a different viewport: then you can add the image views to a pane of some kind, register mouse handlers on them, etc.
If you actually need to store each piece as an individual image, you can snapshot the image view to create a new Image from it. You'll probably find you don't need this, however.
You might want to try PixelReader and WritableImage APIs from JavaFX platform.
I have been making a project in libGDX and started in v0.9.9, I just got a mac in order to get it on ios, and after a series of figuring out the new libGDX and robovm updates and weighing options (through a variety of trial and error) i am going to have to update everything to the new libgdx 1.2.0 structure (gradle, etc.). This came with the addition of viewports and messed up the way stages work. Orginally in my constructor I would start by creating an orthograhiccamera and stage, ie:
camera = new OrthographicCamera(854, 480);
stage = new Stage();
I cant figure out how to factor the camera into the new code because I know somewhere i need to create a viewport for the stage but im not sure how my camera needs to work with it. All that shows up is just a white screen. Now after repeatedly fiddling with how i have a random made viewport, camera and stage setup, I actually got it to show the main menu buttons, but over blank white when there should be 3 moving backgrounds (it makes a cool paralax effect...) and moving title along with it. Could this be how libGDX now uses openGL 2.0 instead of 1.0? These button actors are also completely unresponsive, they should be animated when clicked, and change screen, and output to the console but do not do anything. I have always had the stage as the inputprocessor set in the show method, and add all of my actors aswell, ie:
#Override
public void show() {
Gdx.input.setInputProcessor(stage);
stage.addActor(variousActors);
}
Could the whiteness be opengl not being able to process the images and showing white instead? Could this be because of lack of ram (never a problem before whether on 20mb of available ram or 8gb available), could it be that the images being used are too large (largest being 3840 x 1080)? In my render is:
public void render(float delta) {
Gdx.gl.glClearColor(1F, 1F, 1F, 1F);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.setProjectionMatrix(camera.combined);
camera.update();
stage.act(delta);
batch.begin();
batch.end();
stage.draw();
System.out.println("menuscreen rendering");
}
--All actors/elements are initialized in the constructor
My entire game is actually built out of scene-2d elements --it did actually work out really well:) -- so getting this to work means the whole game. Ive been looking around alot and have found no solutions. So in review, How do i properly use a viewport with stages and how do i setup my camera with it; Why are my stage/actors(buttons) unresponsive; Why does everything show up as complete whiteness other than my buttons?
Try creating the stage this way:
camera = new OrthographicCamera(854, 480);
viewport = new ScalingViewport(Scaling.stretch, Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), camera);
viewport.update(Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), true);
stage = new Stage(viewport, batch);
You don't have to use a ScalingViewport. Check https://github.com/libgdx/libgdx/wiki/Viewports for other possibilities.
In resize(int, int) , as already mentioned, try:
viewport.update(width, height, true);
I've gone through the nice tutorial that creates a simple libgdx game catching raindrops in a bucket. I want to learn more about using images, so I tried replacing the raindrop with a baby.
When I try loading baby.png, I get the following error:
com.badlogic.gdx.utils.GdxRuntimeException: Texture width and height must be
powers of two: 60x83
How can I load an image of whatever size I want?
before loading the image write..
Texture.setEnforcePotImages(false);
you may do this in create function of application listner this is the easiest way if you don't want to create a texture atlas
A little reading led me to a description of TextureAtlas and TexturePacker, which combine a bunch of small images into one large one. That makes them faster to load and draw. As Vikalp says, you can also just disable the rule about image sizes if you don't care about the performance difference.
Texture.setEnforcePotImages(false);
You can learn more about game atlases in Udacity's HTML5 game class.
To create your own atlas, you can start by using the TexturePacker GUI, but I recommend eventually creating a command-line project to automatically pack your raw images.
I posted an example project that takes the example code from the bucket and raindrop tutorial, and switches to using a TextureAtlas. Now, I load the atlas and then load the images from the atlas.
atlas = new TextureAtlas(Gdx.files.internal("atlas/plank.pack"));
dropImage = atlas.findRegion("images/baby");
bucketImage = atlas.findRegion("images/bucket");
One bug I found is that the images wouldn't load in the HTML project. I found out that you can work around the bug by putting all your images in a subfolder.
I created a new project to hold the TexturePacker and any unit tests that I want to add later. The texture packer looks like this:
package com.github.donkirkby.plank;
import com.badlogic.gdx.tools.imagepacker.TexturePacker2;
public class PlankPacker {
public static void main (String[] args) throws Exception {
TexturePacker2.process(
"raw-assets", // source folder
"../plank-game-android/assets/atlas", // destination
"plank.pack"); // data file
}
}
You could also put the picture (top-left corner) into an 128x128 textures aswell:
Afaik is the using of non-power-of-two textures slower and takes more VRAM. Due the architecture of an GPU and "slow" handling of texture bindings in OpenGL, it's always recommended to put your images which are used at the same time into one big pow-two texture and grab them as regions of this texture to speed up your app.
The using and grabbing of your texture would look like:
Texture texture = Gdx.files.internal("data/yourtexture.png");
TextureRegion region = new TextureRegion(texture, 0, 0, 60, 83);
For drawing something like this:
batch.draw(region, positionX, positionY);
so I have this problem with ImageButton class of libgdx, the problem is that in android the image doesnt expand to the full size of the button, and in desktop it does or at least it does more, so I have to ask if theres a way to force the image to get the size of the background(button)? so i can try to make an equal visualitation on both plataforms.
heres a screen shot, the back space button is the ImageButton...
edit: heres the code....
private void createButtons() {
ImageButtonStyle ibs = new ImageButtonStyle(buttonD,buttonD_p,buttonD,bsIcon,bsIcon,bsIcon);
buttonBS = new ImageButton(ibs); // This is the backspace button
....
}
private void addButtonsToTable() {
float pad = 1;
float BUTTON_SIZE = this.BUTTON_SIZE - pad *3;
table.top();
table.center();
table.add(buttonBS).width(BUTTON_SIZE).height(BUTTON_SIZE).pad(pad);
table.row();
...
}
If you want the image to be the background instead of just an icon, you should consider using plain Button or TextButton instead of ImageButton. ImageButton should be used only for buttons that draw an icon additionally to its background. An example of ImageButton usage could be the window closing button with the "X" (cross) image, or music toggle button with a loudspeaker icon.
When you need the image to fill the whole button area, set it as ButtonStyle#up - it will become button's background. ImageButton#imageUp is just an icon that will not be scaled in any way (by default), so that might be the reason why your application behaves differently on each platform.
(Although it still shouldn't, unless you use different assets.)
If you need an icon and still want to use ImageButton, consider that internally it is just a Button with an Image instance added to one of its cells (Button is a Table). You can use ImageButton#getImageCell() to access Cell in which the Image is stored and modify it - for example, force a specific width and height. You might also want to use ImageButton#getImage() to change scaling with Image#setScaling(Scaling).
Anyway, creating styles at runtime can be error-prone - the style constructor is huge and I'm honestly unable to guess which drawable draws what without checking out image button style sources. You should consider using Skin and define your styles with JSON files (you can find some free themes here).