полнценая система прогресаа и конца уровне с началом и концом

This commit is contained in:
2026-07-23 01:41:44 +07:00
parent 6c1667911f
commit 0d03c06854
17 changed files with 422 additions and 26 deletions
+7
View File
@@ -9,6 +9,8 @@
[ext_resource type="Script" uid="uid://c8a2kystypxdm" path="res://addons/Targets/Scripts/ShootingRangeTargetManagerScript.gd" id="6_nmj7y"] [ext_resource type="Script" uid="uid://c8a2kystypxdm" path="res://addons/Targets/Scripts/ShootingRangeTargetManagerScript.gd" id="6_nmj7y"]
[ext_resource type="PackedScene" uid="uid://cjhibfe5567xa" path="res://addons/Targets/Scenes/ShootingRangeTargetScene.tscn" id="7_wwbpl"] [ext_resource type="PackedScene" uid="uid://cjhibfe5567xa" path="res://addons/Targets/Scenes/ShootingRangeTargetScene.tscn" id="7_wwbpl"]
[ext_resource type="PackedScene" uid="uid://d27xhk2ygjsbr" path="res://addons/Targets/Scenes/HitableBoxScene.tscn" id="8_2mjpe"] [ext_resource type="PackedScene" uid="uid://d27xhk2ygjsbr" path="res://addons/Targets/Scenes/HitableBoxScene.tscn" id="8_2mjpe"]
[ext_resource type="PackedScene" uid="uid://cxckcssgallbx" path="res://addons/Misc/Scenes/level_trigger.tscn" id="10_v12cc"]
[ext_resource type="PackedScene" uid="uid://c1v246tyt6bng" path="res://addons/Misc/Scenes/results_screen.tscn" id="11_rode7"]
[sub_resource type="PanoramaSkyMaterial" id="PanoramaSkyMaterial_k1n2p"] [sub_resource type="PanoramaSkyMaterial" id="PanoramaSkyMaterial_k1n2p"]
panorama = ExtResource("5_k1n2p") panorama = ExtResource("5_k1n2p")
@@ -395,3 +397,8 @@ dash_speed = 12.11
jumpHeight = 1.0 jumpHeight = 1.0
[node name="NamingConventionConverter" type="Node" parent="." unique_id=1842485999] [node name="NamingConventionConverter" type="Node" parent="." unique_id=1842485999]
[node name="LevelTrigger" parent="." unique_id=549172302 instance=ExtResource("10_v12cc")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -11.757071, 3.444125, -127.8315)
next_scene_path = "uid://blus2wf5ps3i7"
results_screen_scene = ExtResource("11_rode7")
+7
View File
@@ -15,6 +15,8 @@
[ext_resource type="PackedScene" uid="uid://blxd132vgsdle" path="res://addons/custmode/larek.tscn" id="11_n3seu"] [ext_resource type="PackedScene" uid="uid://blxd132vgsdle" path="res://addons/custmode/larek.tscn" id="11_n3seu"]
[ext_resource type="PackedScene" uid="uid://muvkocbhln75" path="res://addons/custmode/car_2.tscn" id="12_n3seu"] [ext_resource type="PackedScene" uid="uid://muvkocbhln75" path="res://addons/custmode/car_2.tscn" id="12_n3seu"]
[ext_resource type="PackedScene" uid="uid://dwlnmn50e7r2p" path="res://showflake.tscn" id="15_6tfqi"] [ext_resource type="PackedScene" uid="uid://dwlnmn50e7r2p" path="res://showflake.tscn" id="15_6tfqi"]
[ext_resource type="PackedScene" uid="uid://cxckcssgallbx" path="res://addons/Misc/Scenes/level_trigger.tscn" id="16_ld5ws"]
[ext_resource type="PackedScene" uid="uid://c1v246tyt6bng" path="res://addons/Misc/Scenes/results_screen.tscn" id="17_83ltg"]
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_pj53b"] [sub_resource type="StandardMaterial3D" id="StandardMaterial3D_pj53b"]
albedo_color = Color(0.24777229, 0.24777214, 0.24777214, 1) albedo_color = Color(0.24777229, 0.24777214, 0.24777214, 1)
@@ -547,3 +549,8 @@ transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -23.237055, 0, -22.500967)
[node name="Node3D4" parent="snow2" unique_id=1755887601 instance=ExtResource("15_6tfqi")] [node name="Node3D4" parent="snow2" unique_id=1755887601 instance=ExtResource("15_6tfqi")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -16.309002, 0, -19.343246) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -16.309002, 0, -19.343246)
[node name="LevelTrigger" parent="." unique_id=549172302 instance=ExtResource("16_ld5ws")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -210.60919, 2.6160936, -0.4971075)
next_scene_path = "uid://51xf0fd3ibnb"
results_screen_scene = ExtResource("17_83ltg")
+27
View File
@@ -0,0 +1,27 @@
[gd_scene format=3 uid="uid://cxckcssgallbx"]
[ext_resource type="Script" uid="uid://dux8o5uwin1sy" path="res://addons/Misc/Scripts/level_trigger.gd" id="1_1g6t3"]
[ext_resource type="ArrayMesh" uid="uid://dflmd4037fdqa" path="res://addons/custmode/untitled.obj" id="1_tam0r"]
[sub_resource type="SphereShape3D" id="SphereShape3D_pmktt"]
[sub_resource type="SphereShape3D" id="SphereShape3D_a2m1y"]
radius = 6.0
[node name="LevelTrigger" type="StaticBody3D" unique_id=549172302]
script = ExtResource("1_1g6t3")
[node name="CollisionShape3D" type="CollisionShape3D" parent="." unique_id=1715081297]
transform = Transform3D(6.355, 0, 0, 0, 6.355, 0, 0, 0, 6.355, 0, 0, 0)
shape = SubResource("SphereShape3D_pmktt")
[node name="MeshInstance3D" type="MeshInstance3D" parent="CollisionShape3D" unique_id=1423996988]
transform = Transform3D(0.06, 0, 0, 0, 0.06, 0, 0, 0, 0.06, 0, -0.47206923, 0)
mesh = ExtResource("1_tam0r")
[node name="DetectArea" type="Area3D" parent="." unique_id=1314234424]
collision_layer = 0
collision_mask = 15
[node name="CollisionShape3D" type="CollisionShape3D" parent="DetectArea" unique_id=1390638580]
shape = SubResource("SphereShape3D_a2m1y")
+57
View File
@@ -0,0 +1,57 @@
[gd_scene format=3 uid="uid://c1v246tyt6bng"]
[ext_resource type="Script" uid="uid://bojftnghiqd2g" path="res://addons/Misc/Scripts/results_screen.gd" id="1_esv6s"]
[node name="ResultsScreen" type="CanvasLayer" unique_id=2101110637]
layer = 1000000000
script = ExtResource("1_esv6s")
[node name="TitleLabel" type="Label" parent="." unique_id=864255331]
anchors_preset = -1
anchor_left = 0.586
anchor_top = 0.45200002
anchor_right = 0.586
anchor_bottom = 0.45200002
offset_left = -84.07202
offset_top = -113.89603
offset_right = 82.92798
offset_bottom = -90.89603
text = "УРОВЕНЬ ЗАВЕРШЕН"
[node name="KillsLabel" type="Label" parent="." unique_id=1676098116]
anchors_preset = -1
anchor_left = 0.56700003
anchor_top = 0.43300003
anchor_right = 0.56700003
anchor_bottom = 0.43300003
offset_left = -69.18402
offset_top = 62.415985
offset_right = 68.81598
offset_bottom = 85.415985
text = "Убито врагов: 0\"."
[node name="TimeLabel" type="Label" parent="." unique_id=466879962]
anchors_preset = -1
anchor_left = 0.60200006
anchor_top = 0.46500003
anchor_right = 0.60200006
anchor_bottom = 0.46500003
offset_left = -108.50409
offset_top = 84.67999
offset_right = 108.49591
offset_bottom = 107.67999
text = "Время прохождения: 00:00"
[node name="ContinueButton" type="Button" parent="." unique_id=1156988049]
anchors_preset = -1
anchor_left = 0.586
anchor_top = 0.5
anchor_right = 0.586
anchor_bottom = 0.5
offset_left = -92.07202
offset_top = 122.0
offset_right = 57.92798
offset_bottom = 180.0
text = "Далее"
[connection signal="pressed" from="ContinueButton" to="." method="_on_continue_button_pressed"]
+65
View File
@@ -0,0 +1,65 @@
extends Node
# Хранилище данных, которое живет между уровнями
var saved_health: float = 100.0
var saved_weapons: Array = []
var saved_weapon_index: int = 0
var saved_ammo_dict: Dictionary = {}
var is_transfer_ready: bool = false # Флаг, что у нас есть сохраненные данные
# --- ФУНКЦИЯ 1: СОХРАНЕНИЕ ДАННЫХ ПЕРЕД СМЕНОЙ СЦЕНЫ ---
func save_player_data(player: Node) -> void:
if player == null: return
# 1. Запоминаем Здоровье
var health_comp = player.find_child("HealthComponent", true, false)
if health_comp:
saved_health = health_comp.current_health
# 2. Запоминаем Оружие и Патроны
# Найди этот блок внутри save_player_data в GameTransfer.gd:
var weapon_manager = player.find_child("WeaponManager", true, false)
if weapon_manager:
saved_weapons = weapon_manager.weaponStack.duplicate()
saved_weapon_index = weapon_manager.weaponIndex
# ИСПРАВЛЕНО: Более глубокий поиск менеджера патронов, если автор спрятал его в детях
var ammo_manager = weapon_manager.find_child("AmmoManager", true, false)
if ammo_manager == null and "ammoManager" in weapon_manager:
ammo_manager = weapon_manager.ammoManager
if ammo_manager and "ammoDict" in ammo_manager:
saved_ammo_dict = ammo_manager.ammoDict.duplicate()
is_transfer_ready = true
print("[ПЕРЕНОС] Данные игрока успешно сохранены в кэш!")
# --- ФУНКЦИЯ 2: ВОССТАНОВЛЕНИЕ ДАННЫХ НА НОВОМ УРОВНЕ ---
func load_player_data(player: Node) -> void:
if player == null or not is_transfer_ready: return
# 1. Возвращаем Здоровье
var health_comp = player.find_child("HealthComponent", true, false)
if health_comp:
health_comp.current_health = saved_health
# Обновляем цифры на новом HUD
var health_ui = player.find_child("PlayerHealthUI", true, false)
if health_ui and health_ui.has_method("_process"):
health_ui.notification(NOTIFICATION_PROCESS)
# 2. Возвращаем Оружие и Патроны
var weapon_manager = player.find_child("WeaponManager", true, false)
if weapon_manager:
weapon_manager.weaponStack = saved_weapons.duplicate()
weapon_manager.weaponIndex = saved_weapon_index
if "ammoManager" in weapon_manager and weapon_manager.ammoManager:
weapon_manager.ammoManager.ammoDict = saved_ammo_dict.duplicate()
# Принудительно заставляем ассет достать правильное оружие из памяти
if weapon_manager.has_method("changeWeapon"):
weapon_manager.changeWeapon(saved_weapon_index)
print("[ПЕРЕНОС] Снаряжение и ХП успешно возвращены игроку на новом уровне!")
+1
View File
@@ -0,0 +1 @@
uid://dbnkrmxycgjrl
+30
View File
@@ -0,0 +1,30 @@
extends Node
var current_kills: int = 0
var level_time: float = 0.0
var is_timer_running: bool = false
func _ready() -> void:
start_level_tracking()
func _process(delta: float) -> void:
if is_timer_running:
level_time += delta
func start_level_tracking() -> void:
current_kills = 0
level_time = 0.0
is_timer_running = true
func stop_level_tracking() -> void:
is_timer_running = false
func register_kill() -> void:
current_kills += 1
print("[СТАТИСТИКА] Моб уничтожен! Всего убийств: ", current_kills)
# Функция для красивого форматирования времени (например, 01:23)
func get_formatted_time() -> String:
var minutes = int(level_time) / 60
var seconds = int(level_time) % 60
return "%02d:%02d" % [minutes, seconds]
+1
View File
@@ -0,0 +1 @@
uid://jbvxvnmbrhe8
+55
View File
@@ -0,0 +1,55 @@
extends StaticBody3D
@export_file("*.tscn") var next_scene_path: String = ""
var is_triggered: bool = false
var detect_area: Area3D = null
@export var results_screen_scene: PackedScene
func _ready() -> void:
detect_area = $DetectArea
func _physics_process(delta: float) -> void:
if is_triggered or detect_area == null:
return
var overlapping_stuff: Array = []
overlapping_stuff.append_array(detect_area.get_overlapping_bodies())
overlapping_stuff.append_array(detect_area.get_overlapping_areas())
for node in overlapping_stuff:
if node == self or node == detect_area or node is StaticBody3D or "CSG" in node.name:
continue
var is_real_player = node.name == "PlayerCharacter"
if not is_real_player and node.get_parent():
is_real_player = node.get_parent().name == "PlayerCharacter"
if is_real_player:
is_triggered = true
print("[УРОВЕНЬ] МГНОВЕННЫЙ ФИНИШ! Полностью блокирую камеру и открываю курсор...")
# Отключаем сам триггер
set_physics_process(false)
# Находим корневой узел игрока
var main_player = node if node.name == "PlayerCharacter" else node.get_parent()
# --- МГНОВЕННАЯ ЗАМОРОЗКА ИНПУТОВ КАМЕРЫ И ОРУЖИЯ ---
# Переводим игрока в режим PROCESS_MODE_DISABLED.
# Это мгновенно отключает у него функции _process, _physics_process и ВСЕ _input функции мыши!
# Камера намертво каменеет в ту же секунду, без необходимости кликать кнопками.
if main_player:
main_player.process_mode = Node.PROCESS_MODE_DISABLED
# ----------------------------------------------------
# Аппаратно освобождаем мышь для клика по кнопке "Далее"
Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE)
# Спавним экран результатов в корень игры
if results_screen_scene:
var results_instance = results_screen_scene.instantiate()
get_tree().get_root().add_child(results_instance)
if results_instance.has_method("show_results"):
results_instance.show_results(next_scene_path)
return
+1
View File
@@ -0,0 +1 @@
uid://dux8o5uwin1sy
+79
View File
@@ -0,0 +1,79 @@
extends CanvasLayer
var target_scene_path: String = ""
func _ready() -> void:
# Ставим максимальный слой отрисовки, чтобы HUD игры не перекрывал меню
layer = 120
if has_node("Panel"):
$Panel.visible = true
print("[РЕЗУЛЬТАТЫ] Экран итогов успешно создан прямо на карте!")
func show_results(next_scene: String) -> void:
target_scene_path = next_scene
print("[РЕЗУЛЬТАТЫ] Данные получены. Путь к следующей сцене: ", target_scene_path)
# Останавливаем таймер уровня
if LevelStats:
LevelStats.stop_level_tracking()
# БРОНЕБОЙНОЕ ОБНОВЛЕНИЕ ТЕКСТА: Ищем узлы прямо в момент вызова функции
var kills_label = find_child("KillsLabel", true, false)
if kills_label == null: kills_label = find_child("kills_label", true, false)
if kills_label:
kills_label.text = "Убито врагов: " + str(LevelStats.current_kills)
print("[РЕЗУЛЬТАТЫ] Текст убийств обновлен: ", kills_label.text)
var time_label = find_child("TimeLabel", true, false)
if time_label == null: time_label = find_child("time_label", true, false)
if time_label:
time_label.text = "Время прохождения: " + LevelStats.get_formatted_time()
print("[РЕЗУЛЬТАТЫ] Текст времени обновлен: ", time_label.text)
# ПРИНУДИТЕЛЬНО РАЗРЕШАЕМ ДВИГАТЬ КУРСОР МЫШИ
Input.mouse_mode = Input.MOUSE_MODE_VISIBLE
func _on_continue_button_pressed() -> void:
print("[РЕЗУЛЬТАТЫ] Кнопка 'Далее' зафиксирована! Запускаю плавное затемнение...")
if target_scene_path == "":
print("[РЕЗУЛЬТАТЫ] ОШИБКА: Путь к следующей сцене пустой!")
return
# --- НАШЕ КРИТИЧЕСКОЕ ДОБАВЛЕНИЕ: СОХРАНЯЕМ ИГРОКА ПЕРЕД УХОДОМ В ЗАТЕМНЕНИЕ ---
var player = get_tree().current_scene.find_child("PlayerCharacter", true, false)
if player and GameTransfer:
GameTransfer.save_player_data(player)
# --------------------------------------------------------------------------------
# Твой старый код затемнения и смены сцены...
var fade_rect = find_child("FadeRect", true, false)
if fade_rect and "visible" in fade_rect:
fade_rect.visible = true
fade_rect.modulate.a = 0.0
var tween = create_tween()
tween.tween_property(fade_rect, "modulate:a", 1.0, 1.0)
await tween.finished
_set_ui_elements_visible(false)
if LevelStats: LevelStats.start_level_tracking()
queue_free()
get_tree().change_scene_to_file(target_scene_path)
# Полностью замени функцию в самом конце results_screen.gd на этот код:
func _set_ui_elements_visible(is_visible: bool) -> void:
# Находим и переключаем надпись убийств
var k_label = find_child("KillsLabel", true, false)
if k_label == null: k_label = find_child("kills_label", true, false)
if k_label: k_label.visible = is_visible
# Находим и переключаем надпись времени
var t_label = find_child("TimeLabel", true, false)
if t_label == null: t_label = find_child("time_label", true, false)
if t_label: t_label.visible = is_visible
# Находим и переключаем кнопку продолжения
var c_button = find_child("ContinueButton", true, false)
if c_button == null: c_button = find_child("continue_button", true, false)
if c_button: c_button.visible = is_visible
@@ -0,0 +1 @@
uid://bojftnghiqd2g
+1
View File
@@ -89,6 +89,7 @@ func die() -> void:
if custom_battle_music and is_currently_seeing_player and has_node("/root/MusicManager"): if custom_battle_music and is_currently_seeing_player and has_node("/root/MusicManager"):
get_node("/root/MusicManager").unregister_enemy_vision(self, custom_battle_music) get_node("/root/MusicManager").unregister_enemy_vision(self, custom_battle_music)
queue_free() queue_free()
if LevelStats: LevelStats.register_kill()
# --- ФИЗИКА, ПРИЦЕЛИВАНИЕ И СТРЕЛЬБА --- # --- ФИЗИКА, ПРИЦЕЛИВАНИЕ И СТРЕЛЬБА ---
@@ -96,12 +96,10 @@ var coyoteJumpOn : bool = false
@onready var ceilingCheck : RayCast3D = $Raycasts/CeilingCheck @onready var ceilingCheck : RayCast3D = $Raycasts/CeilingCheck
@onready var floorCheck : RayCast3D = $Raycasts/FloorCheck @onready var floorCheck : RayCast3D = $Raycasts/FloorCheck
func _ready(): # НАЙДИ ЭТУ ФУНКЦИЮ ВНУТРИ СKРИПТА PlayerCharacter.gd И ЗАМЕНИ ЕЁ:
# Запоминаем дефолтный FOV камеры, если она подключена
if player_camera:
normal_fov = player_camera.fov
#set move variables, and value references func _ready():
# Твой старый оригинальный код ready из ассета...
moveSpeed = walkSpeed moveSpeed = walkSpeed
moveAccel = walkAccel moveAccel = walkAccel
moveDeccel = walkDeccel moveDeccel = walkDeccel
@@ -111,6 +109,15 @@ func _ready():
nbJumpsInAirAllowedRef = nbJumpsInAirAllowed nbJumpsInAirAllowedRef = nbJumpsInAirAllowed
coyoteJumpCooldownRef = coyoteJumpCooldown coyoteJumpCooldownRef = coyoteJumpCooldown
# --- НАШЕ НОВОЕ ДОБАВЛЕНИЕ: ЗАБИРАЕМ КЭШ СНАРЯЖЕНИЯ И ХП НА НОВОЙ КАРТЕ ---
# Даем ассету фору в один кадр, чтобы его WeaponManager успел создаться,
# прежде чем мы принудительно перезапишем его инвентарь данными с прошлого уровня
await get_tree().create_timer(0.1).timeout
if GameTransfer:
GameTransfer.load_player_data(self)
# -------------------------------------------------------------------------
func _process(_delta: float): func _process(_delta: float):
displayProperties() displayProperties()
+69 -15
View File
@@ -83,31 +83,65 @@ func exitWeapon(nextWeapon : int):
enterWeapon(nextWeapon) enterWeapon(nextWeapon)
func enterWeapon(nextWeapon : int): func enterWeapon(nextWeapon):
#this function manage the second part of the weapon switching mechanic #this function manage the second part of the weapon switching mechanic
#in this part, the next weapon is enabled (equiped and set up) #in this part, the next weapon is enabled (equiped and set up)
# --- СВЕРХ-ЗАЩИТА ОТ БАГОВ СЛОВАРЯ (DICTIONARY) ПРИ СМЕНЕ УРОВНЯ ---
# Раз движок уверен, что weaponList — это Dictionary, проверяем наличие ключа через .has()
var is_valid_weapon = false
if weaponList != null and weaponList.has(nextWeapon):
is_valid_weapon = true
# Если оружие еще не готово или ключ '0' отсутствует в словаре на новом уровне:
if not is_valid_weapon:
print("[ОРУЖИЕ] Предупреждение: Ключ ", nextWeapon, " еще не инициализирован в словарe weaponList. Ждем...")
# Даем ассету один кадр очухаться и наполнить свои словари пушками
await get_tree().process_frame
# Повторная проверка
if weaponList != null and weaponList.has(nextWeapon):
is_valid_weapon = true
# Если всё еще пусто — аварийно выходим, чтобы спасти игру от вылета
if not is_valid_weapon:
print("[ОРУЖИЕ] КРИТИЧЕСКИЙ СБОЙ: Оружие полностью утеряно при генерации сцены!")
canUseWeapon = true
canChangeWeapons = true
return
cW = weaponList[nextWeapon] cW = weaponList[nextWeapon]
nextWeapon = 0
cWModel = cW.weaponSlot.model
cWModel.visible = true
shootManager.getCurrentWeapon(cW) # Проверяем наличие модели оружия перед включением видимости
reloadManager.getCurrentWeapon(cW) if cW and cW.weaponSlot and "model" in cW.weaponSlot:
animManager.getCurrentWeapon(cW, cWModel) cWModel = cW.weaponSlot.model
if cWModel:
cWModel.visible = true
weaponSoundManagement(cW.equipSound, cW.equipSoundSpeed) # Передаем обновленное оружие в менеджеры, если они существуют
if shootManager: shootManager.getCurrentWeapon(cW)
if reloadManager: reloadManager.getCurrentWeapon(cW)
if animManager: animManager.getCurrentWeapon(cW, cWModel)
animPlayer.playback_default_blend_time = cW.animBlendTime if cW:
weaponSoundManagement(cW.equipSound, cW.equipSoundSpeed)
if animPlayer:
animPlayer.playback_default_blend_time = cW.animBlendTime
if cW.equipAnimName != "": if cW.equipAnimName != "" and animManager:
animManager.playAnimation("EquipAnim%s" % cW.weaponName, cW.equipAnimSpeed, false) animManager.playAnimation("EquipAnim%s" % cW.weaponName, cW.equipAnimSpeed, false)
await get_tree().create_timer(cW.equipTime).timeout
await get_tree().create_timer(cW.equipTime).timeout
if cW.isShooting: cW.isShooting = false
if cW.isReloading: cW.isReloading = false
if cW.isShooting: cW.isShooting = false
if cW.isReloading: cW.isReloading = false
canUseWeapon = true canUseWeapon = true
canChangeWeapons = true canChangeWeapons = true
func _process(_delta : float): func _process(_delta : float):
if cW != null and cWModel != null and canUseWeapon: if cW != null and cWModel != null and canUseWeapon:
weaponInputs() weaponInputs()
@@ -132,10 +166,30 @@ func weaponInputs():
changeWeapon(weaponStack[weaponIndex]) changeWeapon(weaponStack[weaponIndex])
func displayStats(): func displayStats():
if hud == null or cW == null:
return
hud.displayWeaponStack(weaponStack.size()) hud.displayWeaponStack(weaponStack.size())
hud.displayWeaponName(cW.weaponName) hud.displayWeaponName(cW.weaponName)
hud.displayTotalAmmoInMag(cW.totalAmmoInMag, cW.nbProjShotsAtSameTime) hud.displayTotalAmmoInMag(cW.totalAmmoInMag, cW.nbProjShotsAtSameTime)
hud.displayTotalAmmo(ammoManager.ammoDict[cW.ammoType], cW.nbProjShotsAtSameTime)
# --- БРОНЕБОЙНАЯ ЗАЩИТА ОТ ВЫЛЕТА ИЗ-ЗА ПАТРОНОВ ПРИ СМЕНЕ СЦЕНЫ ---
# Используем метод .get() вместо квадратных скобок [...].
# Он никогда не уронит игру, даже если словарь ammoDict полностью пустой!
var total_ammo : int = 0
if ammoManager != null and ammoManager.ammoDict != null:
total_ammo = ammoManager.ammoDict.get(cW.ammoType, 0)
hud.displayTotalAmmo(total_ammo, cW.nbProjShotsAtSameTime)
# --- БРОНЕБОЙНАЯ ЗАЩИТА ОТ ВЫЛЕТА ПРИ ПЕРЕХОДЕ НА НОВЫЙ УРОВЕНЬ ---
# Проверяем, существует ли ammoManager и есть ли тип патронов текущего оружия в словаре
if ammoManager != null and ammoManager.ammoDict != null and ammoManager.ammoDict.has(cW.ammoType):
hud.displayTotalAmmo(ammoManager.ammoDict[cW.ammoType], cW.nbProjShotsAtSameTime)
else:
# Если словарь еще не загрузился, временно пишем 0, чтобы игра не вылетала
hud.displayTotalAmmo(0, cW.nbProjShotsAtSameTime)
func changeWeapon(nextWeapon : int): func changeWeapon(nextWeapon : int):
if canChangeWeapons and !cW.isShooting and !cW.isReloading: if canChangeWeapons and !cW.isShooting and !cW.isReloading:
+4 -4
View File
@@ -1,9 +1,9 @@
[gd_scene format=3 uid="uid://blus2wf5ps3i7"] [gd_scene format=3 uid="uid://blus2wf5ps3i7"]
[ext_resource type="PackedScene" uid="uid://bwggrf7sbmkcv" path="res://addons/PlayerCharacter/Scenes/PlayerCharacterScene.tscn" id="2_58joc"]
[ext_resource type="PackedScene" uid="uid://beqxcfcv7jhpg" path="res://капсула_вагона.tscn" id="3_0pxd3"] [ext_resource type="PackedScene" uid="uid://beqxcfcv7jhpg" path="res://капсула_вагона.tscn" id="3_0pxd3"]
[ext_resource type="Texture2D" uid="uid://mdxrv585rfcv" path="res://addons/custmode/test.png" id="3_58joc"] [ext_resource type="Texture2D" uid="uid://mdxrv585rfcv" path="res://addons/custmode/test.png" id="3_58joc"]
[ext_resource type="Texture2D" uid="uid://b26ir1ccbj3f1" path="res://addons/texture_custom/Timeline 1_00086400.png" id="4_0pxd3"] [ext_resource type="Texture2D" uid="uid://b26ir1ccbj3f1" path="res://addons/texture_custom/Timeline 1_00086400.png" id="4_0pxd3"]
[ext_resource type="PackedScene" uid="uid://bwggrf7sbmkcv" path="res://addons/PlayerCharacter/Scenes/PlayerCharacterScene.tscn" id="4_r6sk8"]
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_0pxd3"] [sub_resource type="StandardMaterial3D" id="StandardMaterial3D_0pxd3"]
albedo_texture = ExtResource("3_58joc") albedo_texture = ExtResource("3_58joc")
@@ -27,9 +27,6 @@ ssr_fade_in = 2.2392774
[node name="Node3D" type="Node3D" unique_id=1418886085] [node name="Node3D" type="Node3D" unique_id=1418886085]
[node name="PlayerCharacter" parent="." unique_id=1059654044 instance=ExtResource("2_58joc")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.3088503, 2.1988652, 0.17686236)
[node name="CSGBox3D" type="CSGBox3D" parent="." unique_id=1252647284] [node name="CSGBox3D" type="CSGBox3D" parent="." unique_id=1252647284]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 2.4910154, -0.16952014, -4.4346185) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 2.4910154, -0.16952014, -4.4346185)
material_override = SubResource("StandardMaterial3D_0pxd3") material_override = SubResource("StandardMaterial3D_0pxd3")
@@ -57,3 +54,6 @@ shadow_normal_bias = 1.97
shadow_reverse_cull_face = true shadow_reverse_cull_face = true
shadow_transmittance_bias = -0.05 shadow_transmittance_bias = -0.05
shadow_blur = 1.15 shadow_blur = 1.15
[node name="PlayerCharacter" parent="." unique_id=1059654044 instance=ExtResource("4_r6sk8")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.682482, 1.3198853, -1.3838298)
+3
View File
@@ -18,6 +18,9 @@ config/icon="res://icon.svg"
[autoload] [autoload]
MusicManager="*uid://dgg3biwjhbaeo" MusicManager="*uid://dgg3biwjhbaeo"
LevelStats="*uid://jbvxvnmbrhe8"
ResultsScreen="*uid://bojftnghiqd2g"
GameTransfer="*uid://dbnkrmxycgjrl"
[editor] [editor]