Android Canvas weird shifting - java

I have a problem I was trying to solve for almost 2 days. (It ended up by switching to OpenGL :D)
Anyway... I have Canvas and I am trying to do a simple snake game. Just for this problem imagine our snake is made up from 5x5 pixels rectangles, he is leaving the trail (no clearing) and moving to the right from 0, 50 position... here is the code:
public class Snake extends AnimationWallpaper {
#Override
public Engine onCreateEngine() {
return new SnakeEngine();
}
class SnakeEngine extends AnimationEngine {
int i = 0;
Paint paint = new Paint();
#Override
public void onCreate(SurfaceHolder surfaceHolder) {
super.onCreate(surfaceHolder);
// By default we don't get touch events, so enable them.
setTouchEventsEnabled(true);
}
#Override
public void onSurfaceChanged(SurfaceHolder holder, int format,
int width, int height) {
super.onSurfaceChanged(holder, format, width, height);
}
#Override
public void onOffsetsChanged(float xOffset, float yOffset,
float xOffsetStep, float yOffsetStep, int xPixelOffset,
int yPixelOffset) {
super.onOffsetsChanged(xOffset, yOffset, xOffsetStep, yOffsetStep,
xPixelOffset, yPixelOffset);
}
#Override
public Bundle onCommand(String action, int x, int y, int z,
Bundle extras, boolean resultRequested) {
if ("android.wallpaper.tap".equals(action)) {
}
return super.onCommand(action, x, y, z, extras, resultRequested);
}
#Override
protected void drawFrame() {
SurfaceHolder holder = getSurfaceHolder();
Canvas c = null;
try {
c = holder.lockCanvas();
if (c != null) {
draw(c);
}
} finally {
if (c != null)
holder.unlockCanvasAndPost(c);
}
}
void draw(Canvas c) {
//c.save();
//c.drawColor(0xff000000);
paint.setAntiAlias(true);
// paint the fill
paint.setColor(Color.RED);
paint.setStyle(Paint.Style.FILL_AND_STROKE);
c.drawRect(i*5, 50, (i+1)*5, 55, paint);
//c.restore();
}
#Override
protected void iteration() {
i++;
super.iteration();
}
}
}
And here is output:
And that is not all, when it draws its kinda shifting... meaning what you see is shifted to the right side so it doesnt actualy stand in the same place...
If you have any idea why is it behave like that, please tell me!

In canvas, there's a reusability functionality which practically just add new drawings to whatever is in the canvas, hence if you are drawing 1 square at the time, the next time you will have whatever u had before +1, if you don't want that, and you want to fully manipulate every single draw from scratch, just add this line of code before to start drawing
canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
It will clear anything you had in the previous state of the canvas, and you can start again drawing whatever you want...
Hope It Helps!
Regards!

Related

Changing colour of a png image in java

