godot-game-one 是复古弹幕射击游戏,战斗节奏快,道具和升级系统决定了从开局到通关的成长曲线。这篇讲三件事:道具怎么掉落、升级怎么生效、不同敌人的掉落策略差异。
道具类型与效果 游戏有 6 种道具:
类型
效果
是否累积
spread
增加子弹数量,扩展射击角度
是,上限 10 级
speed
提高射速,缩短射击间隔
是,上限 15 级
power
提高子弹伤害
是,上限 50 级,溢出转回血
heal
恢复 1 点生命值
否,即时效果
bomb
清屏,逐个击杀所有敌人
否,即时效果
core
技能和激光冷却时间 ×0.7
否,即时效果
power 道具有一个特殊设计:当 bullet_power_level 达到上限 50 后,再拾取会自动转为回血。这避免了满级后道具浪费的问题。
核心逻辑在 scripts/game_state.gd:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 func collect_powerup(type : String, peer_id: int = -1 ) -> void: var s := _state(pid) match type : "spread" : if int (s.shoot_level) < 10 : s.shoot_level = min (int (s.shoot_level) + 1 , 10 ) "speed" : if int (s.shoot_speed_level) < 15 : s.shoot_speed_level = min (int (s.shoot_speed_level) + 1 , 15 ) "power" : if int (s.bullet_power_level) >= 15 : heal(1 , pid) else : s.bullet_power_level = min (int (s.bullet_power_level) + 1 , 50 ) "heal" : heal(1 , pid) "bomb" : pass "core" : s.skill_cooldown = max (float (s.skill_cooldown) * 0.7 , 0.0 ) s.laser_cooldown = max (float (s.laser_cooldown) * 0.7 , 0.0 )
升级对射击模式的质变 升级不是简单的数值累加,shoot_level 在不同阶段会改变射击模式。实现在 scripts/player/combat_controller.gd:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 func _shoot() -> void: var level: int = GameState.get_shoot_level(_player.peer_id) if level >= 12 : var spread_angles: Array[float ] = [-0.3 , -0.15 , 0.0 , 0.15 , 0.3 ] for i in range (bullet_count): var a = base_angle + spread_angles[i % 5 ] * (0.5 + (level - 12 ) * 0.1 ) elif level >= 8 : for i in bullet_count: var a = base_angle + positions[i] * 0.008 elif level >= 4 : for i in bullet_count: var offset = perp * positions[i] else :
三个阶段的视觉差异:
阶段
shoot_level
表现
初始
1-3
2-3 发子弹并行,同方向
散射
4-11
多发子弹,角度逐渐展开
扇形
12+
5 路扇形弹幕,带微扰动
子弹数量的计算公式:
1 2 func get_bullet_count() -> int : return min (2 + shoot_level / 3 + extra_bullet, 12 )
射速的计算公式:
1 2 func get_shoot_cooldown() -> float : return max (0.27 - shoot_speed_level * 0.018 , 0.08 )
满级射速(level 15)冷却仅 0.08 秒,配合 12 发扇形弹幕,输出密度极高。
追踪导弹:隐藏的升级链 shoot_level 还附带一个隐藏效果——追踪导弹。每 5 级解锁一个导弹舱,最多 5 个:
1 2 3 4 5 6 7 8 func _get_missile_tier() -> int : return mini(level / 5 , 5 ) func _get_missile_damage() -> int : return (bullet_damage + 2 ) * pow (1.5 , tier - 1 ) func _get_missile_interval() -> float : return 1.5 / tier
导弹伤害是指数增长,tier 5 的导弹伤害是基础的 5 倍多。这个设计让 spread 道具的价值更高——它不仅增加子弹数量,还间接触发导弹升级。
护盾系统 护盾的 HP 与 bullet_power_level 联动:
1 2 3 4 5 func get_shield_max_hp(peer_id: int = -1 ) -> int : var bp := get_bullet_power_level(peer_id) var mhp := get_max_health(peer_id) var bonus := get_shield_bonus(peer_id) return maxi(1 , int ((10 + bp * 2 + int (mhp * 0.2 )) * 0.5 ) + bonus)
护盾被击破后,8 秒自动充能恢复满层:
1 2 3 4 5 6 7 8 9 10 const SHIELD_RECHARGE_INTERVAL: float = 8.0 func _update_shield_recharge(delta: float ) -> void: if GameState.get_shield_layers(peer_id) > 0 : _shield_recharge_timer = SHIELD_RECHARGE_INTERVAL _shield_recharge_timer -= delta if _shield_recharge_timer <= 0.0 : _shield_recharge_timer = SHIELD_RECHARGE_INTERVAL var max_shield := _compute_shield_max_hp() GameState.set_shield_layers(peer_id, max_shield)
这个设计让 power 道具有双重价值:直接增加子弹伤害,同时提升护盾上限。
道具掉落策略 不同敌人的掉落策略差异明显。
普通敌人 20% 基础掉率,随敌人类型递增:
1 2 3 enemy.drop_chance = 0.20 + enemy_type * 0.12
掉落时从 5 种道具中等概率随机选择:
1 2 3 4 5 func _try_spawn_powerup() -> void: if randf() < drop_chance: var types: Array[String] = ["spread" , "speed" , "power" , "heal" , "bomb" ] var picked_type: String = types[randi() % types.size()] pu.setup(picked_type)
精英怪 精英怪死亡时弧形喷射 12 个道具,沿扇形弧度排列:
1 2 3 4 5 6 7 func _spawn_rewards() -> void: var types: Array[String] = ["heal" , "bomb" , "spread" , "speed" , "heal" , "power" , "heal" , "power" , "speed" , "spread" , "heal" , "bomb" ] var step: float = PI / max (float (types.size() - 1 ), 1.0 ) var angle: float = -PI * 0.85 + step * float (i) var offset := Vector2(cos(angle), sin(angle)) * randf_range(26.0 , 58.0 ) pu.global_position = global_position + offset
注意 heal 出现了 4 次——精英怪的掉落偏向恢复,因为精英战通常伴随大量伤害。
在线模式下,道具会标记 assigned_peer_id,轮流分配给存活玩家。
Boss Boss 掉落分两层:普通掉落 + 核心掉落。普通掉落是 4 个道具均匀分布在半径 70 的圆环上:
1 2 3 4 func _drop_supply_fragments() -> void: var types: Array[String] = ["heal" , "speed" , "power" , "heal" ] for i in range (types.size()): _spawn_powerup_fragment(types[i], float (i) * TAU / float (types.size()), 70.0 )
核心掉落额外包含 core 道具,绑定给特定玩家:
1 2 func _spawn_core_fragments() -> void: var types: Array[String] = ["core" , "heal" , "speed" , "power" , "core" , "heal" ]
道具拾取:磁铁机制 道具不是碰到就拾取,而是有一个磁铁吸引的过程。
玩家每 4 帧检测一次附近的道具:
1 2 3 4 5 6 7 8 func _try_pickup_nearby() -> void: _pickup_frame_skip += 1 if _pickup_frame_skip % 4 != 0 : return var powerups := get_tree().get_nodes_in_group("powerups" ) for pu in powerups: if pu.global_position.distance_to(_player.global_position) < _pickup_radius: pu.start_magnet(self )
磁铁飞行有加速曲线:
1 2 3 4 5 6 7 8 9 func _physics_process(delta: float ) -> void: if _magnet_target and is_instance_valid(_magnet_target): _magnet_elapsed += delta var accel_t = clampf(_magnet_elapsed / 0.35 , 0.0 , 1.0 ) _magnet_speed = lerpf(320.0 , 720.0 , accel_t) var dir = global_position.direction_to(_magnet_target.global_position) global_position += dir * _magnet_speed * delta if global_position.distance_to(_magnet_target.global_position) < 40.0 : collect()
磁铁机制的目的是给玩家一个视觉反馈——看到道具飞向自己,比瞬间消失更有满足感。
升级链条全景 1 2 3 4 5 6 7 8 9 击杀掉落 ─┬── "spread" → shoot_level ↑ (上限10,触发射击模式质变) ├── "speed" → shoot_speed_level ↑ (上限15,冷却 0.27→0.08s) ├── "power" → bullet_power_level ↑ (上限50,溢出转回血) ├── "heal" → HP +1 ├── "bomb" → 即时清屏 └── "core" → 技能/激光冷却 ×0.7 shoot_level 额外解锁: 每 5 级 → 追踪导弹舱 +1(伤害 ×1.5^n,间隔 ÷n)
每个道具都有明确的价值,但组合起来会有质变。spread + speed 让输出密度指数上升,power 同时提升伤害和护盾,core 缩短技能冷却让爆发更频繁。单个道具是加法,组合起来是乘法。