文章目录
子弹向上发射
当按下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)
})
}