文章目录

敌方坦克绘制

创建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

运行程序,会发现坦克在转圈圈,以为在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 ->
......
}
......
}

......
}
}

运行程序
【Kotlin】坦克大战7:敌方坦克创建_业务逻辑_02