Full screen image using canvas and bitmap - java

I am tryin to set an image in full screen using canvas and bitmap but whenever I load the app the image gets zoomed in and only displays half of what it's supposed to. How would I do this? I have attached my code snippet and i have tried updating the canvas.drawbitmap line of code inside the onDraw method but it doesn't help, the image still appears zoomed in. Some help would greatly be appreciated thank you in advance...
public class Fish extends View {
private Bitmap fish [] =new Bitmap[2];
private int fishX=10;
private int fishY;
private int fishSpeed;
private int canvasWidth, canvasHeight;
private int yellowX, yellowY, yellowSpeed=16;
private Paint yellowPaint=new Paint();
private int greenX, greenY, greenSpeed=20;
private Paint greenPaint=new Paint();
private int redX, redY, redSpeed=25;
private Paint redPaint=new Paint();
private int score, lifeCountOfLife;
private boolean touch=false;
private Bitmap backgroundImage;
private Paint scorePaint= new Paint();
private Bitmap life[]=new Bitmap[2];
//updates the background
public Fish(Context context) {
super(context);
fish [0]=BitmapFactory.decodeResource(getResources(),R.drawable.fish1);
fish [1]=BitmapFactory.decodeResource(getResources(),R.drawable.fish2);
//updates the bg
backgroundImage=BitmapFactory.decodeResource(getResources(),R.drawable.mn);
//creates the ball/foood color
yellowPaint.setColor(Color.YELLOW);
yellowPaint.setAntiAlias(false);
greenPaint.setColor(Color.GREEN);
greenPaint.setAntiAlias(false);
redPaint.setColor(Color.RED);
redPaint.setAntiAlias(false);
// updates score
scorePaint.setColor(Color.WHITE);
scorePaint.setTextSize(70);
scorePaint.setTypeface(Typeface.DEFAULT_BOLD);
scorePaint.setAntiAlias(true);
//displays the heart and life
life[0]=BitmapFactory.decodeResource(getResources(),R.drawable.heartts);
life[1]=BitmapFactory.decodeResource(getResources(),R.drawable.greyheart);
fishY=550;
score=0;
lifeCountOfLife=3;
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvasWidth=canvas.getWidth();
canvasHeight=canvas.getHeight();
//displays it to the main actiivty
canvas.drawBitmap(backgroundImage,canvasWidth,canvasHeight,null);
int minFish= fish[0].getHeight();
int maxFishY=canvasHeight-fish[0].getHeight() *3;
fishY=fishY+fishSpeed;
if(fishY<minFish){
fishY=minFish;
}
if(fishY> maxFishY){
fishY=maxFishY;
}
fishSpeed=fishSpeed+2;
if(touch){
canvas.drawBitmap(fish[1], fishX,fishY, null);
touch=false;
}else{
canvas.drawBitmap(fish[0],fishX,fishY,null);
}
yellowX=yellowX-yellowSpeed;
//updates the score if the ball is collected
if(hitBallChecker(yellowX,yellowY)){
score=score+10;
yellowX=-100;
}
if(yellowX<0){
yellowX=canvasWidth+21;
yellowY=(int) Math.floor(Math.random() * (maxFishY-minFish))+ minFish;
}
//increases size of ball
canvas.drawCircle(yellowX, yellowY, 25, yellowPaint);
//Green ball
greenX=greenX-greenSpeed;
if(hitBallChecker(greenX,greenY)){
score=score+20;
greenX=-100;
}
if(greenX<0){
greenX=canvasWidth+21;
greenY=(int) Math.floor(Math.random() * (maxFishY-minFish))+ minFish;
}
//increases size of ball
canvas.drawCircle(greenX, greenY, 25, greenPaint);
//red ball
//if the ball gets hit
redX=redX-redSpeed;
if(hitBallChecker(redX,redY)){
redX=-100;
lifeCountOfLife--;
if(lifeCountOfLife==0){
Intent gameOverIntent= new Intent(getContext(), GameOverActivity.class);
gameOverIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
gameOverIntent.putExtra("score", score);
getContext().startActivity(gameOverIntent);
}
}
//increases size of ball
if(redX<0){
redX=canvasWidth+21;
redY=(int) Math.floor(Math.random() * (maxFishY-minFish))+ minFish;
}
canvas.drawCircle(redX, redY, 30, redPaint);
canvas.drawText("Score: " +score, 20, 60, scorePaint);
for(int i=0; i<3; i++){
int x=(int) (580+life[0].getWidth() * 1.5 * i);
int y=30;
if(i<lifeCountOfLife){
canvas.drawBitmap(life[0], x,y, null);
}else{
canvas.drawBitmap(life[1], x,y, scorePaint);
}
}
}
public boolean hitBallChecker(int x, int y){
if(fishX< x && x<(fishX+fish[0].getWidth()) &&fishY<y &&y<(fishY+ fish[0].getHeight())){
return true;
}
return false;
}
//updates fish speed
#Override
public boolean onTouchEvent(MotionEvent event) {
if(event.getAction()==MotionEvent.ACTION_DOWN){
touch=true;
fishSpeed=-22;
}
return true;
}
}

