Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android - Canvas onDraw with zoomed camara following character movements

Some Context:

I am creating an Android game which draws a maze onto a canvas against a background image, this uses a square block and therefore the maze is always automtically zoomed in to a 5 x 5 square, of a maze that may be 20 x 20. The maze is drawn by simply running through a set of for loops and then drawing lines in the relevent places. This is all working perfectly, however I am having an issue with getting my onDraw to work smoothly. This is occuring due to the fact that everytime I invalidate I have to re-run the for look and run various if statements to check positions (unfortunetly this process cannot be improved).

The Question:

I am looking to re-write the way my maze is drawn onto the canvas, below are the 3 main features I need to implement:

1 - Draw the whole maze onto the canvas (this is easy enough) 2 - Zoom in on the maze so only a 5 x 5 is shown 3 - Move the character (who is always centered on the screen) and draw the next seciton of the maze

Now as mentioned above drawing the whole maze is easy enough and will make the onDraw signifcatly quicker as their is no need to run the for loop on invaldate, it can be done once when the level is first loaded up.

In terms of point 2 & 3, the way I see this working is the charcacter to be drawn in the middle of the canvas then a 2d birdseye view camera to be attached / linked to the characters movement. This camera would also need to be zoomed in to an extent that it only displays a 5 x 5 of the overall maze grid. Then as the charcater moves the camera moves with the character and displays the next section of the maze which has already been drawn. I have tried a few things and done some reasearch however I have never worked with canvas before and no idea really where to start and if this is even possible.

So to sum up the main part of the question is whether their is a way to link a birdseye view camera to a character which is zoomed in and moves with the character image.

Below is a snippet as to how the maze is currently drawn, using 2 sets of for loops checking against 2 sets of boolean arrays[][], which simply store the vertical and horixaonl lines to be drawn.

@Override
protected void onDraw(Canvas canvas) 
{
    canvas.drawRect(0, 0, width, 100, background);
    RectBackground.set(0,0, FullScreenWidth, FullScreenWidth);
    canvas.drawBitmap(gameBackground, null, RectBackground, null);

    for(int i = 0; i < 5; i++) 
    {
        for(int j = 0; j < 5; j++)
        {
            float x = j * totalCellWidth;
            float y = i * totalCellHeight;

            indexY = i + currentY;
            indexX = j + currentX;

            // Draw Verticle line (y axis)
            if (indexY < vLength && indexX < vLines[indexY].length && vLines[indexY][indexX])
            {
                RectOuterBackground.set((int)x + (int)cellWidth, (int)y, (int)x + (int)cellWidth + 15,  (int)y + (int)cellHeight + 15);
                canvas.drawBitmap(walls, null, RectOuterBackground, null);
            }
            // Draws Horizontal lines (x axis)
            if (indexY < hLength && indexX < hLines[indexY].length && hLines[indexY][indexX])
            {
                RectOuterBackground.set((int)x, (int)y + (int)cellHeight,(int)x + (int)cellWidth + 15,(int)y + (int)cellHeight + 15);
                canvas.drawBitmap(walls, null, RectOuterBackground, null);
            }
        }
    }
}
like image 782
Raj Avatar asked Nov 25 '13 17:11

Raj


1 Answers

To make the drawing faster, you can double buffer the canvas by drawing directly into a bitmap and flashing the bitmap into the canvas like this. It's very fast.

private void init()
{
        //variables below are class-wide variables
        b = Bitmap.createBitmap(cwidth, cheight, Bitmap.Config.ARGB_8888);
        bitmapPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        bitmapPaint.setStyle(Paint.Style.STROKE);

        bitmapPaint.setStrokeWidth(3);
        myPaint.setColor(0xff000000);
        myCanvas = new Canvas(b);
}

protected void onDraw(Canvas c)
{
    super.onDraw(c);
    c.drawBitmap(b, 0, 0, myPaint);

    for(int i = 0; i < number lines; i++)
    {
        //draw here using myPath
    }

    if(b != null)
        c.drawBitmap(b, 0, 0, myPaint);

    myCanvas.drawPath(myPath, bitmapPaint);

}

Then, to "move around" I would suggest using a crop box. What this means is that a 1:1 scale, the image is larger than the viewport displayed on the screen. Really what's happening when someone "moves" is the bitmap is being moved beneath the crop box.

You could use BitmapRegionDecoder and display only the region the character is in (this might be slowish) or by using

public void drawBitmap (Bitmap bitmap, Rect src, RectF dst, Paint paint)

The src parameter here allows you to specify a small region of the bitmap to display. It is effectively a crop box.

like image 104
mttdbrd Avatar answered Oct 20 '22 18:10

mttdbrd