1. 准备工作
在此在线课程的 Codelab 中,您将构建一个 Dice Roller Android 应用。当用户“掷骰子”时,系统会生成一个随机结果。生成结果时会考虑骰子的面数。例如,6 面的骰子,只能生成 1 到 6 的值。
下面是最终应用呈现的样子。

为帮助您专注于了解此应用的全新编程概念,您将使用基于浏览器的 Kotlin 编程工具来创建核心应用功能。该程序会将您的结果输出到控制台。之后您将在 Android Studio 中实现界面。
在此第一个 Codelab 中,您将创建一个 Kotlin 程序,以模拟掷骰子并输出一个随机数字,就像实际掷骰子的情形一样。
前提条件
- 已了解如何在 https://developer.android.com/training/kotlinplayground 中打开、修改和运行代码
- 能够创建并运行使用变量和函数的 Kotlin 程序,并将结果输出到控制台。
- 能够使用采用
${variable}表示法的字符串模板设置文本中数字的格式。
学习内容
- 如何编写程序来生成随机数字以模拟掷骰子。
- 如何使用变量和方法创建
Dice类,以构建代码。 - 如何创建类的对象实例、修改其变量以及调用其方法。
构建内容
- 使用基于浏览器的 Kotlin 编程工具构建可执行随机掷骰子操作的 Kotlin 程序。
所需条件
- 一台已连接到互联网的计算机
2. 掷出随机数字
游戏通常具有随机性。您可以赢得随机奖励,或在棋盘游戏中移动随机步数。在日常生活中,您可以使用随机数字和字母来生成更安全的密码!
您可以编写一个程序来模拟掷骰子,而无需真的掷骰子。每次掷骰子时,结果可以是可能值范围内的任何数字。幸运的是,您无需为此类程序自行构建随机数字生成器。大多数编程语言(包括 Kotlin)都内置有用于生成随机数字的方法。在此任务中,您将使用 Kotlin 代码来生成随机数字。
设置起始代码
- 在浏览器中,打开网站 https://developer.android.com/training/kotlinplayground。
- 删除代码编辑器中的所有现有代码,并将其替换为以下代码。这是您在之前的 Codelab 中使用的
main()函数。
fun main() {
}
使用随机函数
如要掷骰子,您需要一种方法来表示所有有效的掷骰结果值。对于常规的 6 面骰子,可接受的掷骰结果值包括:1、2、3、4、5 和 6。
在前面的课程中,您学习了数据类型,比如 Int 表示整数,String 表示文字。IntRange 是另一种数据类型,表示从起始值到结束值的整数范围。IntRange 是适合用于表示掷骰可能产生的值的数据类型。
- 在
main()函数中,将一个变量定义为名为diceRange的val。将其分配给 1 到 6 的IntRange,用于表示 6 面骰子可以掷出的整数值范围。
val diceRange = 1..6
可以看出,1..6 是一个 Kotlin 范围,因为它包含起始数字、两个点以及一个结束数字(中间没有空格)。下面再列举两个整数范围的其他例子,2..5 表示数字 2 到 5,100..200 表示数字 100 到 200。
与调用 println() 可指示系统输出给定文本类似,您可以使用 random() 函数生成并返回给定范围内的随机数字。同之前一样,您可以将结果存储在变量中。
- 在
main()中,将一个变量定义为名为randomNumber的val。 - 为
randomNumber设置对diceRange范围调用random()的结果值,如下所示。
val randomNumber = diceRange.random()
请注意,在变量和函数调用之间使用一个句点(即点),即可对 diceRange 调用 random()。您可以将其解读为“从 diceRange 中生成随机数字”。然后结果会存储在 randomNumber 变量中。
- 为了显示随机生成的数字,请使用字符串格式表示法(也称为“字符串模板”)
${randomNumber}进行输出,如下所示。
println("Random number: ${randomNumber}")
完成后的代码应如下所示。
fun main() {
val diceRange = 1..6
val randomNumber = diceRange.random()
println("Random number: ${randomNumber}")
}
- 运行几次代码。每次,您都应看到如下输出内容,其中会显示不同的随机数字。
Random number: 4
3. 创建 Dice 类
当您掷骰子时,它们是您手中的真实物体。而您刚刚编写的代码尽管可以正常运行,但是很难将其与真实的骰子关联起来。编写程序时,如果能让程序更贴合其表示的事物,就会更容易让人理解。所以,如果能用程序创建一个可以投掷的骰子,那就太棒了!
所有骰子的工作原理基本都相同。它们具有相同的属性(如骰面)、相同的行为(例如可以滚动)。在 Kotlin 中,您可以创建骰子的程序蓝图,说明骰子有骰面,并可以掷出一个随机数字。此蓝图称为“类”。
然后,您可以在该类中创建称为“对象实例”的真实骰子对象。例如,您可以创建 12 面的骰子或 4 面的骰子。
定义 Dice 类
在以下步骤中,您将定义一个名为 Dice 的新类来表示可滚动的骰子。
- 为了重新开始,请清除
main()函数中的代码,确保最终代码如下所示。
fun main() {
}
- 在此
main()函数下,添加一个空行,然后添加代码以创建Dice类。如下所示,先输入关键字class,后跟类名称,再跟左大括号和右大括号。在大括号内留出空间,以便放入类的代码。
class Dice {
}
在类定义中,可以使用变量为类指定一个或多个属性。真实的骰子可以具有多个面、一种颜色或重量。在此任务中,您将着重处理骰子的面数属性。
- 在
Dice类中,添加一个名为sides的var,用于表示骰子将具有的面数。将sides设置为 6。
class Dice {
var sides = 6
}
大功告成。现在,您有了一个表示骰子的非常简单的类。
创建 Dice 类的实例
有了这个 Dice 类,您就有了表示骰子的蓝图。为了在程序中呈现出一个真实的骰子,您需要创建一个 Dice 对象实例。(如果您需要有三个骰子,就要创建三个对象实例。)

