I'm making a prototype project in LibGDX and I'm using Box2D for the physics.
I've created a map and added some collision to him, i added entities that has circle shapes too.
These circles are correctly positioned in the World of Box2D, but the textures that i want to get fixed to them are getting based on other coordinates, from the user camera I think.
This is the result:
My render method in the base "Entity" class
public void update() {
handleInput();
}
public void render(SpriteBatch batch) {
update();
batch.begin();
batch.draw(texture, body.getPosition().x, body.getPosition().y);
batch.end();
}
My render method in the BaseMap class
private void update(OrthographicCamera camera) {
camera.position.x = player.getPosition().x;
camera.position.y = player.getPosition().y;
world.step(1/60f, 6, 2);
}
public void render(OrthographicCamera camera, SpriteBatch batch) {
update(camera);
renderer.setView(camera);
batch.begin();
renderer.render();
batch.end();
for(Entity entity : entities) {
entity.render(batch);
}
}
The renderer here is a OrthogonalTiledMapRenderer
Make sure you're setting the matrix for the batch as well:
batch.setProjectionMatrix(camera.combined);
Likewise for the Box2DDebugRenderer:
renderer.render(world, camera.combined);
This is assuming you aren't using a scaled box2d world.
I'm new in creating game.
I have several boxes that move from top to bottom of screen and i need to make 1 unit distance between them.
Every thing works fine except the distance is not precise and i think the deltatime cause this problem
This is how i move the boxes :
objX -= deltatime * speed;
Update
time += deltatime :if(time >= 3.0f) spawn
Im using libgdx
You can schedule your task in this way :
Array<Sprite> sprites;
Texture texture;
SpriteBatch batch;
float speed=35;
#Override
public void create() {
sprites=new Array<Sprite>();
texture=new Texture("badlogic.jpg");
batch=new SpriteBatch();
Timer.instance().scheduleTask(new Timer.Task() {
#Override
public void run() {
spawn();
}
},1,2);
}
private void spawn(){
Sprite sprite=new Sprite(texture);
sprite.setSize(50,50);
sprite.setPosition(Gdx.graphics.getWidth()/2,0);
sprites.add(sprite);
}
#Override
public void render() {
Gdx.gl.glClearColor(1,1,1,1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
float delta=Gdx.graphics.getDeltaTime();
batch.begin();
for (Sprite sprite:sprites){
sprite.setY(sprite.getY()+delta*speed);
sprite.draw(batch);
}
batch.end();
}
After a lot of struggling i came up with an idea which is
instead of moving boxes and spawning them by deltatime , make boxes static and move camera over them!
So i just move camera here
public void render(float delta) {
posCameraDesired.y += 2000.0f * Gdx.graphics.getDeltaTime();
guiCam.position.lerp(posCameraDesired, 0.1f);
SemiRender();
}
and i have static Y that i'll update after each spawn
lastY = 10 + lastY + ((width / 4) / 2) * 3;
and some other logic to recycle them when they passed the viewport.
and every one is happy!
So, I have created a texture, and then a sprite.
On my render() method, I am check for user input. If the user has touched/clicked, then I want my sprite to rotate 90 degrees ONCE.
Right now the rotation works. However, it rotates multiple times per click!
How can I make it rotate only once per touch? I have a feeling that I might have to use delta time, and that occurs because the render method is being called frequently, but I don't know how to fix it... Thanks!
public class MyGame extends ApplicationAdapter {
SpriteBatch batch;
Texture img;
Sprite sprite;
#Override
public void create () {
batch = new SpriteBatch();
img = new Texture("badlogic.jpg");
sprite = new Sprite(img);
}
#Override
public void render () {
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.begin();
sprite.draw(batch);
batch.end();
if (Gdx.input.isTouched()) {
rotateRight();
}
}
private void rotateRight() {
sprite.setRotation(sprite.getRotation() - 90);
}
}
Right now you are polling input inside of your render method. Polling simply checks the status of the input (is it touched or not) and does not care for any actual "event" occurred.
Instead of this you need to look for input events via event handling as this will give you access to the actual event of the screen being touched or untouched. You can do this by implementing InputProcessor which will give you access to override a bunch of touch event methods so you can execute your rotate method only on the event of the touch.
Example:
public void update()
{
Gdx.input.setInputProcessor(new InputProcessor() {
#Override
public boolean TouchDown(int x, int y, int pointer, int button) {
if (button == Input.Buttons.LEFT) {
rotateRight();
return true;
}
return false
}
});
}
Don't forget to call your update() method from your render method. I put it in a separate function just for readability and not to clog up your rendering code.
You can also have your class implement InputProcessor and override the methods in your class so you do not have to do it inline as I did above.
if (Gdx.input.justTouched() && Gdx.input.isTouched()) {
rotateRight();
}
as the title says I'm trying to display a timer in my game that starts from 0 (and ideally, I want it to be on the top left of the screen)
I have the logic for the timer here:
public class Timer {
SpriteBatch batch;
private BitmapFont font;
private float deltaTime = 0;
CharSequence str;
public Timer() {
font = new BitmapFont();
batch = new SpriteBatch();
}
public void drawTime() {
deltaTime += Gdx.graphics.getDeltaTime();
str = Float.toString(deltaTime);
font.draw(batch, str, 0, 0);
}
}
I call this timer in my main class (Game) in the render() method like so:
public void render() {
player.update();
platform1.update();
platform2.update();
batch.begin();
Gdx.gl.glClearColor(135/255f, 206/255f, 235/255f, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
flag.drawS(batch);
flag.draw(batch);
player.draw(batch);
platform1.draw(batch);
platform2.draw(batch);
timer.drawTime();
batch.end();
}
}
I get the error "SpriteBatch begin must be called before draw", so I tried moving the timer.drawTime() method in different places in render() but still no luck.
Anyone know what could be wrong? Any help is highly appreciated :)
You should not create SpriteBatch() inside your Timer object. SpriteBatch should be created once and used by multiple elements to draw themselves. Your Timer draw() method should look more like this:
public void drawTime(SpriteBatch batch) {
deltaTime += Gdx.graphics.getDeltaTime();
str = Float.toString(deltaTime);
font.draw(batch, str, 0, 0);
}
The specific error you are encountering is caused by the fact that you call batch.begin(); on a different SpriteBatch object then the one that gets used in drawTime().
I have been looking for 10 hours (literally) and I'm done, I need to ask. Thing is I'm learning How use LibGdx to program Java games. I'm doing a Horizontal Space Ship Game. So, my worst problem here is that I do not know how do scroll (I think draw will explain better). I want to draw a huge background (Space) and make my OrthographicCamera move right like with my SpaceShip, so it will create a Scroll effect with the Space Background. No enemies and nothing but the ship on the screen.
I'm trying this:
public void moveCamera(float x,float y){
cam.position.set(x, y, 0);
}
Then I use that method in my WorldRender render() method:
public void render(float delta){
ship.Move(delta);
moveCamera(ship.getPosition().x,ship.getPosition().y);
cam.update();
System.out.println(""+cam.position);
spriteBatch.begin();
drawBackground();
drawShip();
spriteBatch.end();
}
I actually move the camera position (I can see that thanks to the println), but It isn't moving in the game, so SpaceShip just disappears by the edge of the window.
I also tried this before spriteBatch.end()
spriteBatch.setProjectionMatrix(camera.combined);
but when I do that windows only shows a black screen, no ship, no nothing.
As I said, I'm desperate, I see lot of examples (scroll with mouse, paralexscrolling etc) but all are to advanced or just nothing to do with my code.
This is how I draw stuff. Background and ship are textures inside WorldRender. I draw background image very wide, so my intention is do some scrolling over as I said. That's the code
private void loadTextures(){
shipTexture=new Texture(Gdx.files.internal("nave.png"));
background=new Texture(Gdx.files.internal("fondo.jpg"));
}
public void drawShip(){
spriteBatch.draw(shipTexture,ship.getPosition().x*ppuX,ship.getPosition().y*ppuY, ship.WIDTH*ppuX,ship.HEIGHT*ppuY);
}
public void drawBackground(){
spriteBatch.draw(background, -10*ppuX,0*ppuY, Gdx.graphics.getWidth()*10,Gdx.graphics.getHeight());
}
Here you can download the code if someone want to help in hardcore mode
My code (not working)
I FINALLY SOLVED IT!
That's the code I used in a class name WorldRenderer, which have methods that are called within GameScreen for render, resize etc
public WorldRenderer(World world) {
// TODO Auto-generated constructor stub
this.world=world;
this.ship=world.getShip();
this.cam = new OrthographicCamera(CAMERA_WIDTH,CAMERA_HEIGHT);
this.cam.setToOrtho(false,CAMERA_WIDTH,CAMERA_HEIGHT);
this.cam.position.set(ship.getPosition().x,CAMERA_HEIGHT/2,0);
this.cam.update();//actualizamos la camara
spriteBatch=new SpriteBatch();
loadTextures();
}
private void loadTextures(){
shipTexture=new Texture(Gdx.files.internal("nave.png"));
background=new Texture(Gdx.files.internal("fondo.jpg"));
}
public void drawShip(){
spriteBatch.draw(shipTexture,ship.getPosition().x,ship.getPosition().y,10,10);
}
public void drawBackground(){
spriteBatch.draw(background, 0,0, 500,50);
}
public void render(float delta){
ship.Move(delta);
moveCamera(ship.getPosition().x);
spriteBatch.setProjectionMatrix(cam.combined);
spriteBatch.begin();
drawBackground();
drawShip();
spriteBatch.end();
}
public void moveCemara(float x){
cam.position.set(x+20,cam.position.y, 0);
cam.update();
}
Inside the Ship I have this method which I call within render in WorldRenderer to move It
public void Move(float delta){
if(Gdx.input.isKeyPressed(Keys.LEFT)) this.position.x -=velocity *delta;
if(Gdx.input.isKeyPressed(Keys.RIGHT)) this.position.x +=velocity *delta;
if(Gdx.input.isKeyPressed(Keys.UP)) this.position.y +=velocity *delta;
if(Gdx.input.isKeyPressed(Keys.DOWN)) this.position.y -=velocity *delta;
}
Also I want to thanks very much to the people who helped me. I'm marking first answer as the good one, but, mix both was what gave me the real solution.
I leave here some tutorials I followed which are pretty good for noobs
That's a good everything-from-scratching-tutorial
LiGdxForNoobs
A simple platform game
platformGame
A very simple game
bucketGame
I can't tell if this is your only mistake, but this is ONE mistake. If this is what you say you were doing:
spriteBatch.begin();
drawBackground();
drawShip();
spriteBatch.setProjectionMatrix(camera.combined);
spriteBatch.end();
You wont see anything. When setProjectionMatrix is called inside a begin()/end() block. the current batch is flushed to the gpu. So, you are actually not drawing anything with the camera matrix. You should do this instead:
spriteBatch.setProjectionMatrix(camera.combined);
spriteBatch.begin();
drawBackground();
drawShip();
spriteBatch.end();
EDIT:
If you don't call that line, spriteBatch uses its own default camera (which wont notice your camera.update() modifications, so that's not what you want).
You should now pay more attention to the coordinates you are using. I'm not quite sure you really need the ppu conversion thing. To begin with, define everything in imaginary world coordinates, note that you'll see some stretching in your world.
public void drawShip(){
spriteBatch.draw(shipTexture,ship.getPosition().x,ship.getPosition().y, 10, 10);
}//your ship is 10 units wide and tall!
public void drawBackground(){
spriteBatch.draw(background, -10,0, 500, 100);
} //your background is 500 units wide, and 100 units tall
//camera setup
camera = new OrthographicCamera(50, 50);
//your camera will print to screen 50 units of your world
If you get to see a stretched world, try to understand how it's working (if you can't see anything, there is something wrong somewhere).
EDIT 2
I took a look at your code. First remove ppu's, as it obscures your code. You were setting your cam position to the ship.postion, while drawing at ship.position * ppu. Also your background was way too big (that's why you see it pixelated). You should see something reasonable with this. (someday you'll have to initialize your camera in another way to deal with stretching, but forget it until you understand how all works).
this.cam = new OrthographicCamera(CAMERA_WIDTH,CAMERA_HEIGHT);
public void drawShip(){
spriteBatch.draw(shipTexture, ship.getPosition().x ,ship.getPosition().y, 10, 10);
}
public void drawBackground(){
spriteBatch.draw(background, -CAMERA_WIDTH/2, -CAMERA_HEIGHT/2, 100, 100); //let bg begin where camera starts. (0,0)
}
public void render(float delta){
ship.Move(delta);
moverCamara(ship.getPosition().x, ship.getPosition().y);
spriteBatch.setProjectionMatrix(cam.combined);
spriteBatch.begin();
drawBackground();
drawShip();
spriteBatch.end();
}
Its not clear how your drawing? I'm not sure if your doing this approach correctly.. Can you provide details of your background and ship? Can you provide details on you background image, is it a huge image that your scrolling around or is it a repeated image you want to repeat as you scroll?
--EDIT--
ok i think i have an idea what might be up. I would normally apply the camera to the current context.
Place the following in your resize
public void resize(int width, int height) {
cam = new OrthographicCamera(width, height);
cam.translate(width / 2, height / 2, 0);
}
Place the following in the start of your render()
cam.position.set(posX,posY,0);
cam.update();
cam.apply(Gdx.gl10);
Gdx.gl.glClearColor(0,0,0,1);
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT); // #14
This will make you have a clear screen with the origin set at the bottom left of the window. You should then draw your background first
spriteBatch.setProjectionMatrix(cam.combined);
spriteBatch.begin();
spriteBatch.draw(background,0,0,sizeX,sizeY);
spriteBatch.end()
see how that looks as you move your camera position posX and posY. Then add your ship to the mix
-- MORE EDITS ---
you can then calculate the posX and posY as
posX = defaultOffsetX+shipX
and so on..
Anyhow hope this helps
I'm still only learning myself so this might not be the best method.. but it seems to work.
I've edited your code. Have a look at the following:
public class WorldRenderer {
private World world;
private Ship ship;
private Texture shipTexture,background;
private SpriteBatch spriteBatch;
private OrthographicCamera cam;
float screenSizeX = 100;
float screenSizeY = 100;
float shipSizeX = 10;
float shipSizeY = 10;
public void setSize (int w, int h) {
cam = new OrthographicCamera(screenSizeX,screenSizeY);
}
public WorldRenderer(World world) {
this.world=world;
this.ship=world.getShip();
spriteBatch=new SpriteBatch();
loadTextures();
}
private void loadTextures(){
shipTexture=new Texture(Gdx.files.internal("nave.png"));
background=new Texture(Gdx.files.internal("fondo2.jpg"));
}
public void drawShip(){
spriteBatch.draw(shipTexture, ship.getPosition().x,ship.getPosition().y, shipSizeX,shipSizeY);
}
public void drawBackground(){
spriteBatch.draw(background, 0,0);
}
public void render(float delta){
ship.Move(delta);
moverCamara(ship.getPosition().x,ship.getPosition().y);
spriteBatch.setProjectionMatrix(cam.combined);
spriteBatch.begin();
drawBackground();
drawShip();
spriteBatch.end();
}
public void moverCamara(float x,float y){
cam.position.set(x, y, 0);
cam.update();
}
}
This way, your ship is always in the middle of the screen and the background moves. Hope this helps.