public void drawBitmap (Bitmap bitmap,
float left,
float top,
Paint paint)
In drawBitmap left and top define the (x,y) of the top left corner of the image, which in your case should be (0,0).
If you want to draw a canvas sized backgound it would probably be best to use:
public void drawBitmap (Bitmap bitmap,
Rect src,
Rect dst,
Paint paint)
Where src is the Rect that defines the subset of the Bitmap that you want to draw (you can leave it at null to draw the entire Bitmap), and dst is the destination Rect that will automatically be filled with the Bitmap.
You are going to need to define the destination Rect:
Rect backgroundRect = new Rect(0, 0, canvas.getWidth(), canvas.getHeight());
You can now call
canvas.drawBitmap(backgroundImage,null,backgroundRect,null);

Related

How to draw different points with canvas in Android

I'm developing an Android application, I have to implement a function that allow me to draw different point in an activity.
This is my code:
public class MainActivity extends AppCompatActivity {
public Paint paint;
public List<Point> coords;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new DrawingView(this));
paint = new Paint();
coords = new ArrayList();
ImageView iv = new ImageView(getApplicationContext());
iv.setImageResource(R.drawable.car);
iv.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
LinearLayout.LayoutParams parms = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.MATCH_PARENT);
iv.setLayoutParams(parms);
}
class DrawingView extends SurfaceView {
private final SurfaceHolder surfaceHolder;
private final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
public DrawingView(Context context) {
super(context);
surfaceHolder = getHolder();
paint.setColor(Color.BLACK);
paint.setStyle(Paint.Style.FILL);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_DOWN) {
addpoint(event.getX(), event.getY());
}
return false;
}
public void addpoint(float x, float y){
Point point = new Point();
point.x = Math.round(x);
point.y = Math.round(y);
coords.add(point);
for(int i = 0; i< coords.size(); i++) {
Canvas canvas = surfaceHolder.lockCanvas();
canvas.drawColor(Color.WHITE);
canvas.drawCircle(coords.get(i).x, coords.get(i).y, 20, paint);
surfaceHolder.unlockCanvasAndPost(canvas);
}
}
}
}
Everytime that I touch the screen I get and save the coordinates in a list, then I try to draw the list of point, but only one point remain on the screen, I don't understand why.
So how I can draw different point on the screen (and save it) ?
Another question: how I can show a background image ?
From the official Javadocs:
drawColor(int color) Fill the entire canvas' bitmap (restricted to the
current clip) with the specified color, using srcover porterduff mode.
So every time you draw a circle, first you clear the whole canvas with white color. So after a draw, the circle drawed before is cleared.
So one option is to save the current state of the background, and always draw it on top of the white, or try not using drawColor
for(int i = 0; i< coords.size(); i++) {
Canvas canvas = surfaceHolder.lockCanvas();
canvas.drawColor(Color.WHITE);
canvas.drawCircle(coords.get(i).x, coords.get(i).y, 20, paint);
surfaceHolder.unlockCanvasAndPost(canvas);
}
should be
Canvas canvas = surfaceHolder.lockCanvas();
canvas.drawColor(Color.WHITE);
for(int i = 0; i< coords.size(); i++) {
canvas.drawCircle(coords.get(i).x, coords.get(i).y, 20, paint);
}
surfaceHolder.unlockCanvasAndPost(canvas);
canvas.drawColor(Color.WHITE); Everytime ereases all the canvas and surfaceHolder.unlockCanvasAndPost(canvas); shows only the last added Circle

