Godot游戲練習(xí)01-第9節(jié)-游戲輪次

今天我給游戲添加了輪次, 大概是關(guān)卡的意思, 每一關(guān)有一個(gè)固定時(shí)間, 當(dāng)玩家殺完輪次內(nèi)生成的所有敵人, 則完成當(dāng)前輪次, 游戲進(jìn)入下一個(gè)輪次, 隨著輪次增加, 游戲難度也會(huì)逐漸增加

看看效果

當(dāng)前游戲輪次的調(diào)整不明顯, 主要是增加機(jī)制, 看它是否運(yùn)行正常 (可以觀察日志打印)


動(dòng)畫(huà)5.gif

大致實(shí)現(xiàn)思路

輪次時(shí)間控制

在上一次實(shí)現(xiàn)的EnemySpawnComponent組件基礎(chǔ)上新增一個(gè)RoundTimer, 用于輪次計(jì)時(shí)

并且新增一些變量, 用于輪次的時(shí)間/參數(shù)調(diào)整

const BASE_ROUND_TIME: float = 10
const ROUND_TIME_GROWTH: float = 5
const BASE_MIN_SPAWN_INTERVAL: float = 2.0
const BASE_MAX_SPAWN_INTERVAL: float = 5.0
const SPAWN_INTERVAL_GROWTH: float = -0.2

var round_count: int = 0
var round_min_spawn_interval: float = BASE_MIN_SPAWN_INTERVAL
var round_max_spawn_interval: float = BASE_MAX_SPAWN_INTERVAL
var enemy_count: int = 0

新增的常量和變量名都比較有描述性

  • 輪次初始時(shí)間為10秒, 每完成一個(gè)輪次, 下次增加5秒時(shí)間
  • 初始的敵人生成隨機(jī)最小最大間隔為2-5秒, 每增加一個(gè)輪次, 間隔時(shí)間的最小最大值均減少0.2秒 (敵人生成加快)
  • 當(dāng)前輪次計(jì)數(shù), 時(shí)間與配置基于輪次數(shù)調(diào)整
  • 記錄敵人數(shù)量, 依據(jù)敵人數(shù)量判斷輪次是否完成

輪次開(kāi)啟與結(jié)束

開(kāi)啟時(shí)計(jì)數(shù)加1, 并且調(diào)整Timer時(shí)間與參數(shù), 同時(shí)開(kāi)啟敵人生成Timer

在ready中調(diào)用_start_round自動(dòng)開(kāi)啟第一個(gè)輪次

func _start_round() -> void:
    round_count += 1
    print("Round %s start" % round_count)
    round_min_spawn_interval = BASE_MIN_SPAWN_INTERVAL + (round_count - 1) * SPAWN_INTERVAL_GROWTH
    round_max_spawn_interval = BASE_MAX_SPAWN_INTERVAL + (round_count - 1) * SPAWN_INTERVAL_GROWTH
    round_timer.start(BASE_ROUND_TIME + (round_count - 1) * ROUND_TIME_GROWTH)
    spawn_timer.start(randf_range(round_min_spawn_interval, round_max_spawn_interval))

輪次的結(jié)束是round_timer計(jì)時(shí)停止, 停止后也同時(shí)停止敵人生成計(jì)時(shí)

func _on_round_timer_timeout() -> void:
    print("Round %s end" % round_count)
    spawn_timer.stop()
    _check_round_completed()

輪次完成檢測(cè)

判斷輪次完成有兩個(gè)條件

  • 輪次計(jì)時(shí)完畢
  • 該輪次的敵人被全部消滅
func _check_round_completed() -> void:
    if !round_timer.is_stopped():
        return
    if enemy_count == 0:
        print("Round %s completed!" % round_count)
        _start_round()

若檢測(cè)到輪次完成, 則自動(dòng)開(kāi)始下一輪次

在輪次Timer結(jié)束時(shí)已經(jīng)進(jìn)行過(guò)一次檢測(cè), 還應(yīng)該在每個(gè)敵人死亡時(shí)也進(jìn)行計(jì)數(shù)和檢測(cè)

func _on_enemy_died() -> void:
    enemy_count -= 1
    _check_round_completed()

這就涉及到一個(gè)問(wèn)題, 在該組件中怎樣獲取到敵人死亡的信號(hào)?

全局信號(hào)總線

有人堅(jiān)決反對(duì)使用信號(hào)總線, 說(shuō)這不符合Godot的設(shè)計(jì)哲學(xué)

但是我會(huì)以務(wù)實(shí)為主, 我認(rèn)為信號(hào)總線應(yīng)該在必要時(shí)使用, 但要避免亂用

在這里, 敵人實(shí)例與該組件實(shí)例不是簡(jiǎn)單的上下級(jí)或者兄弟級(jí), 如果通過(guò)祖先節(jié)點(diǎn)傳遞信號(hào), 會(huì)相當(dāng)麻煩

我認(rèn)為在這里使用信號(hào)總線是非常合適的

使用Autoload實(shí)現(xiàn)一個(gè)全局信號(hào)總線

新建一個(gè)腳本, 在ProjectSettings中的Globals中加載并啟用, 之后就可以全局訪問(wèn)

extends Node

signal enemy_died

func emit_enemy_died() -> void:
    enemy_died.emit()

腳本很簡(jiǎn)單, 主要是為了跨模塊訪問(wèn)

敵人死亡通知

敵人的生命管理被我用一個(gè)HealthComponent組件管理了, 與之前的邏輯一樣, 生命值歸0之后發(fā)出信號(hào), 封裝組件都是為了方便后續(xù)復(fù)用

在生命值歸0后發(fā)出全局信號(hào), 并銷(xiāo)毀自身

func _on_health_ended() -> void:
    GameEvents.emit_enemy_died()
    queue_free()

全局信號(hào)監(jiān)聽(tīng)

與普通信號(hào)監(jiān)聽(tīng)一樣, 只是我們不用再找信號(hào)的源頭是誰(shuí)

GameEvents.enemy_died.connect(_on_enemy_died)

記得處理好服務(wù)器邏輯與客戶(hù)端邏輯

這樣我們的輪次結(jié)構(gòu)就完成了, 后續(xù)開(kāi)發(fā)中可以基于輪次讓游戲內(nèi)容逐漸產(chǎn)生一些變化, 慢慢變得好玩有趣起來(lái)

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

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

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