- 为了创建
Dice的对象实例,请在main()函数中创建一个名为myFirstDice的val,并将其初始化为Dice类的实例。请注意类名称后面的括号,其表示您在通过该类创建一个新的对象实例。
fun main() {
val myFirstDice = Dice()
}
现在,您已经有了依据蓝图构建的 myFirstDice 对象,接下来可以访问其属性了。Dice 的唯一属性是其 sides。您使用“点分表示法”访问属性。因此,如需访问 myFirstDice 的 sides 属性,请调用 myFirstDice.sides,这读作“myFirstDice 点 sides”。
- 在
myFirstDice声明的下方,添加println()语句以输出myFirstDice.的sides数量。
println(myFirstDice.sides)
您的代码应如下所示。
fun main() {
val myFirstDice = Dice()
println(myFirstDice.sides)
}
class Dice {
var sides = 6
}
- 运行程序,它应输出在
Dice类中定义的sides的数量。
6
现在,您有了一个 Dice 类和一个具有 6 个 sides 的真实骰子 myFirstDice。
我们来掷骰子吧!
掷骰子
您之前曾使用函数执行过输出蛋糕层的操作。掷骰子操作也可以用函数实现。由于所有骰子都可以滚动,因此您可以在 Dice 类中为其添加一个函数。在类中定义的函数也称为方法。
- 在
Dice类的sides变量下方,插入一个空行,然后创建一个用于掷骰子的新函数。首先输入 Kotlin 关键字fun,再输入方法的名称,然后是括号(),然后再是左大括号和右大括号{}。可以在大括号内留一个空行,以便输入更多代码,如下所示。您的类应如下所示。
class Dice {
var sides = 6
fun roll() {
}
}
当您掷一个六面骰子时,它会产生一个从 1 到 6 的随机数字。
- 在
roll()方法中,创建一个val randomNumber。在1..6范围内为其分配一个随机数字。使用点分表示法对该范围调用random()。
val randomNumber = (1..6).random()
- 生成随机数字后,将其输出到控制台。完成后的
roll()方法应如以下代码所示。
fun roll() {
val randomNumber = (1..6).random()
println(randomNumber)
}
- 为了真实地滚动
myFirstDice,请在main()中对myFirstDice调用roll()方法。您使用“点分表示法”调用方法。因此,为了对myFirstDice调用roll()方法,请输入myFirstDice.roll(),这读作“myFirstDicedotroll()”。
myFirstDice.roll()
完成后的代码应如下所示。
fun main() {
val myFirstDice = Dice()
println(myFirstDice.sides)
myFirstDice.roll()
}
class Dice {
var sides = 6
fun roll() {
val randomNumber = (1..6).random()
println(randomNumber)
}
}
- 运行代码!您应会看到随机掷骰子的结果小于骰子面数。多运行几次代码,会发现面数保持不变,掷骰子的结果值发生变化。
6 4
祝贺您!您已使用 sides 变量和 roll() 函数定义了 Dice 类。在 main() 函数中,您创建了一个新的 Dice 对象实例,然后对该实例调用了 roll() 方法,以生成随机数字。
4. 返回您掷骰子的结果值
您目前是在 roll() 函数中输出 randomNumber 的值,运行一切正常!但有时,将函数的结果返回给调用该函数的对象会更有用。例如,您可以将 roll() 方法的结果分配给某个变量,然后将玩家移动相应的步数!我们来看看具体操作方法。
- 在
main()中,修改显示myFirstDice.roll()的代码行。创建名为diceRoll的val。将其设置为与roll()方法返回的值相等。
val diceRoll = myFirstDice.roll()
目前还没有任何效果,因为 roll() 尚未返回任何内容。为了使上述代码按预期运行,roll() 必须返回一些内容。
在之前的 Codelab 中,您了解到需要为函数的输入参数指定数据类型。同样,您也必须为函数返回的数据指定数据类型。
- 更改
roll()函数以指定将返回的数据类型。在本例中,随机数字为Int,因此返回类型为Int。指定返回类型的语法如下:在函数名称后面,在括号后添加冒号、空格,然后为函数返回类型添加Int关键字。函数定义应如下代码所示。
fun roll(): Int {
- 运行该代码。您将在问题视图中看到一个错误。错误内容是:
A ‘return' expression required in a function with a block body (‘{...}')
您将函数定义改为了返回 Int,但系统提示说您的代码实际上并未返回 Int。“块主体”或“函数主体”是指函数大括号内的代码。您可以修复此错误,方法是在函数主体末尾使用 return 语句从函数返回值。
- 在
roll()中,移除println()语句,并将其替换为randomNumber的return语句。您的roll()函数应如以下代码所示。
fun roll(): Int {
val randomNumber = (1..6).random()
return randomNumber
}
- 在
main()中,移除有关骰子面数的输出语句。 - 添加一个语句,用信息性句子输出
sides和diceRoll的值。您完成的main()函数应类似于以下代码。
fun main() {
val myFirstDice = Dice()
val diceRoll = myFirstDice.roll()
println("Your ${myFirstDice.sides} sided dice rolled ${diceRoll}!")
}
- 运行代码,输出应如下所示。
Your 6 sided dice rolled 4!
以下是到目前为止所编写的所有代码。
fun main() {
val myFirstDice = Dice()
val diceRoll = myFirstDice.roll()
println("Your ${myFirstDice.sides} sided dice rolled ${diceRoll}!")
}
class Dice {
var sides = 6
fun roll(): Int {
val randomNumber = (1..6).random()
return randomNumber
}
}
5. 更改骰子的面数
并非所有骰子都有 6 个面!骰子形状各异,大小不一:有 4 面的、8 面的,还有 120 面的!
- 在
Dice类的roll()方法中,将硬编码的1..6更改为使用sides,这样,范围和掷出的随机数字将始终适用于面数。
val randomNumber = (1..sides).random()
- 在
main()函数中,在输出掷骰结果的后面,将myFirstDice的sides设置为 20。
myFirstDice.sides = 20
- 复制下面的现有输出语句并将其粘贴在更改面数的位置下方。
- 将
diceRoll的输出结果替换为对myFirstDice调用roll()方法的输出结果。
println("Your ${myFirstDice.sides} sided dice rolled ${myFirstDice.roll()}!")
您的程序应如下所示。
fun main() {
val myFirstDice = Dice()
val diceRoll = myFirstDice.roll()
println("Your ${myFirstDice.sides} sided dice rolled ${diceRoll}!")
myFirstDice.sides = 20
println("Your ${myFirstDice.sides} sided dice rolled ${myFirstDice.roll()}!")
}
class Dice {
var sides = 6
fun roll(): Int {
val randomNumber = (1..sides).random()
return randomNumber
}
}
- 运行程序,您应该会看到一条有关 6 面骰子的消息,以及另一条有关 20 面骰子的消息。
Your 6 sided dice rolled 3! Your 20 sided dice rolled 15!
6. 自定义骰子
类的概念是代表一个事物,通常是现实世界中的事物。在本例中,Dice 类代表实际的骰子。在现实世界中,骰子的面数是不会变的。如果您需要不同的面数,就需要使用不同的骰子。在编程上,这意味着您应该创建一个具有所需面数的新骰子对象实例,而不是更改现有 Dice 对象实例的面数属性。
在此任务中,您将修改 Dice 类,以便在创建新实例时指定面数。您将更改 Dice 类定义,以便可以提供面数。这类似于函数接受输入参数的方式。
- 修改
Dice类定义,以接受名为numSides的整数。类中的代码不变。
class Dice(val numSides: Int) {
// Code inside does not change.
}
- 在
Dice类中,删除sides变量,因为您现在可以使用numSides。 - 此外,修改范围以使用
numSides。
您的 Dice 类应如下所示。
class Dice (val numSides: Int) {
fun roll(): Int {
val randomNumber = (1..numSides).random()
return randomNumber
}
}
如果运行这段代码,您将看到大量错误,因为需要更新 main() 才能使用对 Dice 类的更改。
- 在
main()中,为了创建具有 6 个面的myFirstDice,您现在必须提供面数作为Dice类的参数,如下所示。
val myFirstDice = Dice(6)
- 在输出语句中,将
sides更改为numSides。 - 然后在下方,删除将
sides更改为 20 的代码,因为该变量已不存在。 - 同时删除其下方的
println语句。
您的 main() 函数应类似于以下代码,如果运行该代码段,应该不会再出现错误了。
fun main() {
val myFirstDice = Dice(6)
val diceRoll = myFirstDice.roll()
println("Your ${myFirstDice.numSides} sided dice rolled ${diceRoll}!")
}
- 输出第一个掷骰结果后,添加代码以创建并输出第二个名为
mySecondDice的Dice对象,其具有 20 个面。
val mySecondDice = Dice(20)
- 添加用于掷骰并输出返回值的输出语句。
println("Your ${mySecondDice.numSides} sided dice rolled ${mySecondDice.roll()}!")
- 完成后的
main()函数应如下所示。
fun main() {
val myFirstDice = Dice(6)
val diceRoll = myFirstDice.roll()
println("Your ${myFirstDice.numSides} sided dice rolled ${diceRoll}!")
val mySecondDice = Dice(20)
println("Your ${mySecondDice.numSides} sided dice rolled ${mySecondDice.roll()}!")
}
class Dice (val numSides: Int) {
fun roll(): Int {
val randomNumber = (1..numSides).random()
return randomNumber
}
}
- 运行已完成的程序,输出内容应如下所示。
Your 6 sided dice rolled 5! Your 20 sided dice rolled 7!
7. 采用规范的编码做法
编写代码时,应尽量简洁。您可以去掉 randomNumber 变量并直接返回随机数字。
- 更改
return语句以直接返回随机数字。
fun roll(): Int {
return (1..numSides).random()
}
在第二个输出语句中,您将用于获取随机数的调用放入字符串模板。您可以按照在第一个输出语句中采用的相同方法来去掉 diceRoll 变量。
- 在字符串模板中调用
myFirstDice.roll()并删除diceRoll变量。您的main()代码的前两行现在如下所示。
val myFirstDice = Dice(6)
println("Your ${myFirstDice.numSides} sided dice rolled ${myFirstDice.roll()}!")
- 运行代码,输出内容应该没有变化。
以下是您重构后的最终代码。
fun main() {
val myFirstDice = Dice(6)
println("Your ${myFirstDice.numSides} sided dice rolled ${myFirstDice.roll()}!")
val mySecondDice = Dice(20)
println("Your ${mySecondDice.numSides} sided dice rolled ${mySecondDice.roll()}!")
}
class Dice (val numSides: Int) {
fun roll(): Int {
return (1..numSides).random()
}
}
8. 解决方案代码
fun main() {
val myFirstDice = Dice(6)
println("Your ${myFirstDice.numSides} sided dice rolled ${myFirstDice.roll()}!")
val mySecondDice = Dice(20)
println("Your ${mySecondDice.numSides} sided dice rolled ${mySecondDice.roll()}!")
}
class Dice (val numSides: Int) {
fun roll(): Int {
return (1..numSides).random()
}
}
9. 总结
- 对
IntRange调用random()函数以生成随机数字:(1..6).random() - 类就像是对象的蓝图。它们可以具有作为变量和函数实现的属性和行为。
- 类的实例代表对象,通常是实物,如骰子。可以调用针对对象的操作并更改其属性。
- 创建实例时,可以向类提供值。例如:创建
class Dice(val numSides: Int),然后通过Dice(6)创建实例。 - 函数可以返回一些内容。可以在函数定义中指定要返回的数据类型,并在函数正文中使用
return语句来返回内容。例如:fun example(): Int { return 5 }
10. 了解详情
11. 自行练习
进行以下练习:
- 为
Dice类指定另一种颜色属性,并创建多个具有不同面数和颜色的实例! - 创建
Coin类,使其能够翻转,创建该类的实例,并抛掷多个硬币!您将如何将random()函数与范围结合使用来实现硬币的抛掷?