Clicklistener - different coordinates while resizing

I have a tiled map on which I set characters(every character is of the size of one tile). I managed to make them clickable, even when screen resizes everything works perfect. Every time I click on character I want a button to show up above it. For a button I use stage and place the button in the place I clicked with small transition and it also works.
My problem is when I try to use clicklistener on this button. If the screen does not resize, clicklistener works. Problem starts when the screen get resized - clicks on players works well, only button does not work - after a resize the clicking space and the button space are not aligned. For test purposes I made a test map that shows me grids. It seems that stage is not properly resized. Picture for a reference. I tried many solutions I came upon on the Internet and still can't find a solution to my problem. I have shortened my code down to a minimum basic example:
public class Test extends ApplicationAdapter {
public static Stage stage;
public TiledMap tiledMap;
static OrthographicCamera camera;
TiledMapRenderer tiledMapRenderer;
public static boolean showMenu;
GestureDetector gesture;
InputMultiplexer myInputMultiplexer;
public static int posx, posy;
public static Image move;
public Texture moveMenu;
#Override
public void create() {
moveMenu = new Texture(Gdx.files.internal("move.png"));
gesture = new GestureDetector(new MyGestureListener());
myInputMultiplexer = new InputMultiplexer();
float unitScale = 1 / 32f;
camera = new OrthographicCamera();
camera.setToOrtho(true, 33, 21);
stage = new Stage(new ScreenViewport());
stage.getViewport().setCamera(camera);
tiledMap = new TmxMapLoader().load("test.tmx");
tiledMapRenderer = new OrthogonalTiledMapRenderer(tiledMap, unitScale);
myInputMultiplexer.addProcessor(stage);
myInputMultiplexer.addProcessor(gesture);
Gdx.input.setInputProcessor(myInputMultiplexer);
move = new Image(moveMenu);
move.setWidth(2);
move.setHeight(2);
move.addListener(new ClickListener() {
#Override
public void clicked(InputEvent event, float x, float y) {
move(); //my action, works fine
showMenu = false;
}
});
stage.addActor(move);
}
#Override
public void render() {
super.render();
stage.act();
tiledMapRenderer.setView(camera);
camera.update();
tiledMapRenderer.render();
if (showMenu) {
mainMenuDraw();
}
}
public static void mainMenuDraw() {
move.setPosition(posx, posy-2);
stage.draw();
}
public void resize(int width, int height) {
stage.getViewport().update(width, height, true);
}
public static OrthographicCamera getCamera() {
return camera;
}
public static Vector3 unprojectCoords(Vector3 coords) {
camera.unproject(coords);
return coords;
} }
and part of my gesturelistener:
public boolean touchDown(float x, float y, int pointer, int button) {
Vector3 temp_coord = new Vector3(x, y, 0);
Vector3 coords = Test.unprojectCoords(temp_coord);
return false;
}
#Override
public boolean tap(float x, float y, int count, int button) {
Vector3 temp_coord = new Vector3(x, y, 0);
Vector3 coords = Test.unprojectCoords(temp_coord);
Test.posx = (int) coords.x;
Test.posy = (int) coords.y;
tap = true;
Test.showMenu = true;
return false;
}
I would suggest to you read more about re-sizing and displaying pixels.
You need to recalculate pixels always when you render something.
- player, background image, buttons, events.
Actually you don't need to use resize method, just get the camera width and height.
You need to share more code, because it depends on everything.
I don't see how you are doing rendering.
tiledMapRenderer.render(), background rendering / layers?
player rendering?
menu rendering?
buttons rendering?
Example: (the same should be for event handler)
public GameButton(TextureRegion reg, float x, float y, OrthographicCamera cam) {
this.reg = reg;
this.x = x;
this.y = y;
this.cam = cam;
width = reg.getRegionWidth();
height = reg.getRegionHeight();
vec = new Vector3();
Texture tex = Game.res.getTexture("hud");
font = new TextureRegion[11];
for(int i = 0; i < 11; i++) {
font[i] = new TextureRegion(tex, 32 + i * 9, 16, 9, 9); //use height and width here)
}
}

