Godot Version
4.3
Question
(EVERYTHING HERE HAS BEEN TRANSLATED FROM RUSSIAN INTO ENGLISH, I’M NOT SURE IF THE SPELLING IS CORRECT)
For the second day now, I have been trying to implement a system that when a player enters a building or looks into the passage of the building with his field of view, the roof should disappear, and when he is not in the building or does not look into the open passage, the roof should appear accordingly, but nothing happens.
I write all the code with the help of AI, since I myself am soooo far from the topic of coding, and up to the moment I wanted to implement it, everything worked out for me, now I will explain in more detail the structure of my project.
first of all, this is a 2D game with a top view, here is the structure of the nodes of the scene:
-Node2D
—TileMap
-----TileMapLayer (there are surface tiles here)
-----TileMap Layer 2 (here are the wall tiles)
-----TileMap Layer 3 (here are the roof tiles)
—Character Body 2D
-----Animated Sprite 2D
-----Collision Shape 2D
-----Camera2D
-----FieldOfView
-------CollisionPolygon2D
now about the file system (don’t pay attention to the fact that the names are strange, I just write Russian words with an English layout, it’s more convenient for me to understand):
-Game folder
—sprayty (sprites)
-----beton_stena_old1.png (wall)
-----beton_stena_old(krest).png (wall)
-----beton_stena_old(perekrest).png (wall)
-----beton_stena_old(ugol).png (wall)
-----beton_stena_old.png (wall)
-----Human1(ruki0).png (player)
-----Human1(ruki1).png (player)
-----Human1(ruki).png (player)
-----krysha(metall_old).png (roof)
-----krysha.tres (all roof tiles)
-----krysha_krai1(metall_old).png (roof)
-----krysha_krai(metall_old).png (roof)
-----krysha_ugol1(metall_old).png (roof)
-----krysha_ugol2(metall_old).png (roof)
-----krysha_ugol3(metall_old).png (roof)
-----krysha_ugol(metall_old).png (roof)
-----pesok.png (sand)
-----pesok_plitka.png (sand/tile)
-----pesok_zelen.png (sand)
-----plitka_old.png (tile)
-----poverhnost.tres (all tiles)
-----stena.tres (all wall tiles)
—character_body_2d.gd
—export_presets.cfg
—icon.png
—Player.tscn
—RoofTileMap.gd
in the project settings, in the “layer names” and “2D Physics” sections, I have names for different layers, namely:
Layer 1 stena (wall)
Layer 2 krysha (roof)
Layer 3 igrok (player)
Layer 4 poverhnost (surface)
Layer 5 npc (for the future)
Layer 6 vragi (Enemies for the future)
Layer 7 FieldOfView
just in case, I’ll also write down which nodes are in Nodded and which layers they have in Collision Layer and Collision Mask:
TileMapLayer:
Collision Layer: 4
Mask Layer: nothing
TileMapLayer2:
Collision Layer: 1
Mask Layer: 3, 4, 6, 7
TileMapLayer3:
Collision Layer: 2
Mask Layer: 3, 7
CharacterBody2D:
Layer: 3
Mask: 1
FieldOfView:
Layer: 7
Mask: 1, 2
here is the script that is in CharacterBody2D (if the character is working fine, everything is as it should be, but just in case, I’m describing the whole project to you, because I don’t know how to solve my problem):
extends CharacterBody2D
# Параметры скорости
var walk_speed = 200 # Скорость ходьбы вперёд
var run_speed = 300 # Скорость бега
var slow_speed = 100 # Скорость при движении назад или вбок
func _physics_process(delta):
var input_vector = Vector2.ZERO
# Получаем ввод от игрока
if Input.is_action_pressed("move_forward"):
input_vector.y -= 1 # Вперёд
if Input.is_action_pressed("move_backward"):
input_vector.y += 1 # Назад
if Input.is_action_pressed("move_left"):
input_vector.x -= 1 # Влево
if Input.is_action_pressed("move_right"):
input_vector.x += 1 # Вправо
# Нормализуем вектор ввода, если он не нулевой
if input_vector.length() > 0:
input_vector = input_vector.normalized()
# Позиция курсора мыши
var mouse_position = get_global_mouse_position()
# Вектор взгляда персонажа
var look_direction = (mouse_position - global_position).normalized()
# Поворот персонажа к курсору мыши с корректировкой угла
var target_rotation = look_direction.angle() + PI / 2
rotation = lerp_angle(rotation, target_rotation, 0.2)
if input_vector != Vector2.ZERO:
# Трансформируем ввод в глобальное направление с учётом поворота
var movement = input_vector.rotated(rotation)
# Проверяем, нажата ли клавиша "move_forward" (W)
var is_moving_forward = Input.is_action_pressed("move_forward")
# Определяем текущую скорость и анимацию
var current_speed = slow_speed # По умолчанию медленная скорость
if is_moving_forward:
current_speed = walk_speed # Нормальная скорость при движении вперёд
# Разрешаем бег при нажатии клавиши бега
if Input.is_action_pressed("run"):
current_speed = run_speed
set_animation("bezhit")
else:
set_animation("idet")
else:
# Бег запрещён, движемся медленно
set_animation("idet_medlenno")
# Устанавливаем скорость движения
velocity = movement * current_speed
else:
velocity = Vector2.ZERO
set_animation("stoit")
# Перемещаем персонажа
move_and_slide()
func set_animation(animation_name):
if $AnimatedSprite2D.animation != animation_name:
$AnimatedSprite2D.animation = animation_name
$AnimatedSprite2D.play()
(end of the code)
the script that stands in TileMap (which is just supposed to make the roofs disappear and reappear):
extends TileMap
const CELL_SIZE = Vector2(16, 16) # Укажите фактический размер ваших тайлов
const INVALID_CELL = -1 # Определяем константу для недопустимого ID тайла
var original_roof_tiles = {}
func _process(_delta):
update_roof_visibility()
func update_roof_visibility():
# Получаем узлы игрока и поля зрения
var player = get_node("../CharacterBody2D")
if player == null:
print("Не удалось найти узел CharacterBody2D")
return
var fov = player.get_node("FieldOfView")
if fov == null:
print("Не удалось найти узел FieldOfView")
return
# Предполагаем, что крыши находятся на слое 2
var roof_layer = 3
# Получаем список всех позиций тайлов на слое крыши
var all_tiles = get_used_cells(roof_layer)
if all_tiles.size() == 0:
print("Нет тайлов на слое крыши")
else:
print("Найдено ", all_tiles.size(), " тайлов на слое крыши")
var roof_tiles = []
for tile_pos in all_tiles:
var tile_data = get_cell_tile_data(roof_layer, tile_pos)
if tile_data != null:
var tile_id = tile_data.tile_id
var tile_name = tile_set.tile_get_name(tile_id)
print("Тайл на позиции ", tile_pos, " имеет имя ", tile_name)
if tile_name == "Roof":
roof_tiles.append(tile_pos)
else:
print("Нет данных тайла для позиции ", tile_pos)
if roof_tiles.size() == 0:
print("Не найдено тайлов с именем 'Roof'")
else:
print("Найдено ", roof_tiles.size(), " тайлов крыши с именем 'Roof'")
for tile_pos in roof_tiles:
# Вычисляем мировую позицию тайла
var cell_position = map_to_local(tile_pos)
var world_pos = global_position + cell_position + (CELL_SIZE / 2)
# Проверяем, виден ли тайл из поля зрения
if is_visible_from_fov(world_pos, fov):
# Убираем тайл крыши
var current_tile = get_cell_source_id(roof_layer, tile_pos)
if current_tile != INVALID_CELL:
print("Убираем тайл крыши на позиции ", tile_pos)
original_roof_tiles[tile_pos] = current_tile
set_cell(roof_layer, tile_pos, INVALID_CELL)
else:
# Восстанавливаем тайл крыши
if get_cell_source_id(roof_layer, tile_pos) == INVALID_CELL and tile_pos in original_roof_tiles:
print("Восстанавливаем тайл крыши на позиции ", tile_pos)
set_cell(roof_layer, tile_pos, original_roof_tiles[tile_pos])
original_roof_tiles.erase(tile_pos)
func is_visible_from_fov(target_position, fov):
var space_state = get_world_2d().direct_space_state
var query = PhysicsRayQueryParameters2D.new()
query.from = fov.global_position
query.to = target_position
query.exclude = [self, fov]
# Слой "stena" имеет номер 1
query.collision_mask = 1 << (1 - 1) # 1 << 0 = 1
query.collide_with_bodies = true
query.collide_with_areas = false
var result = space_state.intersect_ray(query)
if result != null:
print("Луч пересек препятствие при проверке позиции ", target_position)
else:
print("Прямая видимость до позиции ", target_position)
return result == null
(end of the code)
please help me, I have been suffering for two days now, if there are any questions, I will try to answer.
Help Programming Physics Animation godot-4 gdscript 2d game tilemap