feat: update
This commit is contained in:
@@ -242,7 +242,18 @@ func _apply_skin_data(character_root: Node3D, skin: Dictionary) -> void:
|
||||
if mode == "overlay":
|
||||
mn.material_overlay = mat
|
||||
else:
|
||||
mn.set_surface_override_material(0, mat)
|
||||
# PRESERVE OUTLINE SHADER: Check if existing material has a next_pass (outline shader)
|
||||
var existing_mat = mn.get_surface_override_material(0)
|
||||
var preserved_next_pass = null
|
||||
if existing_mat and existing_mat.next_pass:
|
||||
preserved_next_pass = existing_mat.next_pass
|
||||
|
||||
# Apply the skin material
|
||||
var skin_mat = mat.duplicate() if mat else null
|
||||
if skin_mat and preserved_next_pass:
|
||||
skin_mat.next_pass = preserved_next_pass
|
||||
|
||||
mn.set_surface_override_material(0, skin_mat)
|
||||
|
||||
|
||||
func _clear_slot(char_node: Node3D, slot: Dictionary) -> void:
|
||||
@@ -254,7 +265,20 @@ func _clear_slot(char_node: Node3D, slot: Dictionary) -> void:
|
||||
if mode == "overlay":
|
||||
mn.material_overlay = null
|
||||
else:
|
||||
mn.set_surface_override_material(0, null)
|
||||
# PRESERVE OUTLINE SHADER: When clearing, check if we need to restore outline
|
||||
var existing_mat = mn.get_surface_override_material(0)
|
||||
if existing_mat and existing_mat.next_pass:
|
||||
# Has outline - restore base material with outline preserved
|
||||
var base_mat = mn.get_active_material(0)
|
||||
if base_mat:
|
||||
var restored_mat = base_mat.duplicate()
|
||||
restored_mat.next_pass = existing_mat.next_pass
|
||||
mn.set_surface_override_material(0, restored_mat)
|
||||
else:
|
||||
# No base material, just clear but this shouldn't happen normally
|
||||
mn.set_surface_override_material(0, null)
|
||||
else:
|
||||
mn.set_surface_override_material(0, null)
|
||||
|
||||
|
||||
func _get_char_node(character_root: Node3D, char_name: String) -> Node3D:
|
||||
|
||||
@@ -6,6 +6,7 @@ extends Node
|
||||
const STAND_SCENE_PATH = "res://scenes/static_tekton_stand.tscn"
|
||||
const TEKTON_SCENE_PATH = "res://scenes/tekton.tscn"
|
||||
const STATIC_CONTROLLER_SCRIPT = "res://scripts/static_tekton_controller.gd"
|
||||
const PERIMETER_BUFFER = 1 # 1-tile safe zone on all sides (matches main.gd)
|
||||
|
||||
# Zone Definitions based on CameraContextManager logic
|
||||
# 9 Zones in a 3x3 grid (approximate for 14x14 map)
|
||||
@@ -16,7 +17,8 @@ const STATIC_CONTROLLER_SCRIPT = "res://scripts/static_tekton_controller.gd"
|
||||
func calculate_spawn_points(_count: int, gridmap: Node) -> Array[Vector2i]:
|
||||
"""
|
||||
Calculates the 5 fixed potential spawn positions for static tektons.
|
||||
Corners: (1,1), (W-2,1), (1,H-2), (W-2,H-2)
|
||||
Now respects 1-tile perimeter buffer to prevent edge spawning.
|
||||
Corners: (2,2), (W-3,2), (2,H-3), (W-3,H-3)
|
||||
Center: (W/2, H/2)
|
||||
Returns exactly 5 spots if possible.
|
||||
"""
|
||||
@@ -25,15 +27,15 @@ func calculate_spawn_points(_count: int, gridmap: Node) -> Array[Vector2i]:
|
||||
var width = gridmap.columns
|
||||
var height = gridmap.rows
|
||||
|
||||
print("[StaticTektonManager] Calculating static tekton positions (Fixed 5-Spots)...")
|
||||
print("[StaticTektonManager] Calculating static tekton positions (Fixed 5-Spots with Buffer)...")
|
||||
|
||||
# Fixed Spots
|
||||
# Fixed Spots with buffer (at least 2 tiles from edge for 3x3 stand + 1 tile buffer)
|
||||
var spots: Array[Vector2i] = [
|
||||
Vector2i(1, 1), # Top-Left
|
||||
Vector2i(width - 2, 1), # Top-Right
|
||||
Vector2i(1, height - 2), # Bottom-Left
|
||||
Vector2i(width - 2, height - 2), # Bottom-Right
|
||||
Vector2i(width / 2, height / 2) # Center
|
||||
Vector2i(PERIMETER_BUFFER + 1, PERIMETER_BUFFER + 1), # Top-Left
|
||||
Vector2i(width - PERIMETER_BUFFER - 2, PERIMETER_BUFFER + 1), # Top-Right
|
||||
Vector2i(PERIMETER_BUFFER + 1, height - PERIMETER_BUFFER - 2), # Bottom-Left
|
||||
Vector2i(width - PERIMETER_BUFFER - 2, height - PERIMETER_BUFFER - 2), # Bottom-Right
|
||||
Vector2i(width / 2, height / 2) # Center
|
||||
]
|
||||
|
||||
# Validate spots (ensure they are walkable and have room)
|
||||
@@ -52,18 +54,17 @@ func _pick_spot_in_zone_biased(zone: Rect2i, gridmap: Node, type: int) -> Vector
|
||||
# ideal target relative to map
|
||||
var target = Vector2i.ZERO
|
||||
match type:
|
||||
0: target = Vector2i(0, 0)
|
||||
1: target = Vector2i(gridmap.columns, 0)
|
||||
2: target = Vector2i(0, gridmap.rows)
|
||||
3: target = Vector2i(gridmap.columns, gridmap.rows)
|
||||
0: target = Vector2i(PERIMETER_BUFFER + 1, PERIMETER_BUFFER + 1)
|
||||
1: target = Vector2i(gridmap.columns - PERIMETER_BUFFER - 2, PERIMETER_BUFFER + 1)
|
||||
2: target = Vector2i(PERIMETER_BUFFER + 1, gridmap.rows - PERIMETER_BUFFER - 2)
|
||||
3: target = Vector2i(gridmap.columns - PERIMETER_BUFFER - 2, gridmap.rows - PERIMETER_BUFFER - 2)
|
||||
4: target = Vector2i(gridmap.columns / 2, gridmap.rows / 2)
|
||||
|
||||
# Clamp target to be inside valid area (taking 3x3 margin into account)
|
||||
# Center of 3x3 must be at least 1 tile from edge
|
||||
var min_x = max(1, zone.position.x + 1)
|
||||
var max_x = min(gridmap.columns - 2, zone.position.x + zone.size.x - 2)
|
||||
var min_y = max(1, zone.position.y + 1)
|
||||
var max_y = min(gridmap.rows - 2, zone.position.y + zone.size.y - 2)
|
||||
# Clamp target to be inside valid area (respecting perimeter buffer + 3x3 margin)
|
||||
var min_x = max(PERIMETER_BUFFER + 1, zone.position.x + 1)
|
||||
var max_x = min(gridmap.columns - PERIMETER_BUFFER - 2, zone.position.x + zone.size.x - 2)
|
||||
var min_y = max(PERIMETER_BUFFER + 1, zone.position.y + 1)
|
||||
var max_y = min(gridmap.rows - PERIMETER_BUFFER - 2, zone.position.y + zone.size.y - 2)
|
||||
|
||||
if min_x > max_x or min_y > max_y:
|
||||
return Vector2i(-1, -1)
|
||||
@@ -111,33 +112,32 @@ func _pick_spot_in_zone(zone: Rect2i, gridmap: Node, zone_idx: int = -1) -> Vect
|
||||
"""
|
||||
Find a valid 3x3 spot in the zone.
|
||||
The returned position is the CENTER of the 3x3 area.
|
||||
If zone_idx is a corner (0, 2, 6, 8), we snap to the absolute map corner.
|
||||
If zone_idx is a corner (0, 2, 6, 8), we snap to corner position with buffer.
|
||||
"""
|
||||
# CORNER SNAPPING: If this is a corner zone, force it to the extreme corner
|
||||
# to ensure the 3x3 Stand fills the corner completely (no 1-tile gaps).
|
||||
# CORNER SNAPPING: If this is a corner zone, force it to the corner with buffer
|
||||
# to ensure the 3x3 Stand stays away from edges (no 1-tile gaps).
|
||||
if zone_idx == 0: # Top-Left
|
||||
var center = Vector2i(1, 1)
|
||||
var center = Vector2i(PERIMETER_BUFFER + 1, PERIMETER_BUFFER + 1)
|
||||
if _is_valid_3x3(center, gridmap): return center
|
||||
elif zone_idx == 2: # Top-Right
|
||||
var center = Vector2i(gridmap.columns - 2, 1)
|
||||
var center = Vector2i(gridmap.columns - PERIMETER_BUFFER - 2, PERIMETER_BUFFER + 1)
|
||||
if _is_valid_3x3(center, gridmap): return center
|
||||
elif zone_idx == 6: # Bottom-Left
|
||||
var center = Vector2i(1, gridmap.rows - 2)
|
||||
var center = Vector2i(PERIMETER_BUFFER + 1, gridmap.rows - PERIMETER_BUFFER - 2)
|
||||
if _is_valid_3x3(center, gridmap): return center
|
||||
elif zone_idx == 8: # Bottom-Right
|
||||
var center = Vector2i(gridmap.columns - 2, gridmap.rows - 2)
|
||||
var center = Vector2i(gridmap.columns - PERIMETER_BUFFER - 2, gridmap.rows - PERIMETER_BUFFER - 2)
|
||||
if _is_valid_3x3(center, gridmap): return center
|
||||
|
||||
# Fallback/Random logic for non-corner zones or if preferred corner was invalid
|
||||
var attempts = 0
|
||||
while attempts < 30:
|
||||
attempts += 1
|
||||
# Ensure center is at least 1 tile away from edges of the map to fit 3x3
|
||||
# zone.position might be 0,0.
|
||||
var min_x = max(1, zone.position.x + 1)
|
||||
var max_x = min(gridmap.columns - 2, zone.position.x + zone.size.x - 2)
|
||||
var min_y = max(1, zone.position.y + 1)
|
||||
var max_y = min(gridmap.rows - 2, zone.position.y + zone.size.y - 2)
|
||||
# Ensure center respects perimeter buffer (1 tile from edge + 1 tile for 3x3 center = 2 tiles)
|
||||
var min_x = max(PERIMETER_BUFFER + 1, zone.position.x + 1)
|
||||
var max_x = min(gridmap.columns - PERIMETER_BUFFER - 2, zone.position.x + zone.size.x - 2)
|
||||
var min_y = max(PERIMETER_BUFFER + 1, zone.position.y + 1)
|
||||
var max_y = min(gridmap.rows - PERIMETER_BUFFER - 2, zone.position.y + zone.size.y - 2)
|
||||
|
||||
if min_x > max_x or min_y > max_y:
|
||||
break # Zone too small
|
||||
|
||||
+18
-5
@@ -407,6 +407,15 @@ func spawn_tiles_around(count: int = 4):
|
||||
"""Spawns a mix of normal and special tiles in a radius."""
|
||||
if not enhanced_gridmap: return
|
||||
|
||||
var radius = 2
|
||||
var rng = RandomNumberGenerator.new()
|
||||
rng.randomize()
|
||||
|
||||
# FIX 1: Make tekton look/rotate toward a random spawning direction
|
||||
if not is_carried and not is_thrown:
|
||||
var random_angle = rng.randf_range(0, TAU)
|
||||
rotation.y = random_angle
|
||||
|
||||
# Play throw animation
|
||||
if not is_carried and not is_thrown:
|
||||
play_animation("tekton_throw_tile")
|
||||
@@ -416,12 +425,11 @@ func spawn_tiles_around(count: int = 4):
|
||||
play_animation("tekton_idle")
|
||||
)
|
||||
|
||||
var radius = 2
|
||||
var rng = RandomNumberGenerator.new()
|
||||
rng.randomize()
|
||||
|
||||
print("[Tekton] Spawning %d tiles around %s" % [count, current_position])
|
||||
|
||||
# FIX 3: Delay tile spawning to match throw animation timing (feels better)
|
||||
await get_tree().create_timer(0.4).timeout
|
||||
|
||||
var spawned = 0
|
||||
var attempts = 0
|
||||
while spawned < count and attempts < 25:
|
||||
@@ -448,7 +456,12 @@ func spawn_tiles_around(count: int = 4):
|
||||
|
||||
if floor_0_item in [4, -1]:
|
||||
continue
|
||||
|
||||
|
||||
# FIX 2: Check if layer 1 already has tiles (purple powerups or any tile) to prevent blocking
|
||||
var floor_1_item = enhanced_gridmap.get_cell_item(Vector3i(pos.x, 1, pos.y))
|
||||
if floor_1_item != -1:
|
||||
continue # Skip if there's already a tile on layer 1
|
||||
|
||||
# 50% chance to spawn something
|
||||
if rng.randf() > 0.5: continue
|
||||
|
||||
|
||||
Reference in New Issue
Block a user