369 lines
12 KiB
Kotlin
369 lines
12 KiB
Kotlin
package com.gogame.minesweeper.swipe
|
||
|
||
import android.app.Dialog
|
||
import android.content.Context
|
||
import android.media.MediaPlayer
|
||
import android.os.Bundle
|
||
import android.os.Handler
|
||
import android.os.Looper
|
||
import android.view.View
|
||
import android.widget.ImageView
|
||
import android.widget.TextView
|
||
import androidx.core.view.ViewCompat
|
||
import androidx.core.view.WindowCompat
|
||
import androidx.core.view.WindowInsetsCompat
|
||
import com.gogame.minesweeper.DifficultyLevel
|
||
import com.gogame.minesweeper.R
|
||
import com.gogame.minesweeper.databinding.ActivitySwipeBinding
|
||
import com.gogame.minesweeper.BaseActivity
|
||
import com.gogame.minesweeper.ad.AdShowFailed
|
||
import com.gogame.minesweeper.ad.AdsInsUtil
|
||
import com.gogame.minesweeper.ad.LoadListener
|
||
import com.gogame.minesweeper.ad.ShowListener
|
||
import com.gogame.minesweeper.bean.GameState
|
||
import com.google.gson.Gson
|
||
import com.ironsource.fa
|
||
import com.thinkup.core.api.TUAdInfo
|
||
import kotlin.random.Random
|
||
|
||
class SwipeActivity : BaseActivity() {
|
||
|
||
private lateinit var binding: ActivitySwipeBinding
|
||
|
||
private var minutes = 0
|
||
private var seconds = 0
|
||
private var isRunning = false
|
||
private var pausedTime = 0L // 暂停时保存的时间戳
|
||
private var isGameStarted = false //游戏是否开始了
|
||
private var isGameOver = false //游戏是否结束了(不管成功还是失败)
|
||
private val handler = Handler(Looper.getMainLooper())
|
||
private lateinit var runnable: Runnable
|
||
private lateinit var winSoundPlayer: MediaPlayer
|
||
private lateinit var loseSoundPlayer: MediaPlayer
|
||
private var isNewGame = true
|
||
|
||
override fun onCreate(savedInstanceState: Bundle?) {
|
||
super.onCreate(savedInstanceState)
|
||
binding = ActivitySwipeBinding.inflate(layoutInflater)
|
||
setContentView(binding.root)
|
||
loadAd()
|
||
immersionBar()
|
||
winSoundPlayer = MediaPlayer.create(this, R.raw.win)
|
||
loseSoundPlayer = MediaPlayer.create(this, R.raw.explosion)
|
||
|
||
var difficulty = intent.getSerializableExtra("difficulty") as? DifficultyLevel
|
||
if (difficulty == null) {
|
||
difficulty = DifficultyLevel.BEGINNER
|
||
}
|
||
isNewGame = intent.getBooleanExtra("isNewGame", true)
|
||
initTimeRun()
|
||
|
||
resetTimer()
|
||
|
||
val sharedPreferences = getSharedPreferences("minesweeper_prefs", Context.MODE_PRIVATE)
|
||
val gameStateJson = sharedPreferences.getString("game_state", null)
|
||
|
||
binding.gridSwipe.postDelayed({
|
||
binding.gridSwipe.setDifficulty(difficulty)
|
||
setNumberImage(binding.gridSwipe.mineNum, binding.hundreds, binding.tens, binding.ones)
|
||
binding.gridSwipe.fillAll()
|
||
|
||
if (!isNewGame) {
|
||
if (!gameStateJson.isNullOrEmpty()) {
|
||
val gameState: GameState = Gson().fromJson(gameStateJson, GameState::class.java)
|
||
minutes = gameState.minutes
|
||
seconds = gameState.seconds
|
||
|
||
startTimeRun()
|
||
}
|
||
binding.gridSwipe.loadGameState()
|
||
}
|
||
}, 120)
|
||
|
||
binding.btnStart.setOnClickListener {
|
||
handleButtonClick()
|
||
}
|
||
binding.gridSwipe.listener = object : SwipeGridLayout.GameStateChange {
|
||
override fun onStart(rest: Int) {
|
||
isGameStarted = true
|
||
binding.stateImg.setImageResource(R.mipmap.smile)
|
||
startTimeRun()
|
||
}
|
||
|
||
override fun onFlagsChange(flags: Int, rest: Int) {
|
||
setNumberImage(rest, binding.hundreds, binding.tens, binding.ones)
|
||
}
|
||
|
||
override fun victory() {
|
||
isGameOver = true
|
||
playWinSound()
|
||
showResultDialog(true)
|
||
stopTimer()
|
||
|
||
binding.gridSwipe.clearGameStateSP()
|
||
}
|
||
|
||
override fun defeat() {
|
||
isGameOver = true
|
||
playLoseSound()
|
||
binding.stateImg.setImageResource(R.mipmap.sorrow)
|
||
showResultDialog(false)
|
||
stopTimer()
|
||
|
||
binding.gridSwipe.clearGameStateSP()
|
||
}
|
||
|
||
}
|
||
}
|
||
|
||
private fun immersionBar() {
|
||
//自适应沉浸式
|
||
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
|
||
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
|
||
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
|
||
insets
|
||
}
|
||
|
||
val windowInsetsController = WindowCompat.getInsetsController(window, window.decorView)
|
||
windowInsetsController.isAppearanceLightStatusBars = true//状态栏文字颜色
|
||
}
|
||
|
||
private val successImages = arrayOf(
|
||
R.drawable.win_emoji_partying_face, // 替换为你的成功图片资源
|
||
R.drawable.win_emoji_cowboy_hat_face,
|
||
R.drawable.win_emoji_smiling_face_with_sunglasses,
|
||
R.drawable.win_emoji_beaming_face_with_smiling_eyes
|
||
)
|
||
|
||
private val failureImages = arrayOf(
|
||
R.drawable.lose_emoji_bomb, // 替换为你的失败图片资源
|
||
R.drawable.lose_emoji_confounded_face,
|
||
R.drawable.lose_emoji_anguished_face,
|
||
R.drawable.lose_emoji_exploding_head, // 替换为你的失败图片资源
|
||
R.drawable.lose_emoji_grimacing_face,
|
||
R.drawable.lose_emoji_downcast_face_with_sweat,
|
||
R.drawable.lose_emoji_face_with_head_bandage,
|
||
R.drawable.lose_emoji_sad_but_relieved_face
|
||
)
|
||
|
||
private fun showResultDialog(isVictory: Boolean) {
|
||
val dialog = Dialog(this)
|
||
dialog.setContentView(R.layout.dialog_result)
|
||
|
||
val imageView = dialog.findViewById<ImageView>(R.id.imageView)
|
||
val titleTextView = dialog.findViewById<TextView>(R.id.textViewTitle)
|
||
val messageTextView = dialog.findViewById<TextView>(R.id.textViewMessage)
|
||
|
||
if (isVictory) {
|
||
val randomSuccessImage = successImages[Random.nextInt(successImages.size)]
|
||
imageView.setImageResource(randomSuccessImage)
|
||
titleTextView.text = getString(R.string.you_win)
|
||
messageTextView.text = getString(R.string.win_desc)
|
||
} else {
|
||
val randomFailureImage = failureImages[Random.nextInt(failureImages.size)]
|
||
imageView.setImageResource(randomFailureImage)
|
||
titleTextView.text = getString(R.string.you_lose)
|
||
messageTextView.text = getString(R.string.lose_desc)
|
||
}
|
||
|
||
val btn = dialog.findViewById<TextView>(R.id.newGameBtn)
|
||
btn.setOnClickListener {
|
||
handleButtonClick()
|
||
dialog.dismiss()
|
||
|
||
showAd(randomAdPlace)
|
||
}
|
||
dialog.setCancelable(false)
|
||
dialog.show()
|
||
}
|
||
|
||
|
||
private fun playWinSound() {
|
||
if (!winSoundPlayer.isPlaying) {
|
||
winSoundPlayer.start()
|
||
}
|
||
}
|
||
|
||
private fun playLoseSound() {
|
||
if (!loseSoundPlayer.isPlaying) {
|
||
loseSoundPlayer.start()
|
||
}
|
||
}
|
||
|
||
private fun handleButtonClick() {
|
||
binding.stateImg.setImageResource(R.mipmap.smile)
|
||
binding.gridSwipe.reset() // 复位逻辑
|
||
setNumberImage(
|
||
binding.gridSwipe.mineNum, binding.hundreds, binding.tens, binding.ones
|
||
) // 设置数字图片
|
||
stopTimer() // 停止计时器
|
||
resetTimer() // 重置计时器
|
||
}
|
||
|
||
private fun startTimeRun() {
|
||
if (!isRunning) {
|
||
isRunning = true
|
||
handler.post(runnable)
|
||
}
|
||
}
|
||
|
||
// 停止计时并移除 runnable
|
||
private fun stopTimer() {
|
||
isRunning = false
|
||
handler.removeCallbacks(runnable) // 移除 runnable,防止继续执行
|
||
}
|
||
|
||
private fun initTimeRun() {
|
||
// 初始化计时器
|
||
runnable = object : Runnable {
|
||
override fun run() {
|
||
if (isRunning) {
|
||
incrementTime()
|
||
updateTimeImage()
|
||
handler.postDelayed(this, 1000) // 每秒更新一次
|
||
}
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
private fun setNumberImage(
|
||
number: Int,
|
||
hundredsImageView: ImageView,
|
||
tensImageView: ImageView,
|
||
onesImageView: ImageView
|
||
) {
|
||
// 数字限制在1-999
|
||
if (number < 1 || number > 999) return
|
||
|
||
// 获取百位、十位、个位
|
||
val hundreds = number / 100
|
||
val tens = (number % 100) / 10
|
||
val ones = number % 10
|
||
|
||
// 根据数字设置图片资源ID,假设图片资源名为c0到c9
|
||
val resIdHundreds = getResourceIdForNumber(hundreds)
|
||
val resIdTens = getResourceIdForNumber(tens)
|
||
val resIdOnes = getResourceIdForNumber(ones)
|
||
|
||
// 设置ImageView的图片资源
|
||
hundredsImageView.setImageResource(resIdHundreds)
|
||
tensImageView.setImageResource(resIdTens)
|
||
onesImageView.setImageResource(resIdOnes)
|
||
}
|
||
|
||
// 获取数字对应的资源ID
|
||
private fun getResourceIdForNumber(num: Int): Int {
|
||
return when (num) {
|
||
0 -> R.mipmap.c0
|
||
1 -> R.mipmap.c1
|
||
2 -> R.mipmap.c2
|
||
3 -> R.mipmap.c3
|
||
4 -> R.mipmap.c4
|
||
5 -> R.mipmap.c5
|
||
6 -> R.mipmap.c6
|
||
7 -> R.mipmap.c7
|
||
8 -> R.mipmap.c8
|
||
9 -> R.mipmap.c9
|
||
else -> R.mipmap.c0 // 默认值,数字应为0-9
|
||
}
|
||
}
|
||
|
||
// 增加时间
|
||
private fun incrementTime() {
|
||
seconds++
|
||
if (seconds == 60) {
|
||
seconds = 0
|
||
minutes++
|
||
}
|
||
|
||
binding.gridSwipe.setTime(minutes, seconds)
|
||
}
|
||
|
||
// 更新时间的图片显示
|
||
private fun updateTimeImage() {
|
||
val minuteTens = minutes / 10
|
||
val minuteOnes = minutes % 10
|
||
val secondTens = seconds / 10
|
||
val secondOnes = seconds % 10
|
||
|
||
binding.minuteTens.setImageResource(getResourceIdForNumber(minuteTens))
|
||
binding.minuteOnes.setImageResource(getResourceIdForNumber(minuteOnes))
|
||
binding.secondTens.setImageResource(getResourceIdForNumber(secondTens))
|
||
binding.secondOnes.setImageResource(getResourceIdForNumber(secondOnes))
|
||
}
|
||
|
||
override fun onResume() {
|
||
super.onResume()
|
||
//如果游戏开始了并且游戏没有结束
|
||
if (isGameStarted && !isGameOver) {
|
||
if (pausedTime > 0L) {
|
||
// 继续计时
|
||
handler.post(runnable)
|
||
isRunning = true
|
||
}
|
||
}
|
||
}
|
||
|
||
override fun onPause() {
|
||
super.onPause()
|
||
|
||
// 保存当前的计时状态
|
||
pausedTime = System.currentTimeMillis()
|
||
isRunning = false
|
||
handler.removeCallbacks(runnable) // 停止计时
|
||
}
|
||
|
||
override fun onDestroy() {
|
||
super.onDestroy()
|
||
// 重置计时器
|
||
resetTimer()
|
||
//释放资源
|
||
binding.gridSwipe.onPlayerRelease()
|
||
winSoundPlayer.release()
|
||
loseSoundPlayer.release()
|
||
}
|
||
|
||
// 重置计时器为00:00
|
||
private fun resetTimer() {
|
||
minutes = 0
|
||
seconds = 0
|
||
updateTimeImage()
|
||
}
|
||
|
||
private var randomAdPlace = ""
|
||
private fun loadAd() {
|
||
// 生成一个随机索引
|
||
val randomIndex = Random.nextInt(AdsInsUtil.Placement.adPlaceAllList.size)
|
||
// 获取随机的广告位
|
||
randomAdPlace = AdsInsUtil.Placement.adPlaceAllList[randomIndex]
|
||
AdsInsUtil.loadAd(
|
||
act = this,
|
||
adID = randomAdPlace,
|
||
loadListener = object : LoadListener {
|
||
override fun loaded(ad: TUAdInfo) {
|
||
}
|
||
|
||
override fun loadFailed(error: String) {
|
||
}
|
||
})
|
||
}
|
||
private fun showAd(randomAdPlace: String) {
|
||
AdsInsUtil.showAd(
|
||
act = this,
|
||
adID = randomAdPlace,
|
||
listener = object : ShowListener {
|
||
override fun onAdShown(ad: TUAdInfo?) {
|
||
}
|
||
|
||
override fun onAdShowFailed(error: AdShowFailed?) {
|
||
loadAd()
|
||
}
|
||
|
||
override fun onAdClosed() {
|
||
loadAd()
|
||
}
|
||
})
|
||
}
|
||
}
|