Android - 使用流畅的角色动画将迷宫绘制到画布上

时间:2013-12-23 16:12:15

标签: java android android-canvas ondraw

我目前正在创建一个基于平铺的游戏,它基本上使用2组布尔数组来绘制迷宫,以确定每个墙需要绘制的位置。

我将这一切都按照应有的方式工作,只绘制了5 x 5的迷宫部分(整体迷宫大小为30 x 30)。然而,我遇到的问题是当我移动角色时,整个屏幕跳跃,这是因为迷宫的下一部分被绘制,以保持5 x 5的宽高比。我尝试了各种不同的东西,试图让它顺利运行,但似乎无法做到这一点。

有人可以建议或指导我一些链接/示例,以便我可以让迷宫和角色动作顺利进行。下面是一些基本代码,关于当前绘制迷宫的主要for循环以及它为了绘制墙而引用的2个布尔数组。

// 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 }
};

如果我可以顺利地绘制代码,我愿意完全重写那段代码,但是尝试了几个不同的版本无法顺利完成,我总是有跳跃。

我试图通过画布翻译来实现它,通过画出整个迷宫,然后缩放它以便只显示5 x 5然后只需使用翻译移动缩放部分,同时保持角色在屏幕中央,有一个平稳的运动。但是,我无法让翻译顺利进行。

4 个答案:

答案 0 :(得分:4)

这是一个完整的迷宫课程。它绘制视图以协调viewX和viewY,它们可以平滑移动(如Boudjnah的答案)或单元格尺寸的乘法。

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();
        }
    }
}

要使用此类,首先在onCreate函数中初始化它,如下所示

// 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);

然后在你的onDraw或类似的函数中绘制它

maze.draw(canvas, viewX, viewY);

getType(int x,int y),getCellWidth()和getCellHeight()函数应该可以帮助您实现与迷宫的任何交互。您还可以将自己的功能添加到课程中。您还可以修改此类以记录任何起始和结束切片。我不会为你制作整场比赛:))

如果将角色设置为坐标(x,y)并将其绘制到坐标(x - viewX,y - viewY),则无论视图位于何处,都可以相对于迷宫具有固定位置。

我希望这有帮助!

答案 1 :(得分:3)

使用LibGDX或其他Android游戏引擎,例如AndEngine(我没有使用过这个)。仅使用Android库开发游戏非常困难并且容易出错(您必须编写很多样板代码,这些代码已经在游戏引擎中为您完成)。 LibGDX可以通过多种方式简化您的任务:

  • 它的图形API是在OenGL中实现的(你在像你这样的简单2D游戏中没有性能问题)。
  • 它非常支持基于2D平铺的游戏(https://code.google.com/p/libgdx-users/wiki/Tiles
  • 这是一个跨平台的引擎。支持的平台包括iOS,BlackBerry,桌面(Windows,Linux和Mac)和HTML 5。

答案 2 :(得分:1)

您可能考虑的一种方法是始终将角色保持在屏幕的中心。而不是移动你的角色,只移动迷宫上的偏移量。这种方法在许多旧的(可能是新的)角色扮演游戏中很常见。

答案 3 :(得分:0)

如何在OpenGL ES中绘制整个迷宫位图 - 查看和调整视口/摄像机位置?这会让你有机会在穿过迷宫时获得很好的效果并且绝对光滑。