Libgdx: Stage only renders at (0, 0) - libgdx

I'm attempting to use LibGDX Stage for my GUI elements, but I'm having loads of difficulty getting it to render properly. Right now, I'm attempting to render a chat window in the lower left corner of the screen.
Here is the construction of the GUI objects:
stage = new Stage();
stage.setCamera(controller.getCamera());
uiSkin = new Skin(Gdx.files.internal("res/gui/skin/uiskin.json"));
Table table = new Table(uiSkin);
stage.addActor(table);
table.setSize(300, 260);
table.setPosition(0, 0);
table.setFillParent(false);
table.bottom();
table.left();
table.pad(10);
lblChatLabel = new Label("", uiSkin);
lblChatLabel.setWrap(true);
final ScrollPane scroll = new ScrollPane(lblChatLabel, uiSkin);
txtChatBar = new TextField("do a chat", uiSkin);
txtChatBar.setName("txtChatBar");
table.add(txtChatBar).width(300f);
table.row();
table.add(scroll).expand().fill().colspan(4);
txtChatBar.addListener(new InputListener() {
public boolean keyDown(InputEvent event, int keycode) {
if (keycode == Input.Keys.ENTER) {
sendMessage();
// Close the chat bar
showChat = false;
return true;
}
return false;
}
});
And here is my render() method:
Log.debug("void", "x: " + stage.getCamera().position.x + ", y: " + stage.getCamera().position.y);
stage.act();
for (Actor a : stage.getActors()) {
a.draw(spriteBatch, 1);
}
In another section of code elsewhere, the game's camera object is translated to center on the player:
camera.translate(targetPosition.x, targetPosition.y);
camera.update();
So that all said, the chat window renders properly, but it only does so at 0, 0. I've also changed called stage.draw() rather than iterate through the Actors individually, but that causes the same issue. Here is a screenshot illustrating the issue:
http://i.imgur.com/8uz5lV6.jpg
Finally, I've tried to translate the stage manually by setting the viewport, but that causes an even weirder issue.
float cx = controller.getCamera().getX();
float cy = controller.getCamera().getY();
float width = controller.getCamera().viewportWidth;
float height = controller.getCamera().viewportHeight;
stage.act();
stage.setViewport(width, height, true, cx, cy, width, height);
stage.draw();
Image here:
http://i.imgur.com/JpSLq1s.jpg
Certainly I am doing something wrong, but I have no idea at this point. I would have assumed that the stage follows the Camera translation, but that doesn't appear to be the case. Any suggestions are welcome! Thanks!

I believe the issue is this line of code:
stage.setCamera(controller.getCamera());
If I'm reading correctly, you want the chat window to always render from (0,0), no matter where the camera is on the screen. If that's the case, then the stage shouldn't have any relation with the camera, which moves around and just further complicates getting the stage in the right position to be rendered properly.
Without that line of code, you should be able to just call
stage.act();
stage.draw();
and it should work fine.

Related

LibGdx TiledMapRenderer leaves a flickering image after each render() call

