9patch looks pixeled when setSize is called too many times - android

I have a sprite that is supposed to act like a loadbar. I have tried this by using an example image that has been created like a 9patch-type (http://cdn.dibbus.com/wp-content/uploads/2011/03/btn_black.9.png). It seems okay in the start, but as the width of the sprite increases the sprite starts to look pixeled. Anyone know what the problem could be, or have any solution? The code is shown below.
public Sprite loaded;
public void init()
{
atlas = new TextureAtlas(Gdx.files.
internal("data/misc/menu_button.pack"));
loaded = atlas.createSprite("loadbar");
loaded.setPosition((Misc.WIDTH/2) - unloaded.getWidth()/2,
Misc.HEIGTH - unloaded.getHeight());
}
public void draw_load_bar() //render function
{
if(loaded.getWidth() < 600)
{
loaded.setSize(loaded.getWidth()+ 0.5f, loaded.getHeight());
}
loaded.draw(batch);
}

Dont use a Sprite to stretch it. I'd recommend a real Ninepatch from libgdx for it.
public NinePatch loaded;
private float posX, posY, width, height;
public void init()
{
loaded = new NinePatch(the Texture here,10, 10, 10, 10); //bounds outside
//set right pos here...
}
public void draw_load_bar(SpriteBatch batch) //render function
{
if(loaded.getWidth() < 600)
{
//update the size of it here (guess pos is static)
width++;
}
//need to parse the batch and the right sizes.
loaded.draw(batch, posx, posy, width, height);
}
after that you can handle it like a Sprite or Texture but it does stratch right without issues. If you want to the full Picture to be Stretched simply do net set any bounds at the creation new NinePatch(texture, 0,0,0,0)

Related

FadeOut Action in libgdx

I'm trying to animate all the actors in a stage but FadeOut Action doesn't work
although the other actions work fine
I have the following code
getRoot().setPosition(Gdx.graphics.getWidth(), 0);
getRoot().getColor().a = 0;
SequenceAction sequenceAction = new SequenceAction();
sequenceAction.addAction(Actions.moveTo(0, 0, 3.0f));
sequenceAction.addAction(Actions.fadeOut(3.0f));
getRoot().addAction(sequenceAction);
I also tried another way to animate them by TweenEngine using class GroupAccessor implements TweenAccessor<Group> and All work fine except manipulating alpha value
public class GroupAccessor implements TweenAccessor<Group> {
public static final int ALPHA = 0;
public static final int POS_XY = 1;
#Override
public int getValues(Group target, int tweenType, float[] returnValues) {
switch (tweenType) {
case ALPHA :
returnValues[0] = target.getColor().a;
return 1;
case POS_XY :
returnValues[0] = target.getX();
returnValues[1] = target.getY();
return 2;
default:
assert false;
return -1;
}
}
#Override
public void setValues(Group target, int tweenType, float[] newValues) {
switch (tweenType) {
case ALPHA :
target.setColor(target.getColor().r, target.getColor().g, target.getColor().b,
newValues[0]);
break;
case POS_XY :
target.setPosition(newValues[0], newValues[1]);
break;
default:
assert false;
}
}
}
Animation using TweenEngine
Timeline.createSequence().
push(Tween.set(getRoot(), GroupAccessor.POS_XY).target(Gdx.graphics.getWidth(),0))
.push(Tween.to(getRoot(), GroupAccessor.POS_XY, 3.0f).target(0,0))
.push(Tween.set(getRoot(), GroupAccessor.ALPHA).target(0))
.push(Tween.to(getRoot(), GroupAccessor.ALPHA, 3.0f).target(1)).start(manager);
I have multiple actors and I made arrays of some of these actors. Here are 2 examples of draw() method of 2 actors
public void draw(Batch batch, float parentAlpha) {
batch.draw(wallSprite, 0, 0, Constants.WIDTH, Constants.HEIGHT);
}
public void draw(Batch batch, float parentAlpha) {
batch.draw(gearSprite, getX(), getY(),
gearSprite.getOriginX(), gearSprite.getOriginY(), gearSprite.getWidth(),
gearSprite.getHeight(), gearSprite.getScaleX(), gearSprite.getScaleY()
, gearSprite.getRotation());
try {
batch.draw(permittedCSprite, getX() + gearSprite.getWidth()/2
- permittedCSprite.getWidth()/2, getY() +
gearSprite.getHeight()/2 - permittedCSprite.getHeight()/2,
permittedCSprite.getWidth(), permittedCSprite.getHeight());
}
catch (NullPointerException e) {}
}
The draw method of an Actor absolutely must set a color on the Batch. This is necessary to support fading. Even if you don't care about fading or changing the color of the actor, you would still need to change the color of the Batch to WHITE to ensure what color the actor is drawn with (because there is no guarantee of what color some other actor has left the batch at.
Typically, you would have something like this at the top of your draw method:
public void draw (Batch batch, float parentAlpha) {
Color color = getColor();
batch.setColor(color.r, color.g, color.b, color.a * parentAlpha);
//...
}
However, if your Actor is drawing a Sprite instead of a TextureRegion, then you must set the color on the Sprite instead. This is because sprites have their own color which they pass on to the batch when you call sprite.draw.
If you are using a Sprite (which I don't recommend with Actors), your draw method should look something like this:
public void draw (Batch batch, float parentAlpha) {
sprite.setColor(getColor());
sprite.draw(batch, parentAlpha);
}
One "gotcha" is that Sprite is a subclass of TextureRegion. Sprite is a TextureRegion that holds information about color, size, orientation, position, etc, so it can be drawn a little bit faster (possibly) than a TextureRegion. It does this at the cost of using more memory. If you are using a Sprite, you should be calling sprite.draw not batch.draw(sprite ...), because the second option treats the sprite as a TextureRegion.
If you want to use Sprite, then you need to apply all the attributes you need to the sprite. For example:
public void draw (Batch batch, float parentAlpha) {
sprite.setColor(getColor());
sprite.setPosition(getX(), getY());
sprite.setSize(getWidth(), getHeight());
//etc. etc. etc. :(
sprite.draw(batch, parentAlpha);
}
For this reason, it really doesn't make sense to use a Sprite in an Actor at all. Way too much redundancy. Just use TextureRegions.

Android TransitionDrawable not fading

I have an ImageView and I am trying to fade from one image to the next using this code:
Drawable bgs[] = new Drawable[2];
public void redraw(int[][] grid) {
bgs[0] = bgs[1];
bgs[1] = new GameDrawable(grid, prefs.colors);
if (bgs[0] == null) {
gameField.setImageDrawable(bgs[1]);
} else {
TransitionDrawable crossfader = new TransitionDrawable(bgs);
crossfader.setCrossFadeEnabled(true);
gameField.setImageDrawable(crossfader);
crossfader.startTransition(500);
}
}
gameField is correctly referenced as an ImageView.
gameDrawable simply extends Drawable and draws the grid.
On each move and action the new GameDrawable is being rendered correctly but there is no fading whatsoever. The new image is simply displayed instantaneously. I have tried lengthening the transition time and swapping the order of the drawables with no effect.
Any help on is appreciated.
Update: I have now set my transition to something ridiculously long like 500000. The first drawable shows for a few seconds and then suddenly the second drawable appears. So still no transition.
Update 2:
I think my Drawable might be implemented incorrectly, so I have attached the code.
public class GameDrawable extends Drawable {
private Paint paint = new Paint();
private float blockWidth = 1;
private int[][] myGrid;
private int myColor;
private List<Point> myPoints;
public GameDrawable(int[][] grid) {
super();
this.myGrid = grid;
this.myColor = colors[yourColor];
paint.setStrokeWidth(1);
paint.setStyle(Paint.Style.FILL);
paint.setAlpha(0);
this.myPoints = yourPoints;
}
#Override
public void draw(Canvas canvas) {
float height = getBounds().height();
float width = getBounds().width();
blockWidth = width / myGrid.length;
if (height / myGrid.length < blockWidth) {
blockWidth = height / myGrid.length;
}
for (int x = 0; x < myGrid.length; x++) {
for (int y = 0; y < myGrid[x].length; y++) {
paint.setColor(colors[myGrid[x][y]]);
canvas.drawRect(x * blockWidth, y * blockWidth, (x+1)*blockWidth, (y+1)*blockWidth, paint);
}
}
}
#Override
public void setAlpha(int alpha) {
paint.setAlpha(alpha);
invalidateSelf();
}
#Override
public void setColorFilter(ColorFilter cf) {
paint.setColorFilter(cf);
invalidateSelf();
}
#Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
}
Looking at your code, I see a problem at the line
bgs[0] = bgs[1];
bgs[1] has not yet been defined before this line and so bgs[0] is null for the first method call. Because of this, (bgs[0] == null) is true, and so the later defined bgs[1] is directly set to the gameField ImageView.
Use corrected code below.
Drawable bgs[] = new Drawable[2];
Drawable firstDrawable = getResources().getDrawable(R.drawable.transparent);
public void redraw(int[][] grid) {
bgs[0] = firstDrawable;
bgs[1] = new GameDrawable(grid, prefs.colors);
firstDrawable = bgs[1];
TransitionDrawable crossfader = new TransitionDrawable(bgs);
crossfader.setCrossFadeEnabled(true);
gameField.setImageDrawable(crossfader);
crossfader.startTransition(500);
}
Note that TransitionDrawable does not work properly when the Drawable sizes are different. So you may need to resize firstDrawable beforehand.
EXTRA: I would avoid setCrossFadeEnabled(true) since the whole TransitionDrawable becomes translucent during the transition, revealing the background. Sometimes, this creates a "blinking" effect and destroys the smoothness of the transition.
EDIT: Looking at your custom Drawable implementation, I think the problem lies in the line
canvas.drawColor(Color.WHITE);
in the draw() method.
I looked at TransitionDrawable.java source and found that setAlpha is called on the drawables to get the cross fade effect. However, your canvas has a solid white color and setAlpha() only affects the paint. Hope this is your answer.
EDIT 2: The actual problem, as pointed out by Michael, was that TransitionDrawable's setAlpha() calls on the Drawables were rendered ineffective due to paint.setColor() in the GameDrawable's draw() method overriding the paint's alpha value set by the TransitionDrawable.

Libgdx OrthographicCamera zoom hidding part of Shaperenderer

I'm trying to make an isometric map on Android using libgdx. I'm basicaly drawing shapes with a ShapeRenderer and handling gestures by moving/zooming the camera. Here is my code.
public class MyGdxGame extends ApplicationAdapter{
private OrthographicCamera cam;
private ShapeRenderer mShapeRenderer;
private InputHandler mInputHandler;
#Override
public void create() {
mShapeRenderer = new ShapeRenderer();
mInputHandler = new AndroidInputHandler();
Gdx.input.setInputProcessor(mInputHandler);
Gdx.graphics.setContinuousRendering(false);
}
#Override
public void render() {
System.out.println("render()");
mInputHandler.handleInput(cam);
cam.update();
// clearing scene
Gdx.graphics.getGL20().glClearColor(1, 1, 1, 1);
Gdx.graphics.getGL20().glClear( GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT );
//drawing updated scene
mShapeRenderer.setProjectionMatrix(cam.combined);
mShapeRenderer.begin(ShapeRenderer.ShapeType.Filled);
mShapeRenderer.setColor( 0.95f, 0.95f, 0.95f,1);
mShapeRenderer.rect(0, 0, 5.1f, 4.8f);
mShapeRenderer.rect( 6.890f,24.014f,2.201f, 6f);
mShapeRenderer.end();
}
#Override
public void resize(int width, int height) {
cam = new OrthographicCamera( 10f,10f * height / width);
cam.position.set(5, 5, 7);
cam.lookAt(0, 0, 0);
Vector3 up =cam.position.cpy();
up.nor();
up.crs((new Vector3(-1, 1, 0)).nor());
cam.up.set(up);
cam.zoom=1f;
cam.far=100000;
cam.near=0;
}
...
}
InputHandler is a custom class that handle gestures like pinch to zoom and camera translation. It only calls camera.translate(Vector3) and camera.zoom = new zoom.
My problem is that whenever i pinch to zoom, some of my shape are cut.
expected drawing
cutted shapes
I don't realy know where this comes from. I think there is something happening with my viewport. I tried modifying the base zoom and camera viewport sizes but I dont realy understand the concept of viewport width and height.
Any help would be apreciated.
Thanks

draw a texture when i touch a specific texture in libgdx

I am making a game with libgdx. if i touch the screen then a texture appears, but what i really want to do is that when i touch a specific texture then the other texture must appear.
this is my code for now:
public class MyGame extends InputAdapter implements ApplicationListener {
SpriteBatch batch;
Texture ball;
Texture bat;
#Override
public void create() {
ball = new Texture("ball.png");
bat = new Texture("bat.png");
batch = new SpriteBatch();
}
#Override
public void render() {
batch.begin();
if (Gdx.input.isTouched()) {
batch.draw(ball, Gdx.input.getX(), Gdx.graphics.getHeight()
- Gdx.input.getY());
batch.draw(bat, 50, 50);
batch.end();
}
}
}
it's not the whole code, just the code that is used to appear those textures.
I really appreciate your help.
Thankyou
The code below gives an example of how you can extend your current approach to test if the touch is within the area of your texture, but I would not recommend it for use in a real game.
It is fine as an exercise to understand what is going on, but manually coding the touch regions in this way will quickly become cumbersome as your game becomes more complex.
I would strongly recommend you become familiar with the scene2d package in libGdx. This package has methods to handle all the common 2D behaviors such as touch events, movement and collisions.
Like a lot of the libGdx library, the documentation can be hard to follow if you're just starting out, and there are not many tutorials around either. I'd recommend working through the Java Game Development (LibGDX) series of youtube videos by dermetfan. It helped me understand many areas when I was starting out. Good luck.
SpriteBatch batch;
Texture firstTexture;
Texture secondTexture;
float firstTextureX;
float firstTextureY;
float secondTextureX;
float secondTextureY;
float touchX;
float touchY;
#Override
public void create() {
firstTexture= new Texture("texture1.png");
firstTextureX = 50;
firstTextureY = 50;
secondTexture = new Texture("texture2.png");
secondTextureX = 250;
secondTextureY = 250;
batch = new SpriteBatch();
}
#Override
public void render() {
batch.begin; // begin the batch
// draw our first texture
batch.draw(firstTexture, firstTextureX, firstTextureY);
// is the screen touched?
if (Gdx.input.isTouched()) {
// is the touch within the area of our first texture?
if (touchX > firstTextureX && touchX < (firstTextureX + firstTexture.getWidth())
&& touchY > firstTextureY && touchY < (firstTextureY + firstTexture.getHeight()) {
// the touch is within our first texture so we draw our second texture
batch.draw(secondTexture, secondTextureX, secondTextureY);
}
batch.end; // end the batch
}

How can i handle the rotation issue with Preview & FaceDetection

i got some issue nagging me for quite some time now.
I got my custom Camera-App that shows a live Preview. Aswell i am using the FaceDetection for getting a better focus on peoples faces. When i check my taken Pictures in Gallery i can see the Rectangle correctly. The next step is to make the FaceDetection-Rectangle visible in the Live-Preview. So i decided to use a canvas that gets the coordinates from the Preview-Rectangle and transform them to coordinates that can be used by the canvas.
My problem is that i had to rotate the Preview by 90degrees that it shows the Preview correctly. So when i also rotate the View of the canvas before i draw it, the rectangle shows correctly and moves the right axis aswell. BUT the rectangle can move out of screen on left and right, and only uses about half of the available height. I assume that the rotating causes the trouble, but i can't manage to put things right. Someone got an idea?
Screenshot (i added purple lines to show the top/bottom-parts that cant be reached by red rectangle):
Preview:
mCamera = Camera.open();
mCamera.getParameters();
mCamera.setDisplayOrientation(90);
mCamera.setFaceDetectionListener(new FaceDetectionListener() {
#Override
public void onFaceDetection(Face[] faces, Camera camera) {
if(mDraw != null) {
mDraw.update(f.rect, f);
}
}
}
}
});
mCamera.startFaceDetection();
}
private DrawOnTop mDraw = null;
public void setDrawOnTop(DrawOnTop d) {
this.mDraw = d;
}
DrawOnTop:
public DrawOnTop(Context context) {
super(context);
myColor = new Paint();
myColor.setStyle(Paint.Style.STROKE);
myColor.setColor(Color.RED);
}
#Override
protected void onDraw(Canvas canvas) {
rect.set((((rect.left+1000)*1000) / WIDTH_DIVISOR),(((rect.top+1000)*1000) / HEIGHT_DIVISOR),(((rect.right+1000)*1000) / WIDTH_DIVISOR),(((rect.bottom+1000)*1000) / HEIGHT_DIVISOR ));
setRotation(90);
canvas.drawRect(rect, myColor);
}
public void update(Rect rect, Face face) {
this.invalidate();
this.rect = rect;
this.face = face;
}
----------------------------------------------------------------------------------------
EDIT:
i came to the conclusion that this is a rare but known bug and that there is so far no other solution but forcing the application to landscape-mode. Works ok, but dimensions look a bit stretched or clinched depending on which perspective the user is operating.
EDIT: I misread the question and talked about the wrong rectangle. This is what i meant:
Basically, you just need to scale the purple rectangle. Find ut where it is defined, then put it onto a canvas and do the following:
float screenWidth = /*get the width of your screen here*/;
float xScale = rect.width / screenWidth;
float screenHeight = /*get the height of your screen here*/;
float yScale = rect.height / screenWidth;
canvas.setScaleX(xScale);
canvas.setScaleY(yScale);
This way, the coordinates will be translated properly.
SECOND EDIT (in response to your comment): You can also do this with views, if you like.
Have fun.

Categories

Resources