成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Android原生控件大顯身手:打造方塊消除小游戲

開發 前端
當玩家點擊一個方塊時,觸發onBlockClicked方法。調用findConnectedBlocks方法使用深度優先搜索(DFS)來查找連接的相同顏色方塊,當連接的相同顏色方塊數量大于等于2時調用removeBlocks方法進行消除。

方塊消除游戲是一種簡單有趣、老少皆宜的休閑益智類游戲。玩家通過將相同顏色的方塊進行消除,從而獲得分數。

????下面我們使用Android原生控件來實現這個小游戲(PS:不包含自定義View的方式)。

實現思路

游戲場景

使用不同顏色的方塊繪制一個8x8的游戲板,可以用GridLayout來進行繪制,同時包含游戲分數和重新開始按鈕。

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="16dp">

    <TextView
        android:id="@+id/scoreTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="16dp"
        android:text="分數: 0"
        android:textSize="18sp" />

    <GridLayout
        android:id="@+id/gameBoard"
        android:layout_width="match_parent"
        android:layout_height="400dp"
        android:columnCount="8"
        android:padding="1dp"
        android:rowCount="8" />

    <Button
        android:id="@+id/restartButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:layout_marginTop="16dp"
        android:text="重新開始" />

</LinearLayout>

定義5種不同的顏色,然后隨機生成不同顏色的方塊,最后添加到GridLayout中。

private val blocks = Array(8) { IntArray(8) }
private val blockButtons = Array(8) { arrayOfNulls<Button>(8) }

private val colors = arrayOf(
    R.color.empty,
    R.color.red,
    R.color.blue,
    R.color.green,
    R.color.yellow,
    R.color.cyan
)

private fun initializeGameBoard() {
    for (i in 0 until 8) {
        for (j in 0 until 8) {
            val button = Button(this).apply {
                layoutParams = GridLayout.LayoutParams().apply {
                    width = 0
                    height = 0
                    columnSpec = GridLayout.spec(j, 1f)
                    rowSpec = GridLayout.spec(i, 1f)
                }
                setOnClickListener {
                    onBlockClicked(i, j)
                }
                background = null
                isAllCaps = false
            }
            blockButtons[i][j] = button
            gameBoard.addView(button)
        }
    }
    for (i in 0 until 8) {
        for (j in 0 until 8) {
            blocks[i][j] = Random.nextInt(1, colors.size)
            updateBlockColor(i, j)
        }
    }
}

private fun updateBlockColor(row: Int, col: Int) {
    blockButtons[row][col]?.setBackgroundColor(
        ContextCompat.getColor(this, colors[blocks[row][col]])
    )
}

效果效果

此時的方塊看起來是連接在一起的,我們可以添加個背景樣式,然后給每個方塊添加間距實現一個網格效果。

<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <solid android:color="#CCCCCC" />
    <stroke
        android:width="1dp"
        android:color="#888888" />
</shape>

給GridLayout設置背景樣式:

<GridLayout
    android:id="@+id/gameBoard"
    android:layout_width="match_parent"
    android:layout_height="400dp"
    android:background="@drawable/grid_background"
    android:columnCount="8"
    android:padding="1dp"
    android:rowCount="8" />

給每個方塊添加間距setMargins(1, 1, 1, 1)。

private fun initializeGameBoard() {
    for (i in 0 until 8) {
        for (j in 0 until 8) {
            val button = Button(this).apply {
                layoutParams = GridLayout.LayoutParams().apply {
                    width = 0
                    height = 0
                    columnSpec = GridLayout.spec(j, 1f)
                    rowSpec = GridLayout.spec(i, 1f)
                    setMargins(1, 1, 1, 1)
                }
                setOnClickListener {
                    onBlockClicked(i, j)
                }
                background = null
                isAllCaps = false
            }
            blockButtons[i][j] = button
            gameBoard.addView(button)
        }
    }
    for (i in 0 until 8) {
        for (j in 0 until 8) {
            blocks[i][j] = Random.nextInt(1, colors.size)
            updateBlockColor(i, j)
        }
    }
}

此時我們的游戲場景已經完成。

消除規則

點擊相鄰方塊顏色相同的塊進行消除,再方塊點擊時找出相鄰的方塊,如果相鄰方塊顏色相同并且數量大于2消除方塊:

private fun onBlockClicked(row: Int, col: Int) {
    if (isGameOver) return
    val color = blocks[row][col]
    if (color != 0) {
        val connectedBlocks = findConnectedBlocks(row, col, color)
        if (connectedBlocks.size >= 2) {
            removeBlocks(connectedBlocks)
        }
    }
}

private fun findConnectedBlocks(row: Int, col: Int, color: Int): List<Pair<Int, Int>> {
    val visited = Array(8) { BooleanArray(8) }
    val connectedBlocks = mutableListOf<Pair<Int, Int>>()
    
    fun dfs(r: Int, c: Int) {
        if (r < 0 || r >= 8 || c < 0 || c >= 8 || visited[r][c] || blocks[r][c] != color) return
        visited[r][c] = true
        connectedBlocks.add(Pair(r, c))
        dfs(r + 1, c)
        dfs(r - 1, c)
        dfs(r, c + 1)
        dfs(r, c - 1)
    }
    
    dfs(row, col)
    return connectedBlocks
}

