diff --git a/assets/models/meshes/tekton/tekton_walking.glb b/assets/models/meshes/tekton/tekton_walking.glb new file mode 100644 index 0000000..1885341 Binary files /dev/null and b/assets/models/meshes/tekton/tekton_walking.glb differ diff --git a/assets/models/meshes/tekton/tekton_walking.glb.import b/assets/models/meshes/tekton/tekton_walking.glb.import new file mode 100644 index 0000000..4e88413 --- /dev/null +++ b/assets/models/meshes/tekton/tekton_walking.glb.import @@ -0,0 +1,42 @@ +[remap] + +importer="scene" +importer_version=1 +type="PackedScene" +uid="uid://bye8rbeqmxy1m" +path="res://.godot/imported/tekton_walking.glb-4042e6c5856f09fa2cc375563a11f70d.scn" + +[deps] + +source_file="res://assets/models/meshes/tekton/tekton_walking.glb" +dest_files=["res://.godot/imported/tekton_walking.glb-4042e6c5856f09fa2cc375563a11f70d.scn"] + +[params] + +nodes/root_type="" +nodes/root_name="" +nodes/root_script=null +nodes/apply_root_scale=true +nodes/root_scale=1.0 +nodes/import_as_skeleton_bones=false +nodes/use_name_suffixes=true +nodes/use_node_type_suffixes=true +meshes/ensure_tangents=true +meshes/generate_lods=true +meshes/create_shadow_meshes=true +meshes/light_baking=1 +meshes/lightmap_texel_size=0.2 +meshes/force_disable_compression=false +skins/use_named_skins=true +animation/import=true +animation/fps=30 +animation/trimming=false +animation/remove_immutable_tracks=true +animation/import_rest_as_RESET=false +import_script/path="" +materials/extract=0 +materials/extract_format=0 +materials/extract_path="" +_subresources={} +gltf/naming_version=2 +gltf/embedded_image_handling=1 diff --git a/assets/models/meshes/tekton/tekton_walking_GOGGLE 2 UV Tex2.png b/assets/models/meshes/tekton/tekton_walking_GOGGLE 2 UV Tex2.png new file mode 100644 index 0000000..90bb7d0 Binary files /dev/null and b/assets/models/meshes/tekton/tekton_walking_GOGGLE 2 UV Tex2.png differ diff --git a/assets/models/meshes/tekton/tekton_walking_GOGGLE 2 UV Tex2.png.import b/assets/models/meshes/tekton/tekton_walking_GOGGLE 2 UV Tex2.png.import new file mode 100644 index 0000000..7754104 --- /dev/null +++ b/assets/models/meshes/tekton/tekton_walking_GOGGLE 2 UV Tex2.png.import @@ -0,0 +1,44 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bskihcaeo1smd" +path.s3tc="res://.godot/imported/tekton_walking_GOGGLE 2 UV Tex2.png-73ef37400d33fb36d94c2bd4fd46bef6.s3tc.ctex" +metadata={ +"imported_formats": ["s3tc_bptc"], +"vram_texture": true +} +generator_parameters={ +"md5": "54c5e1acb27020ed20da0689345f47ec" +} + +[deps] + +source_file="res://assets/models/meshes/tekton/tekton_walking_GOGGLE 2 UV Tex2.png" +dest_files=["res://.godot/imported/tekton_walking_GOGGLE 2 UV Tex2.png-73ef37400d33fb36d94c2bd4fd46bef6.s3tc.ctex"] + +[params] + +compress/mode=2 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=true +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=0 diff --git a/assets/models/meshes/tekton/tekton_walking_WhiteFluffyTowel_normal.jpg b/assets/models/meshes/tekton/tekton_walking_WhiteFluffyTowel_normal.jpg new file mode 100644 index 0000000..2af07a3 Binary files /dev/null and b/assets/models/meshes/tekton/tekton_walking_WhiteFluffyTowel_normal.jpg differ diff --git a/assets/models/meshes/tekton/tekton_walking_WhiteFluffyTowel_normal.jpg.import b/assets/models/meshes/tekton/tekton_walking_WhiteFluffyTowel_normal.jpg.import new file mode 100644 index 0000000..dd05f08 --- /dev/null +++ b/assets/models/meshes/tekton/tekton_walking_WhiteFluffyTowel_normal.jpg.import @@ -0,0 +1,44 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://byepwsmeulscp" +path.s3tc="res://.godot/imported/tekton_walking_WhiteFluffyTowel_normal.jpg-7319bdbeda72417bd0eb9d7bd590fcea.s3tc.ctex" +metadata={ +"imported_formats": ["s3tc_bptc"], +"vram_texture": true +} +generator_parameters={ +"md5": "286009441fbbc5f913f0d3b39741d839" +} + +[deps] + +source_file="res://assets/models/meshes/tekton/tekton_walking_WhiteFluffyTowel_normal.jpg" +dest_files=["res://.godot/imported/tekton_walking_WhiteFluffyTowel_normal.jpg-7319bdbeda72417bd0eb9d7bd590fcea.s3tc.ctex"] + +[params] + +compress/mode=2 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=1 +compress/channel_pack=0 +mipmaps/generate=true +mipmaps/limit=-1 +roughness/mode=1 +roughness/src_normal="res://assets/models/meshes/tekton/tekton_walking_WhiteFluffyTowel_normal.jpg" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=0 diff --git a/assets/models/meshes/tekton/tekton_walking_WhiteFluffyTowel_roughness.png b/assets/models/meshes/tekton/tekton_walking_WhiteFluffyTowel_roughness.png new file mode 100644 index 0000000..862762a Binary files /dev/null and b/assets/models/meshes/tekton/tekton_walking_WhiteFluffyTowel_roughness.png differ diff --git a/assets/models/meshes/tekton/tekton_walking_WhiteFluffyTowel_roughness.png.import b/assets/models/meshes/tekton/tekton_walking_WhiteFluffyTowel_roughness.png.import new file mode 100644 index 0000000..8aba888 --- /dev/null +++ b/assets/models/meshes/tekton/tekton_walking_WhiteFluffyTowel_roughness.png.import @@ -0,0 +1,44 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://ctompad3g7pc3" +path.s3tc="res://.godot/imported/tekton_walking_WhiteFluffyTowel_roughness.png-5ce3697bfe5ea29c1ef189f5d2cf4a98.s3tc.ctex" +metadata={ +"imported_formats": ["s3tc_bptc"], +"vram_texture": true +} +generator_parameters={ +"md5": "3650b521fc7995add9cc4eb21b0b803a" +} + +[deps] + +source_file="res://assets/models/meshes/tekton/tekton_walking_WhiteFluffyTowel_roughness.png" +dest_files=["res://.godot/imported/tekton_walking_WhiteFluffyTowel_roughness.png-5ce3697bfe5ea29c1ef189f5d2cf4a98.s3tc.ctex"] + +[params] + +compress/mode=2 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=true +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=0 diff --git a/scenes/main.gd b/scenes/main.gd index 30ad0d4..0d713e7 100644 --- a/scenes/main.gd +++ b/scenes/main.gd @@ -9,6 +9,7 @@ var ui_manager var goals_cycle_manager var screen_shake_manager var touch_controls +var camera_context_manager # Minimal local state var _connection_check_timer: float = 0.0 @@ -76,9 +77,8 @@ func _init_managers(): screen_shake_manager = load("res://scripts/managers/screen_shake.gd").new() screen_shake_manager.name = "ScreenShakeManager" add_child(screen_shake_manager) - screen_shake_manager.initialize($Camera3D) + screen_shake_manager.initialize($Camera3D200) - # Touch controls for mobile # Touch controls for mobile touch_controls = get_node_or_null("TouchControls") if not touch_controls: @@ -89,6 +89,12 @@ func _init_managers(): touch_controls.initialize(self) + # NEW: Camera Context Manager for dynamic camera position + camera_context_manager = load("res://scripts/managers/camera_context_manager.gd").new() + camera_context_manager.name = "CameraContextManager" + add_child(camera_context_manager) + camera_context_manager.initialize($Camera3D200, screen_shake_manager) + # Connect signals for UI updates goals_cycle_manager.timer_updated.connect(_on_timer_updated) goals_cycle_manager.score_updated.connect(_on_score_updated) @@ -324,6 +330,8 @@ func _setup_host_game(): ui_manager.set_local_player(player_character) if touch_controls: touch_controls.set_player(player_character) + if camera_context_manager: + camera_context_manager.set_player(player_character) # Set host name player_character.display_name = LobbyManager.local_player_name @@ -436,6 +444,8 @@ func _setup_client_game(): ui_manager.set_local_player(player_character) if touch_controls: touch_controls.set_player(player_character) + if camera_context_manager: + camera_context_manager.set_player(player_character) ui_manager.update_button_states() print("Client: Configured local player ", my_id) @@ -654,6 +664,8 @@ func add_player_character(peer_id: int, is_bot: bool = false): ui_manager.set_local_player(player_character) if touch_controls: touch_controls.set_player(player_character) + if camera_context_manager: + camera_context_manager.set_player(player_character) ui_manager.update_button_states() ui_manager.update_playerboard_ui() diff --git a/scenes/main.tscn b/scenes/main.tscn index 296f630..596f4b8 100644 --- a/scenes/main.tscn +++ b/scenes/main.tscn @@ -106,10 +106,10 @@ current = true fov = 35.5 [node name="Camera3D200" type="Camera3D" parent="." unique_id=1763366951] -transform = Transform3D(1, 0, 0, 0, 0.5077037, 0.86153173, 0, -0.86153173, 0.5077037, 7, 19.635756, 19.007332) +transform = Transform3D(1, 0, 0, 0, 0.5077037, 0.86153173, 0, -0.86153173, 0.5077037, 7, 19.636, 22.5) environment = ExtResource("4_ky38j") current = true -fov = 35.5 +fov = 21.0 size = 15.0 [node name="PlayerboardPanel" type="PanelContainer" parent="." unique_id=1098203639] diff --git a/scripts/managers/camera_context_manager.gd b/scripts/managers/camera_context_manager.gd new file mode 100644 index 0000000..6fc7bba --- /dev/null +++ b/scripts/managers/camera_context_manager.gd @@ -0,0 +1,75 @@ +extends Node + +# CameraContextManager +# Handles camera position based on player's row on the board. + +# var screen_shake_manager: Node # Removed +var camera: Camera3D +var player: Node3D + +# Configuration Map: Row Threshold -> Target Position +# We use a list of dictionaries to define ranges. +# Setup A: Rows 0-5 +# Setup B: Rows 6-9 +# Setup C: Rows 10+ +var camera_setups = [ + { "max_row": 5, "position": Vector3(7.0, 19.636, 15.0) }, + { "max_row": 9, "position": Vector3(7.0, 19.636, 19.0) }, + { "max_row": 999, "position": Vector3(7.0, 19.22636, 22.5) } # Default/Bottom +] + +var unique_id: int + +func initialize(p_camera: Camera3D, _p_shake_manager: Node): + camera = p_camera + # screen_shake_manager = p_shake_manager + print("[CameraContextManager] Initialized with camera") + +func set_player(p_player: Node3D): + player = p_player + unique_id = p_player.name.to_int() + # Try to get movement manager (might be initializing) + var movement_mgr = player.get("movement_manager") + + if not movement_mgr and player.get("movement_manager") == null: + # Try direct access if script variable + movement_mgr = player.movement_manager + + if movement_mgr: + if not movement_mgr.movement_finished.is_connected(_on_player_moved): + movement_mgr.movement_finished.connect(_on_player_moved) + else: + print("[CameraContextManager] Warning: movement_manager not found on player. Retrying in 0.5s...") + await get_tree().create_timer(0.5).timeout + if player == p_player: # Ensure player hasn't changed + set_player(p_player) # Retry + _update_camera_target() + +func _on_player_moved(): + # print("[CameraContextManager] Player moved signal received") + _update_camera_target() + +func _update_camera_target(): + if not player or not camera: + return + + # Get player row (Z coordinate in 3D world / Y in GridMap) + # In this game: Grid Y maps to World Z. + # Player current_position is Vector2i(grid_x, grid_y) + + var current_row = player.current_position.y + var target_pos = Vector3.ZERO + + for i in range(camera_setups.size()): + var setup = camera_setups[i] + if current_row <= setup.max_row: + target_pos = setup.position + break + + # print("[CameraContextManager] Player Row: %d -> Selected Setup: %d (Target: %s)" % [current_row, setup_index, target_pos]) + + # Update ScreenShakeManager's target + # Update Camera Position directly with Tween + if camera.position != target_pos: + var tween = create_tween() + tween.tween_property(camera, "position", target_pos, 1.0).set_trans(Tween.TRANS_SINE).set_ease(Tween.EASE_IN_OUT) diff --git a/scripts/managers/camera_context_manager.gd.uid b/scripts/managers/camera_context_manager.gd.uid new file mode 100644 index 0000000..de27c5d --- /dev/null +++ b/scripts/managers/camera_context_manager.gd.uid @@ -0,0 +1 @@ +uid://btvpagdk2gwhg diff --git a/scripts/managers/screen_shake.gd b/scripts/managers/screen_shake.gd index 18850a6..ef4782a 100644 --- a/scripts/managers/screen_shake.gd +++ b/scripts/managers/screen_shake.gd @@ -6,7 +6,7 @@ var camera: Camera3D var shake_intensity: float = 0.0 var shake_duration: float = 0.0 var shake_timer: float = 0.0 -var original_position: Vector3 +var target_position: Vector3 # Replaces original_position # Shake presets const SHAKE_TARGETED: Dictionary = {"intensity": 0.15, "duration": 0.4} @@ -17,56 +17,17 @@ func initialize(p_camera: Camera3D): """Initialize with specific camera instance.""" camera = p_camera if camera: - original_position = camera.position + target_position = camera.position print("[ScreenShakeManager] Initialized with camera: ", camera.name) else: push_warning("[ScreenShakeManager] Initialized with null camera") -func _process(delta): - if shake_timer > 0: - shake_timer -= delta - if camera: - var shake_offset = Vector3( - randf_range(-shake_intensity, shake_intensity), - randf_range(-shake_intensity, shake_intensity), - randf_range(-shake_intensity * 0.5, shake_intensity * 0.5) - ) - camera.position = original_position + shake_offset - - if shake_timer <= 0: - _reset_camera() - -func _reset_camera(): - if camera: - camera.position = original_position - shake_timer = 0.0 - shake_intensity = 0.0 - -func shake(intensity: float, duration: float): - """Trigger camera shake with given intensity and duration.""" - if not camera: - push_warning("Screen shake requested but no camera assigned!") +func set_target_position(new_pos: Vector3, duration: float = 1.0): + """Smoothly transition to a new base camera position.""" + if target_position == new_pos: return - - if camera: - # If already shaking, reset camera first to get true original position - if shake_timer > 0: - camera.position = original_position - else: - original_position = camera.position - shake_intensity = intensity - shake_duration = duration - shake_timer = duration + # Tween the target position + var tween = create_tween() + tween.tween_property(self, "target_position", new_pos, duration).set_trans(Tween.TRANS_SINE).set_ease(Tween.EASE_IN_OUT) -func shake_targeted(): - """Called when local player is targeted by opponent's powerup.""" - shake(SHAKE_TARGETED.intensity, SHAKE_TARGETED.duration) - -func shake_goal_complete(): - """Called when local player completes a goal.""" - shake(SHAKE_GOAL_COMPLETE.intensity, SHAKE_GOAL_COMPLETE.duration) - -func shake_light(): - """Light shake for minor events.""" - shake(SHAKE_LIGHT.intensity, SHAKE_LIGHT.duration)