天天看点

【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 ->
                ......
            }
            ......
        }

      ......
    }
}