【Kotlin】坦克大战4:子弹绘制


在这里插入图片描述

子弹向上发射

当按下Enter键时,发射子弹,修改GameWindow.kt中onKeyPressed方法

 override fun onKeyPressed(event: KeyEvent) {
        //用户操作时
        when(event.code){
            ......
            KeyCode.ENTER -> {
                //发射子弹
                var bullet:Bullet = tank.shot()
                views.add(bullet)
            }
        }
    }

需要创建一个Bullet类

class Bullet(override val x: Int, override val y: Int) : View {
    override val width: Int = Config.block
    override val height: Int = Config.block

    override fun draw() {
        Painter.drawImage("img/bullet_l.gif", x, y)
    }
}

Tank需要实现发射方法

class Tank(override var x: Int, override var y: Int) : Moveable {
    ......
    /**
     * 发射子弹的方法
     */
    fun shot():Bullet{
        return Bullet(x,y)
    }
}

运行结果是,按下Enter时,在坦克的位置留下子弹,但是子弹的方向是写死的,和坦克的方向不同,因此我们应该给子弹一个方向,方向由坦克决定

class Bullet(var direction:Direction,override val x: Int, override val y: Int) : View {
    //给子弹一个方向,方向由坦克决定
    override val width: Int = Config.block
    override val height: Int = Config.block

    override fun draw() {
        val imagePath = when (direction) {
            Direction.up -> "img/shot_bottom.gif"
            Direction.down -> "img/shot_top.gif"
            Direction.left -> "img/shot_right.gif"
            Direction.right -> "img/shot_left.gif"
        }
        Painter.drawImage(imagePath, x, y)
    }
}

Tank.kt中

    fun shot():Bullet{
        return Bullet(currentDirection,x,y)
    }

运行后出现的问题是,子弹总是从左上角出现,我们必须计算出子弹打出的位置
在这里插入图片描述
假设最外层是窗体,正方形为子弹,长方形为子弹,要找到子弹的x,只需坦克的x+(坦克宽度一半-子弹宽度一半)

在这里插入图片描述
同理,计算子弹的y,只需要tankY-子弹高度一半
先写子弹向上的情况。我们查看向上的子弹图片:16x32
因此,修改后的shot方法为

fun shot():Bullet{
        var tankX = x
        var tankY = y
        var tankWidth = width

        var bulletX = 0
        var bulletY = 0

        var bulletWidth = 16
        var bulletHeight = 32

        //计算子弹真实的坐标
        //如果坦克向上:bulletX = tankX+(tankWidth-bulletWidth)/2
        //bulletY = tankY - bulletHeight/2
        when(currentDirection){
            Direction.up -> {
                bulletX = tankX+(tankWidth-bulletWidth)/2
                bulletY = tankY - bulletHeight/2
            }
        }

        return Bullet(currentDirection,bulletX,bulletY)
    }

分析以上代码,子弹宽度:bulletWidth,子弹高度:bulletHeight是写死的,这是不正确的。因为子弹不同方向图片宽高是不同的
在这里插入图片描述
修改Bullet类
Bullet

/**
 * create()函数返回两个值:x,y
 * 同时传递两个值:width、height
 */
class Bullet(var direction: Direction, create: (width: Int, height: Int) -> Pair<Int, Int>) : View {
    //给子弹一个方向,方向由坦克决定
    override val width: Int
    override val height: Int

    override val x: Int
    override val y: Int

    private val imagePath = when (direction) {
        Direction.up -> "img/shot_bottom.gif"
        Direction.down -> "img/shot_top.gif"
        Direction.left -> "img/shot_right.gif"
        Direction.right -> "img/shot_left.gif"
    }

    init {
        //先计算宽高
        val size = Painter.size(imagePath)
        width = size[0]
        height = size[1]

        val pair = create.invoke(width, height)
        x = pair.first
        y = pair.second
    }

    override fun draw() {
        Painter.drawImage(imagePath, x, y)
    }
}

修改Tank

Tank

