I've been having some trouble with libgdx and my code and I wanted to know how you can make the text stop moving with the camera. What I wanted to do was label the corridnates of a 2d array that I created but when I do the text moves with the camera.
here's what I wrote:
batch.begin();
for(int x = 0; x < world.getWidth(); x+=size){
for(int y = 0; y < world.getHeight(); y +=size){
Room r = (Room)dCreator.getRooms(x/size,y/size);
font.draw(batch, x+", "+y, r.getX(), r.getY());
}
}
batch.end();
Any help or questions would be appreciated!
You need to create a new camera, which won't move like the other. It is very common to have more cameras in a game, mostly one for rendering game and the second one for GUI.
OrthographicCamera gameCam = new OrthographicCamera();
OrthographicCamera guiCam = new OrthographicCamera();
guiCam.setToOrtho(false, SCREEN_WIDTH, SCREEN_HEIGHT);
gameCam.setToOrtho(false, GAME_WIDTH, GAME_HEIGHT);
and then in code:
batch.setProjectionMatrix(gameCam.combined);
batch.begin();
//render game stuff
batch.end();
batch.setProjectionMatrix(guiCam.combined);
batch.begin();
//draw gui, text, etc..
batch.end();
And remember only to move the gameCam, not the guiCam.
Related
I made a simple program that simulates cells in a grid with their own color and displays them as 4x4 pixels, at first i made it using java AWT and the performance was ok but i was curious about how LibGDX perform and it was about 5 times slower, am i doing something wrong or is LibGDX just that much slower? here is my rendering loop:
#Override
public void create () {
cam = new OrthographicCamera(width, height);
Gdx.graphics.setWindowedMode(width * scale, height * scale);
renderer = new ShapeRenderer();
inputs = new Inputs();
world = new World(width, height, 8);
Gdx.input.setInputProcessor(inputs);
}
Pixel thisPixel;
#Override
public void render () {
Gdx.gl.glClearColor(0, 1, 1, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
renderer.setProjectionMatrix(cam.combined);
renderer.begin(ShapeRenderer.ShapeType.Filled);
inputs.update();
for (int x = 0; x < width; x ++)
for (int y = 0; y < height; y ++) {
thisPixel = world.getPixel(x, y);
renderer.setColor(world.materials.colors[thisPixel.colorId]);
renderer.rect(x - width / 2 - 1, y - height / 2 - 1, 1, 1);
}
renderer.end();
System.out.println(Gdx.graphics.getFramesPerSecond());
}
AWT use canvas to draw which is a 2D surface. LibGDX use openGL which is for 3D rendering and you have to project it onto a 2D surface (renderer.setProjectionMatrix(cam.combined);)
Drawing rects and scaling are quite costly operations, so if you can find an other way to achieve what you want it might speed things up.
So, im making a game, and i need to display fps in it.
It is how it looks like
You can think that it is okay, but if i try to fly away, text stays there. It is not moving.
public void render(SpriteBatch batch) {
batch.begin();
Draw.draw();
MainScreen.player.draw();
TextManager.displayMessage("FPS: "+ Gdx.graphics.getFramesPerSecond(), true, false, false, false);
PlayerControl.update();
CamControl.update();
UI.drawCurrentBlock();
batch.end();
}
This is a code that displays fps.
I need it moving with my screen.
UPD: idea with making static camera didn't work. It just literally doesn't moves.
If i try to sync text with camera coordinates, it moves, but it is 'shaking'.
Are there another methods to display it literally in screen, or make it's sync with camera normal?
This is often solved with dual cameras, one camera is your game camera that observes the game world, the other is a stationary camera that is the view of the HUD.
The HUD camera never moves and is configured so that the width and height is suitable for whatever graphics it is supposed to display, this can be but does not have to be the pixel-dimensions of the window.
The position of the camera can be whatever suits your needs, but if you set the postion to viewportWidth / 2.0, viewportHeight / 2.0 you'll get a viewport for the HUD where (0, 0) is the lower left corner of the screen:
For example:
hudCamera = new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
hudCamera.position.set(hudCamera.viewportWidth / 2.0f, hudCamera.viewportHeight / 2.0f, 1.0f);
In the render method this can then be used to draw text:
hudCamera.update();
spriteBatch.setProjectionMatrix(hudCamera.combined);
spriteBatch.begin();
font.draw(spriteBatch, "Upper left, FPS=" + Gdx.graphics.getFramesPerSecond(), 0, hudCamera.viewportHeight);
font.draw(spriteBatch, "Lower left", 0, font.getLineHeight());
spriteBatch.end();
In the example below the red circle is the player, and the yellow grid is the game world. The player moves in the game world with the game camera both following it and sometimes being stationary, during both of these operations the HUD text is stationary as that is rendered using the HUD camera which does not move. The full source code for the example is included after the image, it uses the default bitmap font from the libGDX github (Font PNG file and FONT .fnt file)
package somepackage;
import com.badlogic.gdx.Game;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.math.Vector2;
public class HudExampleGame extends Game {
private OrthographicCamera gameCamera;
private OrthographicCamera hudCamera;
private ShapeRenderer shapeRenderer;
private Vector2 playerPosition = new Vector2();
private boolean cameraFollowsPlayer = true;
private SpriteBatch spriteBatch;
private BitmapFont font;
#Override
public void create() {
float aspectRatio = (float) Gdx.graphics.getHeight() / (float) Gdx.graphics.getWidth();
float viewableWorldWidth = 32.0f;
gameCamera = new OrthographicCamera(viewableWorldWidth, viewableWorldWidth * aspectRatio);
gameCamera.position.set(playerPosition.x, playerPosition.y, 1.0f);
hudCamera = new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
hudCamera.position.set(hudCamera.viewportWidth / 2.0f, hudCamera.viewportHeight / 2.0f, 1.0f);
shapeRenderer = new ShapeRenderer();
spriteBatch = new SpriteBatch();
font = new BitmapFont(Gdx.files.internal("default.fnt"));
}
#Override
public void render() {
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
// Use the game camera to render the game world
gameCamera.update();
shapeRenderer.setProjectionMatrix(gameCamera.combined);
shapeRenderer.begin(ShapeRenderer.ShapeType.Line);
shapeRenderer.setColor(Color.YELLOW);
for (int x = -32; x <= 32; ++x)
shapeRenderer.line(x, -32, x, 32);
for (int y = -32; y <= 32; ++y)
shapeRenderer.line(-32, y, 32, y);
shapeRenderer.setColor(Color.RED);
shapeRenderer.circle(playerPosition.x, playerPosition.y, 1.0f, 24);
Vector2 movement = new Vector2();
if (Gdx.input.isKeyPressed(Input.Keys.LEFT))
movement.x -= 1;
if (Gdx.input.isKeyPressed(Input.Keys.RIGHT))
movement.x += 1;
if (Gdx.input.isKeyPressed(Input.Keys.UP))
movement.y += 1;
if (Gdx.input.isKeyPressed(Input.Keys.DOWN))
movement.y -= 1;
if (Gdx.input.isKeyJustPressed(Input.Keys.SPACE))
cameraFollowsPlayer = !cameraFollowsPlayer;
playerPosition.add(movement.scl(Gdx.graphics.getDeltaTime() * 8.0f));
if (cameraFollowsPlayer)
gameCamera.position.set(playerPosition.x, playerPosition.y, 1.0f);
shapeRenderer.end();
// Use the HUD camera to render the text
hudCamera.update();
spriteBatch.setProjectionMatrix(hudCamera.combined);
spriteBatch.begin();
font.draw(spriteBatch, "Upper left, FPS=" + Gdx.graphics.getFramesPerSecond(), 0, hudCamera.viewportHeight);
font.draw(spriteBatch, "Lower left", 0, font.getLineHeight());
spriteBatch.end();
}
}
in my game, I am trying to make a list of sprites move horizontally. Here is my render method:
public void render() {
Gdx.gl.glClearColor(255, 255, 255, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
int speed = 3;
ConveyorBelt cnb = new ConveyorBelt();
for (int i = 0; i < 6; i++) {
Sprite s = new Sprite(img);
s.setPosition(500 - 100 * i, 100);
cnb.belt.push(s);
}
batch.begin();
for (Sprite s : cnb.belt) {
s.draw(batch);
s.setX(s.getX() + speed);
}
batch.end();
}
I want one of the sprites from the list to disappear, once hitting a certain point on the screen. Unfortunately, they dont seem to move. What is the reason fot that?
Thanks in advance!
You're creating a brand new list of sprites every time render() is called. They all start at the initial positions you gave them, regardless of what you did to the sprites from the previous frame that are now all gone.
Move your new ConveyorBelt() and Sprite creation loop into create().
made two circles one of radius 8(image 16x16)
and one of radius 20( image 40x40)
i am calling the circle over overlap method and the collsion is just off. It is colliding with a circle that is around the 0,0 point of where ever my image of the ball is. the bullet can go within the ball on the bottom and right sides.
public class MyGame extends ApplicationAdapter {
SpriteBatch batch;
Texture ballImage, bulletImage;
OrthographicCamera cam;
Circle ball;
Array <Circle> bullets;
long lastShot;
#Override
public void create ()
{
System.out.println("game created");
ballImage = new Texture(Gdx.files.internal("ball.png"));
bulletImage = new Texture(Gdx.files.internal("bullet.png"));
cam = new OrthographicCamera();
cam.setToOrtho(true,320,480);//true starts top right false starts top left
batch = new SpriteBatch();
ball = new Circle();
ball.radius=20;
ball.x=320/2-ball.radius; // half screen size - half image
ball.y=480/2-ball.radius;
bullets = new Array<Circle>();
spawnBullet();
/*
batch.draw(bulletImage,bullet.x,bullet.y);
bullet.x++;
bullet.y++; */
}
public void spawnBullet()
{
Circle bullet = new Circle();
bullet.radius=8;
bullet.x=0;
bullet.y=0;
bullets.add(bullet);
lastShot = TimeUtils.nanoTime();
}
#Override
public void render ()
{
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
cam.update();
batch.setProjectionMatrix(cam.combined);
batch.begin();
batch.draw(ballImage,ball.x,ball.y);
for(Circle bullet: bullets)
{
batch.draw(bulletImage, bullet.x, bullet.y);
}
batch.end();
if(Gdx.input.isTouched())
{
Vector3 pos = new Vector3();
pos.set(Gdx.input.getX(), Gdx.input.getY(),0);
cam.unproject(pos);
ball.y = pos.y - ball.radius;
ball.x = pos.x - ball.radius ;
}
//if(TimeUtils.nanoTime()-lastShot >1000000000) one second
//spawnBullet();
Iterator<Circle> i = bullets.iterator();
while(i.hasNext())
{
Circle bullet = i.next();
bullet.x++;
bullet.y++;
if(bullet.overlaps(ball))
{
System.out.println("overlap");
i.remove();
}
}
}
}
If your bullet and the ball are 2 circles, like you said you don't need an overlap method.
It is simple: 2 circles collide, if their distance is smaller then the sum of their radiuses.
To calculate the distance you need to make a squareroot. This is a pretty expensive calculation, so it would be better to use squared distance and squared sum of radiuses:
float xD = ball.x - bullet.x; // delta x
float yD = ball.y - bullet.y; // delta y
float sqDist = xD * xD + yD * yD; // square distance
boolean collision = sqDist <= (ball.radius+bullet.radius) * (ball.radius+bullet.radius);
Thats it.
Also in your cam.setToOrtho you wrote a cooment:
//true starts top right false starts top left
Thats wrong, it is top left or bottom left. By default it is bottom left, because this is the way a coordinate system works normaly. The top left is, because the monitor addresses pixels starting from top left = pixel 1.
EDIT: this should be the problem: The coordinates you give the batch.draw method are the left lower corner of the Texture by default, if you are using the "y = Down"-System it should be the top left corner (you have to try i am not sure).
The Circles position instead is its center.
To solve the problem you need to adjust the position like this (for "y = Up"-System):
batch.draw(bulletImage, bullet.x - bullet.radius, bullet.y - bullet.radius);
It is possible, that the same formula works also for the "y = Down"-System but i am not sure
I am trying to create a simple board game using libGDX. Just that you have a rough idea of what I'm trying to do, imagine Bejeweled (though mine of course is not as complex).
The game involves a board with cells as squares. Depending on the level, this grid has a different number of cells, like 6x6 or 8x8. I also want to include some nice animation for switching the position of two neighboring cells (like in Bejeweled). Of course there also need to be some buttons on the screen.
My question is: What is the best way to do this? Shall I use a stage and then tables for the grid? Can I then still easily make an animation (using the Universal Tween Engine)? Or is it better to draw the Sprites individually? Or is there another completely different way of approaching this?
Thank you for your answers,
Cheers,
Tony
Sprite square = new Sprite(new Texture("texture"));
Render
float squareWidth = camera.viewportWidth / squaresOnWidth;
float squareHeight = camera.viewportHeight / squaresOnHeight;
square.setWidth(squareWidth);
square.setHeight(squareHeight);
batch.begin(); `
for(int y = 0; y < squaresOnHeight; y++){
for(int x = 0; x < squaresOnWidth; x++){
square.setX(x * squareWidth);
square.setY(y * squareHeight);
square.draw(batch);
}
}
batch.end();
This should output a grid of textures, not tested.
If you want to create smooth animation you should definitely look into UniveralTweenEngine, here's a demo of what it can do : http://www.aurelienribon.com/universal-tween-engine/gwt/demo.html
If you want the grid in buttons instead.
OrthoGraphicCamera camera = new OrthoGraphicCamera();
camera.setToOrtho(false, yourViewportWidth, yourViewportHeight);
camera.translate(xPos, yPos);
Stage stage = new Stage(your wanted stage width, your wanted stage height, false, batch);
stage.setCamera(camera);
for(int y = 0; y < buttonsOnHeight; y++){
for(int x = 0; x < buttonsOnWidth; x++){
stage.addActor(new TextButton("" + x + y * buttonsOnWidth, textButtonStyle);
}
}
The render
float buttonWidth = camera.viewportWidth / buttonsOnWidth;
float buttonHeight = camera.viewportHeight / buttonsOnHeight;
for(int y = 0; y < buttonsOnHeight; y++){
for(int x = 0; x < buttonsOnWidth; x++){
TextButton button = stage.getActors().get(x + y * buttonsOnWidth);
button.setX(x * buttonWidth);
button.setY(y * buttonHeight);
button.setWidth(buttonWidth);
button.setHeight(buttonHeight);
}
}
Then draw the stage, note that you should stop any batch that's currently running because stage has it's own batch.begin() and batch.end(). You could start your batch again after stage.draw();
stage.act(delta);
stage.draw();
To have a grid you could and should use camera:
OrthographicCamera cam = new OrthographicCamera(8,8);
You tell the camera to have a viewport of 8 x and 8 y.
The cameras (0,0) point is in the middle of the screen.
To have it at the left bottom you need to set its position to
cam.translate(camWidth / 2, camHeight / 2);
Now you can add your sqares at sqare.setX(0) for sqares on the bottom line or sqare.setY(3) to add it on the 4rd row from left to right. For the animations you could also use Actions, which allow you to add different movements to an actor and let him perform them over time. Example:
actor.addAction(Actions.parallel(Actions.moveTo(float x, float y, float duration), Actions.rotateTo(float rotation, float duration)));
With this code sample you tell your actor to move from his position to (x,y) in duration seconds and while he moves to this position he rotates from his current rotation to rotation in duration seconds.
Hope this helps