How can I use interpolation in libgdx ?
Say if I have sprite and I want to manipulate its size as it begins at 0,0
and end at its full size
I have this :
SpriteBatch batch = new SpriteBatch();
Sprite star = new Sprite(new Texture("star.png"));
public void render(float delta) {
batch.begin();
batch.draw(star, 100, 100, star.getOriginX(), star.getOriginY(),
star.getWidth(), star.getHeight(), star.getScaleX(), star.getScaleY(),
star.getRotation());
batch.end;
}
With SpriteBatch: You can use Tween engine (https://github.com/libgdx/libgdx/wiki/Universal-Tween-Engine) to do the job with the numbers.
With Scene2D: You can use actors and use addAction() to animate the transformation automatically. Actions are pretty cool and support many types of interpolations.
Related
I'm converting my game Hold & Drag from Swift (SpriteKit) to Android using LibGDX, I created my 'SpriteKit' api a little clone of the official on Xcode.
I'm looking for optimizing the render of textures especially because I got FPS drop (45-60 /60 fps)
When I don't draw textures I got 60 (the maximum).
I hope you will help me as efficiently as possible!
#Override
public void draw() {
if (texture == null)
return;
Gdx.gl.glEnable(GL20.GL_BLEND);
Gdx.gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);
spriteBatch.setTransformMatrix(getTransformMatrix());
spriteBatch.begin();
Color color = spriteBatch.getColor();
color.a = getAlpha();
spriteBatch.setColor(color);
spriteBatch.draw(texture, -size.width / 2, -size.height / 2, size.width, size.height);
spriteBatch.end();
Gdx.gl.glDisable(GL20.GL_BLEND);
}
public List<SKNode> getParents() {
List<SKNode> parents = new ArrayList<>();
if (parent != null) {
parents.add(parent);
parents.addAll(parent.getParents());
}
return parents;
}
public Matrix4 getTransformMatrix() {
List<SKNode> nodes = getParents();
Collections.reverse(nodes);
nodes.add(this);
Matrix4 transformMatrix = new Matrix4();
transformMatrix.idt();
for (SKNode node : nodes) {
transformMatrix.translate(node.position.x + node.origin.x, node.position.y + node.origin.y, 0);
transformMatrix.rotate(0, 0, 1, node.zRotation);
transformMatrix.scale(node.xScale, node.yScale, 0);
transformMatrix.translate(-node.origin.x, -node.origin.y, 0);
}
return transformMatrix;
}
It is slow to do things that cause the sprite batch to "flush", which means it has to issue a number of OpenGL commands and transfer vertex data, etc. A flush occurs when you call spriteBatch.end() but also occurs if you:
Draw something with a different texture instance than the last thing drawn
Change the projection or transform matrices
Enable/disable blending
So you want to organize so you are not triggering a flush on every object you draw. What is typically done is to begin the batch, and then each sprite is drawn at its particular location with one of the spriteBatch.draw() methods that includes all the parameters you want. Like this:
batch.setProjectionMatrix(camera.combined);
batch.begin();
for (GameObject obj : myGameObjects)
obj.draw();
batch.end();
//And in your game object / sprite class
public void draw() {
if (texture == null)
return;
spriteBatch.setColor(1f, 1f, 1f, getAlpha());
spriteBatch.draw(texture, -size.width / 2, -size.height / 2, size.width, size.height);
}
Note that the above assumes you are referring to the same sprite batch instance in every object.
Now, to make it behave more like SpriteKit (I'm assuming since I haven't used it), your objects each need a transform. But you don't want to be calling setTransformMatrix or you will trigger a flush. Instead you can use the Affine2 class instead of Matrix4. It functions just as well for holding transform data for a 2D object. Then you can use spriteBatch.draw(textureRegion, width, height, affine2Transform) to draw it without triggering a flush.
To avoid triggering flushes from using different texture instances, you should use a TextureAtlas and texture regions. You can read up on that in the LibGDX documentation on their wiki.
As an aside, when using SpriteBatch, you do not need to make OpenGL calls to enable and disable blending. That is handled internally by SpriteBatch. Call spriteBatch.enableBlending() instead.
The title pretty much say it all, I need to get a image from a Model is this posible? I searched for this and found nothing.
Solution thanks to #retodaredevil
FrameBuffer fbo = new FrameBuffer(Pixmap.Format.RGBA4444, screenWidth, screenHeight, true);
ModelBatch batch = new ModelBatch();
fbo.begin(); // make fbo the current buffer
Gdx.gl.glViewport(0, 0,screenWidth, screenHeight);
Gdx.gl.glClear(GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);
batch.begin(camera);
batch.render(instance, environment);
batch.end();
try{
FileHandle fh = new FileHandle(output);
Pixmap pixmap = ScreenUtils.getFrameBufferPixmap(0,0,screenWidth,screenHeight);
PixmapIO.writePNG(fh, pixmap);
pixmap.dispose();
}catch (Exception e){
e.printStackTrace();
}
fbo.end(); // Now you can draw on the display again
batch.dispose();
fbo.dispose();
From what I understand, we'll have to use two different tutorials
https://github.com/mattdesl/lwjgl-basics/wiki/FrameBufferObjects
https://xoppa.github.io/blog/basic-3d-using-libgdx/ (You're probably already familiar with this)
FrameBuffer fbo = new FrameBuffer(Pixmap.Format.RGBA4444, width, height, hasDepth);
// I've never used a FrameBuffer before so you may have to play around with constructor parameters
ModelBatch batch = // your ModelBatch initialization here
fbo.begin(); // make fbo the current buffer
glClearColor(0f, 0f, 0f, 1f);
glClear(GL_COLOR_BUFFER_BIT);
batch.resize(fbo.getWidth(), fbo.getHeight());
batch.begin();
batch.render(modelInstance, environment);
batch.end();
fbo.end(); // Now you can draw on the display again
// If you want to, you can resize your batch and use it to draw on the display
batch.resize(Display.getWidth(), Display.getHeight());
Once you do whatever you need to do to your FrameBuffer, you can get the texture
fbo.getTexture();
EDIT: That method doesn't exist, look at OP's question for solution
EDIT 2: FrameBuffer does actually have a method called getColorBufferTexture()
For saving a texture, look at https://www.badlogicgames.com/forum/viewtopic.php?p=8358#p8358 or https://www.badlogicgames.com/forum/viewtopic.php?t=5686
I used this to get one of the links: Libgdx save SpriteBatch in a texture everything else I duckduckgoed
If something doesn't work let me know and I can try to look around more.
In java awt or swing when you want to change painting of some component you usually have to override the method paint(Graphics g) (in awt) or paintComponent(Graphics g) (in swing).
This is usually (maybe allways - I'm not sure) done when you are creating the component for example:
JPanel jPanel = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
//... my implementation of paint, some transfromations, rotation, etc
}
};
Imagine that you have container of components which could for example consists of some JLabels, some JTextFields, some image. Which will be all put on one component.
By container I mean you have some list or map with ids or some similar structure in which are all components you will put on one JFrame.
The question is if I can change the painting method after creating with all of the components which are in this list in the moment when all of them are already created. For example I want do the rotation action (rotate), which is defined in Graphisc2D, with all of them.
So basicaly what I want is that I throught the list of componets I have and say:
"All of you (components) which are in the list will be rotated by some angle". Is that possible? If yes how?
Edit:
This is my not correctly working solution:
graphicalDisplayPanel = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g2d = (Graphics2D) g;
g2d.rotate(Math.PI, anchorx, anchory);
}
#Override
public void paintChildren(Graphics g) {
super.paintChildren(g);
Graphics2D g2d2 = (Graphics2D) g;
g2d2.rotate(Math.PI, anchorx, anchory);
}
};
JFrame jFrame = JFrame();
// ... setting dimension, position, visible etc for JFrame, it works correctly nonrotated
jFrame.setContentPane(graphicalDisplayPanel);
I have not tested this, but it seems like it would work. A JComponent's paint() method calls:
paintComponent(co);
paintBorder(co);
paintChildren(co);
where co is a Graphics object. In theory you create an image, retrieve the graphics object and then pass that into paintChildren(). you will have to call paintComponent() and paintBorder() yourself, if you do this. Then, just rotate the image and draw it into your component. You may have to crop the image or resize your component accordingly for this to work. It might look something like this:
BufferedImage myImage;
#Override
public void paint(Graphics g){
myImage = new BufferedImage(getWidth(), getHeight(), BufferedImage.TRANSLUCENT);
//using a transparent BufferedImage might not be efficient in your case
Graphics myGraphics = myImage.getGraphics();
super.paintComponent(g);
super.paintBorder(g);
super.paintChildren(myGraphics);
//rotation code here
// ...
//draw children onto your component
g.drawImage(myImage, 0, 0,getWidth(), getHeight(), null);
}
I hope I didn't make any mistakes, please let me know if this works.
So basicaly what I want is that I throught the list of componets I have and say: "All of you (components) which are in the list will be rotated by some angle".
If you want to rotate panel and therefore all the components on the panel as a single using then you need to do the custom painting in the paintComponent() method.
If you want to rotate, for example, individual images that each have a different angle of rotation then you can again do this in the paintComponent(...) method and change the angle for each component.
Or, in this second case you can use the Rotated Icon class. In this case the Icon is just added to a JLabel. Then you can change the degrees of rotation and repaint the label, so there is no custom painting (except in the Icon itself).
I am beginning to write a game in LibGDX, only just beginning. I have got a basic tile map loaded, a player sprite and can move the character around and the screen (camera) scrolls around - perfect.
I have two overlayed textures in the bottom right of the screen, a left and right arrow, which are used as the joypad to control the character. I position these in relation to the players.x position, which is always fixed to the centre of the screen. Cool so far .... As below:
/////////////////////////////////////////////////////////////////
private void renderJoypad(float deltaTime)
{
batch.draw(Assets.leftJoypad, blockman.position.x-14, 1, 3, 3);
batch.draw(Assets.rightJoypad, blockman.position.x-9, 1, 3, 3);
}
I am now trying to put the player's score in the top left of the screen. The score is made of a Bitmap font, as below.
font = new BitmapFont(Gdx.files.internal("fonts/minecrafter.fnt"),Gdx.files.internal("fonts/minecrafter.png"),false);
font.setScale(0.02f);
In my render() method I cam calling some other methods to update, like the positions of the
leftJoypad etc, as in renderJoypad(). I am also calling my draw font method to update the position of the score, however, when I scroll it is all jerky, and sometimes it shows less characters than there should be.
public void drawScore(float deltaTime)
{
font.draw(batch, "00000", blockman.position.x, 10);
}
I believe that I need to place the score (and any other on screen texts, HUD etc) into a stage, but I cannot understand how to get it working with my existing code.
My show method is as follows:
public void show()
{
//load assets class to get images etc
Assets Assets = new Assets();
//start logging Framerate
Gdx.app.log( GameScreen.LOG, "Creating game" );
fpsLogger = new FPSLogger();
//set the stage - bazinga
Gdx.input.setInputProcessor(stage);
//stage.setCamera(camera);
//stage.setViewport(480, 360, false);
batch = new SpriteBatch();
//load the Joypad buttons
loadJoypad();
//background image
loadBackground();
//sounds
jumpSound = Gdx.audio.newSound(Gdx.files.internal("sounds/slime_jump.mp3"));
//LOAD block man here
// load the map, set the unit scale to 1/16 (1 unit == 16 pixels)
loadMap();
//draw the score
font = new BitmapFont(Gdx.files.internal("fonts/minecrafter.fnt"),Gdx.files.internal("fonts/minecrafter.png"),false);
font.setScale(0.02f);
// create an orthographic camera, shows us 30x20 units of the world
camera = new OrthographicCamera();
camera.setToOrtho(false, 30, 20);
camera.update();
// create the Blockman we want to move around the world
blockman = new Blockman();
blockman.position.set(25, 8);
}
and my render() method is as follows:
public void render(float delta)
{
// get the delta time
float deltaTime = Gdx.graphics.getDeltaTime();
stage.act(deltaTime);
stage.draw();
// clear the screen
Gdx.gl.glClearColor(0.3f, 0.3f, 0.3f, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
renderBackground(deltaTime);
batch = renderer.getSpriteBatch();
//updateBlockman(deltaTime);
blockman.update(deltaTime);
// let the camera follow the blockMan, x-axis only
camera.position.x = blockman.position.x;
camera.update();
// set the tile map rendere view based on what the
// camera sees and render the map
renderer.setView(camera);
renderer.render();
//start the main sprite batch
batch.begin();
// render the blockMan
renderBlockman(deltaTime);
renderJoypad(deltaTime);
drawScore(deltaTime);
batch.end();
fpsLogger.log();
}
I have tried to change the way things work with relation to the Spritebatch etc and just cannot seem to get it working as I require.
Can anyone suggest how I may approach getting a stage and actors to work, or a second camera or something to help me achieve a fixed score display in the corner.
Do I need to use Scene 2D or something - aahhh! My head is exploding....
I look forward and thank you in advance.
Regards
James
I have a couple of suggestions:
Check to see if you have setUseIntegerPositions set to true
(the default) when you draw your font. If you do, and you're scaling
it, then it can cause some odd effects similar to those that you
describe. Set it to false and see if it fixes the problem.
Reset your spritebatch's matrices before drawing the text, that way you won't need to adjust it for the scrolling.
I'd even go as far as to recommend not scaling the font if you can help it, because fonts often look a little odd after being scaled.
How should I follow the directory structure and what to specify so that assetManger will use that folder for different resolution.
I have studied assetManager and ResolutionFileResolver but until now I couldn't exactly figured how to specify the folder to support different resolutions.
Update: Newer versions of Libgdx use a different strategy to resolve filenames (with directories, not files), so this answer does not apply to newer Libgdx versions after (0.9.2, I think? https://github.com/libgdx/libgdx/commit/3afcfe49c40196765033a90b4610159183dde981)
The built-in ResolutionFileResolver does not use a directory hierarchy. It uses file suffixes to match screen resolutions to assets.
Here's the code from the libGDX AssetManagerTest:
Resolution[] resolutions = { new Resolution(320, 480, ".320480"),
new Resolution(480, 800, ".480800"),
new Resolution(480, 856, ".480854") };
ResolutionFileResolver resolver = new ResolutionFileResolver(new InternalFileHandleResolver(), resolutions);
AssetManager manager = new AssetManager();
manager.setLoader(Texture.class, new TextureLoader(resolver));
...
The resolver appends one of those suffixes based on the current screen resolution. So, for example, if you look up "foo.jpg" on a 480x800 device, the file "foo.jpg.480800" will be opened.
If you want to resolve files based on directories (so "foo.jpg" would be resolved to "480x800/foo.jpg" or something like that), you can write a new resolver. Just implement FileHandleResolver. The ResolutionFileResolver.java source is probably a good place to start.
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 orthogrphic camera 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.
If you use an OrthographicCamera you won't need to deal with different image resolutions.
Say that you have a camera with the size 400x300. Then you draw a 400x300 large image at coordinate (0,0). Then, regardless of screen resolution, the image will be scaled to fill the screen. This is really neat on Android where the screen resolution can vary a lot between different devices, and doing it like this you won't have to think about it.