【Godot4.2】实现简单时钟组件

概述

Godot的CanvasItem类型提供的绘图函数,以及向量旋转,玩起来很有意思。

基于_draw的实现

用向量旋转的方法,可以实现时钟的分针、时针、秒针的旋转。再通过每帧调用_draw更新绘图就可以让时钟动起来了。

当然我们还需要从Time单例那里获取当前的时分秒信息。

extends Control
# 基础参数
var center = Vector2(100,100) # 表盘中心
var r = 80 # 表盘半径
var h_r = 60 # 时针长度
var m_r = 50 # 分针长度
var s_r = 40 # 秒针长度

func _process(delta):
	queue_redraw()

func _draw():
	# 获取当前时间信息
	var dict = Time.get_datetime_dict_from_system()
	# 绘制
	draw_circle(center,80,Color("#ccc"))
	draw_line(center,(Vector2.UP * h_r).rotated((2* PI /12) * dict["hour"])+ center,Color("#444"),4)
	draw_line(center,(Vector2.UP * m_r).rotated((2* PI /60) * dict["minute"])+ center,Color("#444"),2)
	draw_line(center,(Vector2.UP * s_r).rotated((2* PI /60) * dict["second"])+ center,Color("#444"),1)

在这里插入图片描述

绘制表盘数字

上面的表盘光秃秃的,根本没有一个钟表的样子,所以我们draw_string方法绘制表盘数字。

# 绘制表盘数字
extends Control
# 基础参数
var center = Vector2(100,100) # 表盘中心
var r = 80 # 表盘半径
var h_r = 60 # 时针长度
var m_r = 50 # 分针长度
var s_r = 40 # 秒针长度

var default_font = ThemeDB.fallback_font
var default_font_size = ThemeDB.fallback_font_size


func _process(delta):
	queue_redraw()

func _draw():
	# 获取当前时间信息
	var dict = Time.get_datetime_dict_from_system()
	# 绘制
	draw_circle(center,80,Color("#ccc"))
	draw_line(center,(Vector2.UP * h_r).rotated((2* PI /12) * dict["hour"])+ center,Color("#444"),4)
	draw_line(center,(Vector2.UP * m_r).rotated((2* PI /60) * dict["minute"])+ center,Color("#444"),2)
	draw_line(center,(Vector2.UP * s_r).rotated((2* PI /60) * dict["second"])+ center,Color("#444"),1)

	# 绘制表盘数字
	for i in range(1,13):
		draw_string(default_font, 
		(Vector2.UP * 70).rotated((2* PI /12) * i) + center - Vector2(5,-5),
		str(i),HORIZONTAL_ALIGNMENT_CENTER,-1, default_font_size,Color("#444"))

一个由纯绘图函数实现的钟表控件就搞定了。
在这里插入图片描述

基于图片实现

当然,我们也可以用图片来实现一个更好看的钟表。

我在PS中设计了一个简单的钟表:
在这里插入图片描述

分别导出元件:
在这里插入图片描述
在这里插入图片描述

导入Godot中后,进行元件组装:
在这里插入图片描述

修改根节点代码如下:

extends Control

@onready var h_pointer = $pan/HPointer
@onready var m_pointer = $pan/MPointer
@onready var s_pointer = $pan/SPointer

func _process(delta):
	# 获取当前时间信息
	var dict = Time.get_datetime_dict_from_system()
	h_pointer.rotation = dict["hour"] * (2 * PI / 12)
	m_pointer.rotation = dict["minute"] * (2 * PI / 60)
	s_pointer.rotation = dict["second"] * (2 * PI / 60)

效果如下:
在这里插入图片描述
可以看到,代码一下子变少了。

抛砖引玉啊,期望各位可以受到启发。

EasyClock

这是本人纯粹基于_draw制作的简易参数化时钟组件。

可以自由缩放,支持各种颜色、字体、字号修改以及开启或关闭绘制数字、刻度等功能。

目前基于_process刷新有点浪费,后期可能基于Timer进行修改。
在这里插入图片描述

# ========================================================
# 名称:EasyClock
# 类型:Control扩展节点
# 简介:利用_draw实现的参数化的指针型钟表组件
# 作者:巽星石
# Godot版本:4.0.3-stable (official)
# 创建时间:2023-07-02 14:36:14
# 最后修改时间:20237216:22:40
# ========================================================
@tool
extends Control
class_name EasyClock
# =================================== 参数 ===================================
# 功能开关
@export_group("switch")
## 是否绘制中心
@export var draw_center:bool = false:
	set(val):
		draw_center = val
		queue_redraw()
## 是否绘制数字
@export var draw_nums:bool = false:
	set(val):
		draw_nums = val
		queue_redraw()
## 是否绘制刻度
@export var draw_scales:bool = false:
	set(val):
		draw_scales = val
		queue_redraw()
# 颜色
@export_group("Color")
## 表盘 - 颜色
@export var bk_color:Color = Color("#ccc"):
	set(val):
		bk_color = val
		queue_redraw()
## 时针 - 颜色
@export var h_color:Color = Color("#444"):
	set(val):
		h_color = val
		queue_redraw()
## 分针 - 颜色
@export var m_color:Color = Color("#444"):
	set(val):
		m_color = val
		queue_redraw()
## 秒针 - 颜色
@export var s_color:Color = Color("#444"):
	set(val):
		s_color = val
		queue_redraw()
## 中心点 - 颜色
@export var center_color:Color = Color("#ccc"):
	set(val):
		center_color = val
		queue_redraw()
# 宽度
@export_group("Width")
## 时针 - 宽度
@export var h_width:int = 10:
	set(val):
		h_width = val
		queue_redraw()
## 分针 - 宽度
@export var m_width:int = 5:
	set(val):
		m_width = val
		queue_redraw()
## 秒针 - 宽度
@export var s_width:int = 3:
	set(val):
		s_width = val
		queue_redraw()
@export_group("nums")
## 表盘数字 - 颜色
@export var nums_color:Color = Color("#ccc"):
	set(val):
		nums_color = val
		queue_redraw()
## 默认字体大小
@export var font_size = 14:
	set(val):
		font_size = val
		queue_redraw()
## 默认字体	
@export var font:SystemFont:
	set(val):
		font = val
		queue_redraw()


# =================================== 动态计算参数 ===================================
var center = Vector2(100,100) # 表盘中心
var r = 80 # 表盘半径
var h_r = 60 # 时针长度
var m_r = 50 # 分针长度
var s_r = 40 # 秒针长度

func _ready():
	resized.connect(func():
		calc()
	)
	calc()
	queue_redraw()

# 重新计算
func calc():
	center = get_global_rect().get_center()
	r = get_global_rect().size.y/2
	h_r = r * 0.82
	m_r = r * 0.85
	s_r = r * 0.9

func _process(delta):
	queue_redraw()

func _draw():
	# 获取当前时间信息
	var dict = Time.get_datetime_dict_from_system()
	# 绘制表盘
	draw_circle(center,r,bk_color)
	draw_circle(center,r * 0.8,bk_color.darkened(0.2))
	draw_circle(center,r * 0.8 - 10,bk_color.darkened(0.15))
	# 绘制日期
	var date := "%d.%d.%d" % [dict["year"],dict["month"],dict["day"]]
	draw_string(font, 
	Vector2.DOWN * r * 0.4 + center - Vector2(font_size * 2,-font_size/2),
	date,HORIZONTAL_ALIGNMENT_CENTER,-1,font_size * 1.5,nums_color)
	# 绘制时间
	# 绘制数字
	if draw_nums:
		for i in range(1,13):
			var f_size = font_size if i % 3 != 0 else font_size * 2
			draw_string(font, 
			(Vector2.UP * (r - f_size/1.25)).rotated((2* PI /12) * i) + center - Vector2(f_size/3,-f_size/2),
			str(i),HORIZONTAL_ALIGNMENT_CENTER,-1,f_size,nums_color)
	# 绘制
	draw_line(center,(Vector2.UP * h_r).rotated((2* PI /12) * dict["hour"]) + center,h_color,h_width)
	draw_line(center,(Vector2.UP * m_r).rotated((2* PI /60) * dict["minute"]) + center,m_color,m_width)
	draw_line(center,(Vector2.UP * s_r).rotated((2* PI /60) * dict["second"]) + center,s_color,s_width)
	# 绘制中心
	if draw_center:
		draw_circle(center,r * 0.1,center_color)
		draw_circle(center,r * 0.1 - 8,center_color.darkened(0.2))
		draw_circle(center,5,center_color.darkened(0.3))
	# 绘制刻度线
	if draw_scales:
		for i in range(60):
			draw_line((Vector2.UP * r * 0.9).rotated((2* PI /60) * i) + center ,(Vector2.UP * r * 0.95).rotated((2* PI /60) * i) + center,s_color,1)
	

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

巽星石

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

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

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

打赏作者

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

抵扣说明:

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

余额充值