天天看點

【Kotlin】坦克大戰7:敵方坦克建立

文章目錄

  • ​​敵方坦克繪制​​
  • ​​讓敵方坦克動起來​​

敵方坦克繪制

建立Enemy,我們之前建立了很多特性,我們可以仿照Tank檔案來寫,實作Moveable,關于繪制可以直接把Tank的繪制方法拿過來,換張圖檔即可

/**
 * 敵方坦克
 */
class Enemy(override val x: Int, override val y: Int) :Moveable {
    override val currentDirection: Direction = Direction.down
    override val speed: Int = 8

    override val width: Int = Config.block
    override val height: Int = Config.block

    override fun draw() {
        //根據坦克類型進行繪制
        val imagePath: String = when (currentDirection) {
            Direction.up -> "img/enemy_1_u.gif"
            Direction.down -> "img/tank_1_d.gif"
            Direction.left -> "img/tank_1_l.gif"
            Direction.right -> "img/tank_1_r.gif"
        }
        Painter.drawImage(imagePath, x, y)
    }

    override fun willCollision(block: Blockable): Direction? {
        return null
    }

    override fun notifyCollision(direction: Direction?, block: Blockable?) {
    }
}      

之前我們的地圖1.map中有“敵”,隻要像牆一樣畫出來即可,是以修改GameWindow總的onCreate方法,增加一條敵方坦克的畫法

'敵' -> views.add(Enemy(columnNum * Config.block, lineNum * Config.block))      

運作,敵方坦克就畫好了

【Kotlin】坦克大戰7:敵方坦克建立

讓敵方坦克動起來

敵方坦克是可以自動移動的,我們正好有個AutoMoveable,實作這個接口,重寫autoMove()方法。和Tank的move方法類似,直接copy

class Enemy(override var x: Int, override var y: Int) :Moveable, AutoMoveable {
    ......
    override fun autoMove() {
        //坦克的坐标移動
        //根據方向改變坐标
        when (currentDirection) {
            Direction.up -> y -= speed
            Direction.down -> y += speed
            Direction.left -> x -= speed
            Direction.right -> x += speed
        }

        //越界判斷
        if (x < 0) x = 0
        if (x > Config.gameWidth - width) {
            x = Config.gameWidth - width
        }
        if (y < 0) y = 0
        if (y > Config.gameHeight - height) {
            y = Config.gameHeight - height
        }
    }
}      

但是現在運作起來,敵方坦克很傻,隻會直直的走,現在讓它隻能一點,能檢測碰撞。Tank中有willCollision方法,我們把它拿到Moveable中去實作,這樣敵方坦克也能使用這個方法

/**
 * 移動的能力
 */
interface Moveable: View {
    ......
    /**
     * 判斷移動的物體是否和阻塞物體發生碰撞
     * @return 要碰撞的方向 如果為Null,說明沒有發生碰撞
     */
    fun willCollision(block:Blockable):Direction?{
        //将要碰撞時,用未來的坐标
        var x = this.x
        var y = this.y
        when (currentDirection) {
            Direction.up -> y -= speed
            Direction.down -> y += speed
            Direction.left -> x -= speed
            Direction.right -> x += speed
        }
        //檢測下一步是否碰撞碰撞
        var collision = checkCollision(x, y, width, height, block.x, block.y, block.width, block.height)
        return if (collision) currentDirection else null
    }
    ......
}      

這樣我方坦克Tank,敵方坦克Enemy都可以不寫willCollision方法了,再定義一個badDirection,碰撞時通知,然後再給坦克一個随機方向讓它随便走

class Enemy(override var x: Int, override var y: Int) :Moveable, AutoMoveable {
    ......

    //坦克不可以走的方向
    private var badDirection: Direction? = null

    ......
    override fun notifyCollision(direction: Direction?, block: Blockable?) {
        badDirection = direction
    }

    override fun autoMove() {
        if(currentDirection == badDirection){
            //要往錯誤方向走,不允許
            //改變自己方向
            currentDirection = rdmDirection(badDirection)
        }
        //坦克的坐标移動
        //根據方向改變坐标
        when (currentDirection) {
            Direction.up -> y -= speed
            Direction.down -> y += speed
            Direction.left -> x -= speed
            Direction.right -> x += speed
        }

        //越界判斷
        if (x < 0) x = 0
        if (x > Config.gameWidth - width) {
            x = Config.gameWidth - width
        }
        if (y < 0) y = 0
        if (y > Config.gameHeight - height) {
            y = Config.gameHeight - height
        }
    }

    private fun rdmDirection(bad:Direction?):Direction{
        val i:Int = Random.nextInt(4)
        val direction = when(i){
            0->Direction.up
            1->Direction.down
            2->Direction.left
            3->Direction.right
            else->Direction.up
        }
        //判斷,不能要錯誤的方向
        if(direction == bad){
            return rdmDirection(bad)
        }
        return direction
    }
}      

運作程式,發現最終坦克在邊界會停住。因為隻對碰撞物做了檢測,并沒有對邊界做檢測,在剛才的Moveable的willCollision方法中增加邊界的檢測

fun willCollision(block:Blockable):Direction?{
        //将要碰撞時,用未來的坐标
        var x = this.x
        var y = this.y
        when (currentDirection) {
            Direction.up -> y -= speed
            Direction.down -> y += speed
            Direction.left -> x -= speed
            Direction.right -> x += speed
        }

        //邊界檢測
        if (x < 0) return Direction.left
        if (x > Config.gameWidth - width) return Direction.right
        if (y < 0) return Direction.up
        if (y > Config.gameHeight - height) return Direction.down

        //檢測下一步是否碰撞碰撞
        var collision = checkCollision(x, y, width, height, block.x, block.y, block.width, block.height)
        return if (collision) currentDirection else null
    }      

運作程式,會發現坦克能穿過彼此,不符合邏輯,現在Enemy實作Blockable

class GameWindow :
    Window(title = "坦克大戰", icon = "img/kotlin.jpg", width = Config.gameWidth, height = Config.gameHeight) {
    ......

    override fun onRefresh() {
        //業務邏輯
        //判斷運動的物體和阻塞物體發生碰撞
        //1)找到運動的物體
        views.filter { it is Moveable }.forEach { move ->
            //2)找到阻塞的物體
            ......

            //不要和自己比較
            views.filter { (it is Blockable) and  (move != it)}.forEach blockTag@{ block ->
                ......
            }
            ......
        }

      ......
    }
}