【Godot4.2】随机数应用案例 - 制作骰子组件

概述

在学习随机数之后,我们就来用随机数实现骰子。

初期:不要拘泥于形式只要表现了随机,骰子可以不必做成骰子的样子。刚开始因为技术力的原因,可能无法实现比较真实和动态的骰子效果,但是这并不意为着不可以做出一个“表意”的骰子,比如一个纯数字版本的骰子也是完全可以的,因为骰子在游戏里只是提供的随机的一种工具。

设计思路

我们可以用图片来实现骰子。最简单的骰子组件如下:
骰子模拟

  • 它有初始的骰子图片和具体的数字图片两种状态。点一下就出现一个1-6随机对应的图片。
  • 但是这种一点就出现结果的体验与现实中掷骰子的体验是不一样的。现实中,投出的骰子总是需要等待它的旋转结束,然后我们才能看到结果。
  • 所以提升真实度的好办法就是点击后也加入一个过渡和等待的效果。

一个中间过渡,让电子骰子拥有更真实的效果

  • 至于这个中间过渡如何做,仁者见仁智者见智,完全可以自由发挥,这也是编程和设计的乐趣。
  • 可行的办法之一是做一个类似技能冷却的效果。

冷却式的中间过渡

  • 另一个可行的办法是点击后显示随机的数,直到达到冷却时间才停止。

创建纯数字版6面骰子

在实现图片版之前,我们不妨先尝试一下实现纯数字的版本。
创建如下场景:

image.png

一个PanelContainer包起来一个Label,设定Label的文本水平和垂直都居中:

image.png

设定Label在容器中水平居中收缩。

image.png

设定PanelContainer的最小尺寸为30×30px。

image.png

此时的效果:

image.png

PanelContainer添加覆盖的样式盒:

image.png

Label的文本颜色设为黑色。

image.png

此时的效果:

image.png

为根节点添加如下代码:

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():
					# 显示16之间任意数字
					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面或其他面的骰子效果。

测试

创建如下的测试场景:

image.pngimage.png
根节点代码如下:

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

间隔3秒,无冷却(可连续点击)

间隔+冷却(基于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_shookfalse,直到间隔时间结束,结果显示,才再次将can_shook设为true
  • 这样我们就实现了在摇骰子期间无法再次摇骰子

创建图片版拟真骰子

上面已经通过数字版本实现了骰子的基本特性,那么实现图片版本,主要就是将图片与随机数对应了。

下图是我用PS做的一个6面骰子的序列图,其中还加入了摇骰子等待期间的问号图片。

all.png

我们有两种思路处理图片,一种是一个面一张图,导出为7张图片,利用数组,获取对应的图片。

image.png

另一种是将6个面整体导出为一个图片,然后用矩形截取和显示单个面的图片。

两种方法各有千秋,前者更直观简便,后者减少图片资源数目,更容易管理。

这里我首先采用前一种形式。创建如下场景:

image.png

我们用一个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

运行后的效果如下:

图片版6面骰子.gif

加入音效

我们可以在一些素材网站找到摇骰子的音效。

img_dice场景添加一个AudioStreamPlayer节点。

image.png

将骰子音效文件拖到AudioStreamPlayer节点的stream节点:

image.png

修改代码如下:

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(),以及实现摇骰子过程中显示随机的面等等。

这里就不过度拓展了,感兴趣的可以自己尝试一下。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

巽星石

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值