You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

392 lines
14 KiB
GDScript

@tool
extends Node3D
class_name LevelInstance
@export_tool_button("视野锁定", "Callable")
var view_focus_on: Callable = func() -> void:
grid_block_material.set_shader_parameter("is_focus", true)
debug_material.set_shader_parameter("is_hide", true)
set_focus_editor()
@export_tool_button("视野解锁", "Callable")
var view_focus_off: Callable = func() -> void:
grid_block_material.set_shader_parameter("is_focus", false)
debug_material.set_shader_parameter("is_hide", false)
set_focus()
@export var size: Vector3i = Vector3i.ONE:
set(value):
if (value.x < 1) or (value.y < 1) or (value.z < 1):
value = Vector3i.ONE
size = value
_on_size_change()
@export var is_force_battle: bool
@export var enemy_nums: Array[LevelEnemy]
@export_group("快速操作")
@export_tool_button("清空", "Callable")
var remove_all: Callable = func() -> void:
var level_main: GridMap = %LevelGridMain as GridMap
var id_min: Vector3i = Util.get_level_grid_pos2(pos_min())
var id_max: Vector3i = Util.get_level_grid_pos2(pos_max())
for x in range(id_min.x, id_max.x + 1):
for y in range(id_min.y, id_max.y + 1):
for z in range(id_min.z, id_max.z + 1):
var pos: Vector3i = Vector3i(x, y, z)
level_main.set_cell_item(pos, GridMap.INVALID_CELL_ITEM)
@export_tool_button("快速创建", "Callable")
var quick_build: Callable = func() -> void:
var level_main: GridMap = %LevelGridMain as GridMap
var id_min: Vector3i = Util.get_level_grid_pos2(pos_min())
var id_max: Vector3i = Util.get_level_grid_pos2(pos_max())
for x in range(id_min.x, id_max.x + 1):
for y in range(id_min.y, id_max.y + 1):
for z in range(id_min.z, id_max.z + 1):
var pos: Vector3i = Vector3i(x, y, z)
if x == id_min.x or x == id_max.x or y == id_min.y or z == id_min.z:
level_main.set_cell_item(pos, 2)
@export_group("替换item_id")
@export var id_from: int = 0
@export var id_to: int = 0
@export_tool_button("替换", "Callable")
var replace_id: Callable = func() -> void:
var level_main: GridMap = %LevelGridMain as GridMap
var id_min: Vector3i = Util.get_level_grid_pos2(pos_min())
var id_max: Vector3i = Util.get_level_grid_pos2(pos_max())
for x in range(id_min.x, id_max.x + 1):
for y in range(id_min.y, id_max.y + 1):
for z in range(id_min.z, id_max.z + 1):
var pos: Vector3i = Vector3i(x, y, z)
if level_main.get_cell_item(pos) == id_from:
level_main.set_cell_item(pos, id_to, level_main.get_cell_item_orientation(pos))
@export_tool_button("打印item详情", "Callable")
var print_item: Callable = func() -> void:
var level_main: GridMap = %LevelGridMain as GridMap
var id_min: Vector3i = Util.get_level_grid_pos2(pos_min())
var id_max: Vector3i = Util.get_level_grid_pos2(pos_max())
var mesh_library: MeshLibrary = level_main.get_mesh_library()
var item_count_map: Dictionary = {}
for x in range(id_min.x, id_max.x + 1):
for y in range(id_min.y, id_max.y + 1):
for z in range(id_min.z, id_max.z + 1):
var pos: Vector3i = Vector3i(x, y, z)
var item_id: int = level_main.get_cell_item(pos)
if item_id != GridMap.INVALID_CELL_ITEM:
if item_count_map.has(item_id):
item_count_map[item_id] += 1
else:
item_count_map[item_id] = 1
for item_id: int in item_count_map:
print("[", item_id, "]", mesh_library.get_item_name(item_id), ":", item_count_map[item_id])
@onready var grid_block_material: Material = load("res://render/material/level_grid_block.tres") as Material
@onready var debug_material: Material = load("res://render/material/debug.tres") as Material
#character
var level_area_cfg: LevelAreaCfg
var character_spots: Array[ChacacterSpot]
var character_born_spots: Array[ChacacterBornSpot]
var level_active_spots: Array[LevelActiveSpot]
var enemy_cfgs: Array[CharacterCfg]
#main
var mark_white_list: Array[Vector3i]
var mark_black_list: Array[Vector3i]
var grid_main_cache_cells: Array[GridMainCacheCellData]
class ChacacterSpot:
var pos: Vector3
var cfg: CharacterCfg
class ChacacterBornSpot:
var pos: Vector3
var type: int
class LevelActiveSpot:
var pos: Vector3
var scene: PackedScene
class GridMainCacheCellData:
var pos: Vector3i
var id: int
var orientation: int
func _on_size_change() -> void:
var level_range: CSGBox3D = $LevelRange as CSGBox3D
var size_basic: Vector3 = Setting.size_basic
level_range.size = Vector3(size.x * size_basic.x, size.y * size_basic.y, size.z * size_basic.z)
level_range.position = level_range.size / 2
func get_level_size() -> Vector2:
var level_range: CSGBox3D = $LevelRange as CSGBox3D
var level_size: Vector3 = level_range.size
return Vector2(level_size.x, level_size.z)
func get_level_pos() -> Vector2:
var pos: Vector3 = get_global_position()
return Vector2(pos.x, pos.z)
func set_level_range_visible(value: bool) -> void:
var level_range: CSGBox3D = $LevelRange as CSGBox3D
level_range.visible = value
func set_focus_editor() -> void:
var level_range: CSGBox3D = $LevelRange as CSGBox3D
var level_size: Vector3 = level_range.size
var focus_min: Vector3 = get_global_position()
var focus_max: Vector3 = get_global_position() + level_size - Vector3(0, Setting.pixel_size * Setting.grid_pixel_size, Setting.pixel_size * Setting.grid_pixel_size)
grid_block_material.set_shader_parameter("focus_min", focus_min)
grid_block_material.set_shader_parameter("focus_max", focus_max)
func set_focus() -> void:
var level_range: CSGBox3D = $LevelRange as CSGBox3D
var level_size: Vector3 = level_range.size
var focus_min: Vector3 = get_global_position()
var focus_max: Vector3 = get_global_position() + level_size + Vector3(0, Setting.pixel_size * Setting.grid_pixel_size, Setting.pixel_size * Setting.grid_pixel_size)
grid_block_material.set_shader_parameter("focus_min", focus_min)
grid_block_material.set_shader_parameter("focus_max", focus_max)
func init_level_character() -> void:
var level_character: GridMap = %LevelGridCharacter as GridMap
character_spots = []
character_born_spots = []
level_active_spots = []
enemy_cfgs = []
var id_min: Vector3i = Util.get_level_grid_pos2(pos_min())
var id_max: Vector3i = Util.get_level_grid_pos2(pos_max())
var mesh_library: MeshLibrary = level_character.get_mesh_library()
var used_cells: Array[Vector3i] = level_character.get_used_cells()
for pos in used_cells:
if pos.x < id_min.x or pos.x > id_max.x:
continue
if pos.y < id_min.y or pos.y > id_max.y:
continue
if pos.z < id_min.z or pos.z > id_max.z:
continue
var float_pos: Vector3 = Util.get_level_float_pos2_floor(pos)
var item_id: int = level_character.get_cell_item(pos)
if item_id == GridMap.INVALID_CELL_ITEM:
continue
var item_name: String = mesh_library.get_item_name(item_id)
if item_name.begins_with("chara_spot_"):
var character_born_spot = ChacacterBornSpot.new()
character_born_spot.pos = float_pos
character_born_spots.append(character_born_spot)
elif item_name.begins_with("chara_enemy_"):
var character_name: String = item_name.trim_prefix("chara_enemy_")
var character_cfg: CharacterCfg = Util.get_character_cfg_by_name(character_name)
if not character_cfg:
continue
var character_spot = ChacacterSpot.new()
character_spot.cfg = character_cfg
character_spot.pos = float_pos
character_spots.append(character_spot)
elif item_name.begins_with("chara_active_"):
var scene_name: String = item_name.trim_prefix("chara_active_")
var scene: PackedScene = Util.get_level_active_scene_by_name(scene_name)
if not scene:
continue
var level_active_spot = LevelActiveSpot.new()
level_active_spot.scene = scene
level_active_spot.pos = float_pos
level_active_spots.append(level_active_spot)
for enemy_num: LevelEnemy in enemy_nums:
for i in enemy_num.num:
enemy_cfgs.append(enemy_num.cfg)
func init_level_main() -> void:
var level_main: GridMap = %LevelGridMain as GridMap
mark_white_list.clear()
mark_black_list.clear()
grid_main_cache_cells.clear()
var id_min: Vector3i = Util.get_level_grid_pos2(pos_min())
var id_max: Vector3i = Util.get_level_grid_pos2(pos_max())
# 需要延申空气墙的黑块
var air_wall_mark_black_list: Array[Vector3i] = []
# 正前面黑块
for x in range(id_min.x, id_max.x + 1):
var pos: Vector3i = Vector3i(x, id_min.y, id_max.z)
var has_link = false
var mark_black_list_check: Array[Vector3i] = []
for y in range(id_min.y, id_max.y - 1):
var pos_check: Vector3i = Vector3i(x, y + 1, id_max.z)
if not check_grid(level_main, pos_check):
var pos_forward: Vector3i = Vector3i(x, y + 1, id_max.z + 1)
var float_pos_check: Vector3 = Util.get_level_float_pos2(pos_forward)
if Global.level_mgr.get_level_by_pos(float_pos_check):
if y + 1 < id_max.y:
air_wall_mark_black_list.append(pos_check + Vector3i(0, 1, 0))
has_link = true
break
mark_black_list_check.append(Vector3i(x, y, id_max.z))
if has_link:
pass
# for pos_check in mark_black_list_check:
# mark_black_list.append(pos_check)
else:
air_wall_mark_black_list.append(pos)
mark_black_list.append(pos)
# 左面黑块
var black_y_max_left: int = id_max.y - 1
for z in range(id_min.z + 1, id_max.z):
var has_link = false
var mark_black_list_check: Array[Vector3i] = []
for y in range(id_min.y - 1, black_y_max_left):
var pos_check: Vector3i = Vector3i(id_min.x, y + 1, z)
if not check_grid(level_main, pos_check):
has_link = true
black_y_max_left = max(y, id_min.y)
if y + 1 < id_max.y:
air_wall_mark_black_list.append(pos_check + Vector3i(0, 1, 0))
break
mark_black_list_check.append(pos_check)
if not has_link:
for pos_check in mark_black_list_check:
mark_black_list.append(pos_check)
var pos_check: Vector3i = Vector3i(id_min.x, black_y_max_left, z)
air_wall_mark_black_list.append(pos_check)
# 右边面黑块
var black_y_max_right: int = id_max.y - 1
for z in range(id_min.z + 1, id_max.z):
var has_link = false
var mark_black_list_check: Array[Vector3i] = []
for y in range(id_min.y - 1, black_y_max_right):
var pos_check: Vector3i = Vector3i(id_max.x, y + 1, z)
if not check_grid(level_main, pos_check):
has_link = true
black_y_max_right = max(y, id_min.y)
if y + 1 < id_max.y:
air_wall_mark_black_list.append(pos_check + Vector3i(0, 1, 0))
break
mark_black_list_check.append(pos_check)
if not has_link:
for pos_check in mark_black_list_check:
mark_black_list.append(pos_check)
var pos_check: Vector3i = Vector3i(id_max.x, black_y_max_right, z)
air_wall_mark_black_list.append(pos_check)
# 黑块cache
for mark_black in mark_black_list:
add_grid_main_cache_cell(level_main, mark_black)
# 黑块延申空气墙
for mark_black in air_wall_mark_black_list:
for y in range(mark_black.y + 1, id_max.y):
var pos: Vector3i = Vector3i(mark_black.x, y, mark_black.z)
add_grid_main_cache_cell(level_main, pos)
mark_white_list.append(pos)
# 顶面
for x in range(id_min.x, id_max.x + 1):
for z in range(id_min.z, id_max.z + 1):
var pos: Vector3i = Vector3i(x, id_max.y, z)
var pos_up: Vector3i = Vector3i(x, id_max.y + 1, z)
var pos_down: Vector3i = Vector3i(x, id_max.y - 1, z)
var is_link = not check_grid(level_main, pos) and not check_grid(level_main, pos_up) and not check_grid(level_main, pos_down)
if is_link and not pos_down in mark_white_list:
var float_pos_check: Vector3 = Util.get_level_float_pos2(pos_up)
if Global.level_mgr.get_level_by_pos(float_pos_check):
continue
add_grid_main_cache_cell(level_main, pos)
if pos_down in mark_white_list:
mark_white_list.append(pos)
else:
if check_grid(level_main, pos_down):
mark_black_list.append(pos)
else:
mark_white_list.append(pos)
func check_grid(level_main: GridMap, pos: Vector3i) -> bool:
var id: int = level_main.get_cell_item(pos)
return id != GridMap.INVALID_CELL_ITEM
func add_grid_main_cache_cell(level_main: GridMap, pos: Vector3i) -> void:
var id: int = level_main.get_cell_item(pos)
if id == GridMap.INVALID_CELL_ITEM:
return
var cache_data = GridMainCacheCellData.new()
cache_data.pos = pos
cache_data.id = id
cache_data.orientation = level_main.get_cell_item_orientation(pos)
grid_main_cache_cells.append(cache_data)
func set_replace(is_active: bool) -> void:
var level_main: GridMap = %LevelGridMain as GridMap
if is_active:
for pos in mark_white_list:
level_main.set_cell_item(pos, 0)
for pos in mark_black_list:
level_main.set_cell_item(pos, 1)
else:
for pos in mark_white_list:
level_main.set_cell_item(pos, GridMap.INVALID_CELL_ITEM)
for pos in mark_black_list:
level_main.set_cell_item(pos, GridMap.INVALID_CELL_ITEM)
for cache_data in grid_main_cache_cells:
level_main.set_cell_item(cache_data.pos, cache_data.id, cache_data.orientation)
func get_character_spots() -> Array[ChacacterSpot]:
return character_spots
func get_character_born_spots() -> Array[ChacacterBornSpot]:
return character_born_spots
func get_enemy_cfgs() -> Array[CharacterCfg]:
return enemy_cfgs
func get_level_active_spots() -> Array[LevelActiveSpot]:
return level_active_spots
func pos_min() -> Vector3:
return get_global_position()
func pos_max() -> Vector3:
var level_range: CSGBox3D = $LevelRange as CSGBox3D
var level_size: Vector3 = level_range.size
return get_global_position() + level_size
func outter_pos_min() -> Vector3:
return pos_min() - Vector3(0.72, 0.72, 0.72)
func outter_pos_max() -> Vector3:
return pos_max() - Vector3(0.72, 0.72, 0.72)
func is_in_active_area(pos: Vector3) -> bool:
var active_pos_min: Vector3 = pos_min() + Vector3(0.96, 0, 0.96)
var active_pos_max: Vector3 = pos_max() - Vector3(0.96, 0, 0.96)
return pos.x >= active_pos_min.x and pos.x <= active_pos_max.x and \
pos.z >= active_pos_min.z and pos.z <= active_pos_max.z and \
pos.y >= active_pos_min.y and pos.y <= active_pos_max.y