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.
Related
This problem seemed very obvious for me to solve, but whatever I try, it doesn't work. What I'm trying to do is to incorporate a mini-version of my PlayScreen in a ScrollPane as a tutorial where you can read text and try it out immediately.
Because I didn't find any better solution to add this to the Table inside the ScrollPane, I edited the draw() method of the PlayScreen to take the ScrollPane.getScrollPercentY() and offset the camera of the PlayScreen accordingly.
What I want to do now is to only render only part of the viewport that would be normally visible in the real game. Subsequently, I want to be able to control the size and position of this "window".
I also want to be able to resize and move the content, while cutting off the edges that are not visible to the camera. This is what I tried inside the PlayScreenDraw:
public void draw(final float yOffset,
final int xTiles,
final int yTiles) {
view.getCamera().position.y = yTiles / 2f - yOffset * yTiles / HEIGHT; // HEIGHT = 800
view.getCamera().position.x = xTiles / 2f;
view.setWorldSize(xTiles, yTiles); //Do i even need to change the world size?
b.setProjectionMatrix(view.getCamera().combined);
b.begin();
...
b.end();
view.update(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
}
What this gives me, in terms of the picture above, is this
How do I need to change the viewport and/or the camera? Btw., this is how i set the two up:
cam = new OrthographicCamera();
cam.setToOrtho(false, WIDTH, HEIGHT); // WIDTH = 8, HEIGHT = 16
batch.setProjectionMatrix(cam.combined);
view = new FitViewport(WIDTH, HEIGHT, cam);
The Pixmap class can help you achieve what you want since you stated that you wanted to "cut off" the parts outside of the green selection box.
You need to render what the camera sees to an FBO and then get the pixmap from the FBO itself.
Framebuffer Objects are OpenGL Objects, which allow for the creation of user-defined Framebuffers. With them, one can render to non-Default Framebuffer locations, and thus render without disturbing the main screen.
-- OpenGL wiki
// Construct an FBO and keep a reference to it. Remember to dispose of it.
FrameBuffer fbo = new FrameBuffer(Format.RGBA8888, width, height, false);
public void render() {
//Start rendering to the fbo.
fbo.begin();
//From the camera's perspective.
batch.setProjectionMatrix(camera.combined);
batch.begin();
//Draw whatever you want to draw with the camera.
batch.end();
// Finished drawing, get pixmap.
Pixmap pixmap = ScreenUtils.getFrameBufferPixmap(0, 0, width, height);
//Stop drawing to your fbo.
fbo.end();
}
After getting the pixmap you can iterate through the pixels and set the alpha of the pixels outside your green selection window to 0 making them invisible or "cutting them off"
i try to rotate a 3D instance when I move the mouse. i use Orthographic Camera, and i have a tiled isomap in background.
[EDIT] I use this code :
public boolean mouseMoved (int x, int y) {
Vector3 direction = new Vector3();
Vector3 worldCoordinate = cam.unproject(new Vector3(x, y, 0));
direction = (worldCoordinate).sub(position).nor();
direction.set(-direction.x, -direction.y, -direction.z);
Matrix4 instanceRotation = instance.transform.cpy().mul(instance.transform);
instanceRotation.setToLookAt(direction, new Vector3(0,-1,0));
instanceRotation.rotate(0, 0, 1, 180);
quat = new Quaternion();
instanceRotation.getRotation(quat);
instance.transform.set(position, quat);
return false;
}
Now, the instance follows the cursor, but in all axes. I just want to turn on the Y axis. I can change quat.x = 0 and quat.z = 0 to lock the rotation. After that, the rotation only works on the Y axis. But, the model should turn over if my cursor is at the top of the screen, but it remains facing, no matter where my cursor is.
I don't know how to convert the coordinates to tell my rotation that it needs to turn over. And to modify the quat in this way is not very elegant
Edit : Some image for illustrate what i want
Here, with cursor in the bottom of the screen, the model turn to look in good direction :
Here, the model dont turn over, like the cursor is in bottom of the screen :
I am trying to draw a bunch of tiles (10,000 sprites) for a minimap. It lags on android when drawing individually, so I am trying to use a framebuffer. For some reason, I can't get anything drawn to the screen with the buffer. I will show the relevant code.
buffer = new FrameBuffer(Pixmap.Format.RGBA8888, Main.VIRTUAL_WORLD_WIDTH, Main.VIRTUAL_WORLD_HEIGHT, false);
OrthographicCamera cam = new OrthographicCamera(Main.VIRTUAL_WORLD_WIDTH, Main.VIRTUAL_WORLD_HEIGHT);
buffer.begin();
batch.begin();
batch.setProjectionMatrix(cam.combined);
for(Tile[] tiles : world.level.getGrid()){
for(Tile tile : tiles){
tile.getSprite().draw(batch);
}
}
batch.end();
buffer.end();
tiles = new Sprite(buffer.getColorBufferTexture());
The above code creates the framebuffer in the create method.
And this renders
batch.setProjectionMatrix(camera.combined);
batch.begin();
tiles.draw(batch);
batch.end();
Note, The position of the tiles sprite is 0, 0. I have tried changing all kids of stuff with this code, but can never get it to draw on the screen. The actual tiles aren't a problem, they all function correctly. My camera is setup correctly, so are my viewports.
I've searched all around google and this website for infos about this problem, but cannot solve it..
I'm a newbie in game development and LibGDX, and cannot find a solution well explained on how to port my game to all the various screen sizes..
Would you kindly help me?
Thanx
When using the newest libgdx version, you will find the Viewport class...
The viewport describes the transformation of the coordinate system of the screen (being the pixels from 0,0 in the lower left corner to e.g. 1280,768 in the upper right corner (depending on the device)) to the coordinate system of your game and scene.
The Viewport class has different possibilities on how to do that transformation. It can either stretch your scene coordinate system to exactly fit the screen coordinate system, which might change the aspect ratio and for example "stretch" your images or buttons.
It's also possible to fit the scene viewport with its aspect ratio into the viewport, which might produce a black border. E.g. when you have developed the game for 4:3 screens and now embed it into 16:10 displays.
The (in my opinion) best option is through fitting the scene viewport into the screen by matching either the longest or shortest edge.
This way, you can have a screen/window coordinate system from (0,0) to (1280,768) and create your game coordinate system maybe from (0,0) to (16,10) in landscape mode. When matching the longest edge, this means that the lower left corner of the screen will be (0,0), the lower right will be (16,0)... On devices that don't have the same aspect ratio, the y-values on the upper corners might differ a bit.
Or when matching the shortest edge, this means your scene coordinates will always be shown from (x,0) to (x,10) ... But the right edge might not exactly have and x value of 16, since device resolutions differ...
When using that method, you might have to reposition some buttons or UI elements, when they are supposed to be rendered on the top or the right edges...
Hope it helps...
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 OrthographicCamera 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.
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 :)