Godot游戲練習(xí)01-第14節(jié)-Theme,字體,游戲UI

今天來學(xué)習(xí)游戲中的主題(Theme)和字體調(diào)整, 并添加一個能顯示輪次和倒計時的游戲UI

看看效果

像素字體加上, 瞬間有那感覺了! 有點(diǎn)那么回事了, 哈哈

anim1.gif

實現(xiàn)過程

主題和字體設(shè)置

字體我是直接在網(wǎng)上找了一個開源字體, 覺得好看就用了: https://github.com/TakWolf/fusion-pixel-font

下載otf格式, 不帶woff/woff2后綴的字體, 導(dǎo)入Godot, 關(guān)閉抗鋸齒(Antialiasing), Hinting, Subpixel Positioning后重新導(dǎo)入, 像素游戲不需要抗鋸齒/高清/子像素等設(shè)置, 導(dǎo)入zh_hans(簡體中文版本)

新建一個Theme資源, 命名為default.tres, 將Default Font設(shè)置為導(dǎo)入的字體, 調(diào)整字號為20 (自己在預(yù)覽中覺得合適的大小)

設(shè)置默認(rèn)主題: Project -> Project Settings -> GUI -> Theme -> Custom, 設(shè)置為剛剛新建的Theme資源, 并且可以調(diào)整默認(rèn)字體導(dǎo)入選項

這樣, 默認(rèn)字體和主題都設(shè)置完畢

輪次數(shù)和輪次倒計時顯示

新建一個CanvasLayer為根節(jié)點(diǎn)的場景, UI節(jié)點(diǎn)樹如下

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

調(diào)整對齊, 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

它監(jiān)聽外部EnemySpawnComponent組件的輪次變化事件, 以及實時獲取EnemySpawnComponent組件中的當(dāng)前輪次剩余時間, 轉(zhuǎn)換為整數(shù)顯示, 更新UI

之后就是數(shù)據(jù)的通知與同步, 在這個場景中, 數(shù)據(jù)的同步顯得稍微復(fù)雜一點(diǎn), 它涉及到跨組件的Timer處理

主要把握好兩個同步時間點(diǎn):

  • Round變化
  • 新的Peer加入

同步內(nèi)容: 主要同步Round計數(shù), 以及當(dāng)前剩余時間, 倒計時讓每個Peer自己的Timer執(zhí)行, 服務(wù)器只在關(guān)鍵點(diǎn)同步, 避免不必要的寬帶浪費(fèi)

這里主要看一下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收集服務(wù)端信息, 并同步給其他的peer, 所以peer_id中過濾自身id(1)

synchronize在Round發(fā)生變化時與所有peer進(jìn)行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)

當(dāng)每個peer上的round_count發(fā)生變化時, 都會觸發(fā)各自的round_changed信號, 同步到UI界面, 保持?jǐn)?shù)據(jù)與UI顯示一致

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容