Dice
Posted 临风而眠
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Dice相关的知识,希望对你有一定的参考价值。
Dice
我们一起来学习用Android studio做一个Dice roller 掷骰子APP,最终类似于一个随机数猜数小游戏,只是猜数字的形式换成了掷骰子
一.随机数
怎么表现掷骰子的随机性呢,我们很自然的会想到随机数,默默的想起了曾经玩飞行棋当过欧皇也经常当非洲人的经历,我们对C语言的随机数已经很熟悉,下面直接看kotlin语言的随机数代码:
fun main(){
val diceRange = 1..6
val randomNumber = diceRange.random()
println("Random number:${randomNumber}")
}
其中m..n
的用法是一个Kotlin整数范围,表示数字m到数字n(包括m,n)
random()函数是生成并返回给定范围内的随机数
注:
可直接对范围调用random()函数,如(1..6).random()
二.Dice类
kotlin作为一种和java比较类似的面向对象的语言,自然要用到类与对象,那么下面就把骰子的属性和方法封装到Dice类中
1.面数属性
先来测试一下:
fun main(){
val firstDice = Dice()//创建Dice类的对象实例
println(firstDice.sides)
}
class Dice{
var sides = 6//骰子有六个面
}
运行结果是6
看上面的代码会发现和C++类与对象的区别就是实例化的时候,如果用C++就是:
Dice firstDice
注:
与变量命名稍有不同,类名称采用驼峰式大小写形式。例如:AirPlane、OnlineBook 、Dice
2.掷骰子方法
掷骰子产生随机数就要用到前面的random()函数了
fun main(){
val firstDice = Dice()//创建Dice类的对象实例
firstDice.roll()
}
class Dice{
var sides = 6//骰子有六个面
fun roll(){
val randomNumber = (1..6).random()
println(randomNumber)
}
}
学过C++的话上面代码非常好理解
注:
函数和方法的命名惯例是以小写字母开头,采用驼峰式大小写形式,尽可能以操作动词开头
函数返回值
指定返回类型的语法如下:在函数名称后面,在括号后添加冒号、空格,然后为函数返回类型添加关键字
fun main() {
val firstDice = Dice()
val diceRoll = firstDice.roll()
println("Your ${firstDice.sides} sided dice rolled ${diceRoll}!")
}
class Dice {
var sides = 6
fun roll(): Int {
val randomNumber = (1..6).random()
return randomNumber
}
}
3.自定义骰子
自定义骰子的面数numSides
fun main() {
val firstDice = Dice(6)
println("Your ${firstDice.numSides} sided dice rolled ${firstDice.roll()}!")
val secondDice = Dice(20)
println("Your ${secondDice.numSides} sided dice rolled ${secondDice.roll()}!")
}
class Dice (val numSides: Int) {
fun roll(): Int {
return (1..numSides).random()
}
}
三.创建交互按钮
下面就可以去android studio中操作了,先用empty activity新建一个project
1.添加button
打开activity_main.xml,选择Button拖动到显示“Hello world!”的那个TextView下面
2.确定button位置
Button要在TextView正下方,拖动使其重重合
添加从 Button 的左侧和右侧到父级 ConstraintLayout的左侧和右侧的水平约束条件。
3.修改button文字
在Button的text属性里面改成你想要的文字,老问题,规范编码@string
我们之后需要在button上面的textview上显示骰子的点数,所以先把Hello world删掉,此处介绍一个调试功能
tools text
这些文字仅在布局预览中显示,在应用运行时不会显示
4.添加button交互
我们需要实现点击button 就显示骰子的点数
先介绍下导包的配置
用过python和Java 都知道import导包
在这里找到Settings for New Projects
继续找到Auto Import
设置成如下配置
Add unambiguous imports on the fly能让 Android Studio 智能补全import
Optimize imports on the fly(for current project)设置会指示 Android Studio 移除unused的导包
在Mainactivity.kt中添加代码
首先调用setContentView方法,关于这个方法,可以看这位大佬的简书的详细解释
findViewById
val rollButton: Button = findViewById(R.id.button)
findViewById() 方法在布局中找到 Button。R.id.button是 Button 的资源 ID,该 ID 是 Button 的唯一标识符
代码将 Button 对象的引用保存到名为 rollButton 的变量中**,而不是保存 Button 对象本身**(引用的概念学过C++应该知道)
Android 会自动为应用中的资源分配 ID 号。例如,Roll 按钮具有资源 ID,按钮文字的字符串也具有资源 ID资源 ID 的格式为 R.<type>.<name>
;例如 R.string.roll
。对于 View
ID,<type>
为 id
,例如 R.id.button
鼠标监听事件setOnClickListener()
val rollButton: Button = findViewById(R.id.button)
rollButton.setOnClickListener {
val toast = Toast.makeText(this, "Dice Rolled!", Toast.LENGTH_SHORT)
toast.show()
}
其中Toast是一条向用户显示的简短消息
通过调用 Toast.makeText()创建包含文字 “Dice Rolled!” 的 Toast,再调用show()方法让Toast自行显示
也可以将两行代码合为一行
Toast.makeText(this, "Dice Rolled!", Toast.LENGTH_SHORT).show()
效果如下:
点击Button后,下方显示一条简短消息
点击 Button 时更新 TextView
最终代码:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val rollButton: Button = findViewById(R.id.button)
rollButton.setOnClickListener {
val resultTextView: TextView = findViewById(R.id.textView)
resultTextView.text = "6"
}
}
}
现在就实现了如下效果
5.添加掷骰子逻辑
完整代码如下
package com.example.dice_roller
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import android.widget.TextView
import android.widget.Toast
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val rollButton: Button = findViewById(R.id.button)
rollButton.setOnClickListener {
rollDice()
}
}
private fun rollDice() {
val dice=Dice(6)
val diceRoll = dice.roll()
val resultTextView: TextView = findViewById(R.id.textView)
resultTextView.text=diceRoll.toString()
}
}
class Dice(private val numSides: Int){
fun roll(): Int{
return(1..numSides).random()
}
}
toString()是把diceRoll的数字转化为TextView的text属性所需使用的文字
感觉学下来和当时用C++做Qt的时候很相像
效果如下,每点击一次就会随机显示1到numSides的数字
6.代码习惯优化
先全选,再使用键盘快捷键 Ctrl+Alt+L
格式化代码
在每个方法与类前面添加注释
package com.example.dice_roller
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import android.widget.TextView
import android.widget.Toast
/**
* 用户掷骰子,并且能在屏幕上看到结果
*/
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val rollButton: Button = findViewById(R.id.button)
rollButton.setOnClickListener {
rollDice()
}
}
/**
* 点击掷骰子,就更新数字
*/
private fun rollDice() {
//实例化6个面的骰子对象
val dice = Dice(6)
val diceRoll = dice.roll()
//更新数字
val resultTextView: TextView = findViewById(R.id.textView)
resultTextView.text = diceRoll.toString()
}
}
/**
* 骰子类
* 属性:面数
* 方法:返回随机数
*/
class Dice(private val numSides: Int) {
fun roll(): Int {
return (1..numSides).random()
}
}
四.游戏逻辑
在最开头的时候说了,最终类似于一个随机数猜数小游戏,只是猜数字的形式换成了掷骰子
那我们就设置一个幸运数字luckyNumber
1.if else
下面的代码和C语言很像,判断语句也和C语言差不多,较容易看懂,
fun main() {
val myFirstDice = Dice(6)
val rollResult = myFirstDice.roll()
val luckyNumber = 4
if (rollResult == luckyNumber) {
println("You win!")
} else if (rollResult == 1) {
println("So sorry! You rolled a 1. Try again!")
} else if (rollResult == 2) {
println("Sadly, you rolled a 2. Try again!")
} else if (rollResult == 3) {
println("Unfortunately, you rolled a 3. Try again!")
} else if (rollResult == 4) {
println("No luck! You rolled a 4. Try again!")
} else if (rollResult == 5) {
println("Don't cry! You rolled a 5. Try again!")
} else {
println("Apologies! you rolled a 6. Try again!")
}
}
class Dice(val numSides:Int){
fun roll():Int{
return (1..numSides).random()
}
}
这个和刚学C语言的时候学的猜数游戏就是新瓶子里装旧酒啊
2.when (类似于C的switch)
C语言中,如果条件很多,要写好多的if,else于是有时候我们会选择switch
那么在kotlin中,类似的就是when,就是把C语言中的case : 换成了->
直接看代码吧
fun main() {
val myFirstDice = Dice(6)
val rollResult = myFirstDice.roll()
val luckyNumber = 4
when (rollResult) {
luckyNumber -> println("You won!")
1 -> println("So sorry! You rolled a 1. Try again!")
2 -> println("Sadly, you rolled a 2. Try again!")
3 -> println("Unfortunately, you rolled a 3. Try again!")
4 -> println("No luck! You rolled a 4. Try again!")
5 -> println("Don't cry! You rolled a 5. Try again!")
6 -> println("Apologies! you rolled a 6. Try again!")
}
}
class Dice(val numSides:Int){
fun roll():Int{
return (1..numSides).random()
}
}
五.加入Dice
1.更新布局
删除TextView,并将一个ImageView拖动到Button上方
选择 Sample data 中的 avatars作为临时图片
确定 ImageView 和 Button 的位置
- 为 ImageView 添加水平约束条件。将 ImageView 的左侧与父级 ConstraintLayout 的左边缘连接起来
- 将 ImageView 的右侧与父级的右边缘连接起来。这会使 ImageView 在父级内水平居中
- 为 ImageView 添加垂直约束条件,将 ImageView 的顶部与父级的顶部连接起来。ImageView 会向上滑动到 ConstraintLayout的顶部
- 为 Button 添加垂直约束条件,将 Button 的顶部与 ImageView 的底部连接起来。Button 会向上滑动到ImageView的下方
- 再次选择 ImageView,然后添加垂直约束条件,将 ImageView 的底部与父级的底部连接起来。这会使 ImageView 在 ConstraintLayout内垂直居中
此时已经居中
2.导入骰子图片
如果在APP内没有骰子,真的就变成纯猜数游戏了,下面我们就加入骰子的图片
图片下载链接点击👉这里
按我的上一篇博客里所说的导入图片的方法把六张骰子的图片导入
3.替换临时图片
找到ImageView的设置为头像图片的工具 srcCompat 属性
点击那个小头像,进入此界面,先选择dice_1
emm…too big,调整大小
- 找到layout_width 和 layout_height 属性。它们当前设置为 wrap_content,这意味着
ImageView
的高度和宽度将与其中的内容(源图片)保持一致。 - 为
ImageView
设置 160dp 的固定宽度和 200dp 的固定高度。按 Enter 键。
还需要调整Button和ImageView之间的距离,在 Constraint Widget 中将按钮的上边距设置为 16dp
4.修改代码
下面就要修改代码啦,掷出数字几,骰子就显示那一面
注
控件的id可以在Attributes中看到
将rollDice()方法改成如下:
private fun rollDice() {
//实例化6个面的骰子对象
val dice = Dice(6)
val diceRoll = dice.roll()
//更新数字
val diceImage: ImageView = findViewById(R.id.imageView)
when (diceRoll) {
1 -> diceImage.setImageResource(R.drawable.dice_1)
2 -> diceImage.setImageResource(R.drawable.dice_2)
3 -> diceImage.setImageResource(R.drawable.dice_3)
4 -> diceImage.setImageResource(R.drawable.dice_4)
5 -> diceImage.setImageResource(R.drawable.dice_5)
6 -> diceImage.setImageResource(R.drawable.dice_6)
}
}
优化代码
上面的rollDice()方法中,调用了6次diceImage.setImageResource()
改成下面的,就只需要调用一次
val drawableResource = when(diceRoll) {
1 -> R.drawable.dice_1
2 -> R.drawable.dice_2
3 -> R.drawable.dice_3
4 -> R.drawable.dice_4
5 -> R.drawable.dice_5
6 -> R.drawable.dice_6
}
diceImage.setImageResource(drawableResource)
但此时,when下面出现了红色下划线
出现该错误的原因是 when
表达式的值被赋给 drawableResource
,因此 when
必须涵盖所有情况,它必须处理所有可能的情况,这样,即使您更改为 12 面的骰子,也始终会返回值。Android Studio 建议添加一个 else
分支。您可以通过将 6
的情况更改为 else
来解决此问题。从 1
到 5
的情况不变,但包括 6
在内的所有其他情况都通过 else
处理
val drawableResource = when (diceRoll) {
1 -> R.drawable.dice_1
2 -> R.drawable.dice_2
3 -> R.drawable.dice_3
4 -> R.drawable.dice_4
5 -> R.drawable.dice_5
else -> R.drawable.dice_6
}
diceImage.setImageResource(drawableResource)
5.优化界面,添加代码注释
首次打开APP时,也应该显示一个随机的骰子,让用户一目了然这个APP是干什么的,于是在onCreate方法中添加代码
有点像C++里面的构造函数,自动调用
rollDice()
完整代码如下:
package com.example.dice_roller
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import android.widget.ImageView
import android.widget.TextView
import android.widget.Toast
/**
* 用户掷骰子,并且能在屏幕上看到结果
*/
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val rollButton: Button = findViewById(R.id.button)
rollButton.setOnClickListener {
rollDice()
}
//APP初始化的时候就出现骰子
rollDice()
}
/**
* 点击掷骰子,就更新数字
*/
private fun rollDice() {
//实例化6个面的骰子对象
val dice = Dice(6)
val diceRoll = dice.roll()
//更新数字
val diceImage: ImageView = findViewById(R.id.imageView)
val drawableResource = when (diceRoll) {
1 -> R.drawable.dice_1
2 -> R.drawable.dice_2
3 -> R.drawable.dice_3
4 -> R.drawable.dice_4
5 -> R.drawable.dice_5
else -> R.drawable.dice_6
}
//更新显示的图片资源
diceImage.setImageResource(drawableResource)
//屏幕阅读器可以朗读此内容说明 需要添加
diceImage.contentDescription = diceRoll.toString()
}
}
/**
* 骰子类
* 属性:面数
* 方法:返回随机数
*/
class Dice(private val numSides: Int) {
fun roll(): Int {
return (1..numSides).random()
}
}
下面就可以尽情玩耍啦!😃
想把自己做的APP分享给别人一起玩点击菜单栏的Build-Build APKs,然后把.apk文件发给别人就可以啦!😄
以上是关于Dice的主要内容,如果未能解决你的问题,请参考以下文章
CodeForces 534C - Polycarpus' Dice(思路)
SP1026 FAVDICE - Favorite Dice