I have only found a couple of topics regarding this and it seems like everything I have is correct, but it doesn't work.
public Block(Body body, int x, int y, Player player, GameStage stage, GameScreen screen)
{
...
bar = progressBar();
stage.addActor(this);
stage.addActor(bar);
}
public ProgressBar progressBar()
{
ProgressBar.ProgressBarStyle barStyle;
TextureRegionDrawable textureBar;
Skin skin = new Skin();
Pixmap pixmap = new Pixmap(10, 10, Pixmap.Format.RGBA8888);
pixmap.setColor(Color.WHITE);
pixmap.fill();
skin.add("white", new Texture(pixmap));
textureBar = new TextureRegionDrawable(new TextureRegion(new Texture("bar.png")));
barStyle = new ProgressBar.ProgressBarStyle(skin.newDrawable("white", Color.DARK_GRAY), textureBar);
barStyle.knobBefore = barStyle.knob;
bar = new ProgressBar(0f, maxHitPoints, maxHitPoints/30, false, barStyle);
bar.setPosition(this.x, this.y);
bar.setSize(20, 5);
bar.setAnimateDuration(2);
return bar;
}
public void draw(Batch batch, float parentAlpha)
{
super.draw(batch, parentAlpha);
batch.setColor(blockColor);
batch.draw(region, this.getX(), this.getY());
batch.setColor(Color.WHITE);
bar.setValue(hitPoints);
}
stage.act and stage.draw are called elsewhere but are being called.
I get a solid bar but nothing I try causes it to fill/unfill
I imagine I must be missing something stupid, but for the life of me I can't find out what.
Related
Im completly new here and I need some fast help on a Project!!
I use LibGdx to write a little "Risiko" if somebody know it. Im creating a menu and my TextButtons dont work!! Here is the important Part:
stage = new Stage[3];
stage[0] = new Stage();
stage[1]= new Stage();
stage[2]= new Stage();
batch = new SpriteBatch();
setBmap(new Texture("map.png"));
inputMultiplexer=new InputMultiplexer();
inputMultiplexer.addProcessor(this);
inputMultiplexer.addProcessor(stage[0]);
inputMultiplexer.addProcessor(stage[1]);
inputMultiplexer.addProcessor(stage[2]);
Gdx.input.setInputProcessor(inputMultiplexer);
button = new TextButton[8];
//Southamerica
button[0] = new TextButton("Attack", textButtonStyle);
button[0].setBounds(605,463, 100,40);
... Create the buttons.
stage[0].addActor(button[0]);
stage[0].addActor(button[1]);
stage[0].addActor(button[2]);
stage[1].addActor(button[4]);
stage[1].addActor(button[5]);
stage[1].addActor(button[6]);
stage[2].addActor(button[3]);
stage[2].addActor(button[7]);
for(int i= 0; i <= 7 ; i++){
button[i].addListener(new ClickListener(){
#Override
public void clicked(InputEvent event, float x, float y){
System.out.println("Button action");
}});
}
/*button[0].addListener(new ChangeListener() {
public void changed (ChangeEvent event, Actor actor) {
System.out.println("BUTTOn");
}
});*/
button[0].addListener(new ClickListener(){
#Override
public void clicked(InputEvent event, float x, float y){
System.out.println("BUTTON PRESSED!!");
}});
Add Buttons to stages and create the Listener!
And now my render() :
super.render();
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
font = new BitmapFont();
batch.begin();
batch.draw(getBmap(), 0, 0);
stage[0].draw();
-
batch.end();
}
I use different Stages do draw different menus. Just for Info :D
And already Thanks for any answer!!
Sorry, for the request now I got it. I didnt got that I have to do it like this:
inputMultiplexer=new InputMultiplexer();
inputMultiplexer.addProcessor(stage[0]);
inputMultiplexer.addProcessor(stage[1]);
inputMultiplexer.addProcessor(stage[2]);
inputMultiplexer.addProcessor(this);
Gdx.input.setInputProcessor(inputMultiplexer);
and not like this:
inputMultiplexer=new InputMultiplexer();
inputMultiplexer.addProcessor(this);
inputMultiplexer.addProcessor(stage[0]);
inputMultiplexer.addProcessor(stage[1]);
inputMultiplexer.addProcessor(stage[2]);
Gdx.input.setInputProcessor(inputMultiplexer);
I love it :D
RIP
I use the latest libGDX builds from the Maven snapshot repository.
My main menu screen class is below. Notice the code which had to be commented out due to API changes in the latest libGDX snapshot.
public class MainMenuScreen implements Screen {
#Override
public void resize(int width, int height) {
stage.setViewport(new ScreenViewport(cam));
// stage.setViewport(width, height, true); <- Method signature changed
}
#Override
public void show() {
batch = new SpriteBatch();
stage = new Stage();
cam = new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
cam.position.set(Gdx.graphics.getWidth() / 2, Gdx.graphics.getHeight() / 2, 0);
cam.setToOrtho(false, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
// stage.setCamera(cam); <- Method no longer exists
Gdx.input.setInputProcessor(stage);
// Button is an Actor subclass.
final Button playButton = new Button(Assets.getPlayButtonTexture(), positions.playOut);
stage.addActor(playButton);
playButton.addListener(new InputListener() {
#Override
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
// This event no longer fires when I tap playButton!
}
});
}
// ...
private Stage stage;
private SpriteBatch batch;
private OrthographicCamera cam;
}
As you can see from the comment in touchDown, that event is no longer being fired.
What part of my code do I need to change to allow the playButton actor to receive touchDown events as it did before the recent libGDX change?
Solution:
stage = new Stage();
stage.setCamera(cam);
becomes
stage = new Stage(new ScreenViewport(cam));
and
stage.setViewport(width, height, true);
becomes
stage.getViewport().update(width, height, true);
From what I understand when reading other peoples code on how to make different screens. You do a main handler class sort of... And then create a new class for each screen.
The thing that confuses me is that whenever you create a new screen, you have to redefine everything that's going to be rendered, like SpriteBatch, sprites, fonts, etc. Is there any way to reuse these kind of things in all screens? I mean, if I have 10 screens, and want to be able to draw text on every screen. Is it really good programming practice to make a new BitmapFont for all 10 screen classes?
I've created an Abstract Screen class that contains all the common objects for a screen, every one of my screens extend this abstract class. And that looks like this:
public abstract class AbstractScreen implements Screen {
protected final Game game;
protected InputMultiplexer multiInputProcessor;
protected ScreenInputHandler screenInputHandler;
protected Stage uiStage;
protected Skin uiSkin;
public AbstractScreen(Game game) {
this.game = game;
this.uiStage = new Stage();
this.uiSkin = new Skin();
this.screenInputHandler = new ScreenInputHandler(game);
this.multiInputProcessor = new InputMultiplexer();
multiInputProcessor.addProcessor(uiStage);
multiInputProcessor.addProcessor(screenInputHandler);
Gdx.input.setInputProcessor(multiInputProcessor);
}
private static 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);
}
#Override
public void render (float delta) {
Gdx.gl.glClearColor(0.2f, 0.2f, 0.2f, 1);
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
uiStage.act(Math.min(Gdx.graphics.getDeltaTime(), 1 / 30f));
uiStage.draw();
Table.drawDebug(uiStage);
}
#Override
public void resize (int width, int height) {
}
#Override
public void show() {
}
#Override
public void hide() {
dispose();
}
#Override
public void pause() {
}
#Override
public void resume() {
}
#Override
public void dispose() {
uiStage.dispose();
uiSkin.dispose();
}
}
When I want to create a new class I just extend the abstract screen and add what I need. For example I have a basic credits screen, I just need to create the components but the abstract screen draws it:
public class CreditsScreen extends AbstractScreen {
public CreditsScreen(final Game game) {
super(game);
// Generate a 1x1 white texture and store it in the skin named "white".
Pixmap pixmap = new Pixmap(1, 1, Format.RGBA8888);
pixmap.setColor(Color.WHITE);
pixmap.fill();
uiSkin.add("white", new Texture(pixmap));
// Store the default libgdx font under the name "default".
BitmapFont buttonFont = new BitmapFont();
buttonFont.scale(scale);
uiSkin.add("default", buttonFont);
// Configure a TextButtonStyle and name it "default". Skin resources are stored by type, so this doesn't overwrite the font.
TextButtonStyle textButtonStyle = new TextButtonStyle();
textButtonStyle.up = uiSkin.newDrawable("white", Color.DARK_GRAY);
textButtonStyle.down = uiSkin.newDrawable("white", Color.DARK_GRAY);
textButtonStyle.checked = uiSkin.newDrawable("white", Color.BLUE);
textButtonStyle.over = uiSkin.newDrawable("white", Color.LIGHT_GRAY);
textButtonStyle.font = uiSkin.getFont("default");
uiSkin.add("default", textButtonStyle);
// Create a table that fills the screen. Everything else will go inside this table.
Table table = new Table();
table.setFillParent(true);
uiStage.addActor(table);
table.debug(); // turn on all debug lines (table, cell, and widget)
table.debugTable(); // turn on only table lines
// Label
BitmapFont labelFont = new BitmapFont();
labelFont.scale(scale);
LabelStyle labelStyle = new LabelStyle(labelFont, Color.BLUE);
uiSkin.add("presents", labelStyle);
final Label myName = new Label("Credits and all that stuff", uiSkin, "presents");
table.add(myName).expand().center();
}
}
I also have a single class that handles the input for all the screens, the specific purpose for this is to handle how the back button works around the different screens. And this input handler class is created in the abstract class.
public class ScreenInputHandler implements InputProcessor {
private final Game game;
public ScreenInputHandler(Game game) {
this.game = game;
}
#Override
public boolean keyDown(int keycode) {
if(keycode == Keys.BACK || keycode == Keys.BACKSPACE){
if (game.getScreen() instanceof MainMenuScreen) {
Gdx.app.exit();
}
if (game.getScreen() instanceof GameScreen) {
World.getInstance().togglePause(false);
}
if (game.getScreen() instanceof CreditsScreen) {
game.setScreen(new MainMenuScreen(game));
}
}
return false;
}
}
public void render(float delta) {
Gdx.gl.glClearColor(0, 0, 0.2f, 1);
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
stage.act(delta);
batch.setProjectionMatrix(camera.combined);
batch.begin();
if (lifeCount > 0) {
/*
When stage.draw is called here, it only displays the exit button.
The game still operates, but everything is invisible.
If I leave the game on, the game over screen is shown,
*/
stage.draw();
text.setColor(1.0f, 1.0f, 1.0f, 1.0f);
text.draw(batch, score + scoreCount, 25, 100);
text.draw(batch, lives + lifeCount, 25, 120);
text.draw(batch, speed + raindropSpeed, 25, 80);
batch.draw(bucketTexture, bucket.x, bucket.y);
for (Rectangle clearDrop : clearDrops) {
batch.draw(clearDropTexture, clearDrop.x, clearDrop.y);
}
for (Rectangle healthDrop : healthDrops) {
batch.draw(healthDropTexture, healthDrop.x, healthDrop.y);
/*
If I place stage.draw here, health drops are invisible.
This also happens if I place it in the raindrop for-loop and the
cleardrop for-loop
*/
}
for (Rectangle raindrop : raindrops) {
batch.draw(raindropTexture, raindrop.x, raindrop.y);
}
/*
If I place stage.draw here, the bucket, score, life, and speed
display correctly. The drops are still invisible.
*/
} else {
pause();
raindrops.clear();
game.setScreen(new GameOver(game));
}
batch.end();
What I have been trying to do is have an exit button in the top right corner of the GameScreen, although drawing the stage which the button resides in gives me difficulties (see comments in code).
Here is my code for the exit button and stage (resize()):
if (stage == null)
stage = new Stage(width, height, true);
stage.clear();
Gdx.input.setInputProcessor(stage);
TextButtonStyle styleQuit = new TextButtonStyle();
styleQuit.up = skin.getDrawable("buttonnormal");
styleQuit.down = skin.getDrawable("buttonpressed");
styleQuit.font = text;
quitButton = new TextButton(" ", styleQuit);
quitButton.setWidth(128);
quitButton.setHeight(128);
quitButton.setX(800 - 128);
quitButton.setY(480 - 100);
quitButton.addListener(new InputListener() {
public boolean touchDown(InputEvent event, float x, float y,
int pointer, int button) {
return true;
}
public void touchUp(InputEvent event, float x, float y,
int pointer, int button) {
Gdx.app.log(RainCatcher.LOG, "Quit Button Pressed");
game.setScreen(new MainMenu(game));
}
});
stage.addActor(quitButton);
And the rest (in show())
atlas = new TextureAtlas("gamebuttons.pack");
skin = new Skin();
skin.addRegions(atlas);
text = new BitmapFont();
Is there any special trick to allow a stage to be rendered alongside with the falling raindrops, bucket, and text? My friends and I have been stumped and couldn't find a solution anywhere.
Move stage.draw() after batch.end() or before batch.begin()
This is not the right approach you're taking in my opinion. If you're using a stage in libgdx, then you should benefit from other components of Scene2d. So, rather than drawing your raindrops and other game entities separately (and making your job complicated), you should make them actors and add them to stage wherever you need and then draw the stage in the render.
For example:
public class RaindDrop extends Actor {
TextureRegion region;
public RaindDrop () {
region = new TextureRegion(...);
}
public void draw (SpriteBatch batch, float parentAlpha) {
Color color = getColor();
batch.setColor(color.r, color.g, color.b, color.a * parentAlpha);
batch.draw(...);
}
}
So on for other entities. Initialise and add them to your stage.
Here's the official wiki to read more:
https://code.google.com/p/libgdx/wiki/scene2d
I'm having a hard time getting events working with my Actor in libgdx. I'm using nightly builds.
My stage is setup in the show() method of a Screen subclass:
stage = new Stage(Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), true);
Gdx.input.setInputProcessor(stage);
TestActor actor = new TestActor();
stage.addActor(actor);
And my actor class looks like:
class TestActor extends Actor {
private Sprite sprite;
private TextureAtlas atlas;
public TestActor() {
atlas = new TextureAtlas(Gdx.files.internal("textures/images-packed.atlas"));
sprite = atlas.createSprite("logo-96");
setTouchable(Touchable.enabled);
addListener(new InputListener() {
public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) {
Gdx.app.debug(TestGame.TAG, "TestActor.touchDown()");
return true; // must return true for touchUp event to occur
}
public void touchUp (InputEvent event, float x, float y, int pointer, int button) {
Gdx.app.debug(TestGame.TAG, "TestActor.touchUp()");
}
});
}
#Override
public void draw(SpriteBatch batch, float parentAlpha) {
Color color = getColor();
batch.setColor(color.r, color.g, color.b, color.a * parentAlpha);
batch.draw(sprite, getX(), getY());
}
}
The events don't seem to fire. Oddly enough, I've used built-in UI widgets like the TextButton and can get those events to fire just fine. Can anybody see what I'm doing wrong?
You should also setBounds to your actor.
best way to do it (if you want the same size as your texture)
add these lines to your constructor :
setWidth(sprite.getWidth());
setHeight(sprite.getHeight());
setBounds(0, 0, getWidth(), getHeight());
notice you can also set the location of the bounds with the first 2 parameters.