概述
在学习随机数之后,我们就来用随机数实现骰子。
初期:不要拘泥于形式。只要表现了随机,骰子可以不必做成骰子的样子。刚开始因为技术力的原因,可能无法实现比较真实和动态的骰子效果,但是这并不意为着不可以做出一个“表意”的骰子,比如一个纯数字版本的骰子也是完全可以的,因为骰子在游戏里只是提供的随机的一种工具。
设计思路
我们可以用图片来实现骰子。最简单的骰子组件如下:
- 它有初始的骰子图片和具体的数字图片两种状态。点一下就出现一个
1
-6
随机对应的图片。 - 但是这种一点就出现结果的体验与现实中掷骰子的体验是不一样的。现实中,投出的骰子总是需要等待它的旋转结束,然后我们才能看到结果。
- 所以提升真实度的好办法就是点击后也加入一个过渡和等待的效果。
- 至于这个中间过渡如何做,仁者见仁智者见智,完全可以自由发挥,这也是编程和设计的乐趣。
- 可行的办法之一是做一个类似技能冷却的效果。
- 另一个可行的办法是点击后显示随机的数,直到达到冷却时间才停止。
创建纯数字版6面骰子
在实现图片版之前,我们不妨先尝试一下实现纯数字的版本。
创建如下场景:
一个PanelContainer
包起来一个Label
,设定Label
的文本水平和垂直都居中:
设定Label
在容器中水平居中收缩。
设定PanelContainer
的最小尺寸为30×30
px。
此时的效果:
为PanelContainer
添加覆盖的样式盒:
将Label
的文本颜色设为黑色。
此时的效果:
为根节点添加如下代码:
extends PanelContainer
@onready var num_lab = $numLab
func _ready():
randomize()
# gui_input信号处理
connect("gui_input",func(event):
# 鼠标左键点击
if event is InputEventMouseButton:
if event.button_index == MOUSE_BUTTON_LEFT:
if event.is_pressed():
# 显示1到6之间任意数字
num_lab.text = str(randi_range(1,6))
)
这样我们就实现了一个简单的可以交互的6面骰子:
骰子组件化
为了更好的解耦,可以将摇骰子的功能,单独写成一个函数。
extends PanelContainer
@onready var num_lab = $numLab
func _ready():
randomize()
# gui_input信号处理
connect("gui_input",func(event):
# 鼠标左键点击
if event is InputEventMouseButton:
if event.button_index == MOUSE_BUTTON_LEFT:
if event.is_pressed():
shook_dice(6) # 摇骰子
)
# 摇骰子
func shook_dice(max_num:int) -> void:
num_lab.text = str(randi_range(1,max_num))
此时我们就可以在其他场景中实例化我们的骰子组件也就是dice
场景,并调用其shook_dice
方法来掷骰子。
而且因为我们将骰子的面数设定为了max_num
参数,这意为着我们可以实现6面或其他面的骰子效果。
测试
创建如下的测试场景:
根节点代码如下:
extends Control
@onready var dice = $dice
# 按钮点击
func _on_button_pressed():
dice.shook_dice(6) # 掷6面骰子
我们设定按钮点击时掷6面骰子,效果如下:
引入间隔时间
上面的骰子是即时显示出结果的,这与现实的骰子不符。现实中投出骰子之后,都会间隔一段时间,才出现结果。
因此这里我们引入间隔时间参数Interval_time
这里默认值为3.0
,也就是调用shook_dice
掷骰子后,3s
后才出现结果。
extends PanelContainer
@onready var num_lab = $numLab
## 骰子显示数字的间隔时间
@export var Interval_time:float = 3.0
func _ready():
randomize()
# gui_input信号处理
connect("gui_input",func(event):
# 鼠标左键点击
if event is InputEventMouseButton:
if event.button_index == MOUSE_BUTTON_LEFT:
if event.is_pressed():
shook_dice(6) # 摇骰子
)
# 摇骰子
func shook_dice(max_num:int) -> void:
num_lab.text = "-" # 结果出现之前显示无意义的"-"字符
await get_tree().create_timer(Interval_time).timeout # 创建Timer
num_lab.text = str(randi_range(1,max_num))
间隔+冷却(基于Timer)
上面为骰子添加了显示结果的间隔时间,但是我们可以在结果出现之前,不停的重新摇骰子,这与现实中的骰子也是不符合的。因此我们还需要设定在一次摇骰子结束之前,不允许再次摇骰子。
我们修改代码如下:
extends PanelContainer
@onready var num_lab = $numLab
## 骰子显示数字的间隔时间
@export var Interval_time:float = 3.0
var can_shook = true # 能否摇骰子
func _ready():
randomize()
# gui_input信号处理
connect("gui_input",func(event):
# 鼠标左键点击
if event is InputEventMouseButton:
if event.button_index == MOUSE_BUTTON_LEFT:
if event.is_pressed():
if can_shook:
shook_dice(6) # 摇骰子
)
# 摇骰子
func shook_dice(max_num:int) -> void:
can_shook = false
num_lab.text = "-" # 结果出现之前显示无意义的"-"字符
await get_tree().create_timer(Interval_time).timeout # 创建Timer
num_lab.text = str(randi_range(1,max_num))
can_shook = true
可以看到:
- 我们设定一个变量
can_shook
来存储是否可以摇骰子,初始为true
,当我们第一次摇骰子以后,立马标记can_shook
为false
,直到间隔时间结束,结果显示,才再次将can_shook
设为true
- 这样我们就实现了在摇骰子期间无法再次摇骰子
创建图片版拟真骰子
上面已经通过数字版本实现了骰子的基本特性,那么实现图片版本,主要就是将图片与随机数对应了。
下图是我用PS做的一个6面骰子的序列图,其中还加入了摇骰子等待期间的问号图片。
我们有两种思路处理图片,一种是一个面一张图,导出为7张图片,利用数组,获取对应的图片。
另一种是将6个面整体导出为一个图片,然后用矩形截取和显示单个面的图片。
两种方法各有千秋,前者更直观简便,后者减少图片资源数目,更容易管理。
这里我首先采用前一种形式。创建如下场景:
我们用一个TextureRect显示骰子的某个面:
extends TextureRect
## 骰子显示数字的间隔时间
@export var Interval_time:float = 3.0
var can_shook = true # 能否摇骰子
func _ready():
randomize()
# gui_input信号处理
connect("gui_input",func(event):
# 鼠标左键点击
if event is InputEventMouseButton:
if event.button_index == MOUSE_BUTTON_LEFT:
if event.is_pressed():
if can_shook:
shook_dice(6) # 摇骰子
)
# 摇骰子
func shook_dice(max_num:int) -> void:
can_shook = false
texture = load("res://imgs/%d.png" % 0) # 显示问号
await get_tree().create_timer(Interval_time).timeout # 创建Timer
var i = randi_range(1,max_num)
texture = load("res://imgs/%d.png" % i)
can_shook = true
运行后的效果如下:
加入音效
我们可以在一些素材网站找到摇骰子的音效。
为img_dice
场景添加一个AudioStreamPlayer
节点。
将骰子音效文件拖到AudioStreamPlayer
节点的stream
节点:
修改代码如下:
extends TextureRect
## 骰子显示数字的间隔时间
@export var Interval_time:float = 3.0
var can_shook = true # 能否摇骰子
@onready var audio_stream_player = $AudioStreamPlayer
func _ready():
randomize()
# gui_input信号处理
connect("gui_input",func(event):
# 鼠标左键点击
if event is InputEventMouseButton:
if event.button_index == MOUSE_BUTTON_LEFT:
if event.is_pressed():
if can_shook:
shook_dice(6) # 摇骰子
)
# 摇骰子
func shook_dice(max_num:int) -> void:
can_shook = false
texture = load("res://imgs/%d.png" % 0) # 显示问号
audio_stream_player.play() # 播放音效
await get_tree().create_timer(Interval_time).timeout # 创建Timer
var i = randi_range(1,max_num)
texture = load("res://imgs/%d.png" % i)
audio_stream_player.stop() # 停止播放音效
can_shook = true
此时就可以在摇骰子时听到音效了。
总结
本篇主要是随机数应用的一个简单实例。讲解如何手搓简单的纯数字骰子和图片版骰子。
同样只是抛砖引玉,讲解基础的原理,代码其实可以优化的更简洁,也可以使用Timer
节点取代get_tree().create_timer()
,以及实现摇骰子过程中显示随机的面等等。
这里就不过度拓展了,感兴趣的可以自己尝试一下。