I would like to let the sprite where I left it in the screen, and drag the camera in the world. But the sprite sticks to the camera, and is still at the bottom of the screen when I drag the camera.
This is not happening with a tilemap (the .tmx file), and a renderer : the camera can drag over the tilemap, and the tilemap does not stick to the camera. With a spriteBatch tough, the sprite stays at the bottom of the screen.
Here is my code:
map = MyLoader.manager.get("data/mMap.tmx");
float unitScale = 1 / 64f;
renderer = new OrthogonalTiledMapRenderer(map, unitScale);
#Override
public void render() {
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
camera.update();
renderer.setView(camera);
renderer.render();//tilemap works fine
//sprite
//batchMap.setProjectionMatrix(camera.combined);//wrong
batchMap.begin();
if ( scrFactoryMap.maps.size() > 0 ) {
scrFactoryMap.getMap(0).draw(batchMap);//sprite sticks to the camera
}
str = "string";
font.draw(batchMap, str, 50,50);//font sticks to the camera
batchMap.end();
}
private void slerpCamera(){
//...
camera.position.add( camX, camY, 0 );
camera.update();
}
Why did you comment this, an put wrong on it?
//sprite
//batchMap.setProjectionMatrix(camera.combined);//wrong
You must set the new ProjectionMatrix to the SpriteBatch whenever you transform (i.e. move) your camera.
Uncomment it :)
Related
So here is my issue. I have a 800x800 libgdx game and I have created a 800x800 .png using gimp. I add it and draw it but the image now seems to be extremely larger than expected. For instance, if I have a ocean .png, all that renders is a dark blue screen. Seems like it is accepting my image but I am doing something else wrong. Any help would be awesome. Code is below. The player and enemy both render fine and on top of the blue.
private Texture img;
private TextureRegion textureRegion;
float drawingWidth,drawingHeight;
//Constructor
public GameScreen(Game game) {
this.game = game;
img = new Texture("tester2.png");
img.setWrap(Texture.TextureWrap.Repeat, Texture.TextureWrap.ClampToEdge);
int width=Gdx.graphics.getWidth();
textureRegion=new TextureRegion(img,0,0,width,img.getHeight());
drawingWidth=width;
drawingHeight=Gdx.graphics.getHeight();
Gdx.app.log(ID, "GameScreen is loaded! " + drawingWidth + " " + drawingHeight);
}
#Override
public void render(float deltaTime) {
//buffer screen
Gdx.gl20.glClearColor((11f / 255.0f), (11f / 255.0f), (11f / 255.0f), 1);
Gdx.gl20.glClear(GL20.GL_COLOR_BUFFER_BIT);
sb.begin();
sb.setProjectionMatrix(camera.combined);
update(deltaTime);
sb.draw(textureRegion,0,0,drawingWidth,drawingHeight);
sb.draw(img, 0, 0);
player.render(sb);
enemy.render(sb);
sb.end();
}
From my testing it seems like your camera's viewport is improperly configured. If you are using an OrthographicCamera then you want to use OrthographicCamera.setToOrtho() to set the viewport. Right now the camera is set to display a 2x2 pixel corner of your image. HOVEVER, your example is not replicable and I don't know how you set up your SpriteBatch or your Camera, or anything for that matter so I may be off.
P.S. why are you drawing img and texture region when they are the same? img will just put the image in the bottom left corner, textureRegion will repeat a few times across the screen.
I'm having problems setting my orthographic camera to the bottom left part of my screen (0,0)
public GameScreen(Main game) {
this.game = game;
Width = 200;
Height = 300;
view = new ExtendViewport(Width,Height);
camera = new OrthographicCamera(Gdx.graphics.getWidth(),Gdx.graphics.getHeight());
camera.setToOrtho(false,Width/2,Height/2);
camera.position.set(Width,Height,0);
camera.update();
play.Player1();
staple = new Stage();
staple.addActor(play);
staple.addActor(pile);
Gdx.input.setInputProcessor(staple);
}
#Override
public void render(float delta) {
Gdx.gl.glClearColor(0, 1, 1, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
Gdx.graphics.getDeltaTime();
game.getBatch().begin();
game.getBatch().setProjectionMatrix(camera.combined);
game.getBatch().end();
staple.act();
staple.draw();
}
#Override
public void resize(int width, int height) {
view.update(width,height);
view.setScreenPosition(width,height);
}
I've set my viewport as extended viewport using my width and height values I have assigned but I'm struggling to move the camera to the bottom left
part of my screen (0,0) where it can focus on my images on my android device.
Here are a little example how to use camera and viewport:
First we must define how big is our world the camera shows:
private static final int WORLD_WIDTH = 300;
private static final int WORLD_HEIGHT = 250;
Our world is now 300 x 250 units (not Pixel!) big.
It's importent to think in units not in pixels!!
Now we need a OrthographicCamera, a Viewport and a SpriteBatch
OrthographicCamera camera;
Viewport viewport;
SpriteBatch batch;
#Override
public void create () {
camera = new OrthographicCamera(); // we create a OrthographicCamera
viewport = new ExtendViewport(WORLD_WIDTH, WORLD_HEIGHT, camera); // we create a new Viewport with our camera and we will display our world 300 x 250 units
batch = new SpriteBatch(); // we create a new SpriteBatch for draw our textures
}
In our render method we say the batch only to draw what we can see in our Viewport with the method setProjectionMatrix()
#Override
public void render (float delta) {
camera.update(); //update our camera every frame
batch.setProjectionMatrix(camera.combined); //say the batch to only draw what we see in our camera
batch.begin();
batch.draw(texture, 0,0); //draw our texture on point 0,0 bottom left corner
batch.end();
}
And in the resize method:
public void resize(int width, int height){
viewport.update(width, height); //update the viewport to recalculate
}
To understand why you have this issue:
In your code you never set the camera to the viewport: view = new ExtendViewport(Width,Height);
So your viewport never apply to the batch.
To render the correct way without Viewport you must know that the position of OrhographicCamera is in the center.
So when you set a Camera to position 0,0 and size 50,50 you see the world from -25 to 25 in each direction;
To use OrthographicCamera without Viewport:
public void create () {
camera = new OrthographicCamera(WORLD_WIDTH, WORLD_HEIGHT); // we create a OrthographicCamera and we will display our world 300 x 250 units
camera.position.set(camera.viewportWidth / 2, camera.viewportHeight / 2, 0); //we set position of camera, our world point 0,0 is now the bottom left corner in the camera
batch = new SpriteBatch(); // we create a new SpriteBatch for draw our textures
texture = new Texture("badlogic.jpg");
}
public void render () {
camera.update();
batch.setProjectionMatrix(camera.combined);
batch.begin();
batch.draw(texture, 0,0);
batch.end();
}
The important point is in the resize method:
public void resize(int width, int height){
camera.viewportWidth = WORLD_WIDTH;
camera.viewportHeight = WORLD_HEIGHT * height / width;
camera.position.set(camera.viewportWidth / 2, camera.viewportHeight / 2, 0);
}
With this calculation you always see a World of 300 width and 250 * ratio of width, and height.
And exactly this calculation does the viewport for you. Depending on which Vieport (FitViewport, ScreenViewport, ExtendViewport) you use this calculation will be different, try it out.
I hope this helps you to understand how camera, viewport and Spritebatch works together.
Here are useful links to the libgdx wiki which descript the Viewport and Camera:
https://github.com/libgdx/libgdx/wiki/Viewports
https://github.com/libgdx/libgdx/wiki/Orthographic-camera
Use camera.position.set(Width, Height, 1); instead of 0
First you set the Camara width and height equal to the amount of pixels of the window.
camera = new OrthographicCamera(Gdx.graphics.getWidth(),Gdx.graphics.getHeight());
Then you center it at 100, 150. And move it again to 200, 300
camera.setToOrtho(false,Width/2,Height/2);
camera.position.set(Width,Height,0);
You are also using a Viewport but never make use of it.
I would recommend just using a Viewport of choice. A Viewport can take a camera so if you insist using your own camera you can create it but then also pass it to the Viewport when you construct it.
EDIT
Following is a tested minimal example.
public class TestScreen extends ScreenAdapter {
private Viewport viewport;
private ShapeRenderer sr;
public TestScreen() {
// Note that extend viewport extends it's camera so you end up with smaller or larger view of your world depending on the aspect ratio of the physical screen.
viewport = new ExtendViewport(200, 300);
viewport.apply();
System.out.println(viewport.getWorldWidth());
// Just for testing in the resize method.
viewport.getCamera().translate(0, 0, 0);
viewport.getCamera().update();
// ShapeRenderer for testing
sr = new ShapeRenderer();
sr.setAutoShapeType(true);
}
#Override
public void render(float delta) {
Gdx.gl.glClearColor(.04f, .06f, .1f, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
// Draw circle at 0.0 in the world
sr.setProjectionMatrix(viewport.getCamera().combined);
sr.begin(ShapeRenderer.ShapeType.Line);
sr.circle(0, 0, 100);
sr.end();
}
#Override
public void resize(int width, int height) {
// Will center the camera in the world at half it's width and half it's height so left bottom is 0.0 as long as the camera did.
// By using true here you cannot move the camera since you order it to center on the screen and thus the circle we are drawing
// remains in the bottom left.
//viewport.update(width, height, true);
// This will just update the viewport, we moved the camera slightly to the left so the circle appears slight right from the middle.
viewport.update(width, height, false);
// So you want to start your camera centered on something but still want to move it you need to specify that center in the camera
// by either changing it's position or translating it like I did in the constructor. Unfortunately you only get to know the size
// of the world that is being displayed once this resize method did it's job so certain parts might get cut off or your world does
// not fill the screen.
}
}
I am quite new to programming so bear with me here...
I am making a 2d basic game just to practice programming in android studio and can't get my sprite to the correct position on the screen. Also when I draw the sprite it appears stretched and the quality is very poor. Any help is appreciated!
public class MyGdxGame extends ApplicationAdapter {
SpriteBatch batch;
Texture background;
Texture ball;
#Override
public void create () {
batch = new SpriteBatch();
background = new Texture("gamebackground.png");
ball = new Texture("ball2.png");
}
#Override
public void render () {
batch.begin();
batch.draw(background, 0,0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
batch.draw(ball, 0,0, Gdx.graphics.getWidth() / 2, Gdx.graphics.getHeight() / 2);
batch.end();
}
You need to keep the original width/height ratio:
instead of scaling it to half the screen size, define your scaling like that:
float scaleFactor = 2.0f;
batch.draw(ball, 0,0, ball.getWidth()*scaleFactor, ball.getHeight*scaleFactor);
If your image is "blurry", and you want the individual pixels to stay crisp, try loading the texture like that:
ball = new Texture("ball2.png");
ball.setFilter(TextureFilter.Nearest, TextureFilter.Nearest);
This prevents (default) linear interpolation when scaling the texture.
I'm just trying to get libgdx to create a picture wherever I touch the screen.
here's what i have that isn't doing anything
SpriteBatch batch;
Texture img;
#Override
public void create () {
batch = new SpriteBatch();
img = new Texture("badlogic.jpg");
}
#Override
public void render () {
Gdx.gl.glClearColor(1, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
}
public class MyInputProcessor implements InputProcessor {
public boolean touchDown (int x, int y, int pointer, int button) {
batch.begin();
batch.draw(img,Gdx.input.getX(),Gdx.input.getY());
batch.end();
return true;
}
... (the rest of the input methods)
if you can't tell, I don't really know what I'm doing yet, I think it has to do with the batch.draw() being in the touchDown method instead of the render area but I can't figure out from research how to do it a different way either
or maybe this is all wrong too, point is I'm doing this to learn so hopefully the correct answer will help me understand some important things about java in general
LibGDX, like basically all game engines, re-renders the entire scene every time render() is called. render() is called repeatedly at the frame rate of the game (typically 60fps if you don't have a complex and unoptimized game). The first drawing-related thing you usually do in the render() method is to clear the screen, which you have already done with Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);. Then you re-draw the whole scene with whatever changes there might be since the last frame.
You are trying to draw something with the batch outside of the render method. In this case, you are doing it when there is a touch down. But since you are doing this only when there is a touch down, the object will appear and disappear on the next call to render(), so it will only be on screen for 1/60th of a second. If you want to do this with an input processor, you need to set some variable to true to indicate the render method should draw it, and other variables to indicate where to draw it. Then in the render() method, you draw the stuff if the variable is true.
Secondly, the x and y that an input processor gets do not necessarily (and usually don't) correspond with the x and y in OpenGL. This is because OpenGL has it's own coordinate system that is not necessarily sized exactly the same as the screen's coordinate system. The screen has (0,0) in the top left with the Y axis going down, and the width and height of the screen matching the number of actual pixels on the screen. OpenGL has (0,0) in the center of the screen with the Y axis going up, and the width and height of the screen being 2 regardless of the actual screen pixels.
But the OpenGL coordinate system is modified with projection matrices. The LibGDX camera classes make this simpler. For 2D drawing, you need an OrthographicCamera. You set the width and size of the OpenGL world using the camera, and can also position the camera. Then you pass the camera's calculated matrices to the SpriteBatch for it to position the scene in OpenGL space.
So to get an input coordinate into your scene's coordinates, you need to use that camera to convert the coordinates.
Finally, LibGDX cannot magically know that it should pass input commands to any old input processor you have created. You have to tell it which InputProcessor it should use with a call to Gdx.input.setInputProcessor().
So to fix up your class:
SpriteBatch batch;
Texture img;
boolean isTouchDown;
final Vector3 touchPosition = new Vector3();
OrthographicCamera camera;
#Override
public void create () {
batch = new SpriteBatch();
img = new Texture("badlogic.jpg");
camera = new OrthographicCamera();
Gdx.input.setInputProcessor(new MyInputProcessor()); // Tell LibGDX what to pass input to
}
#Override
void resize (int width, int height) {
// Set the camera's size in relation to screen or window size
// In a real game you would do something more sophisticated or
// use a Viewport class to manage the camera's size to make your
// game resolution-independent.
camera.viewportWidth = width;
camera.viewportHeight = height;
camera.update(); // re-calculate the camera's matrices
}
#Override
public void render () {
Gdx.gl.glClearColor(1, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.setProjectionMatrix(camera.combined); // pass camera's matrices to batch
batch.begin();
if (isTouchDown) { // Only draw this while the screen is touched.
batch.draw(img, touchPosition.x, touchPosition.y);
}
batch.end();
}
public class MyInputProcessor implements InputProcessor {
public boolean touchDown (int x, int y, int pointer, int button) {
isTouchDown = true;
touchPosition.set(x, y, 0); // Put screen touch coordinates into vector
camera.unproject(touchPosition); // Convert the screen coordinates to world coordinates
return true;
}
public boolean touchUp (int screenX, int screenY, int pointer, int button){
isTouchDown = false;
return true;
}
//... (the rest of the input methods)
}
I am currently trying to snap a crosshair sprite to my game's cursor using libgdx. The game is top-down view:
Texture crosshair_text = new Texture(Gdx.files.internal("data/crosshair1.png"));
this.crosshair = new Sprite(crosshair_text, 0, 0, 429, 569);
//...
#Override
public void render() {
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
cam.update();
batch.setProjectionMatrix(cam.combined);
batch.begin();
//.. sprites that scale based on camera (top-down view)
batch.end();
//draws 'ui' elements
floatingBatch.begin();
//...
//snap to cursor
this.crosshair.setPosition( Gdx.input.getX(), (Gdx.graphics.getHeight()-Gdx.input.getY()) );
//transform
this.crosshair.setScale(1/cam.zoom);
//draw
this.crosshair.draw(floatingBatch);
floatingBatch.end();
}
Sorry if there are errors that I didn't catch, this isn't an exact copy of my code. The problem here is that 1. The sprite doesn't snap to the correct position and 2. the crosshair sprite lags behind the current position of the mouse on the screen. Can anyone give me insight on how to fix either of these two issues?
Your position might not be correct because the screen location isn't necessarily the right location to draw onto using your OrthographicCamera, try using the unproject first. E.g:
Vector3 mousePos = new Vector3( Gdx.input.getX(), (Gdx.graphics.getHeight()-Gdx.input.getY()), 0); //Get the mouse-x and y like in your code
cam.unproject(mousePos); //Unproject it to get the correct camera position
this.crosshair.setPosition(mousePos.x, mousePos.y); //Set the position
Plus you need to make sure your floating batch is set to the projection matrix of the camera, add the following code:
floatingBatch.setProjectionMatrix(cam.combined);
Instead of drawing a Sprite at the mouse position, you could change the cursor image:
Gdx.input.setCursorImage(cursorPixMap, hotspotX, hotspotY);
Where cursorPixMap is a PixMap of the new cursor image an hotspotX and hotspotY is the "origin" of the PixMap/cursor image. In your case it would be the center of the crosshair.
So basicly the Gdx.input.getX() and Gdx.input.getY() return the current position of the hotspotX and hotspotY.
I suggest to read the wiki artikcle about the cursor.