private fun removeBlocks(connectedBlocks: List<Pair<Int, Int>>) {
    for ((row, col) in connectedBlocks) {
        blocks[row][col] = 0
        updateBlockColor(row, col)
    }
}

當玩家點擊一個方塊時,觸發onBlockClicked方法。調用findConnectedBlocks方法使用深度優先搜索(DFS)來查找連接的相同顏色方塊,當連接的相同顏色方塊數量大于等于2時調用removeBlocks方法進行消除。

查找相鄰方塊實現原理:

  1. 初始化:

創建一個 8x8 的布爾數組 visited,用于標記已訪問的方塊。

創建一個可變列表 connectedBlocks,用于存儲找到的相連方塊。

  1. 深度優先搜索(DFS):

定義一個內部函數 dfs,使用當前方塊的行和列作為參數。

DFS 從給定的起始方塊開始,然后遞歸地探索相鄰的方塊。

  1. 邊界和有效性檢查:

檢查當前位置是否在游戲范圍內(r < 0 || r >= 8 || c < 0 || c >= 8)。

檢查當前方塊是否已被訪問(visited[r][c])。

檢查當前方塊的顏色是否與目標顏色相同(blocks[r][c] != color)。

如果以上任一條件不滿足,則返回,不繼續探索。

  1. 標記和記錄:

通過了所有檢查,將當前方塊標記為已訪問(visited[r][c] = true)。

將當前方塊添加到相連方塊列表中(connectedBlocks.add(Pair(r, c)))。

  1. 遞歸探索:

對當前方塊的上、下、左、右四個相鄰方塊遞歸調用 DFS。

保證所有相連的同色方塊都會被探索到。

  1. 返回結果:

搜索完成后,返回找到的所有相連方塊的列表。

填補空缺

消除方塊后,上方的方塊會下落填補空缺

private fun dropBlocks() {
    for (col in 0 until 8) {
        var emptyRow = 7
        for (row in 7 downTo 0) {
            if (blocks[row][col] != 0) {
                blocks[emptyRow][col] = blocks[row][col]
                updateBlockColor(emptyRow, col)
                if (emptyRow != row) {
                    blocks[row][col] = 0
                    updateBlockColor(row, col)
                }
                emptyRow--
            }
        }
    }
}

生成新方塊

方塊下落后,生成新的隨機顏色方塊填補空缺

private fun fillBlocks() {
    for (col in 0 until 8) {
        for (row in 0 until 8) {
            if (blocks[row][col] == 0) {
                blocks[row][col] = Random.nextInt(1, colors.size)
                updateBlockColor(row, col)
            }
        }
    }
}

分數計算

定義分數score,每消除一個方塊得一分;

private var score = 0

private fun removeBlocks(connectedBlocks: List<Pair<Int, Int>>) {
    for ((row, col) in connectedBlocks) {
        blocks[row][col] = 0
        updateBlockColor(row, col)
        score++
    }
} 

private fun updateScore() {
    scoreTextView.text = "分數: $score"
}

在方塊消除時,分數進行計算,每消除一個方塊加一分;

游戲結束

private var isGameOver = false

private fun onBlockClicked(row: Int, col: Int) {
    if (isGameOver) return
    val color = blocks[row][col]
    if (color != 0) {
        val connectedBlocks = findConnectedBlocks(row, col, color)
        if (connectedBlocks.size >= 2) {
            removeBlocks(connectedBlocks)
            dropBlocks()
            fillBlocks()
            updateScore()
            if (!hasValidMoves()) {
                gameOver()
            }
        }
    }
}

private fun hasValidMoves(): Boolean {
    for (row in 0 until 8) {
        for (col in 0 until 8) {
            val color = blocks[row][col]
            if (color != 0) {
                if (findConnectedBlocks(row, col, color).size >= 2) {
                    return true
                }
            }
        }
    }
    return false
}

private fun gameOver() {
    isGameOver = true
    scoreTextView.text = "Game Over! 最終得分: $score"
}

在每次移動后檢查有沒有相鄰的同顏色方塊,如果沒有有效的移動,游戲結束。

拓展游戲

固定的顏色數量和生成規則致使游戲結束很難觸發,為了增加游戲可玩性和難度,我們可以增加更多的顏色,在方塊消除分數到達一定的數值后增加隨機出來的顏色數量

<resources>
    <color name="white">#FFFFFF</color>
    <color name="red">#FF0000</color>
    <color name="blue">#0000FF</color>
    <color name="green">#00FF00</color>
    <color name="yellow">#FFFF00</color>
    <color name="cyan">#00FFFF</color>
    <color name="empty">#CCCCCC</color>
    <color name="magenta">#FF00FF</color>
    <color name="orange">#FFA500</color>
    <color name="purple">#800080</color>
    <color name="pink">#FFC0CB</color>
    <color name="lime">#00FF00</color>
    <color name="teal">#008080</color>
    <color name="brown">#A52A2A</color>
    <color name="navy">#000080</color>
