Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android - Drawing a maze to canvas with smooth character movement

I am currently creating a Tile based game which essentially draws a maze using 2 sets of booleans arrays to determine where each wall needs to be drawn.

I have this all working as it should, with only a 5 x 5 section of the maze being drawn (overall maze size is 30 x 30). However, the issue I am having is when I move the character, the whole screen jumps, this is due to the fact that the next section of the maze is being drawn, to maintain the 5 x 5 aspect ratio. I have tried various different things to try to get this run smoothly however simply cannot seem to be able to do this.

Can somebody advise or direct me to some links / examples so that I can get the maze and character movements all to happen smoothly. Below is some basic code as to the main for loop that currently draws the maze and the 2 boolean arrays that it references in order to draw the walls.

// THE CODE TO DRAW THE MAZE AND ITS WALLS
for(int i = 0; i < 5; i++) 
{
    for(int j = 0; j < 5; j++)
    {
        float x = j * totalCellWidth;
        float y = i * totalCellHeight;

        if(currentY != 0)
            indexY = i + currentY - 1;
        else
            indexY = i + currentY;

        if(currentX != 0)
            indexX = j + currentX - 1;
        else
            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);
        }
    }
}

// THE 2 BOOLEAN ARRAYS THE FORLOOP REFERENCES
boolean[][] vLines = new boolean[][]{
    {true ,true ,true ,true ,true ,true ,true ,true ,true ,true ,true },
    {true ,true ,true ,true ,true ,true ,true ,true ,true ,true ,true },
    {true ,true ,true ,false,false,false,true ,false,false,true ,true },
    {true ,true ,true ,false,false,true ,false,true ,true ,true ,true },
    {true ,true ,false,true ,false,false,true ,false,false,true ,true },
    {true ,true ,false,true ,true ,false,false,false,true ,true ,true },
    {true ,true ,true ,false,false,false,true ,true ,false,true ,true },
    {true ,true ,false,true ,false,false,true ,false,false,true ,true },
    {true ,true ,false,true ,true ,true ,true ,true ,false,true ,true },
    {true ,true ,false,false,false,true ,false,false,false,true ,true },
    {true ,true ,true ,true ,true ,true ,true ,true ,true ,true ,true },
    {true ,true ,true ,true ,true ,true ,true ,true ,true ,true ,true }
 };
boolean[][] hLines = new boolean[][]{
    {true ,true ,true ,true ,true ,true ,true ,true ,true ,true ,true ,true },
    {true ,true ,true ,true ,true ,true ,true ,true ,true ,true ,true ,true },
    {true ,true ,false,false,true ,true ,false,false,true ,false,true ,true },
    {true ,true ,false,false,true ,true ,false,true ,false,false,true ,true },
    {true ,true ,true ,true ,false,true ,true ,false,true ,true ,true ,true },
    {true ,true ,false,false,true ,false,true ,true ,false,false,true ,true },
    {true ,true ,false,true ,true ,true ,true ,false,true ,true ,true ,true },
    {true ,true ,true ,false,false,true ,false,false,true ,false,true ,true },
    {true ,true ,false,true ,false,false,false,true ,false,true ,true ,true },
    {true ,true ,true ,true ,true ,true ,true ,true ,true ,true ,true ,true },
    {true ,true ,true ,true ,true ,true ,true ,true ,true ,true ,true ,true }
};

I am willing to completly re-write that section of code if I can get it to draw smoothly, however having tried several different varations cannot get it smooth, I always have the jump.

I was trying to also get it to work with canvas translate, by drawing the whoel maze out, then scale it so that only 5 x 5 was displayed then simply moving the scaled section along using translate, whilst keeping the character in the center of the screen, there giving a smooth movement. However, I just could not get the translate to move along smoothly.

like image 742
Raj Avatar asked Feb 15 '23 07:02

Raj


2 Answers

