Tyoh
Tyoh

Reputation: 1

How do I animate a draw call in android studio from the presenter?

Issue

I have a project that I am writing where I have a maze that is randomly created with one button and and I can solve the maze with another button. The issue I am having is that I currently have the solution path drawn all at once in the presenter and then the solve method in the presenter is called in the DrawingView and is activated through a button on the MainActivity. I want each rect that I am drawing in the presenter (render) method to draw with timed pauses in between them. This is my first time using the MVP design and I have done a bunch of research on this and I am just struggling a lot to run methods that don't have the canvas passed to them.

As a warning I did get rid of the imports of the classes to try to cut down a bit.

Drawing View

class DrawingView extends View implements DrawingContract.DrawingCanvas {

    private final DrawingContract.DrawingPresenter drawingPresenter;

    public DrawingView(Context context, AttributeSet attrs) {
        super(context, attrs);

        drawingPresenter = new Presenter(this);
    }


    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        drawingPresenter.render(canvas);
    }

    public void generateNewMaze() {
        drawingPresenter.createMaze();
        postInvalidate();
    }

    public void solveAndPrintMazePath() {
        drawingPresenter.solveMaze();
        postInvalidate();
    }

}

Presenter

public class Presenter implements DrawingContract.DrawingPresenter{
    DrawingContract.DrawingCanvas view;

    //boolean for the maze path to be drawn
    private boolean mazeIsSolved;

    //2d array for maze and start/exit cells
    private Cell[][] cells;
    private Cell start, exit;

    //Static variables for columns, rows and thickness of cell walls
    private static final int COLS = 10, ROWS = 10;
    private static final float WALL_THICKNESS = 4;

    //Cell sizes and screen margins
    private float cellSize, hMargin, vMargin;

    //Paints
    private Paint wallPaint, startPaint, exitPaint, cellPaint;

    //Random for the maze generation
    private Random random;

    //Graph
    private Graph mazeGraph;

    //Depth first object to solve the maze
    private DepthFirst myDFS;

    public Presenter(DrawingContract.DrawingCanvas v) {
        //Set the view
        view = v;

        //Set boolean to false so we don't draw solve path
        mazeIsSolved = false;

        //Create a new graph
        mazeGraph = new Graph();

        //Creating a paint for the walls
        wallPaint = new Paint();
        wallPaint.setColor(Color.WHITE);
        wallPaint.setStrokeWidth(WALL_THICKNESS);

        //Creating the paint for the start of the maze
        startPaint = new Paint();
        startPaint.setColor(Color.GREEN);

        //Creating the paint for the exit of the maze
        exitPaint = new Paint();
        exitPaint.setColor(Color.BLUE);

        //Creating the cell paint
        cellPaint = new Paint();
        cellPaint.setColor(Color.BLACK);

        //Random for maze generation
        random = new Random();

        //Creating the DFS
        myDFS = new DepthFirst();

        //Creating an initial maze
        createMaze();
    }

    @Override
    public void render(Canvas canvas) {
        canvas.drawColor(Color.BLACK);

        int width = canvas.getWidth();
        int height = canvas.getHeight();

        if(width/height < COLS/ROWS)
            cellSize = width/(COLS + 1);
        else
            cellSize = height/(ROWS + 1);

        hMargin = (width - COLS * cellSize)/2;
        vMargin = (height - ROWS * cellSize)/2;

        canvas.translate(hMargin, vMargin - 300);

        for(int x = 0; x < COLS; x++) {
            for(int y = 0; y < ROWS; y++) {
                if(cells[x][y].getTopWall()) {
                    canvas.drawLine(
                            x * cellSize,
                            y * cellSize,
                            (x + 1) * cellSize,
                            y * cellSize,
                            wallPaint);
                }

                if(cells[x][y].getRightWall()) {
                    canvas.drawLine(
                            (x + 1) * cellSize,
                            y * cellSize,
                            (x + 1) * cellSize,
                            (y + 1) * cellSize,
                            wallPaint);
                }

                if(cells[x][y].getBottomWall()) {
                    canvas.drawLine(
                            x * cellSize,
                            (y + 1) * cellSize,
                            (x + 1) * cellSize,
                            (y + 1) * cellSize,
                            wallPaint);
                }

                if(cells[x][y].getLeftWall()) {
                    canvas.drawLine(
                            x * cellSize,
                            y * cellSize,
                            x * cellSize,
                            (y + 1) * cellSize,
                            wallPaint);
                }
            }
        }

        canvas.drawRect(
          start.col*cellSize,
          start.row*cellSize,
                (start.col + 1)*cellSize,
                (start.row + 1)*cellSize,
                startPaint);

        canvas.drawRect(
                exit.col*cellSize,
                exit.row*cellSize,
                (exit.col + 1)*cellSize,
                (exit.row + 1)*cellSize,
                exitPaint);

        if(mazeIsSolved) {
            cellPaint.setColor(Color.WHITE);
            ArrayList<Cell> myList = solveMaze();
            for (int i = 1; i < myList.size(); i++) {
                canvas.drawRect(myList.get(i).col * cellSize + 20,
                        myList.get(i).row * cellSize + 20,
                        (myList.get(i).col + 1) * cellSize - 20,
                        (myList.get(i).row + 1) * cellSize - 20,
                        cellPaint);
            }
        }
        else {
            cellPaint.setColor(Color.BLACK);
            for(int x = 0; x < COLS; x++) {
                for(int y = 0; y < ROWS; y++) {
                    canvas.drawRect(cells[x][y].col * cellSize + 20,
                            cells[x][y].row * cellSize + 20,
                            (cells[x][y].col + 1) * cellSize - 20,
                            (cells[x][y].row + 1) * cellSize - 20,
                            cellPaint);
                    if(x == 0 && y == 0) {
                        canvas.drawRect(
                                start.col*cellSize,
                                start.row*cellSize,
                                (start.col + 1)*cellSize,
                                (start.row + 1)*cellSize,
                                startPaint);
                    }
                    if(x == (COLS - 1) && y == (ROWS - 1)) {
                        canvas.drawRect(
                                exit.col*cellSize,
                                exit.row*cellSize,
                                (exit.col + 1)*cellSize,
                                (exit.row + 1)*cellSize,
                                exitPaint);
                    }
                }
            }
        }

    }