Making touched area of bitmap to transparent

I have 2 bitmaps on a canvas. ontouching the top bitmap , the lower bitmap should be visible and the top bitmap should be erased.
I took help from this thread. Make certain area of bitmap transparent on touch. I can see the bottom bitmap through the circle, but the top bitmap is not erasing on touching. How to erase the the bitmap on touching. I know that this question has been asked before, but i am not able to solve the problem.
this is my code:
public class MainActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new Panel(this));
}
class Panel extends View {
Bitmap bmOverlay;
private Paint mPaint;
Bitmap bm2, bm1;
Bitmap bitmap;
Canvas pcanvas;
int x = 0;
int y = 0;
int r = 0;
public Panel(Context context) {
super(context);
setFocusable(true);
setBackgroundColor(Color.TRANSPARENT);
// setting paint
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setColor(Color.TRANSPARENT);
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT));
mPaint.setAntiAlias(true);
bm1 = BitmapFactory.decodeResource(getResources(), R.drawable.aa);
bm2 = BitmapFactory.decodeResource(getResources(), R.drawable.aaa);
bmOverlay = Bitmap.createBitmap(bm1.getWidth(), bm1.getHeight(),
Bitmap.Config.ARGB_8888);
pcanvas = new Canvas(bmOverlay);
}
#Override
protected void onDraw(Canvas canvas) {
// draw a circle that is erasing bitmap
super.onDraw(canvas);
canvas.drawBitmap(bm2, 0, 0, null);
pcanvas.drawBitmap(bm1, 0, 0, null);
pcanvas.drawCircle(x, y, 40, mPaint);
canvas.drawBitmap(bmOverlay, 0, 0, null);
}
#Override
public boolean onTouchEvent(MotionEvent ev) {
// set parameter to draw circle on touch event
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN: {
x = (int) ev.getX();
y = (int) ev.getY();
invalidate();
break;
}
case MotionEvent.ACTION_MOVE: {
x = (int) ev.getX();
y = (int) ev.getY();
invalidate();
break;
}
case MotionEvent.ACTION_UP:
break;
}
return true;
}
}
}
You need to make two changes to get the top bitmap to erase. First, make it a mutable Bitmap so that you can change the contents as it is erased:
Bitmap temp = BitmapFactory.decodeResource(getResources(), R.drawable.aa);
bm1 = temp.copy(Bitmap.Config.ARGB_8888, true); // mutable = true
Be careful about out of memory errors here.
Secondly, in your onDraw function, update the bitmap contents by writing back to bm1:
#Override
protected void onDraw(Canvas canvas) {
// draw a circle that is erasing bitmap
super.onDraw(canvas);
canvas.drawBitmap(bm2, 0, 0, null);
pcanvas.drawBitmap(bm1, 0, 0, null);
pcanvas.drawCircle(x, y, 40, mPaint);
canvas.drawBitmap(bmOverlay, 0, 0, null);
// erase the top bitmap:
Canvas bitmapCanvas = new Canvas(bm1);
bitmapCanvas.drawBitmap(bm2, 0, 0, null);
bitmapCanvas.drawBitmap(bmOverlay, 0, 0, null);
}
Also, to stop a circle being erased in the top left corner when you start the app, create a boolean with a default value of false and set it inside onTouchEvent when you have valid co-ordinates, and check it before calling drawCircle.