</resources>
private val colors = arrayOf(
    R.color.empty,
    R.color.red,
    R.color.blue,
    R.color.green,
    R.color.yellow,
    R.color.cyan,
    R.color.magenta,
    R.color.orange,
    R.color.purple,
    R.color.pink,
    R.color.lime,
    R.color.teal,
    R.color.brown,
    R.color.navy
)

//初始時顏色個數為5個
private var currentMaxColor = 5

private fun restartGame() {
    score = 0
    isGameOver = false
    currentMaxColor = 5
    updateScore()
    for (i in 0 until 8) {
        for (j in 0 until 8) {
            blocks[i][j] = Random.nextInt(1, currentMaxColor)
            updateBlockColor(i, j)
        }
    }
    if (!hasValidMoves()) {
        restartGame()
    }
}

private fun fillBlocks() {
    for (col in 0 until 8) {
        for (row in 0 until 8) {
            if (blocks[row][col] == 0) {
                blocks[row][col] = Random.nextInt(1, currentMaxColor)
                updateBlockColor(row, col)
            }
        }
    }
}

private fun removeBlocks(connectedBlocks: List<Pair<Int, Int>>) {
    for ((row, col) in connectedBlocks) {
        blocks[row][col] = 0
        updateBlockColor(row, col)
        score++
    }
    if (score > 50 && currentMaxColor < 5) currentMaxColor = 5
    if (score > 100 && currentMaxColor < 6) currentMaxColor = 6
    if (score > 200 && currentMaxColor < 7) currentMaxColor = 7
    if (score > 300 && currentMaxColor < 8) currentMaxColor = 8
    if (score > 400 && currentMaxColor < 9) currentMaxColor = 9
    if (score > 500 && currentMaxColor < 10) currentMaxColor = 10
    if (score > 600 && currentMaxColor < 11) currentMaxColor = 11
    if (score > 700 && currentMaxColor < 12) currentMaxColor = 12
    if (score > 800 && currentMaxColor < 13) currentMaxColor = 13
}

經過修改后在游戲開始時只使用較少的顏色,隨著分數的增加引入更多隨機顏色,從而提升游戲的可玩性和難度。

完整代碼

圖片圖片

游戲效果

Github源碼https://github.com/Reathin/Sample-Android/tree/master/module_block

責任編輯:武曉燕 來源: 沐雨花飛蝶
相關推薦

2012-07-06 09:00:56

微軟CRM

2015-10-22 11:36:44

教育云

2013-10-11 09:31:39

開源數據處理云計算

2022-07-28 15:06:17

人工智能AI

2010-03-25 15:16:30

艾默生

2018-04-24 14:43:01

微軟工業博覽會

2022-01-24 19:45:35

智能機器人新冠疫情

2021-01-21 14:03:18

人工智能醫療健康深度學習

2020-11-19 15:18:40

Nutanix

2017-08-03 11:26:56

筆記本商用筆記本

2016-03-28 09:08:09

OpenDayligh

2023-02-24 15:30:04

ChatGPT代碼

2021-12-09 14:00:59

機器人人工智能AI

2024-04-25 12:31:09

微服務API

2021-04-25 11:25:07

開源 數字化轉型商業市場

2015-09-10 14:33:52

敏捷網絡寧波華為

2012-09-03 10:05:32

好奇號美國宇航局

2021-04-09 15:45:08

神經網絡數據圖形

2009-08-04 09:51:24

至強5500高性能計算

2020-06-27 09:12:49

AI醫療人工智能
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 欧美一区二区二区 | 日日夜夜天天 | av一区二区三区在线观看 | 尤物在线视频 | 日韩欧美国产精品综合嫩v 一区中文字幕 | 国产一区二区三区四区五区加勒比 | 久久久性色精品国产免费观看 | 中文字幕亚洲专区 | 久久国产综合 | 狠狠入ady亚洲精品经典电影 | 一级片在线播放 | 国产精品视频区 | 精品久久国产老人久久综合 | 99精彩视频 | 国产精品精品视频一区二区三区 | 精品少妇一区二区三区日产乱码 | 日一区二区| 精品久久国产 | 亚洲天堂久久新 | 夜夜草导航 | 亚洲成人免费视频在线观看 | 天天躁人人躁人人躁狂躁 | 卡通动漫第一页 | 亚洲欧美一区二区三区国产精品 | 久久99精品国产 | 成人免费一区二区 | 中国一级大黄大片 | 日韩一级精品视频在线观看 | 91久久国产综合久久 | 国产精品永久免费 | 青草福利 | 欧美一级黑人aaaaaaa做受 | 日韩精品一区二区三区在线观看 | 亚洲一区二区三区在线 | 成人在线观看网站 | 美日韩免费视频 | av色噜噜 | 国产午夜精品视频 | 99日韩| 日本精品免费 | 亚洲在线电影 |