前言
前些日子开发过一款小游戏,kotlin快速实现一款小游戏,糖果雨来啦,但由于时间的原因,只开发完成了基础版。如今,我对它进行了升级,新增了进阶版与困难版,分享给大家。
成果展示
现在这款游戏包含三个版本,分别为:
- 基础版:糖果只会在屏幕最上方生成,然后从上往下掉落。
- 进阶版:糖果只会在屏幕中间生成,然后向四周发散
- 困难版:糖果会在屏幕四个角随机生成,然后向大致对角方向发散。
基础版 | 进阶版 | 困难版 |
---|
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0Xt04yYi-1652433709928)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/a574077fd89a43618595a4c15b87704a~tplv-k3u1fbpfcp-zoom-in-crop-mark:1956:0:0:0.image)] | | |
你可以通过点击糖果捕捉器apk 下载地址github进行下载安装apk 来体验一下该游戏。
实现细节
这里关于引导动画的实现,糖果的生成、掉落与收集就不再次展开分析了,。
接下里将重点讲解一下进阶版与困难版的实现原理。
进阶版
具体实现主要分为两步:
- 动态生成一个
View ,居中展示。 - 生成随机坐标,计算平移距离。
- 利用属性动画将
View 向四周平移出屏幕。
TextView(this).apply {
//1. 设置为居中
layoutParams = ConstraintLayout.LayoutParams(tvWidth, tvHeight).apply {
bottomToBottom = ConstraintSet.PARENT_ID
topToTop = ConstraintSet.PARENT_ID
startToStart = ConstraintSet.PARENT_ID
endToEnd = ConstraintSet.PARENT_ID
}
//2. 设置糖果背景
background = ContextCompat.getDrawable(this@AdvancedActivity, generateRandomCandy())
//3. 添加到视图
viewBinding.root.addView(this)
}
动态生成一个TextView ,设置其属性让其居中,然后设置糖果的背景,并添加到视图中。
在对其添加属性动画前,我们需要为它确定一个随机坐标。这里我们利用获取到的屏幕宽高来随机生成一个屏幕内坐标。
fun generateRandomX(leftRange: Int = 0, rightRange: Int = getScreenWidth()): Int {
return (leftRange..rightRange).random()
}
fun generateRandomY(leftRange: Int = 0, rightRange: Int = getScreenHeight()): Int {
return (leftRange..rightRange).random()
}
我们将屏幕分成四块,生成的随机坐标点随机分布在这四块区域中。
在确定了随机坐标后,接着我们就需要通过这个随机坐标来计算出需平移的距离。
我们以随机坐标点位于左上方区域来举例:
我们利用相似三角形来确定需要平移的距离,取两个相同大小的三角形来计算:
X轴 平移的距离为:halfScreenWidth - x) * -2 。Y轴 平移的距离为:(halfScreenHeight - y) * -2 。
除了左上区域,剩下的其他三个区域分别为:
将这四个区域合起来的总的计算方法为:
private fun calculatePosition(x: Int, y: Int): Pair<Int, Int> {
//利用相似三角形来确定平移距离,现在是取一个相同大小的相似三角形。
return if (x <= halfScreenWidth) {
if (y <= halfScreenHeight) {
//left_top
Pair((halfScreenWidth - x) * -2, (halfScreenHeight - y) * -2)
} else {
//left_bottom
Pair((halfScreenWidth - x) * -2, (y - halfScreenHeight) * 2)
}
} else {
if (y <= halfScreenHeight) {
//right_top
Pair((x - halfScreenWidth) * 2, (halfScreenHeight - y) * -2)
} else {
//right_bottom
Pair(((x - halfScreenWidth) * 2).toInt(), (y - halfScreenHeight) * 2)
}
}
}
问题
如上所述,我们利用两个相同的相似三角形来计算平移距离,看起来很美好,但实际调式过程中,发现很多时候糖果无法平移出手机屏幕,因为平移的距离不够。
像这种情况,即使我们用了两个相同的相似三角形来计算平移距离,平移距离还是不够,造成糖果无法平移出手机屏幕。
那怎么办呢?
这里我们采取一个递归算法,来保证我们计算出的平移距离能够支持糖果平移出屏幕。
/**
* 取一个相同大小的三角形的话,还是有可能平移不出屏幕,应该避免这个情况
*/
private fun checkTransitionXy(transitionXyPair: Pair<Int, Int>): Pair<Int, Int> {
//递归的终止条件
if (transitionXyPair.first.absoluteValue > (halfScreenWidth + tvWidth)
|| transitionXyPair.second.absoluteValue > (halfScreenHeight + tvHeight)
) {
return transitionXyPair
}
return checkTransitionXy(
Pair(
(transitionXyPair.first * 1.1).toInt(),
(transitionXyPair.second * 1.1).toInt()
)
)
}
递归的终止条件就是判断X轴 的平移距离或者Y轴 的平移距离能够平移出屏幕,不满足该终止条件则将平移距离不停的放大。
介绍完了进阶版的实现原理,接着我们来看看困难版的实现原理。
困难版
相对比基础版与进阶版,困难版的发球点增加到四个,分别位于屏幕的四周。糖果会随机从这四个点生成,然后向大致对角方向发散。
所以同样,我们将屏幕分成四块。
enum class Direction {
LEFT_TOP,
RIGHT_TOP,
LEFT_BOTTOM,
RIGHT_BOTTOM
}
通过 Direction.values().random() 来随机确定糖果的初始坐标位于哪一块区域中,然后通过设置LayoutParams 属性来让其位于四个角中。
TextView(this).apply {
//1.设置糖果背景
background =
ContextCompat.getDrawable(this@DifficultActivity, generateRandomCandy())
//2.确定初始位置
tv.layoutParams = when (Direction.values().random()) {
Direction.LEFT_TOP -> {
ConstraintLayout.LayoutParams(tvWidth, tvHeight).apply {
startToStart = ConstraintSet.PARENT_ID
topToTop = ConstraintSet.PARENT_ID
}
}
Direction.LEFT_BOTTOM -> {
ConstraintLayout.LayoutParams(tvWidth, tvHeight).apply {
startToStart = ConstraintSet.PARENT_ID
bottomToBottom = ConstraintSet.PARENT_ID
}
}
Direction.RIGHT_TOP -> {
ConstraintLayout.LayoutParams(tvWidth, tvHeight).apply {
endToEnd = ConstraintSet.PARENT_ID
topToTop = ConstraintSet.PARENT_ID
}
}
Direction.RIGHT_BOTTOM -> {
ConstraintLayout.LayoutParams(tvWidth, tvHeight).apply {
endToEnd = ConstraintSet.PARENT_ID
bottomToBottom = ConstraintSet.PARENT_ID
}
}
}
//3.添加到视图中
viewBinding.root.addView(this)
}
接着就是计算平移的距离了。
因为是向对角发散,所以随机坐标是生成在对角区域,也就是左上区域对右下区域,右上区域对左下区域。
我们还是以左上区域来举例:
这里我们简单点直接利用两个相似三角形来计算平移距离:
X轴 平移距离为:x * 2 。Y轴 平移距离为:y * 2 。
其它三个区域这边就不展开分析了,总的计算方法为:
/**
* x, y 是指生成的随机坐标点的坐标
*
* 移动的距离是两个相似三角形相加
*/
private fun calculatePosition(x: Int, y: Int): Pair<Int, Int> {
return if (x > halfScreenWidth) {
if (y > halfScreenHeight) {
//right_bottom
Pair(x * 2, y * 2)
} else {
//right_top
Pair(x * 2, -2 * (screenHeight - y))
}
} else {
if (y > halfScreenHeight) {
//left_bottom
Pair(-2 * (screenWidth - x), 2 * y)
} else {
//left_top
Pair(-2 * (screenWidth - x), -2 * (screenHeight - y))
}
}
}
因为随机坐标点是在对角,所以两个三角形相加的平移距离就够支持糖果平移出屏幕了,当然你也可以参考进阶版采取递归算法来计算平移距离,那也会更加的精准。
总结
在完成了进阶版与困难版后,糖果捕捉器 这款游戏也变得更加完整,当然后续还可以进行更多的升级,比如:让用户来定义糖果的生成速度,定义糖果的掉落速度,后续有时间的话,会对它进行再次升级。
如果你想查看游戏的所有代码,可以点击Github Candy-Catch进行查阅。如果可以,欢迎你给我点个小星星。
你可以通过点击糖果捕捉器apk 下载地址github进行下载安装该apk 来进行体验一下该游戏。
到此本篇文章就结束啦,如果你有任何疑问或者不同的想法,欢迎在评论区留言与我一起探讨。
其实分享文章的最大目的正是等待着有人指出我的错误,如果你发现哪里有错误,请毫无保留的指出即可,虚心请教。
另外,如果你觉得文章不错,对你有所帮助,请帮我点个赞,就当鼓励,谢谢~
|