Android game: Moving bitmap leaves blurry trail at ends

I am trying to create a background scrolling for an Android game. Lets say it is a set of images moving at a speed.
To test out few basic elements, I have taken a small, rectangular image and moving it linearly from top to bottom. It moves but I see a small trail, like a rocket going in clouds(haha!). I tried various options in Paint() class to rectify this, but I couldn't.
I will first post a screen shot and then add relevant code.
So, here the vertical line is a single png image:
Now all I am doing is moving this bitmap from a certain (x,y) by increasing y by 5 at a time. It moves, but notice the ends of the image while moving. Sort of a trail, but not a permanent one. I have tried but unable to remove this effect. I tried on Samsung Galaxy S5. I didnot test on any other model.
The code:
The moving vertical image is a Sprite object:
package com.src.*.*;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Rect;
import android.util.Log;
public class Sprite {
private Rect sourceRect; // the rectangle to be drawn from the animation bitmap
private int frameNr; // number of frames in animation
private int currentFrame; // the current frame
private long frameTicker; // the time of the last frame update
private int framePeriod; // milliseconds between each frame (1000/fps)
private int spriteWidth; // the width of the sprite to calculate the cut out rectangle
private int spriteHeight; // the height of the sprite
private int x; // the X coordinate of the object (top left of the image)
private int y; // the Y coordinate of the object (top left of the image)
private Bitmap bitmap;
private float degrees;
private boolean rotate=false;
private Matrix matrix;
private Bitmap reversedBitmap;
private Paint paint;
public Sprite(Bitmap bitmap, int x, int y, int fps, int frameCount) {
this.bitmap = bitmap;
this.x = x;
this.y = y;
currentFrame = 0;
frameNr = frameCount;
spriteWidth = bitmap.getWidth() / frameCount;
spriteHeight = bitmap.getHeight();
sourceRect = new Rect(0, 0, spriteWidth, spriteHeight);
framePeriod = 1000 / fps;
frameTicker = 0l;
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG
| Paint.FILTER_BITMAP_FLAG);
paint.setDither(true);
}
public void animate(){
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public void setReverse(Bitmap reverse){
this.reversedBitmap = reverse;
}
public void rorateSprite(float degrees){
if(degrees == 0){
rotate = false;
}else{
rotate = true;
}
this.degrees = degrees;
}
public void draw(Canvas canvas) {
// where to draw the sprite
Rect destRect = new Rect(getX(), getY(), getX() + spriteWidth, getY() + spriteHeight);
if(rotate){
canvas.drawBitmap(reversedBitmap, sourceRect, destRect, paint);
}else{
canvas.drawBitmap(bitmap, sourceRect, destRect, paint);
}
}
public void update(long gameTime){
if (gameTime > frameTicker + framePeriod) {
frameTicker = gameTime;
//Log.i("INFO", "In if loop" + currentFrame + " framenr:" + frameNr);
// increment the frame
currentFrame++;
if (currentFrame >= frameNr) {
currentFrame = 0;
}
}else{
//Log.i("INFO", "in else" + currentFrame + "");
}
// define the rectangle to cut out sprite
//Log.i("INFO", "sprite width: " + spriteWidth);
this.sourceRect.left = currentFrame * spriteWidth;
this.sourceRect.right = this.sourceRect.left + spriteWidth;
}
}
The bitmap is setup as follows:
wallAnimation = new Sprite(resizedBitmapWall, 0, 0, 30, 1);
wallAnimation.setX(margin);
The onDraw and Update for the sprite is as follows. It works without any exception or error. The only issue in all of this is the image having the blurry/tail effect at the ends. I dont even know the right word for it.
Code for onDraw and Update:
#Override
protected void onDraw(Canvas canvas) {
// fills the canvas with black
canvas.drawColor(Color.WHITE);
wallAnimation.draw(canvas);
paint.setColor(Color.BLACK);
for (int i = 0; i < 6; i++) {
canvas.drawLine(margin+laneWidth*i, 0, margin+laneWidth*i, laneHeight, paint);
}
canvas.drawText("High Score: "+ highScore, 10, 10, paint);
}
public void Update(long gameTime) {
// TODO Auto-generated method stub
if(wallState < laneHeight+laneHeight/6){
wallAnimation.setY(wallState);
//wallState+=laneHeight/80;
wallState+=20;
}else{
wallState = 0;
}
}

