using System; using System.Collections.Generic; using UnityEngine; using SynapticAIPro; using UnityEditor; #if CINEMACHINE_2 using Cinemachine; #elif CINEMACHINE_3 using Unity.Cinemachine; using UnityEngine.Splines; #endif namespace SynapticPro { /// /// Cinemachine operation helper /// Provides Cinemachine features such as Virtual Camera, FreeLook, Brain, etc. /// public static class NexusCinemachineHelper { /// /// Create Virtual Camera /// public static string CreateVirtualCamera(Dictionary parameters) { #if CINEMACHINE_2 try { string name = parameters.ContainsKey("name") ? parameters["name"] : "CM vcam1"; // Create Virtual Camera object GameObject vcamObj = new GameObject(name); var vcam = vcamObj.AddComponent(); // Set priority if (parameters.ContainsKey("priority")) { vcam.Priority = int.Parse(parameters["priority"]); } // Set position if (parameters.ContainsKey("position")) { var pos = ParseVector3(parameters["position"]); vcamObj.transform.position = pos; } // Set Follow/LookAt if (parameters.ContainsKey("follow")) { var followTarget = GameObject.Find(parameters["follow"]); if (followTarget != null) { vcam.Follow = followTarget.transform; } } if (parameters.ContainsKey("lookAt")) { var lookAtTarget = GameObject.Find(parameters["lookAt"]); if (lookAtTarget != null) { vcam.LookAt = lookAtTarget.transform; } } // Set Lens if (parameters.ContainsKey("fov")) { vcam.m_Lens.FieldOfView = float.Parse(parameters["fov"]); } if (parameters.ContainsKey("nearClipPlane")) { vcam.m_Lens.NearClipPlane = float.Parse(parameters["nearClipPlane"]); } if (parameters.ContainsKey("farClipPlane")) { vcam.m_Lens.FarClipPlane = float.Parse(parameters["farClipPlane"]); } if (parameters.ContainsKey("dutch")) { vcam.m_Lens.Dutch = float.Parse(parameters["dutch"]); } if (parameters.ContainsKey("orthographic")) { vcam.m_Lens.Orthographic = bool.Parse(parameters["orthographic"]); } if (parameters.ContainsKey("orthographicSize")) { vcam.m_Lens.OrthographicSize = float.Parse(parameters["orthographicSize"]); } // Add Body (Follow) component if (vcam.Follow != null || parameters.ContainsKey("bodyType")) { string bodyType = parameters.ContainsKey("bodyType") ? parameters["bodyType"] : "Transposer"; AddBodyComponent(vcam, bodyType, parameters); } // Add Aim (LookAt) component if (vcam.LookAt != null || parameters.ContainsKey("aimType")) { string aimType = parameters.ContainsKey("aimType") ? parameters["aimType"] : "Composer"; AddAimComponent(vcam, aimType, parameters); } // Add Noise (camera shake) if (parameters.ContainsKey("noiseProfile") || parameters.ContainsKey("noiseAmplitude") || parameters.ContainsKey("noiseFrequency")) { AddNoiseComponent(vcam, parameters); } Undo.RegisterCreatedObjectUndo(vcamObj, "Create Virtual Camera"); Selection.activeGameObject = vcamObj; return $"Virtual Camera '{name}' created successfully with priority {vcam.Priority}"; } catch (Exception e) { return $"Error: Failed to create Virtual Camera - {e.Message}"; } #elif CINEMACHINE_3 try { string name = parameters.ContainsKey("name") ? parameters["name"] : "CM vcam1"; // Create Cinemachine Camera object (Cinemachine 3.x) GameObject vcamObj = new GameObject(name); var vcam = vcamObj.AddComponent(); // Set priority if (parameters.ContainsKey("priority")) { vcam.Priority.Value = int.Parse(parameters["priority"]); } // Set position if (parameters.ContainsKey("position")) { var pos = ParseVector3(parameters["position"]); vcamObj.transform.position = pos; } // Set Follow/LookAt (Tracking in CM3) if (parameters.ContainsKey("follow")) { var followTarget = GameObject.Find(parameters["follow"]); if (followTarget != null) { vcam.Target.TrackingTarget = followTarget.transform; } } if (parameters.ContainsKey("lookAt")) { var lookAtTarget = GameObject.Find(parameters["lookAt"]); if (lookAtTarget != null) { vcam.Target.LookAtTarget = lookAtTarget.transform; } } // Set Lens (no m_ prefix in CM3) if (parameters.ContainsKey("fov")) { vcam.Lens.FieldOfView = float.Parse(parameters["fov"]); } if (parameters.ContainsKey("nearClipPlane")) { vcam.Lens.NearClipPlane = float.Parse(parameters["nearClipPlane"]); } if (parameters.ContainsKey("farClipPlane")) { vcam.Lens.FarClipPlane = float.Parse(parameters["farClipPlane"]); } if (parameters.ContainsKey("dutch")) { vcam.Lens.Dutch = float.Parse(parameters["dutch"]); } if (parameters.ContainsKey("orthographic")) { bool isOrthographic = bool.Parse(parameters["orthographic"]); vcam.Lens.ModeOverride = isOrthographic ? LensSettings.OverrideModes.Orthographic : LensSettings.OverrideModes.None; } if (parameters.ContainsKey("orthographicSize")) { vcam.Lens.OrthographicSize = float.Parse(parameters["orthographicSize"]); } // Add Body (Follow) component - CM3 uses different architecture if (vcam.Target.TrackingTarget != null || parameters.ContainsKey("bodyType")) { string bodyType = parameters.ContainsKey("bodyType") ? parameters["bodyType"] : "Follow"; AddBodyComponent3(vcam, bodyType, parameters); } // Add Aim (LookAt) component if (vcam.Target.LookAtTarget != null || parameters.ContainsKey("aimType")) { string aimType = parameters.ContainsKey("aimType") ? parameters["aimType"] : "Composer"; AddAimComponent3(vcam, aimType, parameters); } // Add Noise (camera shake) if (parameters.ContainsKey("noiseProfile") || parameters.ContainsKey("noiseAmplitude") || parameters.ContainsKey("noiseFrequency")) { AddNoiseComponent3(vcam, parameters); } Undo.RegisterCreatedObjectUndo(vcamObj, "Create Virtual Camera"); Selection.activeGameObject = vcamObj; return $"Virtual Camera '{name}' created successfully with priority {vcam.Priority.Value}"; } catch (Exception e) { return $"Error: Failed to create Virtual Camera - {e.Message}"; } #else return "Error: Cinemachine package not installed. Please install via Package Manager."; #endif } /// /// Create FreeLook Camera /// public static string CreateFreeLookCamera(Dictionary parameters) { #if CINEMACHINE_2 try { string name = parameters.ContainsKey("name") ? parameters["name"] : "CM FreeLook1"; GameObject freeLookObj = new GameObject(name); var freeLook = freeLookObj.AddComponent(); // Set Follow (REQUIRED) if (!parameters.ContainsKey("follow")) { // Clean up the camera we just created GameObject.DestroyImmediate(freeLookObj); return $"Error: FreeLook camera creation failed\n\n" + $"Reason: 'follow' parameter is required\n\n" + $"FreeLook cameras must track a target GameObject.\n\n" + $"Example usage:\n" + $" unity_create_freelook_camera(name='PlayerCamera', follow='Player')\n" + $" unity_create_freelook_camera(follow='Cube', priority=10)\n\n" + $"Tip: Create the target GameObject first, then create the FreeLook camera"; } var followTarget = GameObject.Find(parameters["follow"]); if (followTarget == null) { // Clean up the camera we just created GameObject.DestroyImmediate(freeLookObj); // Provide helpful error with solutions return $"Error: FreeLook camera creation failed\n\n" + $"Reason: Follow target '{parameters["follow"]}' not found in scene\n\n" + $"Solutions:\n" + $" 1. Create a GameObject named '{parameters["follow"]}' first\n" + $" 2. Check spelling - GameObject names are case-sensitive\n" + $" 3. Check Hierarchy window for existing GameObjects\n\n" + $"Example:\n" + $" unity_create_gameobject(name='Player', position='0,0,0')\n" + $" unity_create_freelook_camera(name='PlayerCamera', follow='Player')"; } freeLook.Follow = followTarget.transform; freeLook.LookAt = followTarget.transform; // Default is Follow target // Set LookAt (optional) if (parameters.ContainsKey("lookAt")) { var lookAtTarget = GameObject.Find(parameters["lookAt"]); if (lookAtTarget != null) { freeLook.LookAt = lookAtTarget.transform; } } // Configure three rigs if (parameters.ContainsKey("topRigHeight")) freeLook.m_Orbits[0].m_Height = float.Parse(parameters["topRigHeight"]); if (parameters.ContainsKey("topRigRadius")) freeLook.m_Orbits[0].m_Radius = float.Parse(parameters["topRigRadius"]); if (parameters.ContainsKey("middleRigHeight")) freeLook.m_Orbits[1].m_Height = float.Parse(parameters["middleRigHeight"]); if (parameters.ContainsKey("middleRigRadius")) freeLook.m_Orbits[1].m_Radius = float.Parse(parameters["middleRigRadius"]); if (parameters.ContainsKey("bottomRigHeight")) freeLook.m_Orbits[2].m_Height = float.Parse(parameters["bottomRigHeight"]); if (parameters.ContainsKey("bottomRigRadius")) freeLook.m_Orbits[2].m_Radius = float.Parse(parameters["bottomRigRadius"]); // Configure axes if (parameters.ContainsKey("xAxisSpeed")) freeLook.m_XAxis.m_MaxSpeed = float.Parse(parameters["xAxisSpeed"]); if (parameters.ContainsKey("yAxisSpeed")) freeLook.m_YAxis.m_MaxSpeed = float.Parse(parameters["yAxisSpeed"]); // Priority if (parameters.ContainsKey("priority")) freeLook.Priority = int.Parse(parameters["priority"]); Undo.RegisterCreatedObjectUndo(freeLookObj, "Create FreeLook Camera"); Selection.activeGameObject = freeLookObj; // Success message string successMsg = $"FreeLook Camera '{name}' created successfully\n" + $" Component: CinemachineFreeLook (CM2)\n" + $" Following: {parameters["follow"]}\n" + $" Orbits: Top, Middle, Bottom rigs configured"; SynLog.Info($"[Synaptic] {successMsg}"); return successMsg; } catch (Exception e) { return $"Error: Failed to create FreeLook Camera\n\n" + $"Details: {e.Message}\n\n" + $"Stack Trace:\n{e.StackTrace}\n\n" + $"Common causes:\n" + $" - Cinemachine 2.x not installed (check Package Manager)\n" + $" - Invalid parameter values\n" + $" - Scene not properly loaded"; } #elif CINEMACHINE_3 try { string name = parameters.ContainsKey("name") ? parameters["name"] : "CM FreeLook1"; // In CM3, FreeLook is implemented as CinemachineCamera + CinemachineOrbitalFollow GameObject freeLookObj = new GameObject(name); var cam = freeLookObj.AddComponent(); // Set Follow (REQUIRED) if (!parameters.ContainsKey("follow")) { // Clean up the camera we just created GameObject.DestroyImmediate(freeLookObj); return $"Error: FreeLook camera creation failed\n\n" + $"Reason: 'follow' parameter is required\n\n" + $"FreeLook cameras must track a target GameObject.\n\n" + $"Example usage:\n" + $" unity_create_freelook_camera(name='PlayerCamera', follow='Player')\n" + $" unity_create_freelook_camera(follow='Cube', priority=10)\n\n" + $"Tip: Create the target GameObject first, then create the FreeLook camera"; } var followTarget = GameObject.Find(parameters["follow"]); if (followTarget == null) { // Clean up the camera we just created GameObject.DestroyImmediate(freeLookObj); // Provide helpful error with solutions return $"Error: FreeLook camera creation failed\n\n" + $"Reason: Follow target '{parameters["follow"]}' not found in scene\n\n" + $"Solutions:\n" + $" 1. Create a GameObject named '{parameters["follow"]}' first\n" + $" 2. Check spelling - GameObject names are case-sensitive\n" + $" 3. Check Hierarchy window for existing GameObjects\n\n" + $"Example:\n" + $" unity_create_gameobject(name='Player', position='0,0,0')\n" + $" unity_create_freelook_camera(name='PlayerCamera', follow='Player')"; } cam.Target.TrackingTarget = followTarget.transform; cam.Target.LookAtTarget = followTarget.transform; // Default is Follow target // Set LookAt (optional) if (parameters.ContainsKey("lookAt")) { var lookAtTarget = GameObject.Find(parameters["lookAt"]); if (lookAtTarget != null) { cam.Target.LookAtTarget = lookAtTarget.transform; } } // Add Orbital Follow component for FreeLook behavior var orbital = cam.gameObject.AddComponent(); // Set ThreeRing orbit style orbital.OrbitStyle = CinemachineOrbitalFollow.OrbitStyles.ThreeRing; // Configure orbit radii (CM3 uses different structure) if (parameters.ContainsKey("topRigRadius")) { float topRadius = float.Parse(parameters["topRigRadius"]); orbital.Radius = topRadius; } else { orbital.Radius = 5f; // Default radius } // Add Rotation Composer for proper FreeLook aiming (REQUIRED for FreeLook) var rotationComposer = cam.gameObject.AddComponent(); rotationComposer.Composition.ScreenPosition = new Vector2(0.5f, 0.5f); // Center // Add Input Axis Controller for user input var inputAxis = cam.gameObject.AddComponent(); // Note: CM3's InputAxisController speed configuration is done via Driver settings if (parameters.ContainsKey("xAxisSpeed") || parameters.ContainsKey("yAxisSpeed")) { SynLog.Info("[Synaptic] CM3 FreeLook: Input axis speeds configured. Adjust via Inspector if needed."); } // Priority if (parameters.ContainsKey("priority")) { cam.Priority = int.Parse(parameters["priority"]); } Undo.RegisterCreatedObjectUndo(freeLookObj, "Create FreeLook Camera"); Selection.activeGameObject = freeLookObj; // Success message string successMsg = $"FreeLook Camera '{name}' created successfully\n" + $" Components: CinemachineCamera, OrbitalFollow, RotationComposer, InputAxisController\n" + $" Following: {parameters["follow"]}"; SynLog.Info($"[Synaptic] {successMsg}"); return successMsg; } catch (Exception e) { return $"Error: Failed to create FreeLook Camera\n\n" + $"Details: {e.Message}\n\n" + $"Stack Trace:\n{e.StackTrace}\n\n" + $"Common causes:\n" + $" - Cinemachine 3.x not installed (check Package Manager)\n" + $" - Invalid parameter values\n" + $" - Scene not properly loaded"; } #else return "Error: Cinemachine package not installed. Please install via Package Manager."; #endif } /// /// Setup Cinemachine Brain /// public static string SetupCinemachineBrain(Dictionary parameters) { #if CINEMACHINE_2 try { string cameraName = parameters.ContainsKey("camera") ? parameters["camera"] : "Main Camera"; Camera cam = Camera.main; if (cameraName != "Main Camera") { var camObj = GameObject.Find(cameraName); if (camObj != null) cam = camObj.GetComponent(); } if (cam == null) { return $"Error: Camera '{cameraName}' not found"; } // Check for existing Brain var brain = cam.GetComponent(); if (brain == null) { brain = Undo.AddComponent(cam.gameObject); } // Blend settings if (parameters.ContainsKey("blendStyle")) { brain.m_DefaultBlend.m_Style = ParseBlendStyle(parameters["blendStyle"]); } if (parameters.ContainsKey("defaultBlendTime")) { brain.m_DefaultBlend.m_Time = float.Parse(parameters["defaultBlendTime"]); } // Update method if (parameters.ContainsKey("updateMethod")) { brain.m_UpdateMethod = ParseUpdateMethod(parameters["updateMethod"]); } EditorUtility.SetDirty(brain); return $"Cinemachine Brain setup on '{cameraName}' with {brain.m_DefaultBlend.m_Style} blend"; } catch (Exception e) { return $"Error: Failed to setup Cinemachine Brain - {e.Message}"; } #elif CINEMACHINE_3 try { string cameraName = parameters.ContainsKey("camera") ? parameters["camera"] : "Main Camera"; Camera cam = Camera.main; if (cameraName != "Main Camera") { var camObj = GameObject.Find(cameraName); if (camObj != null) cam = camObj.GetComponent(); } if (cam == null) { return $"Error: Camera '{cameraName}' not found"; } // Check for existing Brain var brain = cam.GetComponent(); if (brain == null) { brain = Undo.AddComponent(cam.gameObject); } // Blend settings (no m_ prefix in CM3) if (parameters.ContainsKey("blendStyle")) { brain.DefaultBlend.Style = ParseBlendStyle3(parameters["blendStyle"]); } if (parameters.ContainsKey("defaultBlendTime")) { brain.DefaultBlend.Time = float.Parse(parameters["defaultBlendTime"]); } // Update method if (parameters.ContainsKey("updateMethod")) { brain.UpdateMethod = ParseUpdateMethod3(parameters["updateMethod"]); } EditorUtility.SetDirty(brain); return $"Cinemachine Brain setup on '{cameraName}' with {brain.DefaultBlend.Style} blend"; } catch (Exception e) { return $"Error: Failed to setup Cinemachine Brain - {e.Message}"; } #else return "Error: Cinemachine package not installed. Please install via Package Manager."; #endif } /// /// Update Virtual Camera /// public static string UpdateVirtualCamera(Dictionary parameters) { #if CINEMACHINE_2 try { if (!parameters.ContainsKey("camera")) { return "Error: 'camera' parameter is required"; } var vcamObj = GameObject.Find(parameters["camera"]); if (vcamObj == null) { return $"Error: Virtual Camera '{parameters["camera"]}' not found"; } var vcam = vcamObj.GetComponent(); if (vcam == null) { return $"Error: '{parameters["camera"]}' is not a Virtual Camera"; } Undo.RecordObject(vcam, "Update Virtual Camera"); // Update Priority if (parameters.ContainsKey("priority")) { vcam.Priority = int.Parse(parameters["priority"]); } // Update Follow/LookAt if (parameters.ContainsKey("follow")) { var followTarget = GameObject.Find(parameters["follow"]); vcam.Follow = followTarget?.transform; } if (parameters.ContainsKey("lookAt")) { var lookAtTarget = GameObject.Find(parameters["lookAt"]); vcam.LookAt = lookAtTarget?.transform; } // Update Lens if (parameters.ContainsKey("fov")) { vcam.m_Lens.FieldOfView = float.Parse(parameters["fov"]); } if (parameters.ContainsKey("nearClipPlane")) { vcam.m_Lens.NearClipPlane = float.Parse(parameters["nearClipPlane"]); } if (parameters.ContainsKey("farClipPlane")) { vcam.m_Lens.FarClipPlane = float.Parse(parameters["farClipPlane"]); } if (parameters.ContainsKey("dutch")) { vcam.m_Lens.Dutch = float.Parse(parameters["dutch"]); } if (parameters.ContainsKey("orthographic")) { vcam.m_Lens.Orthographic = bool.Parse(parameters["orthographic"]); } if (parameters.ContainsKey("orthographicSize")) { vcam.m_Lens.OrthographicSize = float.Parse(parameters["orthographicSize"]); } // Change Body/Aim component if (parameters.ContainsKey("bodyType")) { // Remove existing Body component var existingBody = vcam.GetCinemachineComponent(CinemachineCore.Stage.Body); if (existingBody != null) { Component.DestroyImmediate(existingBody); } // Add new Body component AddBodyComponent(vcam, parameters["bodyType"], parameters); } if (parameters.ContainsKey("aimType")) { // Remove existing Aim component var existingAim = vcam.GetCinemachineComponent(CinemachineCore.Stage.Aim); if (existingAim != null) { Component.DestroyImmediate(existingAim); } // Add new Aim component AddAimComponent(vcam, parameters["aimType"], parameters); } // Update Damping (only if existing Transposer exists) if (parameters.ContainsKey("damping") && !parameters.ContainsKey("bodyType")) { var transposer = vcam.GetCinemachineComponent(); if (transposer != null) { var damping = ParseVector3(parameters["damping"]); transposer.m_XDamping = damping.x; transposer.m_YDamping = damping.y; transposer.m_ZDamping = damping.z; } } // Update Noise if (parameters.ContainsKey("noiseAmplitude") || parameters.ContainsKey("noiseFrequency") || parameters.ContainsKey("noiseProfile")) { var noise = vcam.GetCinemachineComponent(); if (noise == null) { noise = vcam.AddCinemachineComponent(); } if (parameters.ContainsKey("noiseProfile")) { NoiseSettings profile = GetNoiseProfile(parameters["noiseProfile"]); if (profile != null) { noise.m_NoiseProfile = profile; } } if (parameters.ContainsKey("noiseAmplitude")) { noise.m_AmplitudeGain = float.Parse(parameters["noiseAmplitude"]); } if (parameters.ContainsKey("noiseFrequency")) { noise.m_FrequencyGain = float.Parse(parameters["noiseFrequency"]); } } EditorUtility.SetDirty(vcam); return $"Virtual Camera '{parameters["camera"]}' updated successfully"; } catch (Exception e) { return $"Error: Failed to update Virtual Camera - {e.Message}"; } #elif CINEMACHINE_3 try { if (!parameters.ContainsKey("camera")) { return "Error: 'camera' parameter is required"; } var vcamObj = GameObject.Find(parameters["camera"]); if (vcamObj == null) { return $"Error: Virtual Camera '{parameters["camera"]}' not found"; } var vcam = vcamObj.GetComponent(); if (vcam == null) { return $"Error: '{parameters["camera"]}' is not a Cinemachine Camera"; } Undo.RecordObject(vcam, "Update Virtual Camera"); // Update Priority if (parameters.ContainsKey("priority")) { vcam.Priority.Value = int.Parse(parameters["priority"]); } // Update Follow/LookAt (Target in CM3) if (parameters.ContainsKey("follow")) { var followTarget = GameObject.Find(parameters["follow"]); vcam.Target.TrackingTarget = followTarget?.transform; } if (parameters.ContainsKey("lookAt")) { var lookAtTarget = GameObject.Find(parameters["lookAt"]); vcam.Target.LookAtTarget = lookAtTarget?.transform; } // Update Lens (no m_ prefix in CM3) if (parameters.ContainsKey("fov")) { vcam.Lens.FieldOfView = float.Parse(parameters["fov"]); } if (parameters.ContainsKey("nearClipPlane")) { vcam.Lens.NearClipPlane = float.Parse(parameters["nearClipPlane"]); } if (parameters.ContainsKey("farClipPlane")) { vcam.Lens.FarClipPlane = float.Parse(parameters["farClipPlane"]); } if (parameters.ContainsKey("dutch")) { vcam.Lens.Dutch = float.Parse(parameters["dutch"]); } if (parameters.ContainsKey("orthographic")) { bool isOrthographic = bool.Parse(parameters["orthographic"]); vcam.Lens.ModeOverride = isOrthographic ? LensSettings.OverrideModes.Orthographic : LensSettings.OverrideModes.None; } if (parameters.ContainsKey("orthographicSize")) { vcam.Lens.OrthographicSize = float.Parse(parameters["orthographicSize"]); } // Change Body/Aim component (CM3 architecture is different) if (parameters.ContainsKey("bodyType")) { // Remove existing follow components var existingFollow = vcam.GetComponent(); var existingOrbital = vcam.GetComponent(); var existingPosition = vcam.GetComponent(); if (existingFollow != null) Component.DestroyImmediate(existingFollow); if (existingOrbital != null) Component.DestroyImmediate(existingOrbital); if (existingPosition != null) Component.DestroyImmediate(existingPosition); // Add new Body component AddBodyComponent3(vcam, parameters["bodyType"], parameters); } if (parameters.ContainsKey("aimType")) { // Remove existing aim components var existingRotation = vcam.GetComponent(); if (existingRotation != null) Component.DestroyImmediate(existingRotation); // Add new Aim component AddAimComponent3(vcam, parameters["aimType"], parameters); } // Update Noise if (parameters.ContainsKey("noiseAmplitude") || parameters.ContainsKey("noiseFrequency") || parameters.ContainsKey("noiseProfile")) { var noise = vcam.GetComponent(); if (noise == null) { noise = vcam.gameObject.AddComponent(); } if (parameters.ContainsKey("noiseProfile")) { NoiseSettings profile = GetNoiseProfile(parameters["noiseProfile"]); if (profile != null) { noise.NoiseProfile = profile; } } if (parameters.ContainsKey("noiseAmplitude")) { noise.AmplitudeGain = float.Parse(parameters["noiseAmplitude"]); } if (parameters.ContainsKey("noiseFrequency")) { noise.FrequencyGain = float.Parse(parameters["noiseFrequency"]); } } EditorUtility.SetDirty(vcam); return $"Virtual Camera '{parameters["camera"]}' updated successfully"; } catch (Exception e) { return $"Error: Failed to update Virtual Camera - {e.Message}"; } #else return "Error: Cinemachine package not installed. Please install via Package Manager."; #endif } /// /// Create State-Driven Camera /// public static string CreateStateDrivenCamera(Dictionary parameters) { #if CINEMACHINE_2 try { string name = parameters.ContainsKey("name") ? parameters["name"] : "CM StateDriven1"; GameObject sdCameraObj = new GameObject(name); var stateDriven = sdCameraObj.AddComponent(); // Set Animator (required) if (!parameters.ContainsKey("animatedTarget")) { return "Error: 'animatedTarget' parameter is required for State-Driven camera"; } var animTarget = GameObject.Find(parameters["animatedTarget"]); if (animTarget == null) { return $"Error: Animated target '{parameters["animatedTarget"]}' not found"; } var animator = animTarget.GetComponent(); if (animator == null) { return $"Error: '{parameters["animatedTarget"]}' does not have an Animator component"; } stateDriven.m_AnimatedTarget = animator; // Set Layer Index if (parameters.ContainsKey("layerIndex")) { stateDriven.m_LayerIndex = int.Parse(parameters["layerIndex"]); } // Set Follow/LookAt if (parameters.ContainsKey("follow")) { var followTarget = GameObject.Find(parameters["follow"]); if (followTarget != null) { stateDriven.Follow = followTarget.transform; } } if (parameters.ContainsKey("lookAt")) { var lookAtTarget = GameObject.Find(parameters["lookAt"]); if (lookAtTarget != null) { stateDriven.LookAt = lookAtTarget.transform; } } // Priority if (parameters.ContainsKey("priority")) { stateDriven.Priority = int.Parse(parameters["priority"]); } Undo.RegisterCreatedObjectUndo(sdCameraObj, "Create State-Driven Camera"); Selection.activeGameObject = sdCameraObj; return $"State-Driven Camera '{name}' created successfully, driven by '{parameters["animatedTarget"]}'"; } catch (Exception e) { return $"Error: Failed to create State-Driven Camera - {e.Message}"; } #elif CINEMACHINE_3 try { string name = parameters.ContainsKey("name") ? parameters["name"] : "CM StateDriven1"; GameObject sdCameraObj = new GameObject(name); var stateDriven = sdCameraObj.AddComponent(); // Set Animator (required) if (!parameters.ContainsKey("animatedTarget")) { return "Error: 'animatedTarget' parameter is required for State-Driven camera"; } var animTarget = GameObject.Find(parameters["animatedTarget"]); if (animTarget == null) { return $"Error: Animated target '{parameters["animatedTarget"]}' not found"; } var animator = animTarget.GetComponent(); if (animator == null) { return $"Error: '{parameters["animatedTarget"]}' does not have an Animator component"; } stateDriven.AnimatedTarget = animator; // Set Layer Index (no m_ prefix in CM3) if (parameters.ContainsKey("layerIndex")) { stateDriven.LayerIndex = int.Parse(parameters["layerIndex"]); } // Set Follow/LookAt if (parameters.ContainsKey("follow")) { var followTarget = GameObject.Find(parameters["follow"]); if (followTarget != null) { stateDriven.Follow = followTarget.transform; } } if (parameters.ContainsKey("lookAt")) { var lookAtTarget = GameObject.Find(parameters["lookAt"]); if (lookAtTarget != null) { stateDriven.LookAt = lookAtTarget.transform; } } // Priority if (parameters.ContainsKey("priority")) { stateDriven.Priority = int.Parse(parameters["priority"]); } Undo.RegisterCreatedObjectUndo(sdCameraObj, "Create State-Driven Camera"); Selection.activeGameObject = sdCameraObj; return $"State-Driven Camera '{name}' created successfully, driven by '{parameters["animatedTarget"]}'"; } catch (Exception e) { return $"Error: Failed to create State-Driven Camera - {e.Message}"; } #else return "Error: Cinemachine package not installed. Please install via Package Manager."; #endif } /// /// Create Clear Shot Camera /// public static string CreateClearShotCamera(Dictionary parameters) { #if CINEMACHINE_2 try { string name = parameters.ContainsKey("name") ? parameters["name"] : "CM ClearShot1"; GameObject clearShotObj = new GameObject(name); var clearShot = clearShotObj.AddComponent(); // Set Follow/LookAt if (parameters.ContainsKey("follow")) { var followTarget = GameObject.Find(parameters["follow"]); if (followTarget != null) { clearShot.Follow = followTarget.transform; } } if (parameters.ContainsKey("lookAt")) { var lookAtTarget = GameObject.Find(parameters["lookAt"]); if (lookAtTarget != null) { clearShot.LookAt = lookAtTarget.transform; } } // Priority if (parameters.ContainsKey("priority")) { clearShot.Priority = int.Parse(parameters["priority"]); } Undo.RegisterCreatedObjectUndo(clearShotObj, "Create Clear Shot Camera"); Selection.activeGameObject = clearShotObj; return $"Clear Shot Camera '{name}' created successfully. Add child Virtual Cameras to create shot candidates."; } catch (Exception e) { return $"Error: Failed to create Clear Shot Camera - {e.Message}"; } #elif CINEMACHINE_3 try { string name = parameters.ContainsKey("name") ? parameters["name"] : "CM ClearShot1"; GameObject clearShotObj = new GameObject(name); var clearShot = clearShotObj.AddComponent(); // Set Follow/LookAt if (parameters.ContainsKey("follow")) { var followTarget = GameObject.Find(parameters["follow"]); if (followTarget != null) { clearShot.Follow = followTarget.transform; } } if (parameters.ContainsKey("lookAt")) { var lookAtTarget = GameObject.Find(parameters["lookAt"]); if (lookAtTarget != null) { clearShot.LookAt = lookAtTarget.transform; } } // Priority if (parameters.ContainsKey("priority")) { clearShot.Priority = int.Parse(parameters["priority"]); } Undo.RegisterCreatedObjectUndo(clearShotObj, "Create Clear Shot Camera"); Selection.activeGameObject = clearShotObj; return $"Clear Shot Camera '{name}' created successfully. Add child Virtual Cameras to create shot candidates."; } catch (Exception e) { return $"Error: Failed to create Clear Shot Camera - {e.Message}"; } #else return "Error: Cinemachine package not installed. Please install via Package Manager."; #endif } /// /// Create Impulse Source /// public static string CreateImpulseSource(Dictionary parameters) { #if CINEMACHINE_2 try { if (!parameters.ContainsKey("gameObject")) { return "Error: 'gameObject' parameter is required"; } var targetObj = GameObject.Find(parameters["gameObject"]); if (targetObj == null) { return $"Error: GameObject '{parameters["gameObject"]}' not found"; } // Add Impulse Source var impulseSource = Undo.AddComponent(targetObj); // Set Raw Signal if (parameters.ContainsKey("amplitudeGain")) { impulseSource.m_ImpulseDefinition.m_AmplitudeGain = float.Parse(parameters["amplitudeGain"]); } if (parameters.ContainsKey("frequencyGain")) { impulseSource.m_ImpulseDefinition.m_FrequencyGain = float.Parse(parameters["frequencyGain"]); } if (parameters.ContainsKey("impulseDuration")) { impulseSource.m_ImpulseDefinition.m_TimeEnvelope.m_SustainTime = float.Parse(parameters["impulseDuration"]); } // Set Velocity if (parameters.ContainsKey("defaultVelocity")) { var velocity = ParseVector3(parameters["defaultVelocity"]); impulseSource.m_DefaultVelocity = velocity; } EditorUtility.SetDirty(targetObj); return $"Impulse Source added to '{parameters["gameObject"]}'"; } catch (Exception e) { return $"Error: Failed to create Impulse Source - {e.Message}"; } #elif CINEMACHINE_3 try { if (!parameters.ContainsKey("gameObject")) { return "Error: 'gameObject' parameter is required"; } var targetObj = GameObject.Find(parameters["gameObject"]); if (targetObj == null) { return $"Error: GameObject '{parameters["gameObject"]}' not found"; } // Add Impulse Source (no m_ prefix in CM3) var impulseSource = Undo.AddComponent(targetObj); // Set Impulse Definition properties if (parameters.ContainsKey("amplitudeGain") || parameters.ContainsKey("frequencyGain") || parameters.ContainsKey("impulseDuration")) { var impulseDef = impulseSource.ImpulseDefinition; if (parameters.ContainsKey("amplitudeGain")) { impulseDef.AmplitudeGain = float.Parse(parameters["amplitudeGain"]); } if (parameters.ContainsKey("frequencyGain")) { impulseDef.FrequencyGain = float.Parse(parameters["frequencyGain"]); } if (parameters.ContainsKey("impulseDuration")) { impulseDef.ImpulseDuration = float.Parse(parameters["impulseDuration"]); } impulseSource.ImpulseDefinition = impulseDef; } // Set Velocity if (parameters.ContainsKey("defaultVelocity")) { var velocity = ParseVector3(parameters["defaultVelocity"]); impulseSource.DefaultVelocity = velocity; } EditorUtility.SetDirty(targetObj); return $"Impulse Source added to '{parameters["gameObject"]}'"; } catch (Exception e) { return $"Error: Failed to create Impulse Source - {e.Message}"; } #else return "Error: Cinemachine package not installed. Please install via Package Manager."; #endif } /// /// Add Impulse Listener /// public static string AddImpulseListener(Dictionary parameters) { #if CINEMACHINE_2 try { if (!parameters.ContainsKey("camera")) { return "Error: 'camera' parameter is required"; } var vcamObj = GameObject.Find(parameters["camera"]); if (vcamObj == null) { return $"Error: Virtual Camera '{parameters["camera"]}' not found"; } var vcam = vcamObj.GetComponent(); if (vcam == null) { return $"Error: '{parameters["camera"]}' is not a Virtual Camera"; } // Add Impulse Listener var listener = vcam.gameObject.AddComponent(); // Set Gain if (parameters.ContainsKey("gain")) { listener.m_Gain = float.Parse(parameters["gain"]); } // Set Use 2D Distance if (parameters.ContainsKey("use2DDistance")) { listener.m_Use2DDistance = bool.Parse(parameters["use2DDistance"]); } // Reaction Settings if (parameters.ContainsKey("amplitudeGain")) { listener.m_ReactionSettings.m_AmplitudeGain = float.Parse(parameters["amplitudeGain"]); } if (parameters.ContainsKey("frequencyGain")) { listener.m_ReactionSettings.m_FrequencyGain = float.Parse(parameters["frequencyGain"]); } EditorUtility.SetDirty(vcam); return $"Impulse Listener added to '{parameters["camera"]}'"; } catch (Exception e) { return $"Error: Failed to add Impulse Listener - {e.Message}"; } #elif CINEMACHINE_3 try { if (!parameters.ContainsKey("camera")) { return "Error: 'camera' parameter is required"; } var vcamObj = GameObject.Find(parameters["camera"]); if (vcamObj == null) { return $"Error: Virtual Camera '{parameters["camera"]}' not found"; } var vcam = vcamObj.GetComponent(); if (vcam == null) { return $"Error: '{parameters["camera"]}' is not a Cinemachine Camera"; } // Add Impulse Listener (no m_ prefix in CM3) var listener = vcam.gameObject.AddComponent(); // Set Gain if (parameters.ContainsKey("gain")) { listener.Gain = float.Parse(parameters["gain"]); } // Set Use 2D Distance if (parameters.ContainsKey("use2DDistance")) { listener.Use2DDistance = bool.Parse(parameters["use2DDistance"]); } // Reaction Settings if (parameters.ContainsKey("amplitudeGain")) { listener.ReactionSettings.AmplitudeGain = float.Parse(parameters["amplitudeGain"]); } if (parameters.ContainsKey("frequencyGain")) { listener.ReactionSettings.FrequencyGain = float.Parse(parameters["frequencyGain"]); } EditorUtility.SetDirty(vcam); return $"Impulse Listener added to '{parameters["camera"]}'"; } catch (Exception e) { return $"Error: Failed to add Impulse Listener - {e.Message}"; } #else return "Error: Cinemachine package not installed. Please install via Package Manager."; #endif } /// /// Create Blend List Camera /// public static string CreateBlendListCamera(Dictionary parameters) { #if CINEMACHINE_2 try { string name = parameters.ContainsKey("name") ? parameters["name"] : "CM BlendList"; // Create Blend List Camera object GameObject blendListObj = new GameObject(name); var blendListCam = blendListObj.AddComponent(); // Set priority if (parameters.ContainsKey("priority")) { blendListCam.Priority = int.Parse(parameters["priority"]); } // Set Follow/LookAt if (parameters.ContainsKey("follow")) { var followObj = GameObject.Find(parameters["follow"]); if (followObj != null) { blendListCam.Follow = followObj.transform; } } if (parameters.ContainsKey("lookAt")) { var lookAtObj = GameObject.Find(parameters["lookAt"]); if (lookAtObj != null) { blendListCam.LookAt = lookAtObj.transform; } } // Set Loop if (parameters.ContainsKey("loop")) { blendListCam.m_Loop = bool.Parse(parameters["loop"]); } // Set Show Debug Text if (parameters.ContainsKey("showDebugText")) { blendListCam.m_ShowDebugText = bool.Parse(parameters["showDebugText"]); } Undo.RegisterCreatedObjectUndo(blendListObj, "Create Blend List Camera"); Selection.activeGameObject = blendListObj; return $"Blend List Camera '{name}' created successfully"; } catch (Exception e) { return $"Error: Failed to create Blend List Camera - {e.Message}"; } #elif CINEMACHINE_3 try { string name = parameters.ContainsKey("name") ? parameters["name"] : "CM Sequencer"; // In CM3, BlendListCamera is renamed to SequencerCamera GameObject sequencerObj = new GameObject(name); var sequencer = sequencerObj.AddComponent(); // Set priority if (parameters.ContainsKey("priority")) { sequencer.Priority = int.Parse(parameters["priority"]); } // Set Follow/LookAt if (parameters.ContainsKey("follow")) { var followObj = GameObject.Find(parameters["follow"]); if (followObj != null) { sequencer.Follow = followObj.transform; } } if (parameters.ContainsKey("lookAt")) { var lookAtObj = GameObject.Find(parameters["lookAt"]); if (lookAtObj != null) { sequencer.LookAt = lookAtObj.transform; } } // Set Loop (no m_ prefix in CM3) if (parameters.ContainsKey("loop")) { sequencer.Loop = bool.Parse(parameters["loop"]); } Undo.RegisterCreatedObjectUndo(sequencerObj, "Create Sequencer Camera"); Selection.activeGameObject = sequencerObj; return $"Sequencer Camera (CM3 BlendList) '{name}' created successfully"; } catch (Exception e) { return $"Error: Failed to create Blend List Camera - {e.Message}"; } #else return "Error: Cinemachine package not installed. Please install via Package Manager."; #endif } /// /// Create Target Group /// public static string CreateTargetGroup(Dictionary parameters) { #if CINEMACHINE_2 try { string name = parameters.ContainsKey("name") ? parameters["name"] : "CM TargetGroup"; // Create Target Group object GameObject targetGroupObj = new GameObject(name); var targetGroup = targetGroupObj.AddComponent(); // Set Position Mode if (parameters.ContainsKey("positionMode")) { targetGroup.m_PositionMode = ParseTargetGroupPositionMode(parameters["positionMode"]); } // Set Rotation Mode if (parameters.ContainsKey("rotationMode")) { targetGroup.m_RotationMode = ParseTargetGroupRotationMode(parameters["rotationMode"]); } // Set Update Method if (parameters.ContainsKey("updateMethod")) { targetGroup.m_UpdateMethod = ParseTargetGroupUpdateMethod(parameters["updateMethod"]); } Undo.RegisterCreatedObjectUndo(targetGroupObj, "Create Target Group"); Selection.activeGameObject = targetGroupObj; return $"Target Group '{name}' created successfully"; } catch (Exception e) { return $"Error: Failed to create Target Group - {e.Message}"; } #elif CINEMACHINE_3 try { string name = parameters.ContainsKey("name") ? parameters["name"] : "CM TargetGroup"; // Create Target Group object (same API in CM3) GameObject targetGroupObj = new GameObject(name); var targetGroup = targetGroupObj.AddComponent(); // Set Position Mode (no m_ prefix in CM3) if (parameters.ContainsKey("positionMode")) { targetGroup.PositionMode = ParseTargetGroupPositionMode3(parameters["positionMode"]); } // Set Rotation Mode if (parameters.ContainsKey("rotationMode")) { targetGroup.RotationMode = ParseTargetGroupRotationMode3(parameters["rotationMode"]); } // Set Update Method if (parameters.ContainsKey("updateMethod")) { targetGroup.UpdateMethod = ParseTargetGroupUpdateMethod3(parameters["updateMethod"]); } Undo.RegisterCreatedObjectUndo(targetGroupObj, "Create Target Group"); Selection.activeGameObject = targetGroupObj; return $"Target Group '{name}' created successfully"; } catch (Exception e) { return $"Error: Failed to create Target Group - {e.Message}"; } #else return "Error: Cinemachine package not installed. Please install via Package Manager."; #endif } /// /// Add Target to Target Group /// public static string AddTargetToGroup(Dictionary parameters) { #if CINEMACHINE_2 try { if (!parameters.ContainsKey("targetGroup")) { return "Error: 'targetGroup' parameter is required"; } if (!parameters.ContainsKey("target")) { return "Error: 'target' parameter is required"; } var targetGroupObj = GameObject.Find(parameters["targetGroup"]); if (targetGroupObj == null) { return $"Error: Target Group '{parameters["targetGroup"]}' not found"; } var targetGroup = targetGroupObj.GetComponent(); if (targetGroup == null) { return $"Error: '{parameters["targetGroup"]}' is not a Target Group"; } var targetObj = GameObject.Find(parameters["target"]); if (targetObj == null) { return $"Error: Target GameObject '{parameters["target"]}' not found"; } // Set Weight float weight = 1.0f; if (parameters.ContainsKey("weight")) { weight = float.Parse(parameters["weight"]); } // Set Radius float radius = 1.0f; if (parameters.ContainsKey("radius")) { radius = float.Parse(parameters["radius"]); } // Add target targetGroup.AddMember(targetObj.transform, weight, radius); EditorUtility.SetDirty(targetGroup); return $"Target '{parameters["target"]}' added to group '{parameters["targetGroup"]}'"; } catch (Exception e) { return $"Error: Failed to add target to group - {e.Message}"; } #elif CINEMACHINE_3 try { if (!parameters.ContainsKey("targetGroup")) { return "Error: 'targetGroup' parameter is required"; } if (!parameters.ContainsKey("target")) { return "Error: 'target' parameter is required"; } var targetGroupObj = GameObject.Find(parameters["targetGroup"]); if (targetGroupObj == null) { return $"Error: Target Group '{parameters["targetGroup"]}' not found"; } var targetGroup = targetGroupObj.GetComponent(); if (targetGroup == null) { return $"Error: '{parameters["targetGroup"]}' is not a Target Group"; } var targetObj = GameObject.Find(parameters["target"]); if (targetObj == null) { return $"Error: Target GameObject '{parameters["target"]}' not found"; } // Set Weight float weight = 1.0f; if (parameters.ContainsKey("weight")) { weight = float.Parse(parameters["weight"]); } // Set Radius float radius = 1.0f; if (parameters.ContainsKey("radius")) { radius = float.Parse(parameters["radius"]); } // Add target (same API in CM3) targetGroup.AddMember(targetObj.transform, weight, radius); EditorUtility.SetDirty(targetGroup); return $"Target '{parameters["target"]}' added to group '{parameters["targetGroup"]}'"; } catch (Exception e) { return $"Error: Failed to add target to group - {e.Message}"; } #else return "Error: Cinemachine package not installed. Please install via Package Manager."; #endif } /// /// Set Virtual Camera priority /// public static string SetCameraPriority(Dictionary parameters) { #if CINEMACHINE_2 try { if (!parameters.ContainsKey("camera")) { return "Error: 'camera' parameter is required"; } if (!parameters.ContainsKey("priority")) { return "Error: 'priority' parameter is required"; } var cameraObj = GameObject.Find(parameters["camera"]); if (cameraObj == null) { return $"Error: Camera '{parameters["camera"]}' not found"; } var vcam = cameraObj.GetComponent(); if (vcam == null) { return $"Error: '{parameters["camera"]}' is not a Cinemachine camera"; } int priority = int.Parse(parameters["priority"]); vcam.Priority = priority; EditorUtility.SetDirty(vcam); return $"Camera '{parameters["camera"]}' priority set to {priority}"; } catch (Exception e) { return $"Error: Failed to set camera priority - {e.Message}"; } #elif CINEMACHINE_3 try { if (!parameters.ContainsKey("camera")) { return "Error: 'camera' parameter is required"; } if (!parameters.ContainsKey("priority")) { return "Error: 'priority' parameter is required"; } var cameraObj = GameObject.Find(parameters["camera"]); if (cameraObj == null) { return $"Error: Camera '{parameters["camera"]}' not found"; } var vcam = cameraObj.GetComponent(); if (vcam == null) { return $"Error: '{parameters["camera"]}' is not a Cinemachine camera"; } int priority = int.Parse(parameters["priority"]); vcam.Priority = priority; EditorUtility.SetDirty(vcam); return $"Camera '{parameters["camera"]}' priority set to {priority}"; } catch (Exception e) { return $"Error: Failed to set camera priority - {e.Message}"; } #else return "Error: Cinemachine package not installed. Please install via Package Manager."; #endif } /// /// Toggle Virtual Camera enabled/disabled /// public static string SetCameraEnabled(Dictionary parameters) { #if CINEMACHINE_2 try { if (!parameters.ContainsKey("camera")) { return "Error: 'camera' parameter is required"; } if (!parameters.ContainsKey("enabled")) { return "Error: 'enabled' parameter is required"; } var cameraObj = GameObject.Find(parameters["camera"]); if (cameraObj == null) { return $"Error: Camera '{parameters["camera"]}' not found"; } var vcam = cameraObj.GetComponent(); if (vcam == null) { return $"Error: '{parameters["camera"]}' is not a Cinemachine camera"; } bool enabled = bool.Parse(parameters["enabled"]); vcam.enabled = enabled; EditorUtility.SetDirty(vcam); return $"Camera '{parameters["camera"]}' {(enabled ? "enabled" : "disabled")}"; } catch (Exception e) { return $"Error: Failed to set camera enabled state - {e.Message}"; } #elif CINEMACHINE_3 try { if (!parameters.ContainsKey("camera")) { return "Error: 'camera' parameter is required"; } if (!parameters.ContainsKey("enabled")) { return "Error: 'enabled' parameter is required"; } var cameraObj = GameObject.Find(parameters["camera"]); if (cameraObj == null) { return $"Error: Camera '{parameters["camera"]}' not found"; } var vcam = cameraObj.GetComponent(); if (vcam == null) { return $"Error: '{parameters["camera"]}' is not a Cinemachine camera"; } bool enabled = bool.Parse(parameters["enabled"]); vcam.enabled = enabled; EditorUtility.SetDirty(vcam); return $"Camera '{parameters["camera"]}' {(enabled ? "enabled" : "disabled")}"; } catch (Exception e) { return $"Error: Failed to set camera enabled state - {e.Message}"; } #else return "Error: Cinemachine package not installed. Please install via Package Manager."; #endif } /// /// Create Mixing Camera /// public static string CreateMixingCamera(Dictionary parameters) { #if CINEMACHINE_2 try { string name = parameters.ContainsKey("name") ? parameters["name"] : "CM MixingCamera"; // Create Mixing Camera object GameObject mixingCameraObj = new GameObject(name); var mixingCamera = mixingCameraObj.AddComponent(); // Set priority if (parameters.ContainsKey("priority")) { mixingCamera.Priority = int.Parse(parameters["priority"]); } // Set Weight(weight0〜weight7) for (int i = 0; i < 8; i++) { string weightKey = $"weight{i}"; if (parameters.ContainsKey(weightKey)) { float weight = float.Parse(parameters[weightKey]); mixingCamera.SetWeight(i, weight); } } Undo.RegisterCreatedObjectUndo(mixingCameraObj, "Create Mixing Camera"); Selection.activeGameObject = mixingCameraObj; return $"Mixing Camera '{name}' created successfully"; } catch (Exception e) { return $"Error: Failed to create Mixing Camera - {e.Message}"; } #elif CINEMACHINE_3 try { string name = parameters.ContainsKey("name") ? parameters["name"] : "CM MixingCamera"; // Create Mixing Camera object (same component in CM3) GameObject mixingCameraObj = new GameObject(name); var mixingCamera = mixingCameraObj.AddComponent(); // Set priority if (parameters.ContainsKey("priority")) { mixingCamera.Priority = int.Parse(parameters["priority"]); } // Set Weight(weight0〜weight7) for (int i = 0; i < 8; i++) { string weightKey = $"weight{i}"; if (parameters.ContainsKey(weightKey)) { float weight = float.Parse(parameters[weightKey]); mixingCamera.SetWeight(i, weight); } } Undo.RegisterCreatedObjectUndo(mixingCameraObj, "Create Mixing Camera"); Selection.activeGameObject = mixingCameraObj; return $"Mixing Camera '{name}' created successfully"; } catch (Exception e) { return $"Error: Failed to create Mixing Camera - {e.Message}"; } #else return "Error: Cinemachine package not installed. Please install via Package Manager."; #endif } /// /// Update Camera Follow/LookAt targets /// public static string UpdateCameraTarget(Dictionary parameters) { #if CINEMACHINE_2 try { if (!parameters.ContainsKey("camera")) { return "Error: 'camera' parameter is required"; } var cameraObj = GameObject.Find(parameters["camera"]); if (cameraObj == null) { return $"Error: Camera '{parameters["camera"]}' not found"; } var vcam = cameraObj.GetComponent(); if (vcam == null) { return $"Error: '{parameters["camera"]}' is not a Cinemachine camera"; } // Follow settings if (parameters.ContainsKey("follow")) { if (string.IsNullOrEmpty(parameters["follow"])) { vcam.Follow = null; } else { var followObj = GameObject.Find(parameters["follow"]); if (followObj != null) { vcam.Follow = followObj.transform; } else { return $"Error: Follow target '{parameters["follow"]}' not found"; } } } // LookAt settings if (parameters.ContainsKey("lookAt")) { if (string.IsNullOrEmpty(parameters["lookAt"])) { vcam.LookAt = null; } else { var lookAtObj = GameObject.Find(parameters["lookAt"]); if (lookAtObj != null) { vcam.LookAt = lookAtObj.transform; } else { return $"Error: LookAt target '{parameters["lookAt"]}' not found"; } } } EditorUtility.SetDirty(vcam); return $"Camera '{parameters["camera"]}' targets updated"; } catch (Exception e) { return $"Error: Failed to update camera target - {e.Message}"; } #elif CINEMACHINE_3 try { if (!parameters.ContainsKey("camera")) { return "Error: 'camera' parameter is required"; } var cameraObj = GameObject.Find(parameters["camera"]); if (cameraObj == null) { return $"Error: Camera '{parameters["camera"]}' not found"; } // CM3 uses CinemachineCamera instead of base class for targets var vcam = cameraObj.GetComponent(); if (vcam == null) { // Fallback to base class var vcamBase = cameraObj.GetComponent(); if (vcamBase != null) { // For non-CinemachineCamera types (rare in CM3) if (parameters.ContainsKey("follow")) { if (string.IsNullOrEmpty(parameters["follow"])) { vcamBase.Follow = null; } else { var followObj = GameObject.Find(parameters["follow"]); if (followObj != null) vcamBase.Follow = followObj.transform; else return $"Error: Follow target '{parameters["follow"]}' not found"; } } if (parameters.ContainsKey("lookAt")) { if (string.IsNullOrEmpty(parameters["lookAt"])) { vcamBase.LookAt = null; } else { var lookAtObj = GameObject.Find(parameters["lookAt"]); if (lookAtObj != null) vcamBase.LookAt = lookAtObj.transform; else return $"Error: LookAt target '{parameters["lookAt"]}' not found"; } } EditorUtility.SetDirty(vcamBase); return $"Camera '{parameters["camera"]}' targets updated"; } return $"Error: '{parameters["camera"]}' is not a Cinemachine camera"; } // Follow settings (Target.TrackingTarget in CM3) if (parameters.ContainsKey("follow")) { if (string.IsNullOrEmpty(parameters["follow"])) { vcam.Target.TrackingTarget = null; } else { var followObj = GameObject.Find(parameters["follow"]); if (followObj != null) { vcam.Target.TrackingTarget = followObj.transform; } else { return $"Error: Follow target '{parameters["follow"]}' not found"; } } } // LookAt settings (Target.LookAtTarget in CM3) if (parameters.ContainsKey("lookAt")) { if (string.IsNullOrEmpty(parameters["lookAt"])) { vcam.Target.LookAtTarget = null; } else { var lookAtObj = GameObject.Find(parameters["lookAt"]); if (lookAtObj != null) { vcam.Target.LookAtTarget = lookAtObj.transform; } else { return $"Error: LookAt target '{parameters["lookAt"]}' not found"; } } } EditorUtility.SetDirty(vcam); return $"Camera '{parameters["camera"]}' targets updated"; } catch (Exception e) { return $"Error: Failed to update camera target - {e.Message}"; } #else return "Error: Cinemachine package not installed. Please install via Package Manager."; #endif } /// /// Update Cinemachine Brain blend settings /// public static string UpdateBrainBlendSettings(Dictionary parameters) { #if CINEMACHINE_2 try { // Get Main Camera var mainCamera = Camera.main; if (mainCamera == null) { return "Error: Main Camera not found"; } var brain = mainCamera.GetComponent(); if (brain == null) { return "Error: CinemachineBrain not found on Main Camera"; } // Default Blend settings if (parameters.ContainsKey("defaultBlendTime")) { brain.m_DefaultBlend.m_Time = float.Parse(parameters["defaultBlendTime"]); } if (parameters.ContainsKey("defaultBlendStyle")) { brain.m_DefaultBlend.m_Style = ParseBlendStyle(parameters["defaultBlendStyle"]); } // Custom Blends settings (requires asset) if (parameters.ContainsKey("customBlendsAsset")) { var asset = AssetDatabase.LoadAssetAtPath(parameters["customBlendsAsset"]); if (asset != null) { brain.m_CustomBlends = asset; } } EditorUtility.SetDirty(brain); return "Cinemachine Brain blend settings updated"; } catch (Exception e) { return $"Error: Failed to update Brain blend settings - {e.Message}"; } #elif CINEMACHINE_3 try { // Get Main Camera var mainCamera = Camera.main; if (mainCamera == null) { return "Error: Main Camera not found"; } var brain = mainCamera.GetComponent(); if (brain == null) { return "Error: CinemachineBrain not found on Main Camera"; } // Default Blend settings (no m_ prefix in CM3) if (parameters.ContainsKey("defaultBlendTime")) { brain.DefaultBlend.Time = float.Parse(parameters["defaultBlendTime"]); } if (parameters.ContainsKey("defaultBlendStyle")) { brain.DefaultBlend.Style = ParseBlendStyle3(parameters["defaultBlendStyle"]); } // Custom Blends settings if (parameters.ContainsKey("customBlendsAsset")) { var asset = AssetDatabase.LoadAssetAtPath(parameters["customBlendsAsset"]); if (asset != null) { brain.CustomBlends = asset; } } EditorUtility.SetDirty(brain); return "Cinemachine Brain blend settings updated"; } catch (Exception e) { return $"Error: Failed to update Brain blend settings - {e.Message}"; } #else return "Error: Cinemachine package not installed. Please install via Package Manager."; #endif } /// /// Get active Cinemachine Camera information /// public static string GetActiveCameraInfo(Dictionary parameters) { #if CINEMACHINE_2 try { var mainCamera = Camera.main; if (mainCamera == null) { return "Error: Main Camera not found"; } var brain = mainCamera.GetComponent(); if (brain == null) { return "Error: CinemachineBrain not found on Main Camera"; } var activeVcam = brain.ActiveVirtualCamera; if (activeVcam == null) { return "No active Cinemachine camera"; } var info = new System.Text.StringBuilder(); info.AppendLine($"Active Camera: {activeVcam.Name}"); info.AppendLine($"State: {activeVcam.State}"); // CM2: ICinemachineCamera has Priority/Follow/LookAt directly info.AppendLine($"Priority: {activeVcam.Priority}"); if (activeVcam.Follow != null) { info.AppendLine($"Follow: {activeVcam.Follow.name}"); } if (activeVcam.LookAt != null) { info.AppendLine($"LookAt: {activeVcam.LookAt.name}"); } return info.ToString(); } catch (Exception e) { return $"Error: Failed to get active camera info - {e.Message}"; } #elif CINEMACHINE_3 try { var mainCamera = Camera.main; if (mainCamera == null) { return "Error: Main Camera not found"; } var brain = mainCamera.GetComponent(); if (brain == null) { return "Error: CinemachineBrain not found on Main Camera"; } var activeVcam = brain.ActiveVirtualCamera; if (activeVcam == null) { return "No active Cinemachine camera"; } var info = new System.Text.StringBuilder(); info.AppendLine($"Active Camera: {activeVcam.Name}"); info.AppendLine($"State: {activeVcam.State}"); // CM3: ICinemachineCamera doesn't have Priority/Follow/LookAt // Need to cast to CinemachineCamera to access these properties if (activeVcam is CinemachineCamera vcam) { info.AppendLine($"Priority: {vcam.Priority}"); if (vcam.Target.TrackingTarget != null) { info.AppendLine($"Follow: {vcam.Target.TrackingTarget.name}"); } if (vcam.Target.LookAtTarget != null) { info.AppendLine($"LookAt: {vcam.Target.LookAtTarget.name}"); } } return info.ToString(); } catch (Exception e) { return $"Error: Failed to get active camera info - {e.Message}"; } #else return "Error: Cinemachine package not installed. Please install via Package Manager."; #endif } /// /// Add Collider Extension to Virtual Camera /// public static string AddColliderExtension(Dictionary parameters) { #if CINEMACHINE_2 try { if (!parameters.ContainsKey("camera")) { return "Error: 'camera' parameter is required"; } var vcamObj = GameObject.Find(parameters["camera"]); if (vcamObj == null) { return $"Error: Virtual Camera '{parameters["camera"]}' not found"; } var vcam = vcamObj.GetComponent(); if (vcam == null) { return $"Error: '{parameters["camera"]}' is not a Virtual Camera"; } // Add Collider Extension var collider = vcam.gameObject.AddComponent(); // Settings if (parameters.ContainsKey("minimumDistanceFromTarget")) { collider.m_MinimumDistanceFromTarget = float.Parse(parameters["minimumDistanceFromTarget"]); } if (parameters.ContainsKey("avoidObstacles")) { collider.m_AvoidObstacles = bool.Parse(parameters["avoidObstacles"]); } if (parameters.ContainsKey("distanceLimit")) { collider.m_DistanceLimit = float.Parse(parameters["distanceLimit"]); } if (parameters.ContainsKey("smoothingTime")) { collider.m_SmoothingTime = float.Parse(parameters["smoothingTime"]); } if (parameters.ContainsKey("damping")) { collider.m_Damping = float.Parse(parameters["damping"]); } EditorUtility.SetDirty(vcam); return $"Collider Extension added to '{parameters["camera"]}'"; } catch (Exception e) { return $"Error: Failed to add Collider Extension - {e.Message}"; } #elif CINEMACHINE_3 try { if (!parameters.ContainsKey("camera")) { return "Error: 'camera' parameter is required"; } var vcamObj = GameObject.Find(parameters["camera"]); if (vcamObj == null) { return $"Error: Virtual Camera '{parameters["camera"]}' not found"; } var vcam = vcamObj.GetComponent(); if (vcam == null) { return $"Error: '{parameters["camera"]}' is not a Cinemachine Camera"; } // Add Deoccluder extension (CM3 equivalent of Collider) var deoccluder = vcam.gameObject.AddComponent(); if (parameters.ContainsKey("minimumDistanceFromTarget")) { deoccluder.MinimumDistanceFromTarget = float.Parse(parameters["minimumDistanceFromTarget"]); } if (parameters.ContainsKey("smoothingTime")) { // CM3: Damping is now inside AvoidObstacles struct var avoidObstacles = deoccluder.AvoidObstacles; avoidObstacles.Damping = float.Parse(parameters["smoothingTime"]); deoccluder.AvoidObstacles = avoidObstacles; } EditorUtility.SetDirty(vcam); return $"Deoccluder Extension (CM3 Collider) added to '{parameters["camera"]}'"; } catch (Exception e) { return $"Error: Failed to add Collider Extension - {e.Message}"; } #else return "Error: Cinemachine package not installed. Please install via Package Manager."; #endif } /// /// Add Confiner Extension to Virtual Camera /// public static string AddConfinerExtension(Dictionary parameters) { #if CINEMACHINE_2 try { if (!parameters.ContainsKey("camera")) { return "Error: 'camera' parameter is required"; } var vcamObj = GameObject.Find(parameters["camera"]); if (vcamObj == null) { return $"Error: Virtual Camera '{parameters["camera"]}' not found"; } var vcam = vcamObj.GetComponent(); if (vcam == null) { return $"Error: '{parameters["camera"]}' is not a Virtual Camera"; } // Add Confiner Extension var confiner = vcam.gameObject.AddComponent(); // Bounding Volume settings if (parameters.ContainsKey("boundingVolume")) { var volumeObj = GameObject.Find(parameters["boundingVolume"]); if (volumeObj != null) { var collider = volumeObj.GetComponent(); if (collider != null) { confiner.m_BoundingVolume = collider; } } } // Confine Mode settings if (parameters.ContainsKey("confineMode")) { string mode = parameters["confineMode"]; confiner.m_ConfineMode = mode == "Confine3D" ? CinemachineConfiner.Mode.Confine3D : CinemachineConfiner.Mode.Confine2D; } // Damping settings if (parameters.ContainsKey("damping")) { confiner.m_Damping = float.Parse(parameters["damping"]); } EditorUtility.SetDirty(vcam); return $"Confiner Extension added to '{parameters["camera"]}'"; } catch (Exception e) { return $"Error: Failed to add Confiner Extension - {e.Message}"; } #elif CINEMACHINE_3 try { if (!parameters.ContainsKey("camera")) { return "Error: 'camera' parameter is required"; } var vcamObj = GameObject.Find(parameters["camera"]); if (vcamObj == null) { return $"Error: Virtual Camera '{parameters["camera"]}' not found"; } var vcam = vcamObj.GetComponent(); if (vcam == null) { return $"Error: '{parameters["camera"]}' is not a Cinemachine Camera"; } // Add Confiner3D extension (CM3 version) var confiner = vcam.gameObject.AddComponent(); if (parameters.ContainsKey("boundingVolume")) { var volumeObj = GameObject.Find(parameters["boundingVolume"]); if (volumeObj != null) { var collider = volumeObj.GetComponent(); if (collider != null) { confiner.BoundingVolume = collider; } } } EditorUtility.SetDirty(vcam); return $"Confiner3D Extension added to '{parameters["camera"]}'"; } catch (Exception e) { return $"Error: Failed to add Confiner Extension - {e.Message}"; } #else return "Error: Cinemachine package not installed. Please install via Package Manager."; #endif } /// /// Create Dolly Track /// public static string CreateDollyTrack(Dictionary parameters) { #if CINEMACHINE_2 try { string name = parameters.ContainsKey("name") ? parameters["name"] : "DollyTrack"; // Create Path object GameObject pathObj = new GameObject(name); var path = pathObj.AddComponent(); // Waypoints settings if (parameters.ContainsKey("waypoints")) { var waypointsJson = parameters["waypoints"]; var waypoints = Newtonsoft.Json.JsonConvert.DeserializeObject>>(waypointsJson); path.m_Waypoints = new CinemachineSmoothPath.Waypoint[waypoints.Count]; for (int i = 0; i < waypoints.Count; i++) { var wp = waypoints[i]; path.m_Waypoints[i] = new CinemachineSmoothPath.Waypoint { position = new Vector3(wp["x"], wp["y"], wp["z"]) }; } } // Loop settings if (parameters.ContainsKey("looped")) { path.m_Looped = bool.Parse(parameters["looped"]); } // Connect to Virtual Camera if (parameters.ContainsKey("cameraName")) { var vcamObj = GameObject.Find(parameters["cameraName"]); if (vcamObj != null) { var vcam = vcamObj.GetComponent(); if (vcam != null) { var dolly = vcam.AddCinemachineComponent(); dolly.m_Path = path; } } } Undo.RegisterCreatedObjectUndo(pathObj, "Create Dolly Track"); Selection.activeGameObject = pathObj; return $"Dolly Track '{name}' created with {path.m_Waypoints.Length} waypoints"; } catch (Exception e) { return $"Error: Failed to create Dolly Track - {e.Message}"; } #elif CINEMACHINE_3 try { string name = parameters.ContainsKey("name") ? parameters["name"] : "DollyTrack"; // In CM3, use Unity Splines instead of CinemachineSmoothPath GameObject pathObj = new GameObject(name); var splineContainer = pathObj.AddComponent(); // Basic spline setup (CM3 uses Unity's Spline system) // Note: Full waypoint configuration requires Unity Splines API if (parameters.ContainsKey("looped") && bool.Parse(parameters["looped"])) { splineContainer.Spline.Closed = true; } // Connect to Virtual Camera (if specified) if (parameters.ContainsKey("cameraName")) { var vcamObj = GameObject.Find(parameters["cameraName"]); if (vcamObj != null) { var vcam = vcamObj.GetComponent(); if (vcam != null) { // Add SplineCart or SplineDolly component var splineDolly = vcam.gameObject.AddComponent(); splineDolly.Spline = splineContainer; } } } Undo.RegisterCreatedObjectUndo(pathObj, "Create Dolly Track"); Selection.activeGameObject = pathObj; return $"Dolly Track '{name}' created (CM3 uses Unity Splines - configure waypoints in Inspector)"; } catch (Exception e) { return $"Error: Failed to create Dolly Track - {e.Message}"; } #else return "Error: Cinemachine package not installed. Please install via Package Manager."; #endif } // Helper methods private static Vector3 ParseVector3(string vectorString) { var parts = vectorString.Split(','); return new Vector3( float.Parse(parts[0]), float.Parse(parts[1]), float.Parse(parts[2]) ); } #if CINEMACHINE_2 /// /// Add Body component /// private static void AddBodyComponent(CinemachineVirtualCamera vcam, string bodyType, Dictionary parameters) { switch (bodyType) { case "Transposer": var transposer = vcam.AddCinemachineComponent(); if (parameters.ContainsKey("damping")) { var damping = ParseVector3(parameters["damping"]); transposer.m_XDamping = damping.x; transposer.m_YDamping = damping.y; transposer.m_ZDamping = damping.z; } if (parameters.ContainsKey("offset")) { transposer.m_FollowOffset = ParseVector3(parameters["offset"]); } break; case "FramingTransposer": var framingTransposer = vcam.AddCinemachineComponent(); if (parameters.ContainsKey("damping")) { var damping = ParseVector3(parameters["damping"]); framingTransposer.m_XDamping = damping.x; framingTransposer.m_YDamping = damping.y; framingTransposer.m_ZDamping = damping.z; } if (parameters.ContainsKey("screenX")) framingTransposer.m_ScreenX = float.Parse(parameters["screenX"]); if (parameters.ContainsKey("screenY")) framingTransposer.m_ScreenY = float.Parse(parameters["screenY"]); break; case "OrbitalTransposer": var orbital = vcam.AddCinemachineComponent(); if (parameters.ContainsKey("offset")) { orbital.m_FollowOffset = ParseVector3(parameters["offset"]); } break; case "HardLockToTarget": vcam.AddCinemachineComponent(); break; case "DoNothing": // No Body component break; default: // Default is Transposer vcam.AddCinemachineComponent(); break; } } /// /// Add Aim component /// private static void AddAimComponent(CinemachineVirtualCamera vcam, string aimType, Dictionary parameters) { switch (aimType) { case "Composer": var composer = vcam.AddCinemachineComponent(); if (parameters.ContainsKey("screenX")) composer.m_ScreenX = float.Parse(parameters["screenX"]); if (parameters.ContainsKey("screenY")) composer.m_ScreenY = float.Parse(parameters["screenY"]); if (parameters.ContainsKey("deadZoneWidth")) composer.m_DeadZoneWidth = float.Parse(parameters["deadZoneWidth"]); if (parameters.ContainsKey("deadZoneHeight")) composer.m_DeadZoneHeight = float.Parse(parameters["deadZoneHeight"]); break; case "GroupComposer": var groupComposer = vcam.AddCinemachineComponent(); if (parameters.ContainsKey("screenX")) groupComposer.m_ScreenX = float.Parse(parameters["screenX"]); if (parameters.ContainsKey("screenY")) groupComposer.m_ScreenY = float.Parse(parameters["screenY"]); break; case "POV": var pov = vcam.AddCinemachineComponent(); if (parameters.ContainsKey("horizontalAxis")) { pov.m_HorizontalAxis.m_MaxSpeed = float.Parse(parameters["horizontalAxis"]); } if (parameters.ContainsKey("verticalAxis")) { pov.m_VerticalAxis.m_MaxSpeed = float.Parse(parameters["verticalAxis"]); } break; case "SameAsFollowTarget": vcam.AddCinemachineComponent(); break; case "HardLookAt": vcam.AddCinemachineComponent(); break; case "DoNothing": // No Aim component break; default: // Default is Composer vcam.AddCinemachineComponent(); break; } } /// /// Add Noise component (camera shake) /// private static void AddNoiseComponent(CinemachineVirtualCamera vcam, Dictionary parameters) { var noise = vcam.AddCinemachineComponent(); // Profile settings (preset) if (parameters.ContainsKey("noiseProfile")) { string profileName = parameters["noiseProfile"]; NoiseSettings profile = GetNoiseProfile(profileName); if (profile != null) { noise.m_NoiseProfile = profile; } } // Amplitude settings if (parameters.ContainsKey("noiseAmplitude")) { noise.m_AmplitudeGain = float.Parse(parameters["noiseAmplitude"]); } // Frequency settings if (parameters.ContainsKey("noiseFrequency")) { noise.m_FrequencyGain = float.Parse(parameters["noiseFrequency"]); } } /// /// Get Noise profile /// private static NoiseSettings GetNoiseProfile(string profileName) { // Search for built-in profiles string[] guids = AssetDatabase.FindAssets("t:NoiseSettings"); foreach (string guid in guids) { string path = AssetDatabase.GUIDToAssetPath(guid); if (path.Contains(profileName) || System.IO.Path.GetFileNameWithoutExtension(path) == profileName) { return AssetDatabase.LoadAssetAtPath(path); } } // Default if not found (6D Shake) foreach (string guid in guids) { string path = AssetDatabase.GUIDToAssetPath(guid); if (path.Contains("6D Shake")) { return AssetDatabase.LoadAssetAtPath(path); } } return null; } private static CinemachineBlendDefinition.Style ParseBlendStyle(string style) { switch (style) { case "Cut": return CinemachineBlendDefinition.Style.Cut; case "EaseInOut": return CinemachineBlendDefinition.Style.EaseInOut; case "EaseIn": return CinemachineBlendDefinition.Style.EaseIn; case "EaseOut": return CinemachineBlendDefinition.Style.EaseOut; case "HardIn": return CinemachineBlendDefinition.Style.HardIn; case "HardOut": return CinemachineBlendDefinition.Style.HardOut; case "Linear": return CinemachineBlendDefinition.Style.Linear; default: return CinemachineBlendDefinition.Style.EaseInOut; } } private static CinemachineBrain.UpdateMethod ParseUpdateMethod(string method) { switch (method) { case "FixedUpdate": return CinemachineBrain.UpdateMethod.FixedUpdate; case "LateUpdate": return CinemachineBrain.UpdateMethod.LateUpdate; case "SmartUpdate": return CinemachineBrain.UpdateMethod.SmartUpdate; default: return CinemachineBrain.UpdateMethod.SmartUpdate; } } private static CinemachineTargetGroup.PositionMode ParseTargetGroupPositionMode(string mode) { switch (mode) { case "GroupCenter": return CinemachineTargetGroup.PositionMode.GroupCenter; case "GroupAverage": return CinemachineTargetGroup.PositionMode.GroupAverage; default: return CinemachineTargetGroup.PositionMode.GroupCenter; } } private static CinemachineTargetGroup.RotationMode ParseTargetGroupRotationMode(string mode) { switch (mode) { case "Manual": return CinemachineTargetGroup.RotationMode.Manual; case "GroupAverage": return CinemachineTargetGroup.RotationMode.GroupAverage; default: return CinemachineTargetGroup.RotationMode.Manual; } } private static CinemachineTargetGroup.UpdateMethod ParseTargetGroupUpdateMethod(string method) { switch (method) { case "Update": return CinemachineTargetGroup.UpdateMethod.Update; case "FixedUpdate": return CinemachineTargetGroup.UpdateMethod.FixedUpdate; case "LateUpdate": return CinemachineTargetGroup.UpdateMethod.LateUpdate; default: return CinemachineTargetGroup.UpdateMethod.Update; } } #elif CINEMACHINE_3 // Cinemachine 3.x Helper Methods /// /// Add Body component for Cinemachine 3.x /// private static void AddBodyComponent3(CinemachineCamera vcam, string bodyType, Dictionary parameters) { switch (bodyType) { case "Follow": case "Transposer": var follow = vcam.gameObject.AddComponent(); if (parameters.ContainsKey("damping")) { var damping = ParseVector3(parameters["damping"]); // CM3: Damping moved to TrackerSettings.PositionDamping var trackerSettings = follow.TrackerSettings; trackerSettings.PositionDamping = damping; follow.TrackerSettings = trackerSettings; } if (parameters.ContainsKey("offset")) { follow.FollowOffset = ParseVector3(parameters["offset"]); } break; case "PositionComposer": case "FramingTransposer": var positionComposer = vcam.gameObject.AddComponent(); if (parameters.ContainsKey("damping")) { var damping = ParseVector3(parameters["damping"]); positionComposer.Damping = damping; } if (parameters.ContainsKey("screenX") || parameters.ContainsKey("screenY")) { var composition = positionComposer.Composition; var screenPos = composition.ScreenPosition; if (parameters.ContainsKey("screenX")) screenPos.x = float.Parse(parameters["screenX"]); if (parameters.ContainsKey("screenY")) screenPos.y = float.Parse(parameters["screenY"]); composition.ScreenPosition = screenPos; positionComposer.Composition = composition; } break; case "OrbitalFollow": case "OrbitalTransposer": var orbital = vcam.gameObject.AddComponent(); if (parameters.ContainsKey("offset")) { orbital.TargetOffset = ParseVector3(parameters["offset"]); } break; case "HardLockToTarget": // In CM3, this is built into CinemachineCamera's tracking // No separate component needed break; case "DoNothing": // No Body component break; default: // Default is Follow vcam.gameObject.AddComponent(); break; } } /// /// Add Aim component for Cinemachine 3.x /// private static void AddAimComponent3(CinemachineCamera vcam, string aimType, Dictionary parameters) { switch (aimType) { case "Composer": case "RotationComposer": var composer = vcam.gameObject.AddComponent(); if (parameters.ContainsKey("screenX") || parameters.ContainsKey("screenY") || parameters.ContainsKey("deadZoneWidth") || parameters.ContainsKey("deadZoneHeight")) { var composition = composer.Composition; if (parameters.ContainsKey("screenX") || parameters.ContainsKey("screenY")) { var screenPos = composition.ScreenPosition; if (parameters.ContainsKey("screenX")) screenPos.x = float.Parse(parameters["screenX"]); if (parameters.ContainsKey("screenY")) screenPos.y = float.Parse(parameters["screenY"]); composition.ScreenPosition = screenPos; } if (parameters.ContainsKey("deadZoneWidth") || parameters.ContainsKey("deadZoneHeight")) { var deadZone = composition.DeadZone; Vector2 size = deadZone.Size; if (parameters.ContainsKey("deadZoneWidth")) size.x = float.Parse(parameters["deadZoneWidth"]); if (parameters.ContainsKey("deadZoneHeight")) size.y = float.Parse(parameters["deadZoneHeight"]); deadZone.Size = size; composition.DeadZone = deadZone; } composer.Composition = composition; } break; case "GroupComposer": // In CM3, use RotationComposer with target group var groupComposer = vcam.gameObject.AddComponent(); if (parameters.ContainsKey("screenX") || parameters.ContainsKey("screenY")) { var composition = groupComposer.Composition; var screenPos = composition.ScreenPosition; if (parameters.ContainsKey("screenX")) screenPos.x = float.Parse(parameters["screenX"]); if (parameters.ContainsKey("screenY")) screenPos.y = float.Parse(parameters["screenY"]); composition.ScreenPosition = screenPos; groupComposer.Composition = composition; } break; case "POV": // POV in CM3 uses InputAxisController var inputAxis = vcam.gameObject.AddComponent(); // Note: CM3's InputAxisController configuration is primarily done via Inspector // Dynamic MaxSpeed modification is not supported in the same way as CM2 if (parameters.ContainsKey("horizontalAxis") || parameters.ContainsKey("verticalAxis")) { SynLog.Warn("[Synaptic] CM3: POV axis speed configuration not supported via script. Configure in Inspector."); } break; case "SameAsFollowTarget": // Built into CM3 tracking break; case "HardLookAt": // Built into CM3 LookAt target break; case "DoNothing": // No Aim component break; default: // Default is RotationComposer vcam.gameObject.AddComponent(); break; } } /// /// Add Noise component for Cinemachine 3.x (camera shake) /// private static void AddNoiseComponent3(CinemachineCamera vcam, Dictionary parameters) { var noise = vcam.gameObject.AddComponent(); // Profile settings (preset) if (parameters.ContainsKey("noiseProfile")) { string profileName = parameters["noiseProfile"]; NoiseSettings profile = GetNoiseProfile(parameters["noiseProfile"]); if (profile != null) { noise.NoiseProfile = profile; } } // Amplitude settings (no m_ prefix in CM3) if (parameters.ContainsKey("noiseAmplitude")) { noise.AmplitudeGain = float.Parse(parameters["noiseAmplitude"]); } // Frequency settings if (parameters.ContainsKey("noiseFrequency")) { noise.FrequencyGain = float.Parse(parameters["noiseFrequency"]); } } /// /// Get Noise profile (CM3) /// private static NoiseSettings GetNoiseProfile(string profileName) { // Search for built-in profiles string[] guids = AssetDatabase.FindAssets("t:NoiseSettings"); foreach (string guid in guids) { string path = AssetDatabase.GUIDToAssetPath(guid); if (path.Contains(profileName) || System.IO.Path.GetFileNameWithoutExtension(path) == profileName) { return AssetDatabase.LoadAssetAtPath(path); } } // Default if not found (6D Shake) foreach (string guid in guids) { string path = AssetDatabase.GUIDToAssetPath(guid); if (path.Contains("6D Shake")) { return AssetDatabase.LoadAssetAtPath(path); } } return null; } private static CinemachineBlendDefinition.Styles ParseBlendStyle3(string style) { switch (style) { case "Cut": return CinemachineBlendDefinition.Styles.Cut; case "EaseInOut": return CinemachineBlendDefinition.Styles.EaseInOut; case "EaseIn": return CinemachineBlendDefinition.Styles.EaseIn; case "EaseOut": return CinemachineBlendDefinition.Styles.EaseOut; case "HardIn": return CinemachineBlendDefinition.Styles.HardIn; case "HardOut": return CinemachineBlendDefinition.Styles.HardOut; case "Linear": return CinemachineBlendDefinition.Styles.Linear; default: return CinemachineBlendDefinition.Styles.EaseInOut; } } private static CinemachineBrain.UpdateMethods ParseUpdateMethod3(string method) { switch (method) { case "FixedUpdate": return CinemachineBrain.UpdateMethods.FixedUpdate; case "LateUpdate": return CinemachineBrain.UpdateMethods.LateUpdate; case "SmartUpdate": return CinemachineBrain.UpdateMethods.SmartUpdate; default: return CinemachineBrain.UpdateMethods.SmartUpdate; } } private static CinemachineTargetGroup.PositionModes ParseTargetGroupPositionMode3(string mode) { switch (mode) { case "GroupCenter": return CinemachineTargetGroup.PositionModes.GroupCenter; case "GroupAverage": return CinemachineTargetGroup.PositionModes.GroupAverage; default: return CinemachineTargetGroup.PositionModes.GroupCenter; } } private static CinemachineTargetGroup.RotationModes ParseTargetGroupRotationMode3(string mode) { switch (mode) { case "Manual": return CinemachineTargetGroup.RotationModes.Manual; case "GroupAverage": return CinemachineTargetGroup.RotationModes.GroupAverage; default: return CinemachineTargetGroup.RotationModes.Manual; } } private static CinemachineTargetGroup.UpdateMethods ParseTargetGroupUpdateMethod3(string method) { switch (method) { case "Update": return CinemachineTargetGroup.UpdateMethods.Update; case "FixedUpdate": return CinemachineTargetGroup.UpdateMethods.FixedUpdate; case "LateUpdate": return CinemachineTargetGroup.UpdateMethods.LateUpdate; default: return CinemachineTargetGroup.UpdateMethods.Update; } } #endif } }