文章目录



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

运行后出现的问题是,子弹总是从左上角出现,我们必须计算出子弹打出的位置
【Kotlin】坦克大战4:子弹绘制_初始化_02
假设最外层是窗体,正方形为子弹,长方形为子弹,要找到子弹的x,只需​​​坦克的x+(坦克宽度一半-子弹宽度一半)​

【Kotlin】坦克大战4:子弹绘制_ide_03
同理,计算子弹的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是写死的,这是不正确的。因为子弹不同方向图片宽高是不同的
【Kotlin】坦克大战4:子弹绘制_kotlin_04
修改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)
})
}

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

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

子弹其他方向发射计算

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

向下时

X:​​坦克x+(坦克宽度一半-子弹宽度一般)​​​【Kotlin】坦克大战4:子弹绘制_kotlin_06
Y:​​坦克y+坦克高度-子弹高度一半​【Kotlin】坦克大战4:子弹绘制_初始化_07

向左时

X:​​坦克x-子弹宽度一般​​​【Kotlin】坦克大战4:子弹绘制_初始化_08
Y:​​坦克y+(坦克高度/2-子弹高度/2)​【Kotlin】坦克大战4:子弹绘制_kotlin_09

向右时

X:​​坦克x+(坦克宽度-子弹宽度/2)​​​【Kotlin】坦克大战4:子弹绘制_ide_10

X:​​坦克y+(坦克高度/2-子弹宽度/2)​​​【Kotlin】坦克大战4:子弹绘制_宽高_11
完善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)
})
}