我在 Android 上创建了简单的游戏。现在我想增加难度级别,我想知道该采取什么方法。我的意思是,我只需要更改类内的一个对象(CountDownTimer)即可改变该难度,首先我认为我将为每个级别只创建 3 个类,但我的直觉告诉我这将是大材小用。做一个类并继承它?或者也许以某种方式创建一个带有参数的对象?你能提出一些建议吗?
package com.whayway.beerrandom
import android.os.Bundle
import android.os.CountDownTimer
import android.os.Handler
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import androidx.databinding.DataBindingUtil
import androidx.fragment.app.Fragment
import androidx.navigation.findNavController
import com.whayway.beerrandom.databinding.FragmentGameBinding
import kotlinx.android.synthetic.main.fragment_game.*
import java.util.*
const val KEY_SCORE = "score_key"
class GameFragment : Fragment() {
var handler: Handler = Handler()
var score: Int = 0
var runnable: Runnable = Runnable { }
var imageArray = ArrayList<ImageView>()
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val binding = DataBindingUtil.inflate<FragmentGameBinding>(
inflater, R.layout.fragment_game, container, false
)
score = 0
if(savedInstanceState != null){
score = savedInstanceState.getInt(KEY_SCORE, 0)
}
hideImages()
object : CountDownTimer(15000, 1000) {
override fun onTick(p0: Long) {
btn_ok.visibility = View.INVISIBLE
timeText.text = "Time: " + (p0 / 1000)
}
override fun onFinish() {
timeText.text = "Time out"
handler.removeCallbacks(runnable)
for (image in imageArray) {
image.visibility = View.INVISIBLE
btn_ok.visibility = View.VISIBLE
}
}
}.start()
score = 0
setHasOptionsMenu(true)
/* val args = .fromBundle(arguments!!)
Toast.makeText(context, "NumCorrect: ${args.numCorrect}, NumQuestions: ${args.numQuestions}", Toast.LENGTH_LONG).show()*/
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
imageArray = arrayListOf(
imageView8,
imageView7,
imageView6,
imageView5,
imageView4,
imageView3,
imageViewPawel,
imageView111
)
scoreText.setOnClickListener {}
imageView8.setOnClickListener { increaseScore() }
imageView7.setOnClickListener { increaseScore() }
imageView8.setOnClickListener{increaseScore() }
imageView6.setOnClickListener { increaseScore() }
imageView5.setOnClickListener { increaseScore() }
imageView4.setOnClickListener { increaseScore()
setImage() }
imageView3.setOnClickListener { decreaseScore()
setImage() }
imageViewPawel.setOnClickListener { increaseScorePawel()
setImage()}
imageView111.setOnClickListener { increaseScore()
setImage()}
btn_ok.setOnClickListener { view: View ->
view.findNavController().navigate(
GameFragmentDirections
.actionGameFragmentToResultFragment(score)
)
}
super.onViewCreated(view, savedInstanceState)
}
private fun setImage(){
var drawableArray = ArrayList<Int>()
drawableArray = arrayListOf(
R.drawable.pawel,
R.drawable.leszek,
R.drawable.lech_free)
val random = Random()
val index = random.nextInt(3 - 1)
val index2 = random.nextInt(8 - 1)
imageArray[index2].setImageResource(drawableArray[index])
}
private fun hideImages() {
runnable = Runnable {
for (image in imageArray) {
image.visibility = View.INVISIBLE
}
val random = Random()
val index = random.nextInt(8 - 1)
imageArray[index].visibility = View.VISIBLE
handler.postDelayed(runnable, 500)
}
handler.post(runnable)
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putInt(KEY_SCORE, score)
}
private fun increaseScore() {
score++
scoreText.text = "Score:" + score
}
private fun increaseScorePawel() {
score += 5
scoreText.text = "Score:" + score
}
private fun decreaseScore() {
score -= 10
scoreText.text = "Score:" + score
}
}
最佳答案
您的问题没有单一的最佳答案,但对我来说最有意义的解决方案是创建 CountDownTimer 的实现。
我不确定您想要在计数器内部更改什么,但您应该能够通过将值传递给构造函数来处理大多数事情:
class GameTimer(interval: Long) : CountDownTimer(15000, interval) {
...
}
或回调(自定义行为):
class GameTimer(onTimeOut: () -> Unit) : CountDownTimer(15000, 1000) {
...
override fun onFinish() { onTimeOut() }
}
我认为引入工厂设计模式是一个好主意。因为这对你来说可能毫无意义,让我给你看一个例子:
// could be also a class with constructor parameters, it all depends on your use case
object GameTimerFactory {
fun easyGameTimer() = GameTimer(1000)
fun mediumGameTimer() = GameTimer(800)
fun hardGameTimer() = GameTimer(650)
}
根据您从更高级别组件调用它的方式,您可能需要使用枚举:
enum class Difficulty { EASY, MEDIUM, HARD }
object GameTimerFactory {
fun gameTimerFor(difficulty: Difficulty): GameTimer = when (difficulty) {
...
}
}
还有一个提示:明智的做法是从 Android 逻辑中提取游戏逻辑,以符合 SoC principle 的要求。 。 tl;dr:在每个程序中都有一些层,例如在您的程序中,我们可以轻松地看到一个显示游戏的 Android 特定层和一个包含游戏规则的层。如果您想将游戏移植到其他平台(例如桌面),它会很有用,如果您想对游戏逻辑进行单元测试,它几乎是必要的。有很多很好的解释:
关于java - 使用一个类的最佳方式,内部只更改一个对象 - Kotlin/Android/Java,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64042099/