godot-genre-tower-defense

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Genre: Tower Defense

游戏类型:塔防游戏

Strategic placement, resource management, and escalating difficulty define tower defense.
策略部署、资源管理和难度升级是塔防游戏的核心特征。

Core Loop

核心循环

  1. Prepare: Build/upgrade towers with available currency
  2. Wave: Enemies spawn and traverse path toward goal
  3. Defend: Towers auto-target and damage enemies
  4. Reward: Kills grant currency
  5. Escalate: Waves increase in difficulty/complexity
  1. 准备阶段:使用可用货币建造/升级炮塔
  2. 波次阶段:敌人生成并沿路径向目标移动
  3. 防御阶段:炮塔自动瞄准并攻击敌人
  4. 奖励阶段:击杀敌人获取货币
  5. 难度升级:后续波次的难度/复杂度提升

NEVER Do in Tower Defense Games

塔防游戏开发中的绝对禁忌

  • NEVER make all towers equally viable — If Sniper = same DPS as Machine Gun, no strategic choice. Each tower MUST have distinct niche (AoE, slow, armor pierce, anti-air).
  • NEVER use synchronous NavigationServer baking for mazing
    NavigationRegion2D.bake_navigation_polygon()
    blocks main thread. Use
    NavigationServer2D.get_maps()
    + worker thread OR fixed paths.
  • NEVER let players fully block the exit path — In mazing TDs, validate
    NavigationServer2D.map_get_path(start, goal)
    before tower placement. Empty path = illegal build.
  • NEVER use
    Area2D.get_overlapping_bodies()
    every frame
    — 500 enemies × 60fps = 30k collision checks. Store
    bodies_entered
    in array, remove on
    body_exited
    . Query once.
  • NEVER make early waves feel like busywork — First 3 waves should introduce mechanics, not bore. Start timer at 50% or give "early call" bonus to skip.
  • NEVER allow death spirals without catch-up mechanics — 1 leaked enemy → less money → harder next wave → inevitable loss. Add interest on saved money OR discrete wave difficulty.

PhaseSkillsPurpose
1. Grid/Path
godot-tilemap-mastery
,
navigation-2d
Defining where enemies walk and towers build
2. Towers
math-geometry
,
area-2d
Range checks, rotation, projectile prediction
3. Enemies
path-following
,
steering-behaviors
Movement along paths
4. Management
state-machines
,
loop-management
Wave spawning logic, game phases
5. UI
ui-system
,
drag-and-drop
Building towers, inspecting stats
  • 绝对不要让所有炮塔的实用性完全相同——如果狙击炮塔和机枪炮塔的DPS相同,玩家就没有策略选择空间。每种炮塔必须有明确的定位(范围伤害、减速、穿甲、防空)。
  • 绝对不要使用同步的NavigationServer烘焙迷宫——
    NavigationRegion2D.bake_navigation_polygon()
    会阻塞主线程。应使用
    NavigationServer2D.get_maps()
    + 工作线程,或采用固定路径。
  • 绝对不要让玩家完全封锁出口路径——在迷宫类塔防游戏中,放置炮塔前需通过
    NavigationServer2D.map_get_path(start, goal)
    验证路径。若路径为空,则该建造操作非法。
  • 绝对不要每帧调用
    Area2D.get_overlapping_bodies()
    ——500个敌人 × 60fps = 3万次碰撞检测。应将进入区域的敌人存储在数组中,离开时移除,仅查询一次。
  • 绝对不要让前期波次沦为繁琐的重复操作——前3波应用于介绍游戏机制,而非让玩家感到无聊。可将初始计时器设为50%进度,或提供“提前召唤波次”的奖励以跳过等待。
  • 绝对不要在没有追赶机制的情况下让玩家陷入死亡螺旋——漏过一个敌人 → 获得的货币减少 → 下一波更难 → 必然失败。可添加储蓄利息机制,或采用独立的波次难度设定。

阶段技术用途
1. 网格/路径
godot-tilemap-mastery
,
navigation-2d
定义敌人行走路径和炮塔建造区域
2. 炮塔
math-geometry
,
area-2d
范围检测、炮塔旋转、弹道预测
3. 敌人
path-following
,
steering-behaviors
沿路径移动
4. 管理模块
state-machines
,
loop-management
波次生成逻辑、游戏阶段管理
5. 用户界面
ui-system
,
drag-and-drop
炮塔建造、属性查看