    public void createMaze() {
        Stack<Cell> stack = new Stack<>();
        mazeGraph = new Graph();
        mazeIsSolved = false;

        Cell current, next;
        cells = new Cell[COLS][ROWS];

        for (int x = 0; x < COLS; x++) {
            for (int y = 0; y < ROWS; y++) {
                cells[x][y] = new Cell(x, y);
            }
        }

        start = cells[0][0];
        exit = cells[COLS - 1][ROWS - 1];
        exit.setExitStatus(true);

        current = cells[0][0];
        current.setVisited(true);
        do {
            next = getNeighbour(current);
            if (next != null) {
                removeWall(current, next);
                stack.push(current);
                mazeGraph.addEdge(current, next);
                current = next;
                current.setVisited(true);
            } else
                current = stack.pop();
        }while(!stack.empty());
    }

    public Cell getNeighbour(Cell cell) {
        ArrayList<Cell> neighbours = new ArrayList<>();

        //left neighbour
        if(cell.col > 0) {
            if (!cells[cell.col - 1][cell.row].getVisited()) {
                neighbours.add(cells[cell.col - 1][cell.row]);
            }
        }

        //right neighbour
        if(cell.col < COLS - 1) {
            if (!cells[cell.col + 1][cell.row].getVisited()) {
                neighbours.add(cells[cell.col + 1][cell.row]);
            }
        }

        //top neighbour
        if(cell.row > 0) {
            if (!cells[cell.col][cell.row - 1].getVisited()) {
                neighbours.add(cells[cell.col][cell.row - 1]);
            }
        }

        //bottom neighbour
        if(cell.row < ROWS - 1) {
            if (!cells[cell.col][cell.row + 1].getVisited()) {
                neighbours.add(cells[cell.col][cell.row + 1]);
            }
        }

        if(neighbours.size() > 0) {
            int index = random.nextInt(neighbours.size());
            return neighbours.get(index);
        }
        return null;
    }

    public void removeWall(Cell current, Cell next) {
        if(current.col == next.col && current.row == next.row + 1) {
            current.setTopWall(false);
            next.setBottomWall(false);
        }

        if(current.col == next.col && current.row == next.row - 1) {
            current.setBottomWall(false);
            next.setTopWall(false);
        }

        if(current.col == next.col + 1 && current.row == next.row) {
            current.setLeftWall(false);
            next.setRightWall(false);
        }

        if(current.col == next.col - 1 && current.row == next.row) {
            current.setRightWall(false);
            next.setLeftWall(false);
        }
    }

    public ArrayList<Cell> solveMaze() {
        mazeIsSolved = true;
        myDFS = new DepthFirst();
        return myDFS.TraverseGraph(mazeGraph, start);
    }
}

Drawing Contract

public interface DrawingContract {
    interface DrawingCanvas {

    }

    interface DrawingPresenter {
        void render(Canvas canvas);
        void createMaze();
        Cell getNeighbour(Cell cell);
        void removeWall(Cell current, Cell next);
        ArrayList<Cell> solveMaze();
    }
}

Main Activity

public class MainActivity extends AppCompatActivity {

    private DrawingView drawView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        drawView = (DrawingView) findViewById(R.id.drawView);

        Button newMaze = (Button) findViewById(R.id.newMazeButton);
        Button solveMaze = (Button) findViewById(R.id.solveMazeButton);

        newMaze.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                drawView.generateNewMaze();
            }
        });

        solveMaze.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {drawView.solveAndPrintMazePath();}
        });
    }
}

My Attempts/More Explanation

I have tried to add thread pauses, timers, and some other things but I don't understand how to implement it with the DrawingView being decouples from the presenter and the model. This whole MVP design is a bit confusing to me and I'm trying my best to understand it and use the correct design structure but I think I am doing some things wrong. I also know that this code isn't very optimal with me drawing colored squares to artificially clear the maze or that I have a boolean in the render for the solving of the maze but I don't know what else to do as of now.

Thank you so much for taking a look and leaving any comments below it means a lot to me. I will continue to do research and try new things as this question is active and if I make any progress I will leave updates.

Upvotes: 0

Views: 61

Answers (0)

Related Questions