diff --git a/Documentation/MemoriadeEvolucion.md b/Documentation/MemoriadeEvolucion.md
index 332f9f4..cff4b9f 100644
--- a/Documentation/MemoriadeEvolucion.md
+++ b/Documentation/MemoriadeEvolucion.md
@@ -30,3 +30,7 @@ simTransporte : Es un box por donde las botellas pueden desplazarse usando un tr
* Se ha mejorado el sistema de guías curvas (`ucTransporteCurvaGuias`) para incluir apertura en cono en los extremos de entrada y salida. Se agregó el parámetro `AnguloAperturaGuias` (por defecto 5 grados) que permite configurar la apertura modificando los radios de las guías en los puntos extremos. En lugar de cambiar ángulos, se reduce el radio de la guía superior (externa) y se aumenta el radio de la guía inferior (interna) en los segmentos inicial y final, creando naturalmente la apertura en cono. La modificación del radio se calcula usando `Math.Sin(anguloApertura)` para obtener el desplazamiento apropiado. Esta apertura facilita la entrada y salida de botellas del transporte curvo, reduciendo atascos y mejorando el flujo de materiales manteniendo la continuidad geométrica de las guías.
+* Se ha implementado un sistema de fricción dinámica que simula el comportamiento de fricción estática vs dinámica para contactos botella-transporte y botella-curva. El sistema calcula el deslizamiento relativo entre la botella y la superficie del transporte: cuando el deslizamiento es bajo (< 0.05 m/s), se aplica fricción estática alta para un arrastre efectivo; cuando el deslizamiento es alto, se aplica fricción dinámica menor para permitir un deslizamiento suave. Para curvas, se calcula la velocidad de superficie usando el producto vectorial (v = ω × r). Para contactos botella-botella, se usa detección de profundidad de penetración para aplicar materiales ultra-suaves cuando hay alta presión, previniendo acumulaciones explosivas. Este enfoque proactivo reemplaza el sistema reactivo de `PressureBuildup` y proporciona un comportamiento más físicamente realista y estable en acumulaciones de botellas.
+
+* Se ha reemplazado el sistema `ProcessPressureSystem` por un nuevo sistema de calibración visual `HighSlippery` que permite ajustar las fricciones de cada componente. Cada botella tiene una propiedad `HighSlippery` (rango 0-9) con sistema de heatup/cooldown que se incrementa durante deslizamiento y se decrementa durante adherencia. El valor se muestra como número en el centro de cada botella para calibración visual. Los `SpringSettings` se mantienen >= 30 para evitar compresiones irreales. El sistema permite calibrar las tasas de heatup/cooldown específicas para transportes (0.2/0.1) y curvas (0.15/0.08), y el umbral de cambio estático/dinámico (HighSlippery > 3). Este sistema elimina el problema del cooldown que reactivaba prematuramente la fricción estática.
+
diff --git a/ObjetosSim/Dinamicos/ucBotella.xaml b/ObjetosSim/Dinamicos/ucBotella.xaml
index cd4b32c..d854a5c 100644
--- a/ObjetosSim/Dinamicos/ucBotella.xaml
+++ b/ObjetosSim/Dinamicos/ucBotella.xaml
@@ -5,8 +5,21 @@
-
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ObjetosSim/Dinamicos/ucBotella.xaml.cs b/ObjetosSim/Dinamicos/ucBotella.xaml.cs
index 1b65d0e..d52649b 100644
--- a/ObjetosSim/Dinamicos/ucBotella.xaml.cs
+++ b/ObjetosSim/Dinamicos/ucBotella.xaml.cs
@@ -93,6 +93,12 @@ namespace CtrEditor.ObjetosSim
[property: Name("En Transporte con Freno")]
private bool enTransporteConFreno;
+ [ObservableProperty]
+ [property: Category("Calibración")]
+ [property: Description("Nivel de deslizamiento/presión (0-9) para calibración de fricción")]
+ [property: Name("Nivel de Deslizamiento")]
+ private float nivelDeslizamiento;
+
[ObservableProperty]
[property: Category("Simulación")]
[property: Description("Masa del objeto en kg")]
@@ -174,7 +180,7 @@ namespace CtrEditor.ObjetosSim
// Sistema de colores jerarquizado para diferentes estados
if (SimGeometria.isOnBrakeTransport)
ColorButton_oculto = Brushes.Blue; // En transporte con freno (prioridad sobre presión)
- else if (!SimGeometria.isOnBrakeTransport && SimGeometria.PressureBuildup>1)
+ else if (!SimGeometria.isOnBrakeTransport && SimGeometria.ContactPressure > 0)
ColorButton_oculto = Brushes.Red; // La botella tiene mucha presion
else
ColorButton_oculto = Brushes.Gray; // 5. Estado libre
@@ -189,6 +195,7 @@ namespace CtrEditor.ObjetosSim
Inercia_desde_simulacion = SimGeometria.Mass; // En BEPU usamos masa en lugar de inercia directa
Porcentaje_Traccion = SimGeometria.OverlapPercentage;
EnTransporteConFreno = SimGeometria.isOnBrakeTransport; // Actualizar estado de freno
+ NivelDeslizamiento = SimGeometria.HighSlippery; // ✅ NUEVO: Mostrar nivel de deslizamiento para calibración
}
public override void ucLoaded()
diff --git a/Simulacion/BEPU.cs b/Simulacion/BEPU.cs
index bd92aa6..ce07f6e 100644
--- a/Simulacion/BEPU.cs
+++ b/Simulacion/BEPU.cs
@@ -124,9 +124,6 @@ namespace CtrEditor.Simulacion
// ✅ CONTACTO BOTELLA-TRANSPORTE: USAR FRICCIÓN Y VELOCIDAD CINEMÁTICA
if (botella != null && (transportA != null || transportB != null))
{
- // La velocidad del cuerpo cinemático del transporte se establece directamente
- // en la clase simTransporte. El motor de físicas se encarga del resto.
-
// ✅ NUEVO: Lógica de control de presión/flotación
botella.IsTouchingTransport = true;
var botellaCollidable = GetBotellaFromCollidable(pair.A) != null ? pair.A : pair.B;
@@ -135,16 +132,11 @@ namespace CtrEditor.Simulacion
var body = _simulationManager.simulation.Bodies.GetBodyReference(botellaCollidable.BodyHandle);
botella.LastTransportCollisionZ = body.Pose.Position.Z;
}
- // Decrementamos la presión acumulada al tocar un transporte. Se reduce más rápido de lo que aumenta.
- botella.PressureBuildup = Math.Max(0, botella.PressureBuildup - 0.1f);
- // ✅ Fricción ajustada para un arrastre firme pero no excesivo.
var transport = transportA ?? transportB;
if (transport.isBrake)
{
- botella.PressureBuildup = 0;
// ✅ NUEVO: Centrar la botella en el transporte de frenado la primera vez que entra.
- // if (!botella.isOnBrakeTransport)
{
if (botella.BodyHandle.Value >= 0 && _simulationManager.simulation.Bodies.BodyExists(botella.BodyHandle) &&
transport.BodyHandle.Value >= 0 && _simulationManager.simulation.Bodies.BodyExists(transport.BodyHandle))
@@ -172,35 +164,23 @@ namespace CtrEditor.Simulacion
}
botella.isOnBrakeTransport = true;
- pairMaterial.FrictionCoefficient = 14f;
- pairMaterial.MaximumRecoveryVelocity = 1.0f;
- pairMaterial.SpringSettings = new SpringSettings(80, 8);
+ pairMaterial.FrictionCoefficient = 4f;
+ pairMaterial.MaximumRecoveryVelocity = 0f;
+ pairMaterial.SpringSettings = new SpringSettings(120, 8f);
}
else
{
- if (botella.PressureBuildup > minPressureToLostFriction)
- {
- botella.isOnBrakeTransport = false;
- pairMaterial.FrictionCoefficient = 0.1f;
- pairMaterial.MaximumRecoveryVelocity = 1.0f;
- pairMaterial.SpringSettings = new SpringSettings(80, 1);
- }
- else
- {
- botella.isOnBrakeTransport = false;
- pairMaterial.FrictionCoefficient = 1.2f;
- pairMaterial.MaximumRecoveryVelocity = 1.0f;
- pairMaterial.SpringSettings = new SpringSettings(80, 1);
- }
+ botella.isOnBrakeTransport = false;
+ // ✅ NUEVO: Usar fricción dinámica basada en deslizamiento
+ pairMaterial.FrictionCoefficient = CalculateTransportFriction(botella, transport, botellaCollidable);
+ pairMaterial.MaximumRecoveryVelocity = 0.1f;
+ pairMaterial.SpringSettings = new SpringSettings(80, 1f);
}
}
// ✅ CONTACTO BOTELLA-CURVA: USAR FRICCIÓN Y VELOCIDAD CINEMÁTICA
else if (botella != null && (curveA != null || curveB != null))
{
- // El motor de físicas usará la velocidad angular del cuerpo cinemático de la curva
- // para calcular las fuerzas de fricción y arrastrar la botella.
-
// ✅ NUEVO: Lógica de control de presión/flotación
botella.IsTouchingTransport = true;
botella.isOnBrakeTransport = false;
@@ -210,59 +190,38 @@ namespace CtrEditor.Simulacion
var body = _simulationManager.simulation.Bodies.GetBodyReference(botellaCollidable.BodyHandle);
botella.LastTransportCollisionZ = body.Pose.Position.Z;
}
- // Decrementamos la presión acumulada al tocar una curva.
- botella.PressureBuildup = Math.Max(0, botella.PressureBuildup - 0.1f);
- // ✅ Fricción ajustada para un arrastre firme pero no excesivo.
- if (botella.PressureBuildup > minPressureToLostFriction)
- {
- pairMaterial.FrictionCoefficient = 0.1f;
- pairMaterial.MaximumRecoveryVelocity = 1.0f;
- pairMaterial.SpringSettings = new SpringSettings(80, 1);
- }else
- {
- pairMaterial.FrictionCoefficient = 1f;
- pairMaterial.MaximumRecoveryVelocity = 1.0f;
- pairMaterial.SpringSettings = new SpringSettings(80, 1);
- }
+ // ✅ NUEVO: Usar fricción dinámica basada en deslizamiento
+ var curve = curveA ?? curveB;
+ pairMaterial.FrictionCoefficient = CalculateCurveFriction(botella, curve, botellaCollidable);
+ pairMaterial.MaximumRecoveryVelocity = 0.1f;
+ pairMaterial.SpringSettings = new SpringSettings(80, 1f); // Colision con la cinta por gravedad
}
// ✅ CONTACTO BOTELLA-GUÍA: Configuración específica de fricción
else if (botella != null && (GetGuiaFromCollidable(pair.A) != null || GetGuiaFromCollidable(pair.B) != null))
{
// Fricción baja para las guías, deben deslizar, no arrastrar.
- pairMaterial.FrictionCoefficient = 0.01f;
- pairMaterial.MaximumRecoveryVelocity = 2f;
- pairMaterial.SpringSettings = new SpringSettings(20, 1);
+ pairMaterial.FrictionCoefficient = 0.1f;
+ pairMaterial.MaximumRecoveryVelocity = 0.8f;
+ pairMaterial.SpringSettings = new SpringSettings(50, 1f); // Rebote lateral moderado
}
- // ✅ NUEVO: CONTACTO BOTELLA-BOTELLA: Configuración más suave para evitar el comportamiento "pegajoso".
+ // ✅ NUEVO: CONTACTO BOTELLA-BOTELLA: Lógica de presión proactiva basada en la penetración.
else if (botellaA != null && botellaB != null)
{
- if (botella.isOnBrakeTransport)
- {
- pairMaterial.FrictionCoefficient = 2.0f; // Un poco menos de fricción.
- pairMaterial.MaximumRecoveryVelocity = 1.5f; // Menos rebote.
- pairMaterial.SpringSettings = new SpringSettings(80, 1f); // Muelle MUCHO más suave y críticamente amortiguado.
- }
- else
- {
- pairMaterial.FrictionCoefficient = 0.01f; // Un poco menos de fricción.
- pairMaterial.MaximumRecoveryVelocity = 1.5f; // Menos rebote.
- pairMaterial.SpringSettings = new SpringSettings(20, 0.5f); // Muelle MUCHO más suave y críticamente amortiguado.
- }
- // Si una botella tiene presion esta presion es transmitia a el resto para que el resto pierda el coeficiente de friccion sobre los transportes
- if (botellaA.PressureBuildup > 0 && botellaB.PressureBuildup == 0)
- botellaB.PressureBuildup = botellaA.PressureBuildup;
- if (botellaB.PressureBuildup > 0 && botellaA.PressureBuildup == 0)
- botellaA.PressureBuildup = botellaB.PressureBuildup;
-
+ // ✅ NUEVO: Usar método especializado para contactos botella-botella
+ CalculateBottlePression(ref manifold, botellaA, botellaB);
+ pairMaterial.FrictionCoefficient = 0.1f;
+ pairMaterial.MaximumRecoveryVelocity = 0.03f;
+ pairMaterial.SpringSettings = new SpringSettings(80, 1f); // Rebote lateral moderado
}
// Ajustes básicos para otras botellas
else if (botella != null)
{
+ System.Diagnostics.Debug.WriteLine($"[ConfigureContactManifold] ERROR: contacto no resuelto!");
// Fricción moderada para colisiones entre botellas.
pairMaterial.FrictionCoefficient = 0.3f;
pairMaterial.MaximumRecoveryVelocity = 1f;
- pairMaterial.SpringSettings = new SpringSettings(80, 1);
+ pairMaterial.SpringSettings = new SpringSettings(30, 1);
}
}
@@ -348,11 +307,139 @@ namespace CtrEditor.Simulacion
- ///
- /// ✅ NUEVO MÉTODO: Aplicar fuerzas de frenado directamente en el manifold
- ///
+ ///
+ /// ✅ NUEVO: Calcula la fricción dinámica para contactos botella-transporte basada en el deslizamiento relativo
+ ///
+ private float CalculateTransportFriction(simBotella botella, simTransporte transport, CollidableReference botellaCollidable)
+ {
+ try
+ {
+ if (botella?.BodyHandle.Value >= 0 && _simulationManager.simulation.Bodies.BodyExists(botella.BodyHandle) &&
+ transport?.BodyHandle.Value >= 0 && _simulationManager.simulation.Bodies.BodyExists(transport.BodyHandle))
+ {
+ var bottleBody = _simulationManager.simulation.Bodies.GetBodyReference(botella.BodyHandle);
+ var transportBody = _simulationManager.simulation.Bodies.GetBodyReference(transport.BodyHandle);
+
+ var bottleVelocity = bottleBody.Velocity.Linear;
+ var transportVelocity = transport.CalcularVelocidadCinematica(); // La velocidad cinemática se actualiza en OnSubstepStarted
+
+ var slipVelocity = bottleVelocity - transportVelocity;
+ slipVelocity.Z = 0; // Ignoramos el deslizamiento vertical
+ var slipSpeed = slipVelocity.Length();
+
+ float slipSpeedThreshold = transportVelocity.Length()*0.85f; // m/s - umbral para cambiar de fricción estática a dinámica
+ const float heatupRate = 1f; // Qué tan rápido sube HighSlippery
+ const float cooldownRate = 0.5f; // Qué tan rápido baja HighSlippery
+ const float staticFriction = 0.25f;
+ const float dynamicFriction = 0.10f;
+
+ // Sistema de heatup/cooldown para HighSlippery
+ if (slipSpeed > slipSpeedThreshold) // && botella.ContactPressure > 0
+ botella.HighSlippery = Math.Min(9f, botella.HighSlippery + heatupRate);
+ else
+ botella.HighSlippery = Math.Max(0f, botella.HighSlippery - cooldownRate);
+
+ // Calcular fricción basada en HighSlippery
+ // HighSlippery > 3 = fricción dinámica, <= 3 = fricción estática
+ if (botella.HighSlippery > 3f)
+ return dynamicFriction;
+ else
+ return staticFriction;
+ }
+ }
+ catch (Exception ex)
+ {
+ System.Diagnostics.Debug.WriteLine($"[CalculateTransportFriction] Error: {ex.Message}");
+ }
+
+ // Valor por defecto si hay algún error
+ return 1.0f;
+ }
+
+ ///
+ /// ✅ NUEVO: Calcula la fricción dinámica para contactos botella-curva basada en el deslizamiento relativo
+ ///
+ private float CalculateCurveFriction(simBotella botella, simCurve curve, CollidableReference botellaCollidable)
+ {
+ try
+ {
+ if (botella?.BodyHandle.Value >= 0 && _simulationManager.simulation.Bodies.BodyExists(botella.BodyHandle) &&
+ curve?.BodyHandle.Value >= 0 && _simulationManager.simulation.Bodies.BodyExists(curve.BodyHandle))
+ {
+ var bottleBody = _simulationManager.simulation.Bodies.GetBodyReference(botella.BodyHandle);
+ var curveBody = _simulationManager.simulation.Bodies.GetBodyReference(curve.BodyHandle);
+
+ // Aproximamos la velocidad de la superficie de la curva en la posición de la botella.
+ // v = ω x r
+ var r = bottleBody.Pose.Position - curveBody.Pose.Position;
+ var curveVelocityAtPoint = Vector3.Cross(curve.CalcularVelocidadCinematica(), r);
+
+ var slipVelocity = bottleBody.Velocity.Linear - curveVelocityAtPoint;
+ slipVelocity.Z = 0; // Ignoramos el deslizamiento vertical
+ var slipSpeed = slipVelocity.Length();
+
+ float slipSpeedThreshold = curveVelocityAtPoint.Length() * 0.85f; // m/s
+ const float heatupRate = 1f; // Qué tan rápido sube HighSlippery en curvas
+ const float cooldownRate = 0.5f; // Qué tan rápido baja HighSlippery en curvas
+ const float staticFriction = 0.20f;
+ const float dynamicFriction = 0.10f;
+
+ // Sistema de heatup/cooldown para HighSlippery
+ if (slipSpeed > slipSpeedThreshold) // && botella.ContactPressure > 0
+ botella.HighSlippery = Math.Min(9f, botella.HighSlippery + heatupRate);
+ else
+ botella.HighSlippery = Math.Max(0f, botella.HighSlippery - cooldownRate);
+
+ // Calcular fricción basada en HighSlippery
+ // HighSlippery > 3 = fricción dinámica, <= 3 = fricción estática
+ if (botella.HighSlippery > 3f)
+ return dynamicFriction;
+ else
+ return staticFriction;
+ }
+ }
+ catch (Exception ex)
+ {
+ System.Diagnostics.Debug.WriteLine($"[CalculateCurveFriction] Error: {ex.Message}");
+ }
+
+ // Valor por defecto si hay algún error
+ return 0.8f;
+ }
+
+ ///
+ /// ✅ NUEVO: Calcula los parámetros de material para contactos botella-botella basado en la profundidad de penetración
+ ///
+ private void CalculateBottlePression(ref TManifold manifold, simBotella botellaA, simBotella botellaB) where TManifold : unmanaged, IContactManifold
+ {
+ var pairMaterial = new PairMaterialProperties();
+
+ try
+ {
+ const float penetrationDepthThreshold = 0.001f; // Umbral de penetración en metros para detectar alta presión.
+
+ // Iteramos sobre todos los puntos de contacto en el manifold.
+ for (int i = 0; i < manifold.Count; ++i)
+ {
+ // Si la profundidad de la penetración supera nuestro umbral,
+ // consideramos que este contacto está bajo alta presión.
+ if (manifold.GetDepth(i) > penetrationDepthThreshold)
+ {
+ botellaA.ContactPressure = Math.Max(botellaA.ContactPressure, manifold.GetDepth(i) - penetrationDepthThreshold);
+ botellaB.ContactPressure = Math.Max(botellaB.ContactPressure, manifold.GetDepth(i) - penetrationDepthThreshold);
+ // break; // Un punto de alta presión es suficiente.
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ System.Diagnostics.Debug.WriteLine($"[CalculateBottleToBottleMaterial] Error: {ex.Message}");
+ // Valores por defecto seguros
+ }
+ }
+
public bool ConfigureContactManifold(int workerIndex, CollidablePair pair, int childIndexA, int childIndexB, ref ConvexContactManifold manifold)
{
return true;
@@ -427,13 +514,54 @@ namespace CtrEditor.Simulacion
var handle = _simulationManager.simulation.Bodies.ActiveSet.IndexToHandle[bodyIndex];
if (_simulationManager.CollidableData.TryGetValue(handle.Value, out simBase baseObj) && baseObj is simBotella)
{
- // B. DAMPING ANGULAR EXTRA EN EJE Z
- // Para modificar un solo carril de un Vector, la forma más segura es extraer
- // los valores a un array, modificar el índice y crear un nuevo Vector.
- var zVel = new float[Vector.Count];
- velocity.Angular.Z.CopyTo(zVel, 0);
- zVel[i] *= bottleZAngularDampingFactor;
- velocity.Angular.Z = new Vector(zVel);
+ //// B. DAMPING ANGULAR EXTRA EN EJE Z
+ //// Para modificar un solo carril de un Vector, la forma más segura es extraer
+ //// los valores a un array, modificar el índice y crear un nuevo Vector.
+ //var zVel = new float[Vector.Count];
+ //velocity.Angular.Z.CopyTo(zVel, 0);
+ //zVel[i] *= bottleZAngularDampingFactor;
+ //velocity.Angular.Z = new Vector(zVel);
+ // --- INICIO DE NUESTRA LÓGICA ANTI-SALTO Y ANTI-VUELCO ---
+
+ // 1. EXTRAER VELOCIDADES DEL PAQUETE A ARRAYS
+ var linearX = new float[Vector.Count];
+ var linearY = new float[Vector.Count];
+ var linearZ = new float[Vector.Count];
+ var angularX = new float[Vector.Count];
+ var angularY = new float[Vector.Count];
+ var angularZ = new float[Vector.Count];
+
+ velocity.Linear.X.CopyTo(linearX, 0);
+ velocity.Linear.Y.CopyTo(linearY, 0);
+ velocity.Linear.Z.CopyTo(linearZ, 0);
+ velocity.Angular.X.CopyTo(angularX, 0);
+ velocity.Angular.Y.CopyTo(angularY, 0);
+ velocity.Angular.Z.CopyTo(angularZ, 0);
+
+ // 2. APLICAR RESTRICCIONES AL CARRIL 'i' (la botella)
+
+ // ANTI-VUELCO: Anular cualquier velocidad angular que tumbe la botella.
+ angularX[i] = 0;
+ angularY[i] = 0;
+
+ // ANTI-SALTO: Si la velocidad Z es positiva (hacia arriba), anularla.
+ // Esto permite que la gravedad actúe (Z negativo) pero impide saltos.
+ if (linearZ[i] > 0)
+ {
+ linearZ[i] = 0;
+ }
+
+ // DAMPING ANGULAR EXTRA EN EJE Z (Tu lógica original)
+ angularZ[i] *= bottleZAngularDampingFactor;
+
+
+ // 3. RECONSTRUIR LOS VECTORES 'WIDE' CON LOS VALORES MODIFICADOS
+ velocity.Linear.X = new Vector(linearX);
+ velocity.Linear.Y = new Vector(linearY);
+ velocity.Linear.Z = new Vector(linearZ);
+ velocity.Angular.X = new Vector(angularX);
+ velocity.Angular.Y = new Vector(angularY);
+ velocity.Angular.Z = new Vector(angularZ);
}
}
}
@@ -511,6 +639,10 @@ namespace CtrEditor.Simulacion
// ✅ NUEVOS - gestión automática de clasificación
private void RegisterObjectHandle(simBase obj)
{
+ if (obj != null && obj.BodyHandle.Value >= 0)
+ {
+ CollidableData[obj.BodyHandle.Value] = obj;
+ }
switch (obj)
{
case simBotella bottle:
@@ -540,6 +672,10 @@ namespace CtrEditor.Simulacion
private void UnregisterObjectHandle(simBase obj)
{
+ if (obj != null && obj.BodyHandle.Value >= 0)
+ {
+ CollidableData.Remove(obj.BodyHandle.Value);
+ }
switch (obj)
{
case simBotella bottle:
@@ -624,8 +760,8 @@ namespace CtrEditor.Simulacion
// ✅ MODIFICADO: Pasar referencia de this al PoseIntegratorCallbacks
var poseIntegratorCallbacks = new PoseIntegratorCallbacks(
gravity: new Vector3(0, 0, -9.81f), // Gravedad en Z
- linearDamping: 0.999f, // Amortiguamiento lineal suave
- angularDamping: 0.995f, // Amortiguamiento angular más fuerte para detener rotaciones
+ linearDamping: 0.03f, // 0.999f, // Amortiguamiento lineal suave
+ angularDamping: 0.03f, // 0.995f, // Amortiguamiento angular más fuerte para detener rotaciones
simulationManager: this // ✅ NUEVA REFERENCIA
);
@@ -799,6 +935,7 @@ namespace CtrEditor.Simulacion
foreach (var botella in Cuerpos.OfType())
{
botella.IsTouchingTransport = false;
+ botella.ContactPressure = 0f;
}
// ✅ CONSERVAR - validación de deltaTime
@@ -857,27 +994,26 @@ namespace CtrEditor.Simulacion
- // ✅ CONSERVAR - limitación de rotación y mantener botellas despiertas
- foreach (var cuerpo in Cuerpos.OfType().ToList())
- {
- try
- {
- if (simulation.Bodies.BodyExists(cuerpo.BodyHandle))
- {
- // cuerpo.LimitRotationToXYPlane();
- // simulation.Awakener.AwakenBody(cuerpo.BodyHandle);
- }
- }
- catch (Exception ex)
- {
- // Error limiting rotation for bottle - continue
- }
- }
+ //// ✅ CONSERVAR - limitación de rotación y mantener botellas despiertas
+ //foreach (var cuerpo in Cuerpos.OfType().ToList())
+ //{
+ // try
+ // {
+ // if (simulation.Bodies.BodyExists(cuerpo.BodyHandle))
+ // {
+ // // cuerpo.LimitRotationToXYPlane();
+ // // simulation.Awakener.AwakenBody(cuerpo.BodyHandle);
+ // }
+ // }
+ // catch (Exception ex)
+ // {
+ // // Error limiting rotation for bottle - continue
+ // }
+ //}
// ✅ CONSERVAR - sistemas que funcionan bien
ProcessBarreraContacts();
ProcessDescarteContacts();
- ProcessPressureSystem();
ProcessCleanupSystem();
// ✅ SIMPLIFICAR - limpiar solo contactos que usamos
@@ -904,59 +1040,7 @@ namespace CtrEditor.Simulacion
- ///
- /// ✅ NUEVO: Sistema para controlar la "presión" y evitar que las botellas floten
- /// Si una botella no toca un transporte por varios frames, se reestablece su altura.
- ///
- private void ProcessPressureSystem()
- {
- try
- {
- var botellas = Cuerpos.OfType().ToList();
- foreach (var botella in botellas)
- {
- try
- {
- if (botella == null || !simulation.Bodies.BodyExists(botella.BodyHandle))
- continue;
-
- if (!botella.IsTouchingTransport && botella.LastTransportCollisionZ.HasValue)
- {
- var body = simulation.Bodies.GetBodyReference(botella.BodyHandle);
- var currentZ = body.Pose.Position.Z;
-
- // ✅ NUEVA CONDICIÓN: Solo actuar si la botella ha subido
- if (currentZ > botella.LastTransportCollisionZ.Value)
- {
- // Incrementar el contador de presión.
- botella.PressureBuildup++;
-
- // Si se acumula suficiente presión (más de 2 frames sin contacto y subiendo),
- // es un indicio de que está flotando. La reestablecemos a su última Z conocida.
- if (botella.PressureBuildup > 2)
- {
- var pose = body.Pose;
- pose.Position.Z = botella.LastTransportCollisionZ.Value;
- body.Pose = pose;
-
- // Opcional: resetear el contador para no aplicarlo constantemente en cada frame
- // botella.PressureBuildup = 0;
- }
- }
- }
- }
- catch (Exception ex)
- {
- System.Diagnostics.Debug.WriteLine($"[ProcessPressureSystem] Error processing bottle {botella?.BodyHandle}: {ex.Message}");
- }
- }
- }
- catch (Exception ex)
- {
- System.Diagnostics.Debug.WriteLine($"[ProcessPressureSystem] Critical error: {ex.Message}");
- }
- }
///
/// ✅ NUEVO: Marca un objeto para eliminación diferida (más seguro)
diff --git a/Simulacion/simBotella.cs b/Simulacion/simBotella.cs
index 3667b71..53b2b6d 100644
--- a/Simulacion/simBotella.cs
+++ b/Simulacion/simBotella.cs
@@ -33,9 +33,12 @@ namespace CtrEditor.Simulacion
// ✅ NUEVO: Propiedades para control de flotación/presión
public float? LastTransportCollisionZ { get; set; }
- public float PressureBuildup { get; set; } = 0;
public bool IsTouchingTransport { get; set; } = false;
+ // ✅ NUEVO: Sistema de fricción dinámica con cooldown/heatup
+ public float HighSlippery { get; set; } = 0f; // Rango 0-9, donde 9 es máxima presión/deslizamiento
+ public float ContactPressure { get; set; } = 0f; // Rango 0-9, donde 9 es mínima presión/deslizamiento
+
// ✅ NUEVO: Propiedades para la física personalizada
public float BaseInverseMass { get; private set; }
public Vector3 InitialPosition3D { get; private set; }
diff --git a/Simulacion/simCurve.cs b/Simulacion/simCurve.cs
index 496557a..746b01c 100644
--- a/Simulacion/simCurve.cs
+++ b/Simulacion/simCurve.cs
@@ -70,6 +70,23 @@ namespace CtrEditor.Simulacion
ActualizarVelocidadCinematica();
}
+
+ public Vector3 CalcularVelocidadCinematica()
+ {
+ float effectiveRadius = (_innerRadius + _outerRadius) / 2.0f;
+ if (effectiveRadius > 0.001f)
+ {
+ // La velocidad tangencial (Speed) se convierte a velocidad angular (ω = v / r)
+ // ✅ CORREGIDO: Convertir velocidad de m/min a m/s para la simulación
+ float angularSpeed = (Speed / SpeedConversionFactor) / effectiveRadius;
+
+ // La rotación es alrededor del eje Z en el sistema de coordenadas de BEPU
+ return new Vector3(0, 0, angularSpeed);
+ }
+ return Vector3.Zero; // Si no hay cuerpo o radio efectivo es muy pequeño, no hay velocidad angular
+ }
+
+
///
/// ✅ NUEVO: Aplica la velocidad angular al cuerpo cinemático de BEPU.
///
@@ -79,20 +96,7 @@ namespace CtrEditor.Simulacion
{
var body = _simulation.Bodies.GetBodyReference(BodyHandle);
- float effectiveRadius = (_innerRadius + _outerRadius) / 2.0f;
- if (effectiveRadius > 0.001f)
- {
- // La velocidad tangencial (Speed) se convierte a velocidad angular (ω = v / r)
- // ✅ CORREGIDO: Convertir velocidad de m/min a m/s para la simulación
- float angularSpeed = (Speed / SpeedConversionFactor) / effectiveRadius;
-
- // La rotación es alrededor del eje Z en el sistema de coordenadas de BEPU
- body.Velocity.Angular = new Vector3(0, 0, angularSpeed);
- }
- else
- {
- body.Velocity.Angular = Vector3.Zero;
- }
+ body.Velocity.Angular = CalcularVelocidadCinematica();
}
}
diff --git a/Simulacion/simTransporte.cs b/Simulacion/simTransporte.cs
index a298fb9..560f3ec 100644
--- a/Simulacion/simTransporte.cs
+++ b/Simulacion/simTransporte.cs
@@ -149,6 +149,14 @@ namespace CtrEditor.Simulacion
ActualizarVelocidadCinematica();
}
+ ///
+ /// ✅ NUEVO: Aplica la velocidad al cuerpo cinemático de BEPU.
+ ///
+ public Vector3 CalcularVelocidadCinematica()
+ {
+ return this.DirectionVector * (this.Speed / SpeedConversionFactor);
+ }
+
///
/// ✅ NUEVO: Aplica la velocidad al cuerpo cinemático de BEPU.
///
@@ -158,7 +166,7 @@ namespace CtrEditor.Simulacion
{
var body = _simulation.Bodies.GetBodyReference(BodyHandle);
// ✅ CORREGIDO: Convertir velocidad de m/min a m/s para la simulación
- body.Velocity.Linear = this.DirectionVector * (this.Speed / SpeedConversionFactor);
+ body.Velocity.Linear = CalcularVelocidadCinematica();
}
}