• Android中球体碰撞代码分享-kotlin,入门版


    * 可以产生形变,回弹的小球
    *
    * 整个view的核心:
    * Scroller函数
    * 1.调用scroller.public void startScroll(int startX, int startY, int dx, int dy, int duration);
    * 在指定时间范围内,startX,startY,会移动dx,dy距离
    *
    * 2.然后调用:invalidate(); 系统内部会调用onDraw();
    *
    * 3.在onDraw方法内部又会调用  computeScrollOffset()函数。
    * 所以,实现scroll.computeScrollOffset(); //如果还没有完全移动完成,就执行XXXXX
    *
    * 4.如果返回true 继续调用 invalidate();
    *
    * 这样就会在位移的过程中,执行你:  if(scroll.computeScrollOffset()){
    * //你自己的方法
    * }
    *

    1. class BallViewTwo @JvmOverloads constructor(
    2. context: Context,
    3. attrs: AttributeSet? = null
    4. ) : androidx.appcompat.widget.AppCompatImageView(context, attrs) {
    5. private var mContext: Context = context
    6. //屏幕的宽高
    7. private var displayHeight: Int = 0
    8. private var displayWidth: Int = 0
    9. private var changelength = 30 //第一次形变的大小
    10. private var mCurrentDirection = -1 //碰撞后,此时的方向
    11. private var mDuration = 450 //变形需要持续的时间
    12. /**
    13. * flag=-1 正常移动
    14. * flag=0 压缩变形
    15. * flag=1 恢复压缩形变
    16. * flag=2 往相反的方向弹
    17. * flag=3 弹回原先的位置
    18. */
    19. private var flag = -1
    20. private var mShotOver: ShotOver? = null //回调函数
    21. private var moveToLeft = 100 //正常状态下,小球移动到x轴的位置
    22. private var moveToTop = 100 //正常状态下,小球移动到y轴的位置
    23. private val centerX = 180 //小球圆心x
    24. private val centerY = 180 //小球圆心y
    25. private val radius = 180 //半径
    26. private val bubbleWidth = radius * 2 //小球的宽
    27. private val bubbleHeight = radius * 2 //小球的高
    28. private var paint: Paint // 画笔
    29. private var scroller: Scroller // 整个view的核心
    30. private var rectF: RectF? = null //绘制椭圆
    31. private var ovalLeft = 0
    32. private var ovalTop = 0
    33. private var ovalRight = 0
    34. private var ovalBottom = 0 //椭圆的左上右下
    35. private var currY = 0
    36. private var currX = 0
    37. private var offset = 0 //发生的移动量
    38. private val shotBackDuration = 100 //回弹执行的时间
    39. private val shotBackChange = 15 //回弹需要移动的距离
    40. private var newOvalLeft = 0
    41. private var newOvalTop = 0
    42. private var newOvalRight = 0
    43. private var newOvalBottom = 0
    44. private var isShotBack = true // 是否开启回弹效果
    45. init {
    46. paint = Paint()
    47. paint.color = Color.RED
    48. scroller = Scroller(context)
    49. rectF = RectF()
    50. }
    51. override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
    52. displayHeight = mContext.resources.displayMetrics.heightPixels
    53. displayWidth = mContext.resources.displayMetrics.widthPixels
    54. Log.i("qq", "ballview-------displayHeight=-$displayHeight displayWidth=$displayWidth")
    55. super.onMeasure(widthMeasureSpec, heightMeasureSpec)
    56. }
    57. override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
    58. super.onSizeChanged(w, h, oldw, oldh)
    59. }
    60. override fun onDraw(canvas: Canvas) {
    61. when (flag) {
    62. -1 -> {
    63. canvas.translate(moveToLeft.toFloat(), moveToTop.toFloat())
    64. canvas.drawCircle(centerX.toFloat(), centerY.toFloat(), radius.toFloat(), paint)
    65. Log.i("qq", "正常移动小球 小球left=$moveToLeft top=$moveToTop")
    66. }
    67. 0 -> circleToOval(canvas)
    68. 1 -> ovalToCircle(canvas)
    69. 2 -> shotBackLeaveBounds(canvas)
    70. 3 -> shotBackGotoBounds(canvas)
    71. }
    72. super.onDraw(canvas)
    73. }
    74. /**
    75. * 小球变形完再回弹,靠近边界
    76. */
    77. private fun shotBackGotoBounds(canvas: Canvas) {
    78. if (scroller.computeScrollOffset()) {
    79. ovalLeft = scroller.currX
    80. ovalTop = scroller.currY
    81. canvas.translate(ovalLeft.toFloat(), ovalTop.toFloat())
    82. canvas.drawCircle(centerX.toFloat(), centerY.toFloat(), radius.toFloat(), paint)
    83. invalidate()
    84. Log.i("shotBack", "远离边界。。moveToLeft=$ovalLeft moveToTop=$ovalTop")
    85. } else {
    86. Log.i("shotBack", "所有效果都结束")
    87. canvas.translate(ovalLeft.toFloat(), ovalTop.toFloat())
    88. canvas.drawCircle(centerX.toFloat(), centerY.toFloat(), radius.toFloat(), paint)
    89. isShotBack = false
    90. startChange(shotBackChange)
    91. }
    92. }
    93. /**
    94. * 小球变形完再回弹,也就是远离边界
    95. */
    96. private fun shotBackLeaveBounds(canvas: Canvas) {
    97. if (scroller.computeScrollOffset()) {
    98. ovalLeft = scroller.currX
    99. ovalTop = scroller.currY
    100. canvas.translate(ovalLeft.toFloat(), ovalTop.toFloat())
    101. canvas.drawCircle(centerX.toFloat(), centerY.toFloat(), radius.toFloat(), paint!!)
    102. invalidate()
    103. Log.i("shotBack", "远离边界。。moveToLeft=$ovalLeft moveToTop=$ovalTop")
    104. } else {
    105. canvas.translate(ovalLeft.toFloat(), ovalTop.toFloat())
    106. canvas.drawCircle(centerX.toFloat(), centerY.toFloat(), radius.toFloat(), paint!!)
    107. flag = 3
    108. finishShotBack()
    109. }
    110. }
    111. /**
    112. * 将椭圆恢复成圆形
    113. */
    114. private fun ovalToCircle(canvas: Canvas) {
    115. if (scroller!!.computeScrollOffset()) {
    116. when (mCurrentDirection) {
    117. 0 -> {
    118. currY = scroller!!.currY
    119. offset = newOvalTop - currY
    120. ovalLeft = newOvalLeft + offset
    121. ovalTop = currY + offset
    122. ovalRight = newOvalRight - offset
    123. ovalBottom = newOvalBottom + offset + offset
    124. rectF!![ovalLeft.toFloat(), ovalTop.toFloat(), ovalRight.toFloat()] =
    125. ovalBottom.toFloat()
    126. canvas.drawOval(rectF!!, paint!!)
    127. Log.i(
    128. "qq",
    129. "将椭圆----恢复成圆形,方向向北 currY=$currY offset=$offset"
    130. )
    131. Log.i(
    132. "qq",
    133. "将椭圆----恢复成圆形,方向向北 ovalLeft=$ovalLeft ovalTop=$ovalTop ovalRight=$ovalRight ovalBottom=$ovalBottom"
    134. )
    135. }
    136. 1 -> {
    137. currX = scroller!!.currX
    138. offset = newOvalLeft - currX
    139. ovalLeft = currX - offset
    140. ovalTop = newOvalTop + offset
    141. ovalRight = newOvalRight + offset - offset
    142. ovalBottom = newOvalBottom - offset
    143. rectF!![ovalLeft.toFloat(), ovalTop.toFloat(), ovalRight.toFloat()] =
    144. ovalBottom.toFloat()
    145. canvas.drawOval(rectF!!, paint!!)
    146. }
    147. 2 -> {
    148. currY = scroller!!.currY
    149. offset = newOvalTop - currY
    150. ovalLeft = newOvalLeft + offset
    151. ovalTop = currY - offset
    152. ovalRight = newOvalRight - offset
    153. ovalBottom = newOvalBottom
    154. rectF!![ovalLeft.toFloat(), ovalTop.toFloat(), ovalRight.toFloat()] =
    155. ovalBottom.toFloat()
    156. canvas.drawOval(rectF!!, paint!!)
    157. Log.i(
    158. "qq",
    159. "将椭圆----恢复成圆形,方向向南 currY=$currY offset=$offset"
    160. )
    161. Log.i(
    162. "qq",
    163. "将椭圆----恢复成圆形,方向向南 ovalLeft=$ovalLeft ovalTop=$ovalTop ovalRight=$ovalRight ovalBottom=$ovalBottom"
    164. )
    165. }
    166. 3 -> {
    167. currX = scroller!!.currX
    168. offset = newOvalLeft - currX
    169. ovalLeft = currX + offset
    170. ovalTop = newOvalTop + offset
    171. ovalRight = newOvalRight + offset + offset
    172. ovalBottom = newOvalBottom - offset
    173. rectF!![ovalLeft.toFloat(), ovalTop.toFloat(), ovalRight.toFloat()] =
    174. ovalBottom.toFloat()
    175. canvas.drawOval(rectF!!, paint!!)
    176. }
    177. }
    178. invalidate()
    179. } else {
    180. canvas.drawOval(rectF!!, paint!!)
    181. //如果需要回弹的话
    182. if (isShotBack) {
    183. flag = 2
    184. startShotBack()
    185. } else {
    186. flag = -1
    187. if (mShotOver != null) {
    188. mShotOver!!.bubbleShotEnd()
    189. }
    190. }
    191. }
    192. }
    193. /**
    194. * 圆挤压成椭圆
    195. */
    196. private fun circleToOval(canvas: Canvas) {
    197. if (scroller!!.computeScrollOffset()) {
    198. when (mCurrentDirection) {
    199. 0 -> {
    200. currY = scroller!!.currY
    201. offset = currY - ovalTop
    202. newOvalLeft = ovalLeft - offset
    203. newOvalTop = currY - offset
    204. newOvalRight = ovalRight + offset
    205. newOvalBottom = ovalBottom - offset - offset
    206. rectF!![newOvalLeft.toFloat(), newOvalTop.toFloat(), newOvalRight.toFloat()] =
    207. newOvalBottom.toFloat()
    208. canvas.drawOval(rectF!!, paint!!)
    209. }
    210. 1 -> {
    211. currX = scroller!!.currX
    212. offset = currX - ovalLeft
    213. newOvalLeft = currX + offset
    214. newOvalTop = ovalTop - offset
    215. newOvalRight = ovalRight - offset + offset
    216. newOvalBottom = ovalBottom + offset
    217. rectF!![newOvalLeft.toFloat(), newOvalTop.toFloat(), newOvalRight.toFloat()] =
    218. newOvalBottom.toFloat()
    219. canvas.drawOval(rectF!!, paint!!)
    220. }
    221. 2 -> {
    222. currY = scroller!!.currY
    223. offset = currY - ovalTop
    224. newOvalLeft = ovalLeft - offset
    225. newOvalTop = currY + offset
    226. newOvalRight = ovalRight + offset
    227. newOvalBottom = ovalBottom
    228. rectF!![newOvalLeft.toFloat(), newOvalTop.toFloat(), newOvalRight.toFloat()] =
    229. newOvalBottom.toFloat()
    230. canvas.drawOval(rectF!!, paint!!)
    231. Log.i("qq", "圆挤压成椭圆,方向向南 currY=$currY offset=$offset")
    232. Log.i(
    233. "qq",
    234. "圆挤压成椭圆,方向向南 newOvalLeft=$newOvalLeft newOvalTop=$newOvalTop newOvalRight=$newOvalRight newOvalBottom=$newOvalBottom"
    235. )
    236. }
    237. 3 -> {
    238. currX = scroller!!.currX
    239. offset = currX - ovalLeft
    240. newOvalLeft = currX - offset
    241. newOvalTop = ovalTop - offset
    242. newOvalRight = ovalRight - offset - offset
    243. newOvalBottom = ovalBottom + offset
    244. rectF!![newOvalLeft.toFloat(), newOvalTop.toFloat(), newOvalRight.toFloat()] =
    245. newOvalBottom.toFloat()
    246. canvas.drawOval(rectF!!, paint!!)
    247. }
    248. }
    249. invalidate()
    250. } else {
    251. canvas.drawOval(rectF!!, paint!!)
    252. reverse()
    253. }
    254. }
    255. /**
    256. * 碰撞变形结束后,开启弹一弹效果
    257. */
    258. fun startShotBack() {
    259. when (mCurrentDirection) {
    260. 0 -> scroller!!.startScroll(ovalLeft, ovalTop, 0, shotBackChange, shotBackDuration)
    261. 1 -> scroller!!.startScroll(ovalLeft, ovalTop, -shotBackChange, 0, shotBackDuration)
    262. 2 -> scroller!!.startScroll(ovalLeft, ovalTop, 0, -shotBackChange, shotBackDuration)
    263. 3 -> scroller!!.startScroll(ovalLeft, ovalTop, shotBackChange, 0, shotBackDuration)
    264. }
    265. invalidate()
    266. }
    267. /**
    268. * 结束 “弹的一段距离”
    269. */
    270. fun finishShotBack() {
    271. when (mCurrentDirection) {
    272. 0 -> scroller!!.startScroll(ovalLeft, ovalTop, 0, -shotBackChange, shotBackDuration)
    273. 1 -> scroller!!.startScroll(ovalLeft, ovalTop, shotBackChange, 0, shotBackDuration)
    274. 2 -> scroller!!.startScroll(ovalLeft, ovalTop, 0, shotBackChange, shotBackDuration)
    275. 3 -> scroller!!.startScroll(ovalLeft, ovalTop, -shotBackChange, 0, shotBackDuration)
    276. }
    277. invalidate()
    278. }
    279. /**
    280. * 移动小球
    281. */
    282. fun moveTo(l: Int, t: Int, direction: Int, duration: Int, shotBack: Boolean) {
    283. isShotBack = shotBack
    284. mDuration = duration
    285. mCurrentDirection = direction
    286. moveToLeft = l
    287. moveToTop = t
    288. if (t == 0) {
    289. mCurrentDirection = 0
    290. startChange(30)
    291. } else if (l == displayWidth - bubbleWidth) {
    292. mCurrentDirection = 1
    293. startChange(30)
    294. } else if (t == displayHeight - bubbleHeight) {
    295. mCurrentDirection = 2
    296. startChange(30)
    297. } else if (l == 0) {
    298. mCurrentDirection = 3
    299. startChange(30)
    300. } else {
    301. invalidate()
    302. }
    303. }
    304. /**
    305. * 开始变形
    306. */
    307. private fun startChange(change: Int) {
    308. changelength = change
    309. if (mShotOver != null) {
    310. mShotOver!!.bubbleShotStart(mCurrentDirection)
    311. }
    312. flag = 0
    313. //发生变形时,先初始化椭圆刚发生变形时的位置
    314. ovalLeft = moveToLeft
    315. ovalTop = moveToTop
    316. ovalRight = moveToLeft + bubbleWidth
    317. ovalBottom = ovalTop + bubbleHeight
    318. when (mCurrentDirection) {
    319. 0 -> scroller!!.startScroll(moveToLeft, moveToTop, 0, changelength, mDuration)
    320. 1 -> scroller!!.startScroll(moveToLeft, moveToTop, changelength, 0, mDuration)
    321. 2 -> scroller!!.startScroll(moveToLeft, moveToTop, 0, changelength, mDuration)
    322. 3 -> scroller!!.startScroll(moveToLeft, moveToTop, changelength, 0, mDuration)
    323. }
    324. Log.i(
    325. "qq",
    326. "小球开始变形,方向=$mCurrentDirection 当前小球的坐标ovalLeft=$ovalLeft ovalTop=$ovalTop ovalRight=$ovalRight ovalBottom=$ovalBottom"
    327. )
    328. invalidate()
    329. }
    330. /**
    331. * 回复变形前的状态
    332. */
    333. private fun reverse() {
    334. flag = 1
    335. when (mCurrentDirection) {
    336. 0 -> scroller!!.startScroll(newOvalLeft, newOvalTop, 0, -changelength, mDuration)
    337. 1 -> scroller!!.startScroll(newOvalLeft, newOvalTop, -changelength, 0, mDuration)
    338. 2 -> scroller!!.startScroll(newOvalLeft, newOvalTop, 0, -changelength, mDuration)
    339. 3 -> scroller!!.startScroll(newOvalLeft, newOvalTop, -changelength, 0, mDuration)
    340. }
    341. invalidate()
    342. }
    343. fun setShotOver(shotOver: ShotOver?) {
    344. mShotOver = shotOver
    345. }
    346. /**
    347. * 碰撞变形效果完成
    348. */
    349. interface ShotOver {
    350. fun bubbleShotStart(direction: Int)
    351. fun bubbleShotEnd()
    352. }
    353. /**
    354. * (辅助函数)//没有实现效果
    355. * 圆挤压成椭圆时,变形加速减少
    356. */
    357. /*
    358. public void circleToOvalAndAcceleratedReduce(Canvas canvas){
    359. if(gradient == 0){
    360. newOvalLeft = ovalLeft;
    361. newOvalTop = ovalTop;
    362. newOvalRight = ovalRight;
    363. newOvalBottom = ovalBottom;
    364. }
    365. if((offset - oldOffset) >= 10 && gradient == 0){
    366. Log.i("qq", "移动距离大于10时绘制一次");
    367. newOvalLeft = ovalLeft - offset;
    368. newOvalTop = currY - offset;
    369. newOvalRight = ovalRight + offset;
    370. newOvalBottom = ovalBottom - offset - offset;
    371. rectF.set(newOvalLeft, newOvalTop, newOvalRight, newOvalBottom);
    372. canvas.drawOval(rectF, paint);
    373. oldOffset = offset;
    374. gradient = 1;
    375. }else if((offset - oldOffset) >= 7 && gradient == 1){
    376. Log.i("qq", "移动距离大于7时绘制一次");
    377. newOvalLeft = ovalLeft - offset;
    378. newOvalTop = currY - offset;
    379. newOvalRight = ovalRight + offset;
    380. newOvalBottom = ovalBottom - offset - offset;
    381. rectF.set(newOvalLeft, newOvalTop, newOvalRight, newOvalBottom);
    382. canvas.drawOval(rectF, paint);
    383. gradient = 2;
    384. oldOffset = offset;
    385. }else if((offset - oldOffset) >= 4 && gradient == 2){
    386. Log.i("qq","移动距离大于4时绘制一次");
    387. newOvalLeft = ovalLeft - offset;
    388. newOvalTop = currY - offset;
    389. newOvalRight = ovalRight + offset;
    390. newOvalBottom = ovalBottom - offset - offset;
    391. rectF.set(newOvalLeft, newOvalTop, newOvalRight, newOvalBottom);
    392. canvas.drawOval(rectF, paint);
    393. gradient = 3;
    394. oldOffset = offset;
    395. }else if((offset - oldOffset) >= 2 && gradient == 3){
    396. Log.i("qq","移动距离大于2时绘制一次");
    397. newOvalLeft = ovalLeft - offset;
    398. newOvalTop = currY - offset;
    399. newOvalRight = ovalRight + offset;
    400. newOvalBottom = ovalBottom - offset - offset;
    401. rectF.set(newOvalLeft, newOvalTop, newOvalRight, newOvalBottom);
    402. canvas.drawOval(rectF, paint);
    403. gradient = -1;
    404. oldOffset = offset;
    405. }else{
    406. Log.i("qq", "移动绘制一次");
    407. rectF.set(newOvalLeft, newOvalTop, newOvalRight, newOvalBottom);
    408. canvas.drawOval(rectF, paint);
    409. }
    410. Log.i("qq", "圆挤压成椭圆,方向向北 currY=" + currY + " offset=" + offset);
    411. Log.i("qq", "圆挤压成椭圆,方向向北 newOvalLeft=" + newOvalLeft + " newOvalTop=" + newOvalTop + " newOvalRight=" + newOvalRight + " newOvalBottom=" + newOvalBottom);
    412. }*/
    413. }

    1. /**
    2. * 1.根据重力感应移动小球
    3. * 2.一般重力感应使用的重力加速,这样的话每次移动距离不是固定的
    4. * 3.此应用,将速度固定。
    5. * 4.小球碰撞到边缘时,会发生形变。(小球压缩形变)
    6. * 5.可以点击按钮添加,发生形变后回弹效果
    7. */
    8. class AnimationActivity : Activity(), View.OnClickListener {
    9. private var sensorManager: SensorManager? = null
    10. private var sensor: Sensor? = null
    11. private var init = false
    12. // 因为布局是填充父窗体的,且设置了出掉状态栏,所有求出的宽高就是屏幕的宽高。
    13. private var containerWidth = 0
    14. private var containerHeight = 0
    15. // 小球的宽高
    16. private val ballWidth = 360
    17. private val ballHeight = 360
    18. // 自定义球
    19. private lateinit var ball: BallViewTwo
    20. // 小球的起始位置
    21. private var ballX = 100f
    22. private var ballY = 100f
    23. private var currentState = -1 // 初始方向
    24. private var shotDirection = -1 // 小球发生碰撞时的那刻的方向
    25. // 初始化 东 西 南 北 四个方向
    26. private val NORTH = 0
    27. private val EAST = 1
    28. private val SOUTH = 2
    29. private val WEST = 3
    30. private var constantsSpeed = 100 // 每次斜边移动的距离
    31. private val SPEED = 10 // 比例
    32. private var canMove = true // 小球是否可以移动
    33. private val durationPiece = 150 // 执行动画的时间块
    34. private var duration = 450 // 初始速度下的执行时间
    35. private var isShotBack = false
    36. /**
    37. * -1: 小球正常移动
    38. * 0: 小球正在碰撞
    39. * 1: 小球碰撞刚结束
    40. */
    41. private var shot = -1
    42. /** Called when the activity is first created. */
    43. override fun onCreate(savedInstanceState: Bundle?) {
    44. super.onCreate(savedInstanceState)
    45. window.setFlags(
    46. WindowManager.LayoutParams.FLAG_FULLSCREEN,
    47. WindowManager.LayoutParams.FLAG_FULLSCREEN
    48. )
    49. setContentView(R.layout.activity_animation)
    50. // 初始化重力感应
    51. sensorManager = getSystemService(SENSOR_SERVICE) as SensorManager
    52. sensor = sensorManager!!.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
    53. }
    54. private fun init() {
    55. val container = findViewById(R.id.ball_container)
    56. findViewById(R.id.accelerate).setOnClickListener(this) // 加速移动
    57. findViewById(R.id.reduce).setOnClickListener(this) // 减少移动
    58. findViewById(R.id.normal).setOnClickListener(this) // 正常速度移动
    59. findViewById(R.id.isShowBack).setOnClickListener(this) // 是否弹一弹
    60. containerWidth = container.width
    61. containerHeight = container.height
    62. ball = findViewById(R.id.ball)
    63. /**
    64. * 碰撞监听
    65. */
    66. ball.setShotOver(object : BallViewTwo.ShotOver {
    67. override fun bubbleShotStart(direction: Int) {
    68. shotDirection = direction
    69. shot = 0 // 正在压缩变形
    70. canMove = false
    71. // Log.i("shotDirection", "小球发生碰撞时的方向==" + shotDirection);
    72. }
    73. override fun bubbleShotEnd() {
    74. shot = 1 // 刚压缩变形结束
    75. }
    76. })
    77. }
    78. /**
    79. * 移动小球
    80. * @param x
    81. * @param y
    82. */
    83. private fun moveTo(x: Float, y: Float) {
    84. ballX += x
    85. ballY += y
    86. if (ballX < 0) {
    87. ballX = 0f
    88. }
    89. if (ballY < 0) {
    90. ballY = 0f
    91. }
    92. if (ballX > containerWidth - ballWidth) {
    93. ballX = (containerWidth - ballWidth).toFloat()
    94. }
    95. if (ballY > containerHeight - ballHeight) {
    96. ballY = (containerHeight - ballHeight).toFloat()
    97. }
    98. ball.moveTo(ballX.toInt(), ballY.toInt(), currentState, duration, isShotBack)
    99. }
    100. private val listener = object : SensorEventListener {
    101. override fun onAccuracyChanged(sensor: Sensor, accuracy: Int) {
    102. // TODO Auto-generated method stub
    103. }
    104. override fun onSensorChanged(event: SensorEvent) {
    105. if (!init) return
    106. currentState = calc(event)
    107. // 如果当前方向不等于碰撞方向 并且圆刚碰撞结束
    108. if (shotDirection != currentState && shot == 1) {
    109. canMove = true
    110. }
    111. Log.i("direction", "当前方向==$currentState canMove=$canMove")
    112. // 可以移动的话才计算移动速度,调用移动方法
    113. if (canMove) {
    114. // 如果刚碰撞结束,根据位置,将其挪动一段距离
    115. if (shot == 1) {
    116. when (shotDirection) {
    117. 0 -> moveTo(0f, 20f)
    118. 1 -> moveTo(-20f, 0f)
    119. 2 -> moveTo(0f, -20f)
    120. 3 -> moveTo(20f, 0f)
    121. }
    122. shot = -1
    123. // 直接移动小球
    124. } else {
    125. constantSpeed(event)
    126. }
    127. } else {
    128. Log.i("qq", "正在执行“弹”,所以先不移动小球")
    129. }
    130. }
    131. }
    132. /**
    133. * 计算x,y轴应该移动的值(为了使每次移动距离保持不变)
    134. * @param event
    135. */
    136. private fun constantSpeed(event: SensorEvent) {
    137. val x = event.values[SensorManager.DATA_X] * SPEED
    138. val y = event.values[SensorManager.DATA_Y] * SPEED
    139. val tan = x / y
    140. val movey: Double
    141. val movex: Double
    142. if (x == 0f && y != 0f) {
    143. movex = 0.0
    144. movey = constantsSpeed.toDouble()
    145. } else if (x != 0f && y == 0f) {
    146. movex = constantsSpeed.toDouble()
    147. movey = 0.0
    148. } else if (x == 0f && y == 0f) {
    149. movex = 0.0
    150. movey = 0.0
    151. } else {
    152. val temp = constantsSpeed / (tan * tan + 1)
    153. movey = Math.sqrt(temp.toDouble()) // 开根号
    154. movex = movey * tan
    155. }
    156. moveTo(
    157. (if (x < 0) -Math.abs(movex) else Math.abs(movex)).toFloat(),
    158. (if (y < 0) -Math.abs(movey) else Math.abs(movey)).toFloat()
    159. )
    160. }
    161. // 注册重力感应监听
    162. private fun register() {
    163. sensorManager?.registerListener(listener, sensor, SensorManager.SENSOR_DELAY_GAME)
    164. }
    165. // 解除重力感应监听
    166. private fun unregister() {
    167. sensorManager?.unregisterListener(listener)
    168. Log.i("vv", "结束监听")
    169. }
    170. override fun onWindowFocusChanged(hasFocus: Boolean) {
    171. super.onWindowFocusChanged(hasFocus)
    172. if (hasFocus && !init) {
    173. init()
    174. init = true
    175. }
    176. }
    177. /**
    178. * 计算当前球的方向
    179. */
    180. private fun calc(event: SensorEvent): Int {
    181. val x = event.values[0]
    182. val y = event.values[1]
    183. val tempVertical: Int
    184. val tempHorizontal: Int
    185. tempHorizontal = when {
    186. x > 0 -> WEST
    187. x < 0 -> EAST
    188. else -> -1
    189. }
    190. tempVertical = when {
    191. y > 0 -> SOUTH
    192. y < 0 -> NORTH
    193. else -> -1
    194. }
    195. currentState = when {
    196. tempHorizontal == EAST && tempVertical == NORTH ->
    197. if (Math.abs(x) > Math.abs(y)) EAST else NORTH
    198. tempHorizontal == EAST && tempVertical == SOUTH ->
    199. if (Math.abs(x) > Math.abs(y)) EAST else SOUTH
    200. tempHorizontal == WEST && tempVertical == NORTH ->
    201. if (Math.abs(x) > Math.abs(y)) WEST else NORTH
    202. tempHorizontal == WEST && tempVertical == SOUTH ->
    203. if (Math.abs(x) > Math.abs(y)) WEST else SOUTH
    204. else -> currentState
    205. }
    206. return currentState
    207. }
    208. override fun onDestroy() {
    209. super.onDestroy()
    210. unregister()
    211. }
    212. override fun onPause() {
    213. super.onPause()
    214. unregister()
    215. }
    216. override fun onRestart() {
    217. super.onRestart()
    218. register()
    219. }
    220. override fun onResume() {
    221. super.onResume()
    222. register()
    223. }
    224. override fun onClick(v: View) {
    225. when (v.id) {
    226. R.id.accelerate -> adjustSpeedAndDuration(5)
    227. R.id.reduce -> adjustSpeedAndDuration(-5)
    228. R.id.normal -> {
    229. constantsSpeed = 10
    230. duration = 450
    231. }
    232. R.id.isShowBack -> isShotBack = !isShotBack
    233. }
    234. }
    235. /**
    236. * 改变小球的移动速度和变形时间
    237. * 因为移动速度越快,碰撞时间越短
    238. */
    239. private fun adjustSpeedAndDuration(change: Int) {
    240. constantsSpeed += change
    241. duration = if (change < 0) {
    242. duration + durationPiece
    243. } else {
    244. duration - durationPiece
    245. }
    246. when {
    247. constantsSpeed <= 5 -> {
    248. constantsSpeed = 5
    249. duration = 750
    250. }
    251. constantsSpeed >= 25 -> {
    252. constantsSpeed = 25
    253. duration = 150
    254. }
    255. }
    256. }
    257. }

     xml

    1. "http://schemas.android.com/apk/res/android"
    2. android:layout_width="match_parent"
    3. android:layout_height="match_parent"
    4. xmlns:tools="http://schemas.android.com/tools"
    5. tools:context=".ui.activity.AnimationActivity">
    6. android:id="@+id/ball_container"
    7. android:layout_width="match_parent"
    8. android:layout_height="match_parent">
    9. android:id="@+id/ball"
    10. android:layout_width="360dp"
    11. android:layout_height="360dp" />
    12. android:id="@+id/accelerate"
    13. android:layout_width="wrap_content"
    14. android:layout_height="wrap_content"
    15. android:text="加速" />
    16. android:id="@+id/reduce"
    17. android:layout_width="wrap_content"
    18. android:layout_height="wrap_content"
    19. android:layout_below="@id/accelerate"
    20. android:text="减速" />
    21. android:id="@+id/normal"
    22. android:layout_width="wrap_content"
    23. android:layout_height="wrap_content"
    24. android:layout_below="@id/reduce"
    25. android:text="正常速度" />
    26. android:id="@+id/isShowBack"
    27. android:layout_width="wrap_content"
    28. android:layout_height="wrap_content"
    29. android:layout_below="@id/normal"
    30. android:text="是否弹一弹" />

  • 相关阅读:
    VSCode修改主题为Eclipse 绿色护眼模式
    webpack--加载器(loader)
    【公众号文章备份】从零开始学或许是一个谎言
    进程控制——进程等待
    数据结构之顺序表及其实现!
    山东大学数字图像处理实验(一)
    CSS笔记(黑马程序员pink老师前端)选择器,字体,文本属性,Emmet语法,元素显示模式,CSS背景
    OSError: [WinError 1455] 页面文件太小,无法完成操作 报错解决
    vue2+elTree 实现右键菜单
    浮点数基础知识
  • 原文地址:https://blog.csdn.net/Chinese_H/article/details/139681217