class Tank(override var x: Int, override var y: Int) : Moveable {
    ......
    /**
     * 发射子弹的方法
     */
    fun shot():Bullet{
        return Bullet(currentDirection,{bulletWidth,bulletHeight->
            var tankX = x
            var tankY = y
            var tankWidth = width

            var bulletX = 0
            var bulletY = 0

            //计算子弹真实的坐标
            //如果坦克向上:bulletX = tankX+(tankWidth-bulletWidth)/2
            //bulletY = tankY - bulletHeight/2
            when(currentDirection){
                Direction.up -> {
                    bulletX = tankX+(tankWidth-bulletWidth)/2
                    bulletY = tankY - bulletHeight/2
                }
            }

            Pair(bulletX,bulletY)
        })
    }
}

对以上代码做些解释。首先Bullet中

关键字init:init{}它被称作是初始化代码块,这里做一些初始化操作

因为子弹不同方向图片宽高是不同的,所以我们使用Painter.size(imagePath)方法,传入一个图片路径,来计算出子弹图片大小,取值时像数组一样取出宽高即可。这样Tank中需要的bulletWidth和bulletHeight就有了

我们需要把刚才得到的两个值传给Tank,这里把函数作为参数传给Tank

class Bullet(var direction: Direction, create: (width: Int, height: Int) -> Pair<Int, Int>) : View {
......
}

后边的Pair是接收的两个值,使用以下方法可以取出接收的这两个值,这两个值就是绘制子弹的位置,我们可以在Tank的shot方法中传过来

		val pair = create.invoke(width, height)
        x = pair.first
        y = pair.second

好了,看Tank中的shot方法,因为是作为一个函数传的,所以可以直接写一个大括号,像这样

fun shot():Bullet{
        return Bullet(currentDirection,{
            ......
        })
    }
fun shot():Bullet{
        return Bullet(currentDirection,{bulletWidth,bulletHeight->
            ......
        })
    }

其中bulletWidth,bulletHeight按照以上写法就可以接收到了,传值可以在最后写

fun shot():Bullet{
        return Bullet(currentDirection,{bulletWidth,bulletHeight->
        	......
            Pair(bulletX,bulletY)
        })
    }

运行程序,当坦克方向朝上的时候,我们成功打出了方向和位置都正确的子弹,有点像打火机…

在这里插入图片描述

子弹其他方向发射计算

记住要求的是子弹左上角的坐标

向下时

X:坦克x+(坦克宽度一半-子弹宽度一般)
在这里插入图片描述
Y:坦克y+坦克高度-子弹高度一半
在这里插入图片描述

向左时

X:坦克x-子弹宽度一般
在这里插入图片描述
Y:坦克y+(坦克高度/2-子弹高度/2)
在这里插入图片描述

向右时

X:坦克x+(坦克宽度-子弹宽度/2)
在这里插入图片描述

X:坦克y+(坦克高度/2-子弹宽度/2)在这里插入图片描述
完善Tank中shot方法即可

/**
     * 发射子弹的方法
     */
    fun shot():Bullet{
        return Bullet(currentDirection,{bulletWidth,bulletHeight->
            var tankX = x
            var tankY = y
            var tankWidth = width
            var tankHeight = height

            var bulletX = 0
            var bulletY = 0

            //计算子弹真实的坐标
            //如果坦克向上:bulletX = tankX+(tankWidth-bulletWidth)/2
            //bulletY = tankY - bulletHeight/2
            when(currentDirection){
                Direction.up -> {
                    bulletX = tankX+(tankWidth-bulletWidth)/2
                    bulletY = tankY - bulletHeight/2
                }
                Direction.down -> {
                    bulletX = tankX+(tankWidth-bulletWidth)/2
                    bulletY = tankY+tankHeight-bulletHeight/2
                }
                Direction.left -> {
                    bulletX = tankX-bulletWidth/2
                    bulletY = tankY + (tankHeight-bulletHeight)/2
                }
                Direction.right -> {
                    bulletX = tankX+(tankWidth-bulletWidth/2)
                    bulletY = tankY + (tankHeight-bulletHeight)/2
                }
            }

            Pair(bulletX,bulletY)
        })
    }
发布了640 篇原创文章 · 获赞 143 · 访问量 54万+

猜你喜欢

转载自blog.csdn.net/u010356768/article/details/103508332