【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))

运行,敌方坦克就画好了
在这里插入图片描述

让敌方坦克动起来

敌方坦克是可以自动移动的,我们正好有个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

运行程序,会发现坦克在转圈圈,以为在GameWindow的onRefresh中,检测有攻击能力和被攻击能力的物体间是否发生了碰撞时,因为敌方坦克既是移动物体,又是阻塞物体,所以在过滤时,最终和自己进行了比较,因此修改

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

      ......
    }
}

运行程序
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值