Architecture Overview

架构概述

1. Wave Manager

1. 波次管理器

Handles the timing and godot-composition of enemy waves.
gdscript
undefined
负责敌人波次的计时和组合生成。
gdscript
undefined

wave_manager.gd

wave_manager.gd

extends Node
signal wave_started(wave_index: int) signal wave_cleared signal enemy_spawned(enemy: Node2D)
@export var waves: Array[Resource] # Array of WaveDefinition resources var current_wave_index: int = 0 var active_enemies: int = 0
func start_next_wave() -> void: if current_wave_index >= waves.size(): print("All waves cleared!") return
var wave_data = waves[current_wave_index]
wave_started.emit(current_wave_index)
_spawn_wave(wave_data)
current_wave_index += 1
func _spawn_wave(wave: WaveResource) -> void: for group in wave.groups: await get_tree().create_timer(group.delay).timeout for i in group.count: var enemy = group.enemy_scene.instantiate() add_child(enemy) active_enemies += 1 enemy.tree_exiting.connect(_on_enemy_died) await get_tree().create_timer(group.interval).timeout
func _on_enemy_died() -> void: active_enemies -= 1 if active_enemies <= 0: wave_cleared.emit()
undefined
extends Node
signal wave_started(wave_index: int) signal wave_cleared signal enemy_spawned(enemy: Node2D)
@export var waves: Array[Resource] # Array of WaveDefinition resources var current_wave_index: int = 0 var active_enemies: int = 0
func start_next_wave() -> void: if current_wave_index >= waves.size(): print("All waves cleared!") return
var wave_data = waves[current_wave_index]
wave_started.emit(current_wave_index)
_spawn_wave(wave_data)
current_wave_index += 1
func _spawn_wave(wave: WaveResource) -> void: for group in wave.groups: await get_tree().create_timer(group.delay).timeout for i in group.count: var enemy = group.enemy_scene.instantiate() add_child(enemy) active_enemies += 1 enemy.tree_exiting.connect(_on_enemy_died) await get_tree().create_timer(group.interval).timeout
func _on_enemy_died() -> void: active_enemies -= 1 if active_enemies <= 0: wave_cleared.emit()
undefined

2. Tower Logic (State Machine)

2. 炮塔逻辑(状态机)

Towers act as autonomous agents.
  • States:
    Idle
    ,
    AcquireTarget
    ,
    Attack
    ,
    Cooldown
    .
  • Targeting Priority:
    First
    ,
    Last
    ,
    Strongest
    ,
    Weakest
    ,
    Closest
    .
gdscript
undefined
炮塔作为自主代理运行。
  • 状态
    Idle
    ,
    AcquireTarget
    ,
    Attack
    ,
    Cooldown
  • 瞄准优先级
    First
    ,
    Last
    ,
    Strongest
    ,
    Weakest
    ,
    Closest
gdscript
undefined

tower.gd

tower.gd

extends Node2D
var targets_in_range: Array[Node2D] = [] var current_target: Node2D
func _physics_process(delta: float) -> void: if current_target == null or not is_instance_valid(current_target): _acquire_target()
if current_target:
    _rotate_turret(current_target.global_position)
    if can_fire():
        fire_projectile()
func _acquire_target() -> void: # Example: Target closest to end of path var max_progress = -1.0 for enemy in targets_in_range: if enemy.progress > max_progress: current_target = enemy max_progress = enemy.progress
undefined
extends Node2D
var targets_in_range: Array[Node2D] = [] var current_target: Node2D
func _physics_process(delta: float) -> void: if current_target == null or not is_instance_valid(current_target): _acquire_target()
if current_target:
    _rotate_turret(current_target.global_position)
    if can_fire():
        fire_projectile()
func _acquire_target() -> void: # Example: Target closest to end of path var max_progress = -1.0 for enemy in targets_in_range: if enemy.progress > max_progress: current_target = enemy max_progress = enemy.progress
undefined

3. Pathfinding Variants

3. 寻路变体

A. Fixed Path (Kingdom Rush style)

A. 固定路径(《王国保卫战》风格)

Enemies follow a pre-defined
Path2D
.
  • Implementation:
    PathFollow2D
    as parent of Enemy.
  • Pros: Deterministic, easy to balance, optimized.
  • Cons: Less player agency in shaping the path.
敌人沿预定义的
Path2D
移动。
  • 实现方式:将
    PathFollow2D
    作为敌人节点的父节点。
  • 优点:确定性强,易于平衡,性能优化。
  • 缺点:玩家在路径塑造上的自主性较低。

B. Mazing (Fieldrunners style)

B. 迷宫机制(《坚守阵地》风格)

Players build towers to block/reroute enemies.
  • Implementation:
    NavigationAgent2D
    on enemies. Towers update
    NavigationRegion2D
    (bake on separate thread).
  • Pros: High strategic depth.
  • Cons: Computationally expensive recalculation, needs anti-blocking logic (don't let player seal the exit).
玩家通过建造炮塔来阻挡/改道敌人。
  • 实现方式:在敌人节点上添加
    NavigationAgent2D
    ,炮塔放置时更新
    NavigationRegion2D
    (在独立线程中进行烘焙)。
  • 优点:策略深度高。
  • 缺点:路径重计算的算力消耗大,需要防封锁逻辑(禁止玩家完全封锁出口)。

Key Mechanics Implementation

核心机制实现

Targeting Math (Projectile Prediction)

瞄准算法(弹道预测)

To hit a moving target, you must predict where it will be.
gdscript
func get_predicted_position(target: Node2D, projectile_speed: float) -> Vector2:
    var to_target = target.global_position - global_position
    var time_to_hit = to_target.length() / projectile_speed
    return target.global_position + (target.velocity * time_to_hit)
要击中移动目标,必须预测其未来位置。
gdscript
func get_predicted_position(target: Node2D, projectile_speed: float) -> Vector2:
    var to_target = target.global_position - global_position
    var time_to_hit = to_target.length() / projectile_speed
    return target.global_position + (target.velocity * time_to_hit)

Economy

经济系统

Money management is the secondary core loop.
  • Kill Rewards: Direct feedback for success.
  • Interest/Income: Rewarding saved money (risk/reward).
  • Early Calling: Bonus money for starting the next wave early.
货币管理是次要核心循环。
  • 击杀奖励:成功击杀的直接反馈。
  • 利息/收益:奖励储蓄行为(风险/收益权衡)。
  • 提前召唤波次:提前启动下一波次可获得额外货币奖励。

Common Pitfalls

常见陷阱

  1. Death Spirals: If a player leaks one enemy, they lose money/lives, making the next wave harder, leading to inevitable failure. Fix: Catch-up mechanics or discrete wave difficulty.
  2. Useless Towers: Every tower type must have a distinct niche (AoE, Slow, Armor Pierce, Anti-Air).
  3. Path Blocking: In mazing games, ensure players cannot completely block the path to the exit. Use
    NavigationServer2D.map_get_path
    to validate placement before building.
  1. 死亡螺旋:如果玩家漏过一个敌人,就会损失货币/生命值,导致下一波更难,最终必然失败。解决方法:添加追赶机制或采用独立的波次难度设定。
  2. 无用炮塔:每种炮塔类型必须有明确的定位(范围伤害、减速、穿甲、防空)。
  3. 路径封锁:在迷宫类游戏中,需确保玩家无法完全封锁通往出口的路径。使用
    NavigationServer2D.map_get_path
    在建造前验证位置合法性。

Godot-Specific Tips

Godot专属技巧

  • Physics Layers: Put enemies on a specific layer (e.g., Layer 2) and tower "range" Areas on a different mask to avoid towers detecting each other or walls.
  • Area2D Performance: For massive numbers of enemies, avoid
    monitorable/monitoring
    on every frame if possible. Use
    PhysicsServer2D
    queries for optimization if enemy count > 500.
  • Object Pooling: Essential for projectiles and enemies to avoid garbage collection stutters during intense waves.
  • 物理层:将敌人放在特定层(例如第2层),将炮塔的“范围检测”区域设为不同的遮罩,避免炮塔检测到彼此或墙体。
  • Area2D性能优化:当敌人数量众多时,尽可能避免每帧启用
    monitorable/monitoring
    。若敌人数量超过500,可使用
    PhysicsServer2D
    查询来优化性能。
  • 对象池:对于弹道和敌人来说是必不可少的,可避免密集波次期间因垃圾回收导致的卡顿。

Reference

参考资料

  • Master Skill: godot-master
  • 核心技能:godot-master