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

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.

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 ..

LibGdx View Port, resolutions, sprite size

Helllo, im new to libgdx, i need some help, if my desktoplauncher resolution is 480x320, sprite takes 80% of the screen, but if 1280x720, sprite is small, i need to make it look the same at all resoltions so how do i do this? may be easy for you, but not for my, im using libgdx 1.3.1
this is my libgdx code:
SpriteBatch batch;
Texture img;
Sprite mysprite;
#Override
public void create ()
{
batch = new SpriteBatch();
img = new Texture("badlogic.jpg");
mysprite = new Sprite(img);
stage = new Stage(new StretchViewport(480, 320));
}
StretchViewport myviewport = new StretchViewport(480, 320);
public void resize(int width, int height)
{
// use true here to center the camera
// that's what you probably want in case of a UI
stage.setViewport(myviewport);
stage.getCamera().position.set(640/2, 480/2, 0);
}
private Stage stage;
#Override
public void render ()
{
Gdx.gl.glClearColor(1, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.begin();
mysprite.draw(batch);
batch.end();
}
You are allready using the right thing: Viewport.
There are different Viewport classes, some of them support working with a virtual screen size, which is what you are looking for.
What is a virtual screen size? Well it is the screen size your code is working with and which is then scaled up to match the real resolution.
Basicly you can work with your own units and they are then automatically scaled up to match pixels.
I guess in your case there are 2 possible Viewport-types:
- StretchViewport supports virtual screen sizes and scales it up to match the real screen size and the real aspect ratio. If the real aspect ration does not match the virtual one the Sprites will be stretched, which could look strange.
- FitViewport is the same as the StretchViewport, but it will keep the aspect ratio. If the real aspect ration does not match the virtual one, black borders will appear.
How to use it:
First you need to create it:
myViewport = new StretchViewport(VIRTUAL_WIDTH, VIRTUAL_HEIGHT);
Then set the Stages Viewport:
stage = new Stage(myViewport);
In the resize method you need to update your Viewport:
myViewport.update(width, height);
Thats all.
The stage now uses the Viewport and its camera to render. You don't need to touch the camera, unless you need to move it arround.
So your errors are:
stage = new Stage(new StretchViewport(480, 320));
Which creates a new StretchViewport you don't store/use.
stage.setViewport(myviewport);
You only need to set it once, when you create the stage
You never call update(width, height) for the Viewport.

Libgdx: Stage only renders at (0, 0)

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.

Supporting Multiple image resolution for libgdx

How should I follow the directory structure and what to specify so that assetManger will use that folder for different resolution.
I have studied assetManager and ResolutionFileResolver but until now I couldn't exactly figured how to specify the folder to support different resolutions.
Update: Newer versions of Libgdx use a different strategy to resolve filenames (with directories, not files), so this answer does not apply to newer Libgdx versions after (0.9.2, I think? https://github.com/libgdx/libgdx/commit/3afcfe49c40196765033a90b4610159183dde981)
The built-in ResolutionFileResolver does not use a directory hierarchy. It uses file suffixes to match screen resolutions to assets.
Here's the code from the libGDX AssetManagerTest:
Resolution[] resolutions = { new Resolution(320, 480, ".320480"),
new Resolution(480, 800, ".480800"),
new Resolution(480, 856, ".480854") };
ResolutionFileResolver resolver = new ResolutionFileResolver(new InternalFileHandleResolver(), resolutions);
AssetManager manager = new AssetManager();
manager.setLoader(Texture.class, new TextureLoader(resolver));
...
The resolver appends one of those suffixes based on the current screen resolution. So, for example, if you look up "foo.jpg" on a 480x800 device, the file "foo.jpg.480800" will be opened.
If you want to resolve files based on directories (so "foo.jpg" would be resolved to "480x800/foo.jpg" or something like that), you can write a new resolver. Just implement FileHandleResolver. The ResolutionFileResolver.java source is probably a good place to start.
Once me too suffered from this problem but at end i got the working solution, for drawing anything using SpriteBatch or Stage in libgdx. Using orthogrphic camera we can do this.
first choose one constant resolution which is best for game. Here i have taken 1280*720(landscape).
class ScreenTest implements Screen{
final float appWidth = 1280, screenWidth = Gdx.graphics.getWidth();
final float appHeight = 720, screenHeight = Gdx.graphics.getHeight();
OrthographicCamera camera;
SpriteBatch batch;
Stage stage;
Texture img1;
Image img2;
public ScreenTest(){
camera = new OrthographicCamera();
camera.setToOrtho(false, appWidth, appHeight);
batch = new SpriteBatch();
batch.setProjectionMatrix(camera.combined);
img1 = new Texture("your_image1.png");
img2 = new Image(new Texture("your_image2.png"));
img2.setPosition(0, 0); // drawing from (0,0)
stage = new Stage(new StretchViewport(appWidth, appHeight, camera));
stage.addActor(img2);
}
#Override
public void render(float delta) {
batch.begin();
batch.draw(img, 0, 0);
batch.end();
stage.act();
stage.act(delta);
stage.draw();
// Also You can get touch input according to your Screen.
if (Gdx.input.isTouched()) {
System.out.println(" X " + Gdx.input.getX() * (appWidth / screenWidth));
System.out.println(" Y " + Gdx.input.getY() * (appHeight / screenHeight));
}
}
//
:
:
//
}
run this code in Any type of resolution it will going to adjust in that resolution without any disturbance.
If you use an OrthographicCamera you won't need to deal with different image resolutions.
Say that you have a camera with the size 400x300. Then you draw a 400x300 large image at coordinate (0,0). Then, regardless of screen resolution, the image will be scaled to fill the screen. This is really neat on Android where the screen resolution can vary a lot between different devices, and doing it like this you won't have to think about it.

How can I load a Papervision/Flex application (SWF) as a material on a Papervision plane?

I am trying to build a portfolio application similar to the used by Whitevoid. I am using Flex 4 and Papervision3D 2. I have everything working except for one issue. When I try to load an external SWF as a material on one of the planes, I can see any native Flex or Flash components in their correct positions, but the papervision objects are not being rendered properly. It looks like the viewport is not being set in the nested swf. I have posted my code for loading the swf below.
private function loadMovie(path:String=""):void
{
loader = new Loader();
request = new URLRequest(path);
loader.contentLoaderInfo.addEventListener(Event.INIT, addMaterial);
loader.load(request);
}
private function addMaterial(e:Event):void
{
movie = new MovieClip();
movie.addChild(e.target.content);
var width:Number = 0;
var height:Number = 0;
width = loader.contentLoaderInfo.width;
height = loader.contentLoaderInfo.height;
//calculate the aspect ratio of the swf
var matAR:Number = width/height;
if (matAR > aspectRatio)
{
plane.scaleY = aspectRatio / matAR;
}
else if (matAR < aspectRatio)
{
plane.scaleX = matAR / aspectRatio;
}
var mat:MovieMaterial = new MovieMaterial(movie, false, true, false, new Rectangle(0, 0, width, height));
mat.interactive = true;
mat.smooth = true;
plane.material = mat;
}
Below I have posted two pictures. The first is a shot of the application running by itself. The second is the application as a MovieMaterial on a Plane. You can see how the button created as a spark object in the mxml stays in the correct position, but papervision sphere (which is rotating) is in the wrong location. Is there something I am missing here?
Man. I haven't seen that site in a while. Still one of the cooler PV projects...
What do you mean by:
I cannot properly see the scene rendered in Papervision
You say you can see the components in their appropriate positions, as in: you have a plane with what looks like the intended file loading up? But I'm guessing that you can't interact with it.
As far as I know, and I've spent a reasonable amount of time trying to make something similar work, the MovieMaterial (which I assume you're using) draws a Bitmap of whatever contents exist in your MovieClip, and if you set it to animated=true, then it will render out a series of bitmaps - equating animation. What it's not doing, is displaying an actual MovieClip (or SWF) on the plane. So you may see your components, but this is how:
MovieMaterial.as line 137
// ______________________________________________________________________ CREATE BITMAP
/**
*
* #param asset
* #return
*/
protected function createBitmapFromSprite( asset:DisplayObject ):BitmapData
{
// Set the new movie reference
movie = asset;
// initialize the bitmap since it's new
initBitmap( movie );
// Draw
drawBitmap();
// Call super.createBitmap to centralize the bitmap specific code.
// Here only MovieClip specific code, all bitmap code (maxUVs, AUTO_MIP_MAP, correctBitmap) in BitmapMaterial.
bitmap = super.createBitmap( bitmap );
return bitmap;
}
Note in the WhiteVoid you never actually interact with a movie until it "lands" = he's very likely swapping in a Movie on top of the bitmap textured plane.
The part that you are interacting with is probably another plane that holds the "button" that simply becomes visible on mouseover.
I think PV1.0 had access to real swfs as a material but this changed in 2.0. Sadly. Hopefully Molehill will.
cheers