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
}
}