How to extract the Bitmap out of the onDraw() method of a View?

How can I extract a Bitmap object out of my onDraw() routine in my CustomView?
Here is my code:
public class DrawView extends View {
private Paint paint = new Paint();
private Point point;
private LinkedList<Point> listaPontos;
private static Context context;
class Point {
public Point(float x, float y) {
this.x = x;
this.y = y;
}
float x = 0;
float y = 0;
}
public DrawView(Context context) {
super(context);
this.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.MATCH_PARENT));
this.context = context;
paint.setColor(Color.YELLOW);
this.listaPontos = new LinkedList<Point>();
}
#Override
public void onDraw(Canvas canvas) {
if(listaPontos.size() != 0){
for(Point point : listaPontos){
canvas.drawCircle(point.x, point.y, 25, paint);
}
}
calculateAmount(canvas);
}
private void calculateAmount(Canvas canvas) {
LinkedList<Integer> colors = new LinkedList<Integer>();
for(int i = 0 ; i != canvas.getWidth(); i++)
{
for(int j = 0; j != canvas.getHeight(); j++){
int color = BITMAP.getPixel(i,j); //How can I get the bitmap generated on onDraw ?
colors.add(color);
}
}
int yellow = 0;
int white = 0;
for(Integer cor : colors) {
if(cor == Color.WHITE) {
white++;
}
if(cor == Color.YELLOW) {
yellow++;
}
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
listaPontos.add(new Point(event.getX(), event.getY()));
break;
}
invalidate();
return true;
}
}
Thanks alot in advance ;)
EDIT: The bitmap thing is to calculate each pixel color, how can I add a background image to my DrawView ? I tested this.setBackgroundResource(R.drawable.a); at constructor but didn't work, thanks again ;)
There is no way to extract a Bitmap out of a Canvas. At least not directly.
However, it is possible to draw on a Bitmap with the Canvas and then use the Bitmap.
Bitmap mDrawBitmap;
Canvas mBitmapCanvas;
Paint drawPaint = new Paint();
#Override
public void onDraw(Canvas canvas) {
drawPaint.setColor(Color.RED);
if (mDrawBitmap == null) {
mDrawBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
mBitmapCanvas = new Canvas(mDrawBitmap);
}
// clear previously drawn stuff
mBitmapCanvas.drawColor(Color.WHITE);
// draw on the btimapCanvas
mBitmapCanvas.drawStuff(...);
//... and more
// after drawing with the bitmapcanvas,
//all drawn information is stored in the Bitmap
// draw everything to the screen
canvas.drawBitmap(mDrawBitmap, 0, 0, drawPaint);
}
After the onDraw() method has finished, all drawn information will be drawn on the screen (by calling canvas.drawBitmap(...), and also be stored in your Bitmap object (because all draw operations have been done on the Canvas that was created with the Bitmap).

Categories