文章目錄
- 敵方坦克繪制
- 讓敵方坦克動起來
敵方坦克繪制
建立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
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 ->
......
}
......
}
......
}
}