Here is a full Maze class. It draws the view to coordinates viewX and viewY which can be moved either smoothly (as in Boudjnah's answer) or with multiplies of the cell dimensions.

import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.RectF;

public class Maze {
    private RectF drawRect = new RectF();

    private Bitmap[] bitmaps;
    private int[][] tileType;

    private float screenWidth, screenHeight;

    /**
     * Initialize a new maze.
     * @param wallBitmap The desired bitmaps for the floors and walls
     * @param isWall The wall data array. Each true value in the array represents a wall and each false represents a gap
     * @param xCellCountOnScreen How many cells are visible on the screen on the x axis
     * @param yCellCountOnScreen How many cells are visible on the screen on the y axis
     * @param screenWidth The screen width
     * @param screenHeight The screen height
     */
    public Maze(Bitmap[] bitmaps, int[][] tileType, float xCellCountOnScreen, float yCellCountOnScreen, float screenWidth, float screenHeight){
        this.bitmaps = bitmaps;
        this.tileType = tileType;

        this.screenWidth = screenWidth;
        this.screenHeight = screenHeight;

        drawRect.set(0, 0, screenWidth / xCellCountOnScreen, screenHeight / yCellCountOnScreen);
    }

    /**
     * Get the type of the cell. x and y values are not coordinates!
     * @param x The x index of the cell
     * @param y The y index of the cell
     * @return The cell type
     */
    public int getType(int x, int y){
        if(y < tileType.length && x < tileType[y].length) return tileType[y][x];
        return 0;
    }

    public float getCellWidth(){ return drawRect.width(); }
    public float getCellHeight(){ return drawRect.height(); }

    /**
     * Draws the maze. View coordinates should have positive values.
     * @param canvas Canvas for the drawing
     * @param viewX The x coordinate of the view
     * @param viewY The y coordinate of the view
     */
    public void drawMaze(Canvas canvas, float viewX, float viewY){
        int tileX = 0;
        int tileY = 0;
        float xCoord = -viewX;
        float yCoord = -viewY;

        while(tileY < tileType.length && yCoord <= screenHeight){
            // Begin drawing a new column
            tileX = 0;
            xCoord = -viewX;

            while(tileX < tileType[tileY].length && xCoord <= screenWidth){
                // Check if the tile is not null
                if(bitmaps[tileType[tileY][tileX]] != null){

                    // This tile is not null, so check if it has to be drawn
                    if(xCoord + drawRect.width() >= 0 && yCoord + drawRect.height() >= 0){

                        // The tile actually visible to the user, so draw it
                        drawRect.offsetTo(xCoord, yCoord); // Move the rectangle to the coordinates
                        canvas.drawBitmap(bitmaps[tileType[tileY][tileX]], null, drawRect, null);
                    }
                }

                // Move to the next tile on the X axis
                tileX++;
                xCoord += drawRect.width();
            }

            // Move to the next tile on the Y axis
            tileY++;
            yCoord += drawRect.height();
        }
    }
}

To use this class, first initialize it in your onCreate function like this

// 0 == floor, 1 == wall, 2 == different looking wall
int[][] maze = {
        {0, 0, 0, 0, 0},
        {0, 1, 2, 1, 0},
        {0, 0, 0, 1, 0},
        {1, 1, 2, 1, 0},
        {0, 0, 0, 0, 0}
};

Bitmap[] bitmaps = {
        BitmapFactory.decodeResource(getResources(), R.drawable.floor),
        BitmapFactory.decodeResource(getResources(), R.drawable.firstwall)
        BitmapFactory.decodeResource(getResources(), R.drawable.secondwall)
};

// Chance the 480 and 320 to match the screen size of your device
maze = new Maze(bitmaps, maze, 5, 5, 480, 320);

And then draw it in your onDraw or similar function like this

maze.draw(canvas, viewX, viewY);

The getType(int x, int y), getCellWidth() and getCellHeight() functions should help you to implement any interactions with the maze. You can also add your own functions to the class. You can also modify this class to note any starting and ending tiles. I won't make your whole game for you :)

If you set your character to coordinates (x, y) and draw it to coordinates (x - viewX, y - viewY) you can have a fixed position for it relative to the maze wherever the view is.

I hope this helps!

like image 70
Finnboy11 Avatar answered Feb 17 '23 01:02

Finnboy11


Use LibGDX or another Android game engine like AndEngine (I haven't used this one). Developing a game using only Android library is really hard and error-prone (you have to write a lot of boilerplate code which is already done for you in the game engines). LibGDX can simplify your task in many ways:

  • It's graphics API is implemented in OenGL (you wan't have problems with performance in a simple 2D game like yours)
  • It has a nice support for 2D tile based games ( https://code.google.com/p/libgdx-users/wiki/Tiles)
  • It is a cross-platform engine. The supported platforms are iOS, BlackBerry, Desktop(Windows, Linux and Mac) and HTML 5.
like image 22
GareginSargsyan Avatar answered Feb 17 '23 03:02

GareginSargsyan