So i am having trouble keeping a display of the score in a game i am creating. I was wondering how would i go about doing that? this is what i have so far:
package com.catgame.game;
import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.InputProcessor;
import com.badlogic.gdx.audio.Music;
import com.badlogic.gdx.audio.Sound;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
public class CatGame extends ApplicationAdapter implements InputProcessor {
SpriteBatch batch;
Sprite cat;
OrthographicCamera camera;
final float CAT_WIDTH = 0.75f;
final float CAT_HEIGHT = 0.50f;
Sound meow;
int score = 0;
String scorePrint;
BitmapFont scoreFont;
#Override
public void create () {
batch = new SpriteBatch();
cat = new Sprite(new Texture(Gdx.files.internal("Cat.png")));
cat.setSize(CAT_WIDTH,CAT_HEIGHT);
scoreFont = new BitmapFont(Gdx.files.internal("score.fnt"));
float aspectRatio = (float)Gdx.graphics.getHeight()/
(float)Gdx.graphics.getWidth();
scoreFont.getData().setScale(0.5f);
camera = new OrthographicCamera(CAT_HEIGHT * aspectRatio,
CAT_HEIGHT);
camera.position.set(CAT_WIDTH/2,CAT_HEIGHT/2,0);
meow = Gdx.audio.newSound(Gdx.files.internal("Meow.wav"));
Gdx.input.setInputProcessor(this);
scorePrint = "Hello";
}
#Override
public void render () {
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
camera.update();
batch.begin();
batch.setProjectionMatrix(camera.combined);
//cat.draw(batch);
scoreFont.draw(batch,scorePrint,camera.position.x,camera.position.y);
batch.end();
}
I have tried scoreFont.draw() method but it doesn't seem to work. not sure why, maybe my positioning is wrong since I have an ortho camera or something. But When i tried to used the draw font, nothing appeared. The red circle in the image below shows where i would want the score around.
http://imgur.com/gallery/ywFF6SZ/new
Draw your font in render method and change your font colour or background colour.It might be possible because you black background colour match with BitmapFont colour.
You need to draw the score (or whatever you want to see on screen) inside the render function, because each render clears the canvas and redraws.
You are drawing the font too big. When you don't specify a scale for the font before drawing it, it draws it at a scale of one font pixel to one world unit. In your case, your camera height is less than one, so you are only seeing a fraction of one pixel of the first letter in your text, which is likely just empty space. Call setScale on the font after setting up your camera, using the appropriate scale to get it down to the size you want.
Related
I have just started with LibGdx and I have figured out how to center text with it. Now I am having trouble with center justifying text. I was wondering if someone can help. I have attach my code for centering. Thank you in advance.
package com.tutorials.game;
import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.GlyphLayout;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
public class TextDemo extends ApplicationAdapter {
SpriteBatch batch;
BitmapFont font;
String myText;
GlyphLayout layout = new GlyphLayout();
#Override
public void create () {
batch = new SpriteBatch();
font = new BitmapFont(Gdx.files.internal("myFont.fnt"));
myText = "I took one, one cause you left me\n"
+ "Two, two for my family\n"
+ "Three, three for my heartache";
layout.setText(font,myText);
}
#Override
public void render () {
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
float x = Gdx.graphics.getWidth()/2 - layout.width/2;
float y = Gdx.graphics.getHeight()/2 + layout.height/2;
batch.begin();
font.draw(batch,layout,x,y);//Center Text
batch.end();
}
You can use following setText() method instead and set targetWidth to screen width, Aligh.center, and set wrap to true. Also, set x = 0 so the text is centered across the whole screen.
import com.badlogic.gdx.graphics.g2d.GlyphLayout;
public void setText(BitmapFont font,
java.lang.CharSequence str,
Color color,
float targetWidth,
int halign,
boolean wrap)
Updated example:
#Override
public void create () {
batch = new SpriteBatch();
font = new BitmapFont(Gdx.files.internal("myFont.fnt"));
myText = "I took one, one cause you left me\n"
+ "Two, two for my family\n"
+ "Three, three for my heartache";
layout.setText(font,myText,Color.BLACK,Gdx.graphics.getWidth(),Align.center,true);
}
#Override
public void render () {
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
float x = 0;
float y = Gdx.graphics.getHeight()/2 + layout.height/2;
batch.begin();
font.draw(batch,layout,x,y);//Center Text
batch.end();
}
Instead of using the font.draw method, use the following one instead...
public TextBounds drawMultiLine (Batch batch, CharSequence str, float x, float y, float alignmentWidth, HAlignment alignment)
alignmentWidth is the max width you want your text to take up. Any more than that and it will wrap. Set it to something stupidly high if you don't want wrapping.
'alignment' is the key thing and takes an HAlignment enum and can be either LEFT, RIGHT or CENTER
The batch, str, x and y parameters are the same as you're already doing.
Here's the line I'm getting the error on:
bucket.x = touchPos.x - 64 / 2;
Here's the full code block:
package com.badlogic.drop;
import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.audio.Music;
import com.badlogic.gdx.audio.Sound;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.Vector3;
import java.awt.Rectangle;
public class Drop extends ApplicationAdapter {
private Texture dropImage;
private Texture bucketImage;
private Sound dropSound;
private Music rainMusic;
private OrthographicCamera camera;
private SpriteBatch batch;
private Rectangle bucket;
#Override
public void create () {
// load the images for the droplet and the bucket, 64x64 pixels each
dropImage = new Texture(Gdx.files.internal("droplet.png"));
bucketImage = new Texture(Gdx.files.internal("bucket.png"));
//instantiating the rectangle and specify its initial values
bucket = new Rectangle();
bucket.x = 800 / 2 - 64 / 2;
bucket.y = 20;
bucket.width = 64;
bucket.height = 64;
// setting the camera to show an area of the game world that is 800x480 units wide
camera = new OrthographicCamera();
camera.setToOrtho(false, 800, 480);
// creating the sprite batch
batch = new SpriteBatch();
// load the drop sound effect and the rain background "music"
dropSound = Gdx.audio.newSound(Gdx.files.internal("drop.wav"));
rainMusic = Gdx.audio.newMusic(Gdx.files.internal("rain.mp3"));
// start the playback of the background music immediately
rainMusic.setLooping(true);
rainMusic.play();
}
#Override
public void render () {
Gdx.gl.glClearColor(0, 0, 0.2f, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
// render the bucket
batch.setProjectionMatrix(camera.combined);
batch.begin();
batch.draw(bucketImage, bucket.x, bucket.y);
batch.end();
// telling the camera to make sure its updated
camera.update();
// making the button move through touch
if(Gdx.input.isTouched()) {
Vector3 touchPos = new Vector3();
touchPos.set(Gdx.input.getX(), Gdx.input.getY(), 0);
camera.unproject(touchPos);
bucket.x = touchPos.x - 64 / 2;
}
}
}
The error I'm receiving is telling me I have an incompatible types: Possible lossy conversion from float to int
Thanks in advance for the help, this is my first time posting to stackoverflow, I hope I formatted this correctly if you have any other questions let me know. :)
Based on the error message, your touchPos.x is a float. The compiler is telling you that when you try to put a floating-point value into an integer type, you will lose the fractional part (and if the number is really big, it might not fit), and you have to explicitly okay the conversion with a cast:
bucket.x = (int) (touchPos.x - 64) / 2;
Note also that you almost certainly meant the above version with parentheses; standard order of operations applies in Java. If you didn't, make your code clearer by just subtracting 32 instead.
So, I am working with LiBGDX and Box2D, using the PixelsPerMeter conversion, and I have a camera that follows the player around, but when I turn debug mode on I need to be able to draw a font with the fps on screen, so I always can see it in the corner. The problem is that when I try to scale the BitmapFont down, so it looks normal, cause everything else is scaled down, because of the Box2D. I found something that said something about using multiple cameras, so I don't have to scale the font down, but it didn't have any documentation. I tried to figure how to do it, but with no luck. How should I draw the font to the screen?
Here is my game state in which I tried the multiple cameras:
package com.platformer.gamestates;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.PerspectiveCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.Box2DDebugRenderer;
import com.badlogic.gdx.physics.box2d.World;
import com.platformer.Entities.Player;
import com.platformer.game.Game;
import com.platformer.generation.MenuTiles;
import com.platformer.generation.TiledMaps;
import com.platformer.managers.GameContacts;
import com.platformer.managers.GameStateManager;
import static com.platformer.managers.B2DVars.PPM;
public class MenuState extends GameState {
World world;
Box2DDebugRenderer debugRenderer;
Texture close, far, house;
BitmapFont font;
OrthographicCamera fontCam;
public static Player player;
MenuTiles menuTiles;
SpriteBatch batch;
float camx,camy;
float lerp=0.1f,lerpy=0.2f;
GameContacts gameContacts;
public MenuState(GameStateManager gsm){
super(gsm);
}
public void init(){
close=new Texture(Gdx.files.internal("menu_backgrounds/background_close.png"));
far=new Texture(Gdx.files.internal("menu_backgrounds/background_far.png"));
house=new Texture(Gdx.files.internal("menu_backgrounds/house_selected.png"));
batch=new SpriteBatch();
font=new BitmapFont();
fontCam=new OrthographicCamera();
fontCam.setToOrtho(false,Game.WIDTH,Game.HEIGHT);
fontCam.position.set(Game.WIDTH/2/PPM,Game.HEIGHT/2/PPM,0);
world=new World(new Vector2(0,-9.81f),true);
world.setVelocityThreshold(0);
gameContacts=new GameContacts();
world.setContactListener(gameContacts);
debugRenderer=new Box2DDebugRenderer();
player=new Player(world,960/2,49+20);
menuTiles=new MenuTiles(world);
}
public void update(float dt){
world.step(1/60f,6,2);
player.update(dt,gameContacts);
if(player.shouldPlay){gsm.setState(GameStateManager.PLAY);dispose();}
camx+=(player.x-camx)*lerp;
camy+=(player.y-camy)*lerpy;
}
public void draw(OrthographicCamera camera){
camera.position.x=Math.min(Math.max(camx,Game.WIDTH/2/PPM),(MenuTiles.levelWidth/PPM)-(Game.WIDTH/2/PPM));
camera.position.y=Math.min(Math.max(camy,Game.HEIGHT/2/PPM),(MenuTiles.levelHeight/PPM)-(Game.HEIGHT/2/PPM));
batch.begin();
batch.draw(far, 0, 0, 960 / PPM, 720 / PPM);
batch.draw(close,0,0,960/PPM,720/PPM);
batch.end();
//draw map
menuTiles.draw(camera);
batch.begin();
if(gameContacts.isOnHouse())batch.draw(house,192/PPM,48/PPM,2*MenuTiles.tileSize/PPM,2*MenuTiles.tileSize/PPM);
batch.end();
//draw player
player.draw(batch);
if(player.DebugOn){
debugRenderer.render(world, camera.combined);
batch.setProjectionMatrix(fontCam.combined);
batch.begin();
font.draw(batch,"fps",0,0);
batch.end();
System.out.println(Gdx.graphics.getFramesPerSecond()+" fps");
}
camera.update();
batch.setProjectionMatrix(camera.combined);
}
public void handleInput(){}
public void dispose(){
menuTiles.dispose();
close.dispose();
far.dispose();
house.dispose();
}
}
I don't think you want to divide by PPM in this line...
fontCam.position.set(Game.WIDTH/2/PPM,Game.HEIGHT/2/PPM,0);
I'm assuming the Game.WIDHT and HEIGHT are in pixels (this is not clear from your code snippet). If that's not teh case, then you should include the divide by PPM into this line...
fontCam.setToOrtho(false,Game.WIDTH,Game.HEIGHT);
At present it's not being consistently applied.
Also, you need to call fontcam.update() after setting its position.
Additionally: This is not to do with your question per se, but I'm not sure why you have the following lines at the end of teh render. I would place them right after I've changed the position of the standard camera.
camera.update();
batch.setProjectionMatrix(camera.combined);
Ok, I need to crop an ImageView in a particular shape, and I can't do this by adding over a png, because the background can be variable (ex. a pattern). So, I need that the area outside the shape is transparent.
The shape must be this:
I thought to use Path() to draw this shape and use it to mask the ImageView, but I have absolutely no idea how to draw a complex shape like this with Path().
Many thanks.
So I was bored and this looked like fun, so I've thrown together a simple Drawable you can use to do this. You could get fancier and add strokes and whatnot to it, but this works for the basic case you've suggested, and allows you to set the arrow to be pointing to any of the corners, and will also scale your image to fit the bounds of the Drawable. Here's the result:
You can use it by:
BubbleDrawable bubbleDrawable = new BubbleDrawable(
this, R.drawable.your_image, BubbleDrawable.Corner.TOP_RIGHT);
myImageView.setImageDrawable(bubbleDrawable);
And here's the code for BubbleDrawable:
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.drawable.Drawable;
import static android.graphics.Matrix.ScaleToFit.FILL;
import static android.graphics.Paint.ANTI_ALIAS_FLAG;
import static android.graphics.Path.Direction.CW;
import static android.graphics.PixelFormat.TRANSPARENT;
import static android.graphics.Shader.TileMode.CLAMP;
import static test.com.testrotationanimation.BubbleDrawable.Corner.TOP_LEFT;
public final class BubbleDrawable extends Drawable {
private final Matrix mMatrix = new Matrix();
private final Paint mPaint = new Paint(ANTI_ALIAS_FLAG);
private final Path mPath = new Path();
private final RectF mSrcRect = new RectF();
private final RectF mDstRect = new RectF();
private final Shader mShader;
private Corner mArrowCorner = TOP_LEFT;
public BubbleDrawable(Bitmap bitmap, Corner arrowCorner) {
// Initialize a BitmapShader with the image you wish to draw
// (you can use other TileModes like REPEAT or MIRROR if you prefer)
mShader = new BitmapShader(bitmap, CLAMP, CLAMP);
mPaint.setShader(mShader);
// Save the bounds of the bitmap as the src rectangle -- will
// be used later to update the matrix when the bounds change
// so that the image fits within the bounds of this drawable
mSrcRect.set(0, 0, bitmap.getWidth(), bitmap.getHeight());
// Set the corner in which the arrow will be drawn
mArrowCorner = arrowCorner;
}
public BubbleDrawable(Context ctx, int drawableResource, Corner arrowCorner) {
this(BitmapFactory.decodeResource(ctx.getResources(), drawableResource), arrowCorner);
}
public Corner getArrowCorner() {
return mArrowCorner;
}
public void setArrowCorner(Corner corner) {
mArrowCorner = corner;
updatePath();
invalidateSelf();
}
#Override
protected void onBoundsChange(Rect bounds) {
super.onBoundsChange(bounds);
updateMatrix(bounds);
updatePath();
}
private void updateMatrix(Rect bounds) {
// Set the destination rectangle for the bitmap to be the
// new drawable bounds
mDstRect.set(bounds);
// Scale the bitmap's rectangle to the bounds of this drawable
mMatrix.setRectToRect(mSrcRect, mDstRect, FILL);
// Update the shader's matrix (to draw the bitmap at the right size)
mShader.setLocalMatrix(mMatrix);
}
private void updatePath() {
final Rect bounds = getBounds();
final float x = bounds.exactCenterX();
final float y = bounds.exactCenterY();
// Draw the initial circle (same for all corners)
mPath.reset();
mPath.addCircle(x, y, Math.min(x, y), CW);
// Add the rectangle which intersects with the center,
// based on the corner in which the arrow should draw
switch (mArrowCorner) {
case TOP_LEFT:
mPath.addRect(bounds.left, bounds.top, x, y, CW);
break;
case TOP_RIGHT:
mPath.addRect(x, bounds.top, bounds.right, y, CW);
break;
case BOTTOM_LEFT:
mPath.addRect(bounds.left, y, x, bounds.bottom, CW);
break;
case BOTTOM_RIGHT:
mPath.addRect(x, y, bounds.right, bounds.bottom, CW);
break;
}
}
#Override
public void draw(Canvas canvas) {
// Easy enough, just draw the path using the paint.
// It already has the BitmapShader applied which
// will do the work for you.
canvas.drawPath(mPath, mPaint);
}
#Override
public int getOpacity() {
// Indicate that this Drawable has fully-transparent pixel values
return TRANSPARENT;
}
#Override
public void setColorFilter(ColorFilter colorFilter) {
// Yay, you can even support color filters for your drawable
mPaint.setColorFilter(colorFilter);
}
#Override
public void setAlpha(int i) {
// You could do this by doing some canvas magic but I'm
// lazy and don't feel like it. Exercise for the reader. :)
throw new UnsupportedOperationException("Not implemented.");
}
public enum Corner {
TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT, BOTTOM_RIGHT
}
}
I've tried to get my text to appear, but I cannot get it on screen. I've played with the numbers a few times and found out that LibGDX drew the font to abnormally large sizes, but I don't exactly know if I still need to scale the font size smaller, or if I'm drawing them offscreen. I've copied the entire code and pasted it below.
I used Hiero to make a 256x256 bitmapfont of ariel black on white background.
package com.me.manners;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.graphics.GL10;
import com.badlogic.gdx.graphics.PerspectiveCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.Texture.TextureFilter;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.me.input.Input;
public class Choice implements Screen
{
private PerspectiveCamera camera;
private SpriteBatch batch;
private Texture arrowT;
private Sprite arrowS;
private BitmapFont font;
private String str1 = "Hello World!";
private Input input = new Input();
private Manners game;
public Choice(Manners game)
{
this.game = game;
camera = new PerspectiveCamera();
batch = new SpriteBatch();
font = new BitmapFont(Gdx.files.internal("data/choice/ariel.fnt"), Gdx.files.internal("data/choice/ariel.png"),false);
Gdx.input.setInputProcessor(input);
arrowT = new Texture(Gdx.files.internal("data/choice/arrow.png"));
arrowT.setFilter(TextureFilter.Linear, TextureFilter.Linear);
arrowS = new Sprite(new TextureRegion(arrowT, 0, 0, 64, 64));
arrowS.setSize(0.125f, 0.25f);
arrowS.setPosition(-0.75f, 0);
}
#Override
public void dispose() {
batch.dispose();
arrowT.dispose();
}
#Override
public void render(float delta) {
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
batch.setProjectionMatrix(camera.combined);
batch.begin();
arrowS.draw(batch);
font.setColor(1.0f,1.0f,0.0f,1.0f);
font.setScale(0.5f,0.5f);
font.draw(batch, str1, Gdx.graphics.getWidth()*0.5f, Gdx.graphics.getHeight()*0.5f);
batch.end();
}
}
I think your game is 2D game, so using camera = new OrthographicCamera(viewportWidth, viewportHeight) can fix your problem.
phucvin makes a very good observation. It seems your game is 2d ,so you should use an OrtographicCamera. I would recommend you to use big numbers, because the BitmapFont will render using its correct pixel size (thus thats the reason you saw very big letters).
camera = new OrthographicCamera(480, 320); //for example.
Of course you will need to change the Sprite size to something bigger
arrowS.setSize(100, 20); //for example
Or using a second camera with low viewport values for the sprites.