Godot游戏练习01-第14节-Theme,字体,游戏UI

0 阅读2分钟

今天来学习游戏中的主题(Theme)和字体调整, 并添加一个能显示轮次和倒计时的游戏UI

看看效果

像素字体加上, 瞬间有那感觉了! 有点那么回事了, 哈哈

anim1.gif

实现过程

主题和字体设置

字体我是直接在网上找了一个开源字体, 觉得好看就用了: github.com/TakWolf/fus…

下载otf格式, 不带woff/woff2后缀的字体, 导入Godot, 关闭抗锯齿(Antialiasing), Hinting, Subpixel Positioning后重新导入, 像素游戏不需要抗锯齿/高清/子像素等设置, 导入zh_hans(简体中文版本)

新建一个Theme资源, 命名为default.tres, 将Default Font设置为导入的字体, 调整字号为20 (自己在预览中觉得合适的大小)

设置默认主题: Project -> Project Settings -> GUI -> Theme -> Custom, 设置为刚刚新建的Theme资源, 并且可以调整默认字体导入选项

这样, 默认字体和主题都设置完毕

轮次数和轮次倒计时显示

新建一个CanvasLayer为根节点的场景, UI节点树如下

RoundTimerUI (CanvasLayer)
└── MarginContainer
    └── VBoxContainer
        ├── RoundLabel
        └── TimerLabel

调整对齐, Margin等属性, 让UI在靠顶居中的位置显示

RoundTimerUI脚本如下

extends CanvasLayer

@export var enemy_spawn_component: EnemySpawnComponent

@onready var round_label: Label = %RoundLabel
@onready var timer_label: Label = %TimerLabel

func _ready() -> void:
	enemy_spawn_component.round_changed.connect(_on_round_changed)


func _process(_delta: float) -> void:
	var time_left := enemy_spawn_component.get_round_time_left()
	timer_label.text = str(ceili(time_left))


func _on_round_changed(round_count: int) -> void:
	round_label.text = "Round %s" % round_count

它监听外部EnemySpawnComponent组件的轮次变化事件, 以及实时获取EnemySpawnComponent组件中的当前轮次剩余时间, 转换为整数显示, 更新UI

之后就是数据的通知与同步, 在这个场景中, 数据的同步显得稍微复杂一点, 它涉及到跨组件的Timer处理

主要把握好两个同步时间点:

  • Round变化
  • 新的Peer加入

同步内容: 主要同步Round计数, 以及当前剩余时间, 倒计时让每个Peer自己的Timer执行, 服务器只在关键点同步, 避免不必要的宽带浪费

这里主要看一下EnemySpawnComponent组件中提供的"同步"接口

func synchronize(peer_id: int = -1) -> void:
	if not is_multiplayer_authority():
		return
	var data = {
		"round_count": round_count,
		"round_timer_time_left": round_timer.time_left,
		"round_timer_running": not round_timer.is_stopped()
	}
	if peer_id < 0:
		_synchronize.rpc(data)
	elif peer_id > 1:
		_synchronize.rpc_id(peer_id, data)


@rpc("authority", "call_remote", "reliable")
func _synchronize(data: Dictionary) -> void:
	round_count = data.round_count
	round_timer.wait_time = data.round_timer_time_left
	if data.round_timer_running:
		round_timer.start()

同步接口synchronize收集服务端信息, 并同步给其他的peer, 所以peer_id中过滤自身id(1)

synchronize在Round发生变化时与所有peer进行RPC同步; 在新peer加入时, 仅与新peer同步(传入peer_id)

对round_count字段添加getter和setter

var round_count: int = 0:
	get:
		return round_count
	set(value):
		round_count = value
		round_changed.emit(value)

当每个peer上的round_count发生变化时, 都会触发各自的round_changed信号, 同步到UI界面, 保持数据与UI显示一致