i need to change the colour of a car PNG image when it crash to a block, like a kind of filter here's the 2 class
public class Sprite {
//classe estendibile a tutti gli oggetti
protected int x;
protected int y;
protected int width;
protected int height;
protected boolean visible;
protected Image image;
public Sprite(int x, int y) {
this.x = x;
this.y = y;
visible = true;
}
protected void getImageDimensions() {
width = image.getWidth(null);
height = image.getHeight(null);
}
protected void loadImage(String imageName) {
ImageIcon ii = new ImageIcon(imageName);
image = ii.getImage();
}
public Image getImage() {
return image;
public Rectangle getBounds() {
return new Rectangle(x, y, width,
height);
}
}`
public class Car extends Sprite {
public Car(int x, int y) {
super(x, y);
loadImage("src/car.png");
getImageDimensions();
}
Well I suppose it depends on the picture. If your picture looks like this
I suppose that going pixel by pixel and using image.setRGB(x, y, newColour) on pixels, that satisfy a condition of image.getRGB(x, y) == colourToChange will work. If you want to process a picture like
you would probably first need to run some recognition algorithm to find out which pixels are actually of the car and which are the background (wheels, shadows, etc.) and then run a filter over those. While this time based on the RGB of the original pixel you would need to calculate the new colour so that what was originally dark, remains dark and what was originally light remains light and so on.

How to implement a vertical ProgressBar as an Activity Background

I ran into this app concept by Oleg Frolov on Dribble.
The implementation seems pretty basic, with a horizontal ScrollView and a button which triggers the reveal animation.
I want to know :-
How to implement the vertical ProgressBar as the background of the
countdown activity
How to sync the progress of the ProgressBar, and the TextView's text change with the Chronometer/ System clock.
this project show you how to implement such a progress bar.
that is very simple to do with a custom drawable, there's no need to use libraries.
below is an UNTESTED example on how to do it.
public class CustomDrawable extends Drawable {
private final int color1;
private final Paint paint;
float level;
public CustomDrawable(int color1, int color2) {
this.color1 = color1;
paint = new Paint();
paint.setColor(color2);
paint.setStyle(Paint.Style.FILL_AND_STROKE);
}
#Override protected boolean onLevelChange(int level) {
invalidateSelf();
return true;
}
#Override public void draw(Canvas canvas) {
canvas.drawColor(color1);
level = getLevel() / 100f;
canvas.drawRect(
0,
canvas.getHeight() * level, // tweak this line if not drawing properly
canvas.getWidth(),
canvas.getHeight(), paint);
}
#Override public void setAlpha(int alpha) {
}
#Override public void setColorFilter(ColorFilter colorFilter) {
}
#Override public int getOpacity() {
return 0;
}
}
on the background view just use this drawable like:
background.setBackground(new CustomDrawable(color1, color2));
then to update the value u call
background.getBackground().setLevel(... between 0-100...);

Transparency not working in java

I have an image, with a complete transparent background. However when I draw this image, ingame, it has a kind of shade to it, and I have no clue why. I would like to get that out of there. Does anyone have an idea? I don't have the reputation to post images of it apparently... So I'll try to give some more information.
I have the Color.DARK_GRAY as background, and when I draw the image, you see a lighter gray square around it.
Then when I draw a couple of these images ontop of eachother, that square gets lighter and lighter.
If I draw the image ontop of another image however, this effect does not occur.
Here I load the image
public BlackChip() {
this.value = 500;
this.url = "res/images/poker/blackchip.png";
this.file = new File(url);
BufferedImage bi;
try {
bi = ImageIO.read(file);
this.image = bi;
} catch (IOException e) {
e.printStackTrace();
}
}
Here I draw the image
public void renderChip(Chip chip, int x, int y) {
g.drawImage(chip.getImage(), x, y, null);
}
Here I call that method
public void render() {
screen.renderBackground(Color.DARK_GRAY);
pokertable.render(Game.width / 2 - pokertable.getImage().getWidth(null) / 2, 50);
screen.renderChip(cs.getWhiteChip(), 380, 310);
screen.renderChip(cs.getRedChip(), 430, 310);
screen.renderChip(cs.getGreenChip(), 480, 310);
screen.renderChip(cs.getBlueChip(), 530, 310);
screen.renderChip(cs.getBlackChip(), 580, 310); //this one is it
}
link to the images:
https://drive.google.com/file/d/0Bz-4pfUssUeHRWkxaUhodWNILWc/edit?usp=sharing
Well... this doesn't work either because i need 10 reputation to post more then 1 link
you can see the effect on this link, it's the image with full transparent background, drawn multiple times.
I can't tell if this is the exact cause of the problem, because you haven't provided a MCVE but this method
public void renderChip(Chip chip, int x, int y) {
g.drawImage(chip.getImage(), x, y, null);
}
Just looks wrong. All custom painting should be done within the context of the provided Graphics object in the overridden paintComponent method. If you have not overriden paintComponent in a JPanel or a JComponent then you are likely not painting correctly. You may be doing something like
public class SomePanel extends JPanel {
private Graphics g;
public SomePanel() {
g = getGraphics();
}
}
Which is completely wrong. You should instead be doing something like
public class SomePanel extends JPanel {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// do painting here
}
}
You Classes can then have it's own render method that takes a Graphics object as an argument. Then can be called in the paintComponent method. Maybe something like
public class Chip {
private JComponent imageObserver;
private BufferedImage chipImage;
int x, y;
public Chip(BufferedImage chipImage, int x, int y, JComponent imageObserver){
this.chipImage;
this.x = x;
this.y = y;
this.imageObserver = imageObserver;
}
public void renderChip(Graphics g) {
g.getImage(chipImage, x, y, imageObserver);
}
}
And your panel
public class SomePanel extends JPanel {
private List<Chip> chips;
public SomePanel() {
chips = new ArrayList<Chip>();
// add new Chips
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for (Chip chip: chips) {
chip.renderChip(g);
}
}
}

bitmap being drawn multiple times on surfaceview

I'm just trying to draw a circle on the spot where I touch the screen. When I touch the screen, a circle is drawn there, but then when I touch the screen somewhere else a new circle is drawn (the old one is supposed to appear there, not a new one). Does anyone understand why this is happening? Code:
Thread class:
public class GameThread extends Thread{
private SurfaceHolder sHolder;
private DrawingSurface dSurface;
private boolean okToRun;
Paint redPaint = new Paint();
public int x, y;
boolean myTouchEvent(MotionEvent event){
int touch = event.getAction();
switch(touch){
case MotionEvent.ACTION_DOWN:
x = (int) event.getX();
y = (int) event.getY();
}
return true;
}
public GameThread(SurfaceHolder holder, DrawingSurface surface){
sHolder = holder;
dSurface = surface;
redPaint.setARGB(255, 255, 0, 0);
}//GameThread()
public void setOkToRun(boolean status){
okToRun = status;
}//setOkToRun()
public void run(){
while(okToRun){//gameloop
Canvas canvas = null;
try{
canvas = sHolder.lockCanvas(null);
synchronized(sHolder){
try{
canvas.drawCircle(x, y, 60, redPaint);
} catch (Exception e){
}
}
} finally {
if (canvas != null) {
sHolder.unlockCanvasAndPost(canvas);
}
}
}
}//run()
}
Here are the relevant methods of my surfaceview class:
#Override
public boolean onTouchEvent(MotionEvent event) {
return drawingThread.onTouchEvent(event);
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
drawingThread = new GameThread(getHolder(), this);
drawingThread.start();
drawingThread.setOkToRun(true);
}
#Override
public void surfaceDestroyed(SurfaceHolder arg0) {
radius += 10;
drawingThread.setOkToRun(false);
try {
drawingThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
TO BE CLEAR: I want to draw a single circle, and have it appear wherever I tap the screen. It does not do that. Can you tell why that is the case in this code?
I hope I am right that you need to draw a circle at the place where the screen was touched and the problem is that circles from previous touches still appear on the screen.
In this case the problem is, that you are drawing circles on canvas without clearing it. Canvas is represented in a memory as a array. When you call Canvas.drawCircle() part of memory is rewritten by an image of circle. When you do it repeatedly, the canvas contains more circles which are being drawn on the screen. You need to repaint the whole canvas before you draw a new circle. It can be done by calling the method Canvas.drawColor() before calling the method Canvas.drawCircle(). It clears the whole Canvas with selected color.

touch scrolling with libgdx

I'm trying to implement touch scrolling in a libgdx game. I have a wide image that is a panorama of a room. I want to be able to scroll the image so the user can see around the room. I have it so that I can scroll a certain distance but when a new touchDragged event is registered the image is moved back to the original position.
This is how I'm implementing it
public class AttackGame implements ApplicationListener {
AttackInputProcessor inputProcessor;
Texture backgroundTexture;
TextureRegion region;
OrthographicCamera cam;
SpriteBatch batch;
float width;
float height;
float posX;
float posY;
#Override
public void create() {
posX = 0;
posY = 0;
width = Gdx.graphics.getWidth();
height = Gdx.graphics.getHeight();
backgroundTexture = new Texture("data/pancellar.jpg");
region = new TextureRegion(backgroundTexture, 0, 0, width, height);
batch = new SpriteBatch();
}
#Override
public void resize(int width, int height) {
cam = new OrthographicCamera();
cam.setToOrtho(false, width, height);
cam.translate(width / 2, height / 2, 0);
inputProcessor = new AttackInputProcessor(width, height, cam);
Gdx.input.setInputProcessor(inputProcessor);
}
#Override
public void render() {
Gdx.gl.glClearColor(0,0,0,1);
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
batch.setProjectionMatrix(cam.combined);
batch.begin();
batch.draw(backgroundTexture, 0, 0, 2400, 460);
batch.end();
}
#Override
public void pause() {
// TODO Auto-generated method stub
}
#Override
public void resume() {
// TODO Auto-generated method stub
}
#Override
public void dispose() {
backgroundTexture.dispose();
}
}
And in the InputProcessor
#Override
public boolean touchDragged(int screenX, int screenY, int pointer) {
cam.position.set(screenX, posY / 2, 0);
cam.update();
return false;
}
I got this far with help from this question LibGdx How to Scroll using OrthographicCamera?. However it doesn't really solve my problem.
I think the problem is with the touchDragged corodinates not being world coordinates but I have tried unprojecting the camera with no effect.
I have been struggling with this for a few weeks and I would really appreciate some help on this.
Thanks in advance.
I recently did something as what you want. This is my Input class that I use for move the map, you only need to change my 'stage.getCamera()' for your 'cam':
public class MapInputProcessor implements InputProcessor {
Vector3 last_touch_down = new Vector3();
...
public boolean touchDragged(int x, int y, int pointer) {
moveCamera( x, y );
return false;
}
private void moveCamera( int touch_x, int touch_y ) {
Vector3 new_position = getNewCameraPosition( touch_x, touch_y );
if( !cameraOutOfLimit( new_position ) )
stage.getCamera().translate( new_position.sub( stage.getCamera().position ) );
last_touch_down.set( touch_x, touch_y, 0);
}
private Vector3 getNewCameraPosition( int x, int y ) {
Vector3 new_position = last_touch_down;
new_position.sub(x, y, 0);
new_position.y = -new_position.y;
new_position.add( stage.getCamera().position );
return new_position;
}
private boolean cameraOutOfLimit( Vector3 position ) {
int x_left_limit = WINDOW_WIDHT / 2;
int x_right_limit = terrain.getWidth() - WINDOW_WIDTH / 2;
int y_bottom_limit = WINDOW_HEIGHT / 2;
int y_top_limit = terrain.getHeight() - WINDOW_HEIGHT / 2;
if( position.x < x_left_limit || position.x > x_right_limit )
return true;
else if( position.y < y_bottom_limit || position.y > y_top_limit )
return true;
else
return false;
}
...
}
This is the result: http://www.youtube.com/watch?feature=player_embedded&v=g1od3YLZpww
You need to do a lot more computation in the touchDragged callback, you can't just pass whatever screen coordinates were touched on to the camera. You need to figure out how far the user has dragged their finger, and in what direction. The absolute coordinates are not immediately useful.
Consider dragging down from the top-right or dragging down from the top-left. In both cases you want (I presume) to move the camera the same distance, but the absolute values of the screen coordinates will be very different in the two cases.
I think the simplest thing is to just track previousX and previousY (initialize them in the touchDown method. Then invoke cam.translate() with the delta (deltaX = screenX - previousX, for example), during touchDragged. And also update the previous* in touchDragged.
Alternatively, you can look at some of the fancier InputProcessor wrappers libgdx provides (see https://code.google.com/p/libgdx/wiki/InputGestureDetection).
Simple answer:
Declare 2 fields to hold the new and old drag location:
Vector2 dragOld, dragNew;
When just touched you set both of these equal to the touched location or your cam will jump.
if (Gdx.input.justTouched())
{
dragNew = new Vector2(Gdx.input.getX(), Gdx.input.getY());
dragOld = dragNew;
}
Update dragNew each frame and simply subtract the vectors from each other to get the x and y for translating the camera.
if (Gdx.input.isTouched())
{
dragNew = new Vector2(Gdx.input.getX(), Gdx.input.getY());
if (!dragNew.equals(dragOld))
{
cam.translate(dragOld.x - dragNew.x, dragNew.y - dragOld.y); //Translate by subtracting the vectors
cam.update();
dragOld = dragNew; //Drag old becomes drag new.
}
}
This is all I use to drag my ortho cam around, simple and effective.
Used drinor's answer but added the line on "touchDown) function so it doesn't reset the camera every time you start dragging again:
#Override
public boolean touchDown(int screenX, int screenY, int pointer, int button) {
last_touch_down.set( screenX, screenY, 0);
return false;
}
I have not used it myself, but I would start by looking at the code of:
Have you looked at the code of http://libgdx.l33tlabs.org/docs/api/com/badlogic/gdx/scenes/scene2d/ui/FlickScrollPane.html
See: touchDragged

Categories

Resources