godot-genre-battle-royale
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseGenre: Battle Royale
游戏类型:Battle Royale
Expert blueprint for Battle Royale games with zone mechanics, large-scale networking, and survival gameplay.
包含缩圈机制、大规模网络和生存玩法的Battle Royale游戏专家蓝图。
NEVER Do
绝对禁止的操作
- NEVER sync all 100 players every frame — Use relevancy system: only sync players within visual range. Far players update at 4Hz, nearby at 20Hz+.
- NEVER make zone center fully random — New circle must overlap significantly with old circle, or players teleport. Limit offset to .
current_radius - target_radius - NEVER use client-side hit detection — Client says "I shot at direction X", Server validates "Did it hit?". Prevents cheating.
- NEVER spawn loot without pooling — 1000+ loot items cause GC spikes. Pool loot pickups and reuse instances.
- NEVER forget VisibilityNotifier3D for distant players — Disable and AnimationPlayer for players behind or far away. Saves 60-80% CPU.
_process()
- 绝对不要每帧同步所有100名玩家 — 使用相关性系统:仅同步视觉范围内的玩家。远处玩家以4Hz更新,近处玩家以20Hz+更新。
- 绝对不要让缩圈中心完全随机 — 新的安全区必须与旧安全区有显著重叠,否则玩家会被强制传送。将偏移量限制为。
current_radius - target_radius - 绝对不要使用客户端命中检测 — 客户端仅发送"我朝X方向射击",由服务器验证"是否命中"。以此防止作弊。
- 绝对不要不使用对象池就生成Loot — 1000+件Loot物品会导致GC峰值。对Loot拾取物使用对象池并复用实例。
- 绝对不要忘记为远距离玩家设置VisibilityNotifier3D — 对身后或远处的玩家禁用和AnimationPlayer。可节省60-80%的CPU资源。
_process()
Available Scripts
可用脚本
MANDATORY: Read the appropriate script before implementing the corresponding pattern.
强制要求:在实现对应模式前,请先阅读相应的脚本。
kill_feed_bus.gd
kill_feed_bus.gd
Global elimination signal bus with match stat tracking. Single emission point for UI/logging, sorted killer rankings for end-game summary.
带有比赛统计跟踪的全局淘汰信号总线。为UI/日志提供单一发射点,可生成排序后的击杀者排行榜用于游戏结束总结。
storm_system.gd
storm_system.gd
Dynamic zone shrinking with damage interpolation. Tweens center/radius smoothly, scales damage by zone size for end-game intensity.
带有伤害插值的动态缩圈系统。平滑过渡中心点/半径,根据缩圈大小缩放伤害以提升游戏后期的紧张感。
Core Loop
核心循环
- Deploy: Player chooses a landing spot from an air vehicle.
- Loot: Player scavenges weapons and armor.
- Move: Player runs to the safe zone to avoid taking damage.
- Engage: Player fights others they encounter.
- Survive: Player attempts to be the last one standing.
- 部署:玩家从飞行器上选择降落点。
- 搜刮:玩家搜寻武器和护甲。
- 转移:玩家前往安全区以避免受到伤害。
- 交战:玩家与遭遇的其他玩家战斗。
- 存活:玩家尝试成为最后一名存活者。
Skill Chain
技能链
| Phase | Skills | Purpose |
|---|---|---|
| 1. Net | | Authoritative server, lag compensation |
| 2. Map | | Large terrain, chunking, distant trees |
| 3. Items | | Managing backpack, attachments, armor |
| 4. Combat | | Projectile physics, damage calculation |
| 5. Logic | | Managing the Storm/Zone state |
| 阶段 | 技能 | 用途 |
|---|---|---|
| 1. 网络 | | 权威服务器、延迟补偿 |
| 2. 地图 | | 大型地形、分块处理、远距离树木 |
| 3. 物品 | | 管理背包、配件、护甲 |
| 4. 战斗 | | 抛射物物理、伤害计算 |
| 5. 逻辑 | | 管理风暴/缩圈状态 |
Architecture Overview
架构概述
1. The Zone Manager (The Storm)
1. 缩圈管理器(风暴系统)
Manages the shrinking safe area.
gdscript
undefined管理不断缩小的安全区域。
gdscript
undefinedzone_manager.gd
zone_manager.gd
extends Node
@export var phases: Array[ZonePhase]
var current_phase_index: int = 0
var current_radius: float = 2000.0
var target_radius: float = 2000.0
var center: Vector2 = Vector2.ZERO
var target_center: Vector2 = Vector2.ZERO
var shrink_speed: float = 0.0
func start_next_phase() -> void:
var phase = phases[current_phase_index]
target_radius = phase.end_radius
# Pick new center WITHIN current circle but respecting new radius
var random_angle = randf() * TAU
var max_offset = current_radius - target_radius
var offset = Vector2.RIGHT.rotated(random_angle) * (randf() * max_offset)
target_center = center + offset
shrink_speed = (current_radius - target_radius) / phase.shrink_timefunc _process(delta: float) -> void:
if current_radius > target_radius:
current_radius -= shrink_speed * delta
center = center.move_toward(target_center, (shrink_speed * delta) * (center.distance_to(target_center) / (current_radius - target_radius)))
undefinedextends Node
@export var phases: Array[ZonePhase]
var current_phase_index: int = 0
var current_radius: float = 2000.0
var target_radius: float = 2000.0
var center: Vector2 = Vector2.ZERO
var target_center: Vector2 = Vector2.ZERO
var shrink_speed: float = 0.0
func start_next_phase() -> void:
var phase = phases[current_phase_index]
target_radius = phase.end_radius
# Pick new center WITHIN current circle but respecting new radius
var random_angle = randf() * TAU
var max_offset = current_radius - target_radius
var offset = Vector2.RIGHT.rotated(random_angle) * (randf() * max_offset)
target_center = center + offset
shrink_speed = (current_radius - target_radius) / phase.shrink_timefunc _process(delta: float) -> void:
if current_radius > target_radius:
current_radius -= shrink_speed * delta
center = center.move_toward(target_center, (shrink_speed * delta) * (center.distance_to(target_center) / (current_radius - target_radius)))
undefined2. Loot Spawner
2. Loot生成器
Efficiently populating the world.
gdscript
undefined高效填充游戏世界。
gdscript
undefinedloot_manager.gd
loot_manager.gd
func spawn_loot() -> void:
for spawn_point in get_tree().get_nodes_in_group("loot_spawns"):
if randf() < spawn_point.spawn_chance:
var item_id = loot_table.roll_item()
var loot_instance = loot_scene.instantiate()
loot_instance.setup(item_id)
add_child(loot_instance)
undefinedfunc spawn_loot() -> void:
for spawn_point in get_tree().get_nodes_in_group("loot_spawns"):
if randf() < spawn_point.spawn_chance:
var item_id = loot_table.roll_item()
var loot_instance = loot_scene.instantiate()
loot_instance.setup(item_id)
add_child(loot_instance)
undefined3. Deployment System
3. 部署系统
Transitioning from plane to ground.
gdscript
undefined从飞机到地面的过渡逻辑。
gdscript
undefinedplayer_controller.gd
player_controller.gd
enum State { IN_PLANE, FREEFALL, PARACHUTE, GROUNDED }
func _physics_process(delta: float) -> void:
match current_state:
State.FREEFALL:
velocity.y = move_toward(velocity.y, -50.0, gravity * delta)
move_and_slide()
if position.y < auto_deploy_height:
deploy_parachute()
undefinedenum State { IN_PLANE, FREEFALL, PARACHUTE, GROUNDED }
func _physics_process(delta: float) -> void:
match current_state:
State.FREEFALL:
velocity.y = move_toward(velocity.y, -50.0, gravity * delta)
move_and_slide()
if position.y < auto_deploy_height:
deploy_parachute()
undefinedKey Mechanics Implementation
核心机制实现
Zone Damage
缩圈伤害
Checking if player is outside the circle.
gdscript
func check_zone_damage() -> void:
var dist = Vector2(global_position.x, global_position.z).distance_to(ZoneManager.center)
if dist > ZoneManager.current_radius:
take_damage(ZoneManager.dps * delta)检测玩家是否在安全区外。
gdscript
func check_zone_damage() -> void:
var dist = Vector2(global_position.x, global_position.z).distance_to(ZoneManager.center)
if dist > ZoneManager.current_radius:
take_damage(ZoneManager.dps * delta)Networking Optimization
网络优化
You cannot sync 100 players every frame.
- Relevancy: Only send updates for players within visual range.
- Frequency: Update far-away players at 4Hz, nearby at 20Hz+ (Server Tick).
- Snapshot Interpolation: Client buffers headers to play them back smoothly.
你无法每帧同步100名玩家。
- 相关性系统:仅发送视觉范围内玩家的更新。
- 更新频率:远距离玩家以4Hz更新,近处玩家以20Hz+更新(服务器 Tick)。
- 快照插值:客户端缓存数据头以实现平滑回放。
Godot-Specific Tips
Godot专属技巧
- MultiplayerSynchronizer: Use to lower bandwidth for distant objects.
replication_interval - VisibilityNotifier3D: Critical. Disable and AnimationPlayer for players behind you or far away.
_process - Occlusion Culling: Essential for large maps with buildings. Bake occlusion data.
- HLOD: Use Hierarchical Level of Detail for terrain and large structures.
- MultiplayerSynchronizer:使用来降低远距离对象的带宽消耗。
replication_interval - VisibilityNotifier3D:至关重要。对身后或远处的玩家禁用和AnimationPlayer。
_process - 遮挡剔除:对于包含建筑的大型地图必不可少。烘焙遮挡数据。
- HLOD:对地形和大型结构使用层级细节(Hierarchical Level of Detail)。
Common Pitfalls
常见陷阱
- Too Main Loot: Too much loot causes lag. Fix: Use object pooling for loot pickups.
- Camping: Players hide forever. Fix: The Zone forces movement. Also, anti-camping mechanics like "scan reveals" (optional).
- Cheating: Client-side hit detection. Fix: Authoritative server logic. Client says "I shot at direction X", Server calculates "Did it hit?".
- Loot过多:过多的Loot会导致卡顿。解决方法:对Loot拾取物使用对象池。
- 蹲点:玩家一直躲着不出来。解决方法:缩圈机制强制玩家转移。还可加入反蹲点机制,比如"扫描暴露位置"(可选)。
- 作弊:客户端侧命中检测。解决方法:使用权威服务器逻辑。客户端仅发送"我朝X方向射击",由服务器计算"是否命中"。
Reference
参考资料
- Master Skill: godot-master
- 核心技能:godot-master