In LibGdx when I use the below code to render a tiled map the tiledMapRenderer.render() call leaves a flickering image in the black area after just one call (I tested this by rendering in the create method only) and I haven't been able to remove it. This flickering image becomes a problem when the window size changes.
TiledMap tiledMap;
OrthogonalTiledMapRenderer tMR;
ExtendViewport viewPort;
#Override
public void create () {
OrthographicCamera camera = new OrthographicCamera();
camera.setToOrtho(false, 512, 512);
viewPort = new ExtendViewport(512, 512, 512, 512, camera );
viewPort.update(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
tiledMap = new TmxMapLoader().load("LibGdxTutorial.tmx");
tMR = new OrthogonalTiledMapRenderer(tiledMap);
}
#Override
public void render () {
viewPort.update(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
tMR.setView((OrthographicCamera) viewPort.getCamera());
tMR.render();
}
This is the default window you get after pressing run
This is the window after I dragged the right side out
The map image on the right of the second photo is the full and correct one. The map image on the left is the flickering after image (it appears full because it's one frame). Any help would be appreciated, thanks.
You need to clear the screen each frame. This happens in the render method and should be used before you start drawing.
Gdx.gl.glClearColor(0f,0f,0f,1); // set the clear color
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); // clear the screen with the given color.
.. draw next frame ..

AS3 - How to use pixel/point detection with mouse event instead of object detection

This seems like it should be so easy that I'm embarrassed to ask, but I just can't get it.
I have a large round MovieClip (being used as a button). This MovieClip contains a PNG with a transparent background inserted into the MovieClip.
Due to its size there are large empty registration areas on the 4 corners (the bounding box).
How can I have the mouse register as being over only the circle pixels and not the blank space (of Alpha channel pixels) in the square boundary box?
Simple sample code:
public function simpleSample () : void
{
mc1.buttonMode = true;
mc1.addEventListener(MouseEvent.CLICK, doStuff);
}
public function doStuff (event:MouseEvent) : void
{
mc2.gotoAndStop(2);
}
Here are 3 different ways to accomplish this.
EDIT Since you've later explained that your button is an image, this first option won't work for you
If the shape flag on hitTestPoint works with your button (eg it's a shape), you can use hitTestPoint inside your mouse click handler to figure out if the click is actually over the object:
public function doStuff(event:MouseEvent){
//only continue if hit test point is true,
//the x and y values are global (not relative to the mc your testing as one might suppose)
//the third parameter should be true, so it takes into account the shape of object and not just it's bounds
if(mc1.hitTestPoint(stage.mouseX, stage.mouseY, true)){
mc2.gotoAndStop(2);
}
}
If the above doesn't work because you have bimtap data in your button, then an easy way to accomplish this is to just add a shape mask to the button.
So, either inside your button using FlasPro, mask everything with a circle shape, or, do it via code by doing the following when you first show the button:
var s:Shape = new Shape();
s.graphics.beginFill(0);
s.graphics.drawCircle(mc1.x + (mc1.width * .5), mc1.y + (mc1.height * .5), mc1.width / 2);
addChild(s);
mc1.mask = s;
If using an image as the button, or you want to set a threshold of how transparent to consider a click, then you can check the transparency of the pixel under the mouse:
function doStuff(event:MouseEvent){
//only continue if pixel under the mosue is NOT transparent
//first, you need a bitmap to work with
//if you know for sure the position of your bitmap, you can do something like this:
var bm:Bitmap = mc1.getChildAt(0) as Bitmap;
//annoyingly though, FlashPro makes timeline bitmaps shapes,
//so the above won't work UNLESS you take your bitmap in the FlashPro Library
//and export it for actionscript, giving it a class name, then it will be an actual bitmap on the timeline.
//As an alternative, you could (very CPU expensively) draw the whole button as a bitmap
var bmd:BitmapData = new BitmapData(mc1.width,mc1.height,true,0x00000000);
bmd.draw(mc1);
var bm:Bitmap = new Bitmap(bmd);
//we get the 32bit pixel under the mouse point
var pixel:uint = bm.bitmapData.getPixel32(bm.x + event.localX,bm.y + event.localY);
//then we grab just the Alpha part of that pixel ( >> 24 & 0xFF ).
//if the value is 0, it's totally transparent, if it's 255, it's totally opaque.
//for this example, let's say anything greater than 0 is considered good to be a click
if((pixel >> 24 & 0xFF) > 0){
mc2.gotoAndStop(2);
}
}

Texture of ImageButton is not displayed on some devices when used TextureAtlas

I am using libGDX 1.0 and not sure if it is a bug or not.
My ImageButton is displayed correctly on a LG OPtimus and HTC Desire using TextureAtlas. However, on a Galaxy Tab2 the it becomes completely back, but it is still clickable.
If I load its texture from the AssetsManger, everything works fine on any device.
Here is the relevant part of the code:
stage = new Stage(new StretchViewport(fontCamera.viewportWidth,fontCamera.viewportHeight));
ImageButtonStyle styleButtonPlay = new ImageButtonStyle();
//this works
//textureButtonPlay = new TextureRegion(game.manager.get("data/ui/play.png",Texture.class));
//styleButtonPlay.imageUp = new TextureRegionDrawable(textureButtonPlay);
//this don't on Samsung Tab2
atlas = new TextureAtlas("data/shot/atlas.pack");
styleButtonPlay.imageUp = new TextureRegionDrawable(atlas.findRegion("ui/play"));
buttonPlay = new ImageButton(styleButtonPlay);
buttonPlay.addListener(
new ClickListener() {
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button)
{
startGame();
return true;
}
});
buttonPlay.setSize(80, 60);
buttonPlay.setPosition(camera.viewportWidth/2 - buttonPlay.getWidth()/2,5);
stage.addActor(buttonPlay);
I now am concerned about packing all my sprites onto single imaged.
The problem has been resolved by creating a texturepack.png with the size smaller than 4096x4096.
For some reason it was ok only on some devices and no similar problem has been noticed on the desktop.
Hope this help someone...
see your code here:
atlas = new TextureAtlas("data/shot/atlas.pack");
style.imageUp = new TextureRegionDrawable(atlas.findRegion("ui/play"));
^^^^^
buttonPlay = new ImageButton(styleButtonPlay);
^^^^^^^^^^^^^^^
it looks like you assign the wrong style to your imageButton, try putting the drawable into the correct button style ("styleButtonPlay" instead "style"):
styleButtonPlay.imageUp = new TextureRegionDrawable(atlas.findRegion("ui/play"));

LibGDX Android Game - displaying fixed text (ie Score) over a scrolling screen

I am beginning to write a game in LibGDX, only just beginning. I have got a basic tile map loaded, a player sprite and can move the character around and the screen (camera) scrolls around - perfect.
I have two overlayed textures in the bottom right of the screen, a left and right arrow, which are used as the joypad to control the character. I position these in relation to the players.x position, which is always fixed to the centre of the screen. Cool so far .... As below:
/////////////////////////////////////////////////////////////////
private void renderJoypad(float deltaTime)
{
batch.draw(Assets.leftJoypad, blockman.position.x-14, 1, 3, 3);
batch.draw(Assets.rightJoypad, blockman.position.x-9, 1, 3, 3);
}
I am now trying to put the player's score in the top left of the screen. The score is made of a Bitmap font, as below.
font = new BitmapFont(Gdx.files.internal("fonts/minecrafter.fnt"),Gdx.files.internal("fonts/minecrafter.png"),false);
font.setScale(0.02f);
In my render() method I cam calling some other methods to update, like the positions of the
leftJoypad etc, as in renderJoypad(). I am also calling my draw font method to update the position of the score, however, when I scroll it is all jerky, and sometimes it shows less characters than there should be.
public void drawScore(float deltaTime)
{
font.draw(batch, "00000", blockman.position.x, 10);
}
I believe that I need to place the score (and any other on screen texts, HUD etc) into a stage, but I cannot understand how to get it working with my existing code.
My show method is as follows:
public void show()
{
//load assets class to get images etc
Assets Assets = new Assets();
//start logging Framerate
Gdx.app.log( GameScreen.LOG, "Creating game" );
fpsLogger = new FPSLogger();
//set the stage - bazinga
Gdx.input.setInputProcessor(stage);
//stage.setCamera(camera);
//stage.setViewport(480, 360, false);
batch = new SpriteBatch();
//load the Joypad buttons
loadJoypad();
//background image
loadBackground();
//sounds
jumpSound = Gdx.audio.newSound(Gdx.files.internal("sounds/slime_jump.mp3"));
//LOAD block man here
// load the map, set the unit scale to 1/16 (1 unit == 16 pixels)
loadMap();
//draw the score
font = new BitmapFont(Gdx.files.internal("fonts/minecrafter.fnt"),Gdx.files.internal("fonts/minecrafter.png"),false);
font.setScale(0.02f);
// create an orthographic camera, shows us 30x20 units of the world
camera = new OrthographicCamera();
camera.setToOrtho(false, 30, 20);
camera.update();
// create the Blockman we want to move around the world
blockman = new Blockman();
blockman.position.set(25, 8);
}
and my render() method is as follows:
public void render(float delta)
{
// get the delta time
float deltaTime = Gdx.graphics.getDeltaTime();
stage.act(deltaTime);
stage.draw();
// clear the screen
Gdx.gl.glClearColor(0.3f, 0.3f, 0.3f, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
renderBackground(deltaTime);
batch = renderer.getSpriteBatch();
//updateBlockman(deltaTime);
blockman.update(deltaTime);
// let the camera follow the blockMan, x-axis only
camera.position.x = blockman.position.x;
camera.update();
// set the tile map rendere view based on what the
// camera sees and render the map
renderer.setView(camera);
renderer.render();
//start the main sprite batch
batch.begin();
// render the blockMan
renderBlockman(deltaTime);
renderJoypad(deltaTime);
drawScore(deltaTime);
batch.end();
fpsLogger.log();
}
I have tried to change the way things work with relation to the Spritebatch etc and just cannot seem to get it working as I require.
Can anyone suggest how I may approach getting a stage and actors to work, or a second camera or something to help me achieve a fixed score display in the corner.
Do I need to use Scene 2D or something - aahhh! My head is exploding....
I look forward and thank you in advance.
Regards
James
I have a couple of suggestions:
Check to see if you have setUseIntegerPositions set to true
(the default) when you draw your font. If you do, and you're scaling
it, then it can cause some odd effects similar to those that you
describe. Set it to false and see if it fixes the problem.
Reset your spritebatch's matrices before drawing the text, that way you won't need to adjust it for the scrolling.
I'd even go as far as to recommend not scaling the font if you can help it, because fonts often look a little odd after being scaled.

Movieclip -> BitmapData and origin

I'm trying to draw a MovieClip to a BitmapData so that it looks exactly the same as if I had done addChild(movieclip).
I can't seem to figure out what magic formula I need to use to keep the animation in place around it's origin.
This is the relevant bit of code:
private function update(e:Event):void
{
var bounds:Rectangle = movieClip.getBounds(movieClip);
bitmapData = new BitmapData(maxMCwidth, maxMCheight, true, 0x0);
bitmapData.draw(movieClip, new Matrix(1, 0, 0, 1, maxMCwidth - (bounds.x + bounds.width), maxMCheight - (bounds.y + bounds.height)));
bitmap.bitmapData = bitmapData;
}
Full code here: http://pastebin.com/KyU5FPeJ
And this is what the result looks like:
http://www.swfcabin.com/open/1339173476
The top animation is done using addChild(mc). The bottom animation is done using bitmapData.draw. Notice how the sword on the right doesn't move horizontally in the bottom version. Almost as if the whole animation was getting right-aligned.
Here's also a link to my flashdevelop project with the full code in case anybody wants to play around with it: https://www.dropbox.com/s/gvt4scknqdian2a/bitmapdatadrawing.zip
I just want both versions to look the same. What do I need to change to my bitmapData drawing code to make this happen?
Ok I figured it out!
The cause of the problem was that I'm not calculating maxMCwidth or maxMCheight correctly. I was going through the movieclip looking for the widest/highest single frame. BUT that doesn't take into account that the position of bounds across frames changes. To get the actual maximum width/height across the whole animation, I used this code:
maxBounds = new Rectangle();
for (var i:uint = 0; i < movieClip.totalFrames; i++)
{
var tempBounds:Rectangle = movieClip.getBounds(movieClip);
maxBounds = maxBounds.union(tempBounds);
movieClip.nextFrame();
}
Then this allowed me to fix the translation matrix:
bitmapData.draw(movieClip, new Matrix(1, 0, 0, 1, -maxBounds.x, -maxBounds.y));
And like this it works for every animation I've tested.
Ok I can't get your project to run since you didn't supply a main mxml.
However, I think I found your issue.
I don't think getBounds is returning the values you think they are.
I can't look into the skeleton swc but I have a feeling there is on object off the top or bottom of the screen in it and the way you coded it would cause it to shrink down to make it fit.
getBounds is probably adding that to the height.
bitmapData = new BitmapData(movieClip.width, movieClip.height, true, 0x0);
bitmapData.draw(movieClip, new Matrix(1, 0, 0, 1, movieClip.width/2, movieClip.height/2 ));
bitmap = new Bitmap(bitmapData);
bitmap.x = 70;
bitmap.y = 200;
Remember untested code here. :(