iT邦幫忙

2023 iThome 鐵人賽

DAY 28
0
SideProject30

初探 Godot系列 第 28

[DAY 28] 暫停功能

  • 分享至 

  • xImage
  •  

今日目標:加入暫停功能到遊戲中


▍事前準備

在先前的遊戲中,我們實作了遊戲狀態並提供處理狀態方法,提供開始及結束時應該要有的操作,同時我們保留了暫停的狀態,今天我們就來實現暫停的功能到我們的遊戲中。

準備我們暫停按鈕的 icon,儲存到 arts 下建立一個新的資料夾 icons


▍出發

  • 新增暫停按鈕
    1. HUD 場景中新增一個按鈕節點命名為: PauseButton,移動位置到右上角。
    2. 將事前準備好的圖片拖曳到屬性面板中的 icon 欄位,調整 Control Transform postion 到理想的位置。
      https://ithelp.ithome.com.tw/upload/images/20231013/201628752m1e2T8sav.png
  • 編輯程式碼
    1. 修改根節點程式碼,宣告並初始化暫停按鈕
    var pause_button:Button
    func _ready():
        pause_button = $PauseButton
    
    1. 新增按鈕邏輯。
    # 新增暫停、結束暫停訊號。
    signal game_pause
    signal game_unpause
    
    # 宣告是否暫停中。
    var is_stop:bool = false
    
    # 綁定按鈕方法。
    func _ready():
        pause_button.pressed.connect(_on_pause_button_pressed)
    
    # 新增暫停邏輯。
    func _on_pause_button_pressed():
        if is_stop:
            show_game_unpause()
            game_unpause.emit()
        else:
            show_game_pause()
            game_pause.emit()
    
        is_stop = !is_stop
    
    # 暫停及結束暫停顯示畫面更新。
    func show_game_pause():
        message_label.text = "STOP"
        message_label.show()
    
    func show_game_unpause():
        message_label.hide()
    
    1. 修改按鈕出現時機。
      先點擊按鈕旁的眼睛讓他預設為關閉。
    func _on_start_button_pressed():
        # ...
        # 點擊遊戲開始後開啟。
        pause_button.visible = true
    func show_game_over():
        # 遊戲結束時關閉。
        pause_button.visible = false
        # ...
    
  • 處理暫停狀態時的所有物件
    1. 現在到主場景根節點修改程式,綁定暫停及結束暫停訊號到新增方法上。
    # 紀錄暫停的時間
    var pause_time: int
    
    # 綁定方法
    func _ready():
        hud.game_pause.connect(handle_game_pause)
        hud.game_unpause.connect(handle_game_unpause)
    
    # 紀錄暫停時間、更新狀態、暫停場景物件。
    func handle_game_pause():
        pause_time = Time.get_ticks_msec()
        game_state = GAME_STATE.STOP
        background.stop()
        player.stop()
        move_obstacles_timer.set_paused(true)
    
    # 調整開始時間,將時間往後整個暫停的時間確保時間紀錄是正確的。
    # 更新狀態、開始場景物件。
    func handle_game_unpause():
        start_time += (Time.get_ticks_msec() - pause_time)
        game_state = GAME_STATE.START
        background.start()
        player.start()
        move_obstacles_timer.set_paused(false)
    
    1. 移動障礙物場景修改運作邏輯。
    # 宣告變數是否運行中。
    var is_start:bool = true
    # 將更新邏輯移動到運行狀態判斷中。
    func _process(delta):
        if is_start:
            # ...
    
    # 暫停邏輯
    func _on_game_pause():
        timer.stop()
        is_start = !is_start
    
    # 重啟邏輯
    func _on_game_unpause():
        timer.start()
        is_start = !is_start
    
    1. 修改主場景程式碼綁定訊號到移動障礙上。
    func _on_move_obstacle_timeout():
        var instantiated_obj = move_obstacle_scene.instantiate()
        var randf_pos = Vector2(randf_range(0, get_viewport().size.x), -3)
        instantiated_obj.position = randf_pos
        # 新增下面兩行,綁定訊號到生成的物件上。
        hud.game_pause.connect(instantiated_obj._on_game_pause)
        hud.game_unpause.connect(instantiated_obj._on_game_unpause)
        add_child(instantiated_obj)
    
    1. 修改角色場景程式碼修改角色狀態邏輯。
    # 宣告儲存暫停時仍在運行的計時器。
    var stopped_timer:Timer = null
    
    func start():
        game_state = GAME_STATE.START
        # 新增下述:當有計時器被暫停則重新啟動並重置。
        if stopped_timer != null:
            stopped_timer.set_paused(false)
            stopped_timer = null
        get_node("CollisionShape2D").disabled = false
    
    func stop():
        get_node("CollisionShape2D").disabled = true
        game_state = GAME_STATE.STOP
        # 在三個計時器中檢查如果有正在運行的計時器則暫停並將計時器記錄到前面宣告的變數中,等待重啟。
        for timer in [invincible_timer, slow_timer, stop_timer]:
            if not timer.is_stopped():
                timer.set_paused(true)
                stopped_timer = timer
                break
    

▍執行

Yes

其實執行起來好像偶爾會出 bug 就讓我先假裝沒看到。
:)


上一篇
[DAY 27] 優化 (clamp, Fonts)
下一篇
[DAY 29] 紀錄分數 (FileAccess)
系列文
初探 Godot30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言