开发中会涉及以下技术的使用,没有高精尖、都是大路货:
- 相机:使用Camera2完成相机的预览和人脸识别
- 自定义View:定义并控制障碍物和潜艇
- 属性动画:控制障碍物和潜艇的移动及各种动效
少啰嗦,先看东西!下面介绍各部分代码的实现。
2、后景(Background)
Bar
首先定义障碍物基类Bar,主要负责是将bitmap资源绘制到指定区域。由于障碍物从屏幕右侧定时刷新时的高度随机,所以其绘制区域的x、y、w、h需要动态设置
/**
* 屏幕下方障碍物
*/
class DnBar(context: Context, container: ViewGroup) : Bar(context) {
override val bmp = super.bmp.let {
Bitmap.createBitmap(
it, 0, 0, it.width, it.height,
Matrix().apply { postRotate(-180F) }, true
)
}
private val _srcRect by lazy(LazyThreadSafetyMode.NONE) {
Rect(0, 0, bmp.width, (bmp.height * (h / container.height)).toInt())
}
override val srcRect: Rect
get() = _srcRect
}
障碍物分为上方和下方两种,由于使用了同一张资源,所以绘制时要区别对待,因此定义了两个子类:UpBar和DnBar
/**
* 屏幕下方障碍物
*/
class DnBar(context: Context, container: ViewGroup) : Bar(context) {
override val bmp = super.bmp.let {
Bitmap.createBitmap(
it, 0, 0, it.width, it.height,
Matrix().apply { postRotate(-180F) }, true
)
}
private val _srcRect by lazy(LazyThreadSafetyMode.NONE) {
Rect(0, 0, bmp.width, (bmp.height * (h / container.height)).toInt())
}
override val srcRect: Rect
get() = _srcRect
}
下方障碍物的资源旋转180度后绘制
/**
* 屏幕下方障碍物
*/
class DnBar(context: Context, container: ViewGroup) : Bar(context) {
override val bmp = super.bmp.let {
Bitmap.createBitmap(
it, 0, 0, it.width, it.height,
Matrix().apply { postRotate(-180F) }, true
)
}
private val _srcRect by lazy(LazyThreadSafetyMode.NONE) {
Rect(0, 0, bmp.width, (bmp.height * (h / container.height)).toInt())
}
override val srcRect: Rect
get() = _srcRect
}
BackgroundView
接下来创建后景的容器BackgroundView,容器用来定时地创建、并移动障碍物。
通过列表barsList管理当前所有的障碍物,onLayout中,将障碍物分别布局到屏幕上方和下方
/**
* 后景容器类
*/
class BackgroundView(context: Context, attrs: AttributeSet?) : FrameLayout(context, attrs) {
internal val barsList = mutableListOf()
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
barsList.flatMap { listOf(it.up, it.down) }.forEach {
val w = it.view.measuredWidth
val h = it.view.measuredHeight
when (it) {
is UpBar -> it.view.layout(0, 0, w, h)
else -> it.view.layout(0, height - h, w, height)
}
}
}
提供两个方法start和stop,控制游戏的开始和结束:
- 游戏结束时,要求所有障碍物停止移动。
- 游戏开始后会通过Timer,定时刷新障碍物
/**
* 游戏结束,停止所有障碍物的移动
*/
@UiThread
fun stop() {
_timer.cancel()
_anims.forEach { it.cancel() }
_anims.clear()
}
/**
* 定时刷新障碍物:
* 1. 创建
* 2. 添加到视图
* 3. 移动
*/