MinesweeperGo/app/src/main/java/com/gogame/minesweeper/swipe/SwipeActivity.kt
2025-12-05 17:45:05 +08:00

369 lines
12 KiB
Kotlin
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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()
}
})
}
}