检测子弹和砖墙的磕碰
- 子弹具有进犯的才能
- 砖墙具有受进犯的才能
- 什么时候发生进犯和被进犯
不要乱想了。开端写代码
创立两个接口Attackable、Sufferable
/**
* 进犯的才能
*/
interface Attackable : View {
//判别是否磕碰
fun isCollision(suffer:Sufferable):Boolean
//告诉
fun notifyAttack(suffer: Sufferable)
}
/**
* 遭受进犯的才能
*/
interface Sufferable : View {
fun notifySuffer(attackable: Attackable)
}
GameWindow的业务逻辑中添加
class GameWindow :
......
override fun onRefresh() {
......
//检测有进犯才能和被进犯才能的物体间是否发生了磕碰
//1)过滤具有进犯才能的
views.filter { it is Attackable }.forEach{attack->
attack as Attackable
//2)具有受进犯才能的
views.filter { it is Sufferable }.forEach sufferTag@ {suffer->
suffer as Sufferable
//3)判别是否发生磕碰
if(attack.isCollision(suffer)){
//发生磕碰,找到磕碰者
//告诉进犯者发生磕碰了
attack.notifyAttack(suffer)
//告诉被进犯者发生磕碰
suffer.notifySuffer(attack)
return@sufferTag
}
}
}
}
}
子弹完成Attackable,完成两个办法,其中是否磕碰isCollision咱们在Tank中写过,直接拿过来,由于是重复代码,咱们能够把它放到View中
interface View {
......
//显现
fun draw()
fun checkCollision(x1:Int,y1:Int,w1:Int,h1:Int,
x2:Int,y2:Int,w2:Int,h2:Int):Boolean{
//两个物体的坐标x,y,w,h的比较
return when {
y2 + h2 <= y1 -> //假如阻挠物在运动物上方 不磕碰
false
y1 + h1 <= y2 -> //假如阻挠物在运动物下方 不磕碰
false
x2+ w2 <= x1 -> //假如阻挠物在运动物左面 不磕碰
false
else -> x1 + w1 > x2
}
}
}
那么Tank中的磕碰办法能够修改为
class Tank(override var x: Int, override var y: Int) : Moveable {
......
override 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
}
//检测下一步是否磕碰磕碰
//kotlin写法
/* val collision:Boolean = when {
block.y + block.height <= y -> //假如阻挠物在运动物上方 不磕碰
false
y + height <= block.y -> //假如阻挠物在运动物下方 不磕碰
false
block.x + block.width <= x -> //假如阻挠物在运动物左面 不磕碰
false
else -> x + width > block.x
}*/
var collision = checkCollision(x, y, width, height, block.x, block.y, block.width, block.height)
return if(collision) currentDirection else null
}
......
}
现在传8个参数,是有点麻烦,咱们能够在View中对办法进行重载。但是假如View的代码已经写死了,咱们能够为View进行扩展,创立ViewExt
import com.errol.gradle.model.View
fun View.checkCollision(view: View): Boolean {
return checkCollision(x, y, width, height, view.x, view.y, view.width, view.height)
}
Bullet中
class Bullet(override val currentDirection: Direction, create: (width: Int, height: Int) -> Pair<Int, Int>) : AutoMoveable,Destroyable,Attackable {
......
override fun isCollision(suffer: Sufferable): Boolean {
return checkCollision(suffer)
}
override fun notifyAttack(suffer: Sufferable) {
println("子弹接遭到磕碰")
}
}
让Wall完成Sufferable
class Wall(override var x: Int, override var y: Int) :Blockable,Sufferable{
......
override fun notifySuffer(attackable: Attackable) {
println("砖墙接遭到进犯")
}
}
运行程序,当子弹磕碰到砖墙,会有告诉打印
磕碰后子弹消失
磕碰后子弹应该消失,咱们看到Bullet具有毁掉的才能,但是代码中咱们只是让给它越界后消失,这里咱们添加一个变量isDestroyed
class Bullet(override val currentDirection: Direction, create: (width: Int, height: Int) -> Pair<Int, Int>) : AutoMoveable,Destroyable,Attackable {
private var isDestroyed:Boolean = false
......
override fun isDestroyed(): Boolean {
if(isDestroyed) return true
//子弹脱离屏暗地需要被毁掉
if(x<-width) return true
if(x>Config.gameWidth) return true
if(y<-height) return true
if(y>Config.gameHeight) return true
return false
}
......
override fun notifyAttack(suffer: Sufferable) {
println("子弹接遭到磕碰")
//子弹碰到砖墙后,应该毁掉
isDestroyed = true
}
}
墙遭到进犯后损失
咱们界说能遭受进犯的物体都有一个生命值,修改Sufferable,添加一个生命值
interface Sufferable : View {
//生命值
var blood:Int
fun notifySuffer(attackable: Attackable)
}
给具有进犯才能的物体,一个进犯力。一个普通坦克可能有1点进犯力。一个超级坦克可能有10点进犯力
interface Attackable : View {
//进犯力
var attackPower:Int
//判别是否磕碰
fun isCollision(suffer:Sufferable):Boolean
//告诉
fun notifyAttack(suffer: Sufferable)
}
Bullet咱们给它1点进犯力
override var attackPower: Int = 1
砖墙没血的时候应该被毁掉,因此完成Destroyable
/**
* 砖墙
* 具有阻塞才能
* 具有受进犯才能
* 具有毁掉才能
*/
class Wall(override var x: Int, override var y: Int) :Blockable,Sufferable,Destroyable{
override var blood: Int = 3
......
override fun notifySuffer(attackable: Attackable) {
println("砖墙接遭到进犯")
//砖墙掉血
blood -= attackable.attackPower
}
override fun isDestroyed(): Boolean = blood<=0
}
运行
爆破物显现
现在作用不够劲爆,添加音效
class Wall(override var x: Int, override var y: Int) :Blockable,Sufferable,Destroyable{
......
override fun notifySuffer(attackable: Attackable) {
......
//声音播放
Composer.play("snd/hit.wav")
}
......
}
添加爆破特效,咱们能够对Sufferable中的notifySuffer进行修改,让它回来一个或许多个View,能够为空
interface Sufferable : View {
......
fun notifySuffer(attackable: Attackable):Array<View>?
}
Wall被进犯后发生爆破作用
class GameWindow :
......
override fun onRefresh() {
......
//检测有进犯才能和被进犯才能的物体间是否发生了磕碰
//1)过滤具有进犯才能的
views.filter { it is Attackable }.forEach{attack->
attack as Attackable
//2)具有受进犯才能的
views.filter { it is Sufferable }.forEach sufferTag@ {suffer->
suffer as Sufferable
//3)判别是否发生磕碰
if(attack.isCollision(suffer)){
//发生磕碰,找到磕碰者
//告诉进犯者发生磕碰了
attack.notifyAttack(suffer)
//告诉被进犯者发生磕碰
var sufferView:Array<View>? = suffer.notifySuffer(attack)
sufferView?.let {
//显现被进犯的作用
views.addAll(sufferView)
}
return@sufferTag
}
}
}
}
}
新建Blast
/**
* 爆破物
*/
/**
* 爆破物
*/
class Blast(override val x: Int, override val y: Int) :Destroyable {
override val width: Int = Config.block
override val height: Int = Config.block
private var index:Int = 0
private val imagePaths = arrayListOf<String>()
init{
(1..32).forEach {
imagePaths.add("img/blast_${it}.png")
}
}
override fun draw() {
val i:Int = index%imagePaths.size
Painter.drawImage(imagePaths[i],x,y)
index++
}
override fun isDestroyed(): Boolean {
return index>=imagePaths.size
}
}
Wall
class Wall(override var x: Int, override var y: Int) :Blockable,Sufferable,Destroyable{
......
override fun notifySuffer(attackable: Attackable):Array<View>? {
......
Composer.play("snd/hit.wav")
return arrayOf(Blast(x,y))
}
......
}
运行