Autor Tema: Detectar colisiones y fórmula de rozamiento.

0 Usuarios y 1 Visitante están viendo este tema.

13 Noviembre, 2024, 09:40 pm
Leído 687 veces

Tachikomaia

  • $$\Large \color{#5b61b3}\pi\,\pi\,\pi\,\pi\,\pi$$
  • Mensajes: 1,297
  • País: uy
  • Karma: +0/-0
  • Sexo: Masculino
Hasta ahora, cuando intenté programar eso, ponía que cada cierto tiempo los objetos se movían y luego se chequeaba si había colisión:
Código: [Seleccionar]
Sumar 1 a la PosiciónXdeObjeto1
Sumar 1 a la PosiciónXdeObjeto2
¿Hay colisión?
El método más sencillo para ver si hay colisión es pedir al programa que mire si los objetos se están tocando. No es la forma ideal, y no recuerdo otro modo de hacerlo.

A altas velocidades, y más aún si los objetos van en direcciones opuestas, una colisión que debería ocurrir podría no detectarse:
Código: [Seleccionar]
AnchoYalturaDeObjeto1 = 1
AnchoYalturaDeObjeto2 = 2
PosiciónXDeObjeto1 = 20
PosiciónXDeObjeto2 = 25
Sumar 10 a la PosiciónXdeObjeto1, queda en 30
Restar 10 a la PosiciónXdeObjeto2, queda en 15
¿Hay colisión?
No.
Incluso si se chequea luego de cada movimiento, en ese caso no se detectaría.

El método para detectarla se puede hacer más complejo, no sé bien cómo, creo que tenía relación con ver si 2 funciones tenían un punto en común. Tal vez sea lo más eficiente. Se tienen 2 segmentos de recta, en mi caso ambos horizontales, con cierta posición, y se ve si se están tocando. El planteo es algo así:
Código: [Seleccionar]
AnchoYalturaDeObjeto1 = 1
AnchoYalturaDeObjeto2 = 2
PosiciónXDeObjeto1 = 20
PosiciónXDeObjeto2 = 25
InicioDeSegDeRecta1 = 20
LargoDeSegDeRecta1 = VelocidadXdeObjeto1+AnchoYalturaDeObjeto1/2
InicioDeSegDeRecta2 = 25
LargoDeSegDeRecta2 = VelocidadXdeObjeto2+AnchoYalturaDeObjeto2/2
El inicio de la 1 está en su punto más izquierdo, el inicio de 2 en su derecho. Quizá pueda mejorarse.
La posiciónX de los objetos se basa en su centro, por eso al tamaño de los segm. de rectas le agrego la mitad del ancho de los objetos. O se podría poner que los inicios consideren eso.
Luego no sé cómo se sigue. ¿Cómo saber si 2 segmentos de recta colisionan? Además, tal vez deba necesitar saber dónde.

Por otro lado, he pensado que quisiera que el programa intente simular varios movimientos antes de actualizar la pantalla, es decir, en vez de mover los objetos 10 pixeles 1 vez antes de actualizar la pantalla, que los mueva 0.5 píxeles 20 veces antes de actualizar la pantalla. Y en esas 20 veces que vea si hay colisión. Probablemente sea poco eficiente, pero detecta todas las colisiones y bastante bien el lugar donde ocurren ¿no?
¿Conviene que la cantidad de movimiento sea la mitad del ancho de los objeto más corto? ¿o su ancho propio sirve? Creo que no lo último, en el caso de que estuvieran justo a esa distancia y si tuvieran el mismo ancho. No estaban colisionando y luego sería como si hubieran intercambiado posiciones. Ok.
¿Y el resto cómo se hace? Creo que debo poner que se repita algo cierta cantidad de veces. En el ejemplo que puse se movían 10 píxeles en cada momento, y yo quería que se movieran 0.5 así que a 10 lo dividí entre 0.5, que da 20, entonces sería algo como:
Código: [Seleccionar]
Movimientos = VelocidadDelObjetoFaster/(AnchoDelObjetoSmaller/2)
Repetir:
  Movimientos--
  Objeto = 0
  Repetir:
    Objeto++
    "PosiciónDelObjeto"+Objeto = SuPosición + SuVelocidad/(AnchoDelObjetoSmaller/2)
  mienteas Objeto < Objetos
mientras Movimientos > 1
¿Está bien?
Luego, si Movimientos es 1 vuelvo a mover los objetos 1 vez. Sino... tengo que moverlos pero menos. O sea, si en vez de que falte 1 movimiento falta 0.2, por ejemplo, en vez de mover el 100% tengo que mover el 20%, o sea:
Código: [Seleccionar]
    "PosiciónDelObjeto"+Objeto = SuPosición + SuVelocidad/(AnchoDelObjetoSmaller/2)*Movimiento
¿Correcto?

¿Y si quisiera que la velocidad disminuya por rozamiento? La forma sencilla, creo, es antes de sumarle la velocidad, a ella restarle algo, por ejemplo:
Velocidad-0.001
¿Pero lo que debo restar depende de cuánta sea la velocidad?
Los objetos en cuestión serían barriles en una superficie horizontal. No me interesa tanto realismo en eso, que si no son exactamente cilíndricos o que si el suelo tiene piedritas. Digamos que son cilíndricos y el suelo es, como dije, horizontal, no hay mucho miniobstáculo.
Si resto algo acorde a la velocidad, podría ser que nunca se detenga, siempre disminuiría un porcentaje menor a 100%, pero lo que disminuye debería ser acorde a cuánto recorre ¿no? ¿cómo es la fórmula entonces?

16 Noviembre, 2024, 05:21 am
Respuesta #1

Tachikomaia

  • $$\Large \color{#5b61b3}\pi\,\pi\,\pi\,\pi\,\pi$$
  • Mensajes: 1,297
  • País: uy
  • Karma: +0/-0
  • Sexo: Masculino
Aquí mi juego aún no terminado:

Puse:
Código: [Seleccionar]
if (EvaluedBarrilSpeed > 0) {
EvaluedBarrilSpeed = EvaluedBarrilSpeed-0.001;
if (EvaluedBarrilSpeed < 0) {
EvaluedBarrilSpeed = 0;
}
set(BarrilSpeed, EvaluedBarrilSpeed);
}

O sea, si la velocidad es > 0, baja, y si queda por debajo de 0 queda en 0.

Lo hablé con GPT pero sigo teniendo la duda de cómo es realmente:
Para hacer que la simulación del rozamiento sea más realista, deberías tener en cuenta que el rozamiento (o resistencia) normalmente depende de la velocidad del objeto. En lugar de reducir la velocidad de manera constante en cada frame, lo más realista sería hacer que la velocidad disminuya proporcionalmente a su valor actual. Así, la reducción será mayor cuando el objeto se esté moviendo rápido, y menor cuando esté moviéndose lentamente, lo cual es más consistente con la física del rozamiento.

### Fórmula para el rozamiento proporcional a la velocidad

Una forma común de modelar el rozamiento es mediante una fuerza de fricción proporcional a la velocidad, lo que produce una desaceleración que depende directamente de la velocidad actual del objeto. Esto se puede expresar como:

\[
\text{Velocidad} = \text{Velocidad} - (\text{Velocidad} \times \text{coeficiente\_de\_fricción})
\]

Donde `coeficiente_de_fricción` es un valor que define qué tan fuerte es la fricción. Un valor más cercano a 1 significa que el objeto perderá rápidamente velocidad, y un valor cercano a 0 significa que la fricción es muy baja y el objeto seguirá moviéndose durante más tiempo.

### Implementación

Supongamos que estás programando en un lenguaje típico de videojuegos, como JavaScript o C#. El pseudocódigo se vería así:

```csharp
// Coeficiente de fricción (entre 0 y 1)
float coeficiente_de_friccion = 0.05f;  // Puedes ajustar este valor para obtener el efecto deseado

// Actualización de la velocidad en cada frame
if (velocidad > 0) {
    velocidad -= velocidad * coeficiente_de_friccion;
   
    // Asegurarse de que la velocidad no sea negativa
    if (velocidad < 0) {
        velocidad = 0;
    }
}
```

### Explicación de la lógica

1. **`velocidad -= velocidad * coeficiente_de_friccion`:** Este es el núcleo del cálculo. Está reduciendo la velocidad en cada frame, pero la cantidad de reducción es proporcional a la velocidad actual. Eso significa que cuando el objeto se mueve rápido, la velocidad disminuirá más rápido. A medida que la velocidad disminuye, la fricción también lo hace, y por lo tanto, la velocidad se reduce más lentamente.
   
2. **`if (velocidad < 0) velocidad = 0;`:** Esta línea asegura que la velocidad nunca caiga por debajo de cero, lo que evitaría que el objeto acelere en la dirección opuesta debido a un cálculo erróneo.

### ¿Por qué esto es más realista?

En la vida real, cuando un objeto se mueve sobre una superficie con fricción (como una caja deslizándose sobre el suelo), la fuerza de fricción es proporcional a la velocidad en ciertos casos, especialmente cuando modelas fricción de tipo aerodinámico o fricción viscosa. En este tipo de modelos, la velocidad no disminuye de manera lineal, sino de manera exponencial. Por eso, un objeto que se mueve rápido pierde velocidad rápidamente al principio, pero luego la pérdida de velocidad se va haciendo más lenta a medida que el objeto se desacelera.

### Consideraciones adicionales

- **Coeficiente de fricción variable:** El valor de `coeficiente_de_friccion` puede variar dependiendo del tipo de superficie o del medio por el que se mueve el objeto (por ejemplo, aire, agua, etc.).
 
- **Masa del objeto:** Si quieres ser aún más realista, podrías aplicar la segunda ley de Newton y hacer que la desaceleración también dependa de la masa del objeto. Pero en este caso, estamos simplificando al suponer que la fuerza de fricción es directamente proporcional a la velocidad.

Con este modelo, tu simulación debería tener un comportamiento más realista, donde los objetos se desaceleran de manera suave y natural.


pero en la realidad no hay un if, y si aplicamos tu fórmula sin if siempre va a disminuir menos del 100%, por lo que la velocidad nunca llegará a 0 ¿cómo es la realidad entonces?

Tienes razón, en la realidad no hay un "if" que detenga la velocidad en cero, sino que el objeto eventualmente se detiene debido a la fricción o a fuerzas disipativas como el rozamiento. Sin embargo, en la simulación basada en la fórmula que discutimos, si no pones ningún límite, la velocidad **teóricamente** nunca llegaría exactamente a 0, ya que la reducción es exponencial y decrece indefinidamente, acercándose a 0 sin alcanzarlo del todo.

### ¿Cómo ocurre esto en la realidad?

En la física real, hay dos tipos de fricción que comúnmente encontramos:

1. **Fricción dinámica (o cinética):** Actúa sobre un objeto en movimiento y es proporcional (hasta cierto punto) a la velocidad.
   
2. **Fricción estática:** Es la fuerza que evita que un objeto se empiece a mover desde el reposo. Esta fricción es la que realmente detiene completamente al objeto una vez que la velocidad es lo suficientemente baja.

En la vida real, cuando la velocidad de un objeto disminuye lo suficiente, las fuerzas de fricción estática y otras fuerzas microscópicas (como las imperfecciones en las superficies de contacto) hacen que el objeto se detenga por completo.

### ¿Cómo simular esto de manera más realista?

Lo que puedes hacer es seguir aplicando el modelo de fricción proporcional a la velocidad, pero introducir un **umbral mínimo** de velocidad. Una vez que la velocidad es lo suficientemente pequeña, puedes considerar que el objeto ha "parado" y simplemente establecer su velocidad a cero. Esto es más realista porque en la vida real, cuando la velocidad es extremadamente baja, cualquier pequeña irregularidad en la superficie o resistencia residual detendría el objeto.

### Implementación con un umbral

Puedes agregar un pequeño umbral que simule el efecto de la fricción estática, por ejemplo:

```csharp
// Coeficiente de fricción (entre 0 y 1)
float coeficiente_de_friccion = 0.05f;  // Ajusta según tu necesidad
float umbral_minimo = 0.01f;  // Velocidad mínima antes de detenerse

// Actualización de la velocidad en cada frame
if (velocidad > 0) {
    velocidad -= velocidad * coeficiente_de_friccion;

    // Si la velocidad es menor que el umbral mínimo, considerar que se ha detenido
    if (velocidad < umbral_minimo) {
        velocidad = 0;
    }
}
```

### Explicación del umbral

1. **`umbral_minimo`:** Es un valor muy pequeño que representa la velocidad por debajo de la cual consideramos que el objeto ya está prácticamente detenido. Este valor es arbitrario y puede ajustarse según las necesidades de la simulación. En la realidad, una velocidad muy baja ya no es significativa debido a las pequeñas fuerzas que actúan y detienen al objeto.
   
2. **`if (velocidad < umbral_minimo) velocidad = 0;`:** Aquí es donde estableces que, si la velocidad es suficientemente baja (por debajo del umbral), el objeto se detiene por completo. Esto simula el efecto de la fricción estática o cualquier otra fuerza residual que termine de frenar al objeto.

### ¿Por qué esto es más realista?

1. **Desaceleración suave:** El objeto se desacelera de manera progresiva cuando la velocidad es alta, pero cuando la velocidad es muy baja, la fricción estática que también actúa en la realidad lo detiene completamente.

2. **Simulación finita:** En la realidad, aunque teóricamente una fórmula exponencial nunca llega a 0, las fuerzas microscópicas en la superficie (como las irregularidades) acaban deteniendo el objeto. Este umbral simula ese comportamiento.

### Sin el `if`

Si te interesa una simulación aún más fluida sin el uso del `if`, puedes trabajar con una aproximación continua, pero en la mayoría de los casos, incluso los motores físicos de videojuegos simplifican el problema con un umbral similar para evitar cálculos infinitos. Sin embargo, si no incluyes el `if` y trabajas solo con la fórmula exponencial, la velocidad se acercará a cero cada vez más, pero nunca llegará exactamente a 0:

```csharp
// Coeficiente de fricción (entre 0 y 1)
float coeficiente_de_friccion = 0.05f;

// Actualización de la velocidad en cada frame (sin umbral)
velocidad -= velocidad * coeficiente_de_friccion;
```

### Conclusión

En la realidad, la velocidad de un objeto en movimiento bajo fricción disminuiría hasta un punto donde las fuerzas de fricción estática y otras pequeñas fuerzas lo detendrían completamente. En las simulaciones, usualmente se utiliza un umbral mínimo para evitar que la velocidad se acerque indefinidamente a cero sin llegar nunca, lo que hace que la simulación sea más eficiente y realista.


¿Será que acaso sí hay un if en la realidad? Que si la velocidad del objeto supera la resistencia del aire y lo que se le opone. Ok.

18 Noviembre, 2024, 08:02 pm
Respuesta #2

Richard R Richard

  • Ingeniero Industrial
  • $$\Large \color{#9c57a6}\pi\,\pi\,\pi\,\pi\,\pi\,\pi$$
  • Mensajes: 4,041
  • País: ar
  • Karma: +2/-0
  • Sexo: Masculino
  • Dentro de la ciencia todo,fuera de la ciencia nada

Hola, no se si esto responde a tu juego de tenis, veamos, tu estrategía de hacer un paso de loop y checar la colision es buena mientras la velocidad multiplicada por el tiempo del paso, es  menor que la longitud de lo objetos del juego, , así no te los pasas de largo. Eso ya lo detectaste.


Pero si tu quieres pronosticar la colisión  no te queda otra que conocer las ecuaciones de las trayectorias y ver si existe un lapso de tiempo donde la distancia entre los objetos es menor a sus respectivos centros. Si tienes dos esferas de radio $$R_1$$ y $$R_2$$, y quieres saber si chocaran debes conocer la ecuación  de la posición de cada uno  $$x_i(t),y_i(t),z_i(t)$$ en función del tiempo y ver si  $$R_1+R_2>\sqrt{(x_1(t)-x_2(t))^2+(y_1(t)-y_2(t))^2+(z_1(t)-z_2(t))^2}$$  para algún tiempo t dado, si esto sucede hay colisión y puedes guardar en valor de ese $$t$$ que lo hace posible, y cuando ejecutes el paso $$t_x$$ y $$t_{x+1}$$ entre cuyos tiempos se encuentre $$t$$ es decir que verifique $$t_x<t<t_{x+1}$$ allí ejecutas el programa que quieras como consecuencia de la colisión.


Si  de algún modo ejecutas la posición de múltiples personajes es probable que no sepas cual colisionará primero con quien, y que de ello dependa la trayectoria resultante, pues haces ciclos proyectando las trayectorias actuales  sin mediar modificación y  ejecutas el programa hasta el tiempo de la primer colisión entre cada par de personajes, allí cambias la trayectoria de los que colisionan, y continuas evaluando las nuevas trayectorias, evalúas cual será la próxima colisión nuevamente, y ejecutas hasta ese tiempo y así sucesivamente.
 
Saludos





.
Saludos  \(\mathbb {R}^3\)

19 Noviembre, 2024, 05:15 am
Respuesta #3

Tachikomaia

  • $$\Large \color{#5b61b3}\pi\,\pi\,\pi\,\pi\,\pi$$
  • Mensajes: 1,297
  • País: uy
  • Karma: +0/-0
  • Sexo: Masculino
no se si esto responde a tu juego de tenis
Ese quedó para más delante por ser demasiado complicado matemáticamente para mí, mira el video, este es simplón.

19 Noviembre, 2024, 06:07 pm
Respuesta #4

Richard R Richard

  • Ingeniero Industrial
  • $$\Large \color{#9c57a6}\pi\,\pi\,\pi\,\pi\,\pi\,\pi$$
  • Mensajes: 4,041
  • País: ar
  • Karma: +2/-0
  • Sexo: Masculino
  • Dentro de la ciencia todo,fuera de la ciencia nada
Es en una sola dimensión 

para cada barril

posicion_actual = posicion_inicial +velocidad *( tiempo_actual - tiempo_inicial)

o bien

posicion_actual = posicion_anterior+velocidad * tiempo_del_paso(entre frames)


Si hay choque elastico

si
posicion_actual_barril1-posicion_actual barril2<2*radio_barril


entonces hay colisión

así intercambias velocidades entre barriles por ejemplo así

velocidad_barril_2=velocidad barril_2+ velocidad_barril_1
velocidad_barril_1=velocidad barril_2-velocidad_barril_1
velocidad_barril_2= velocidad barril_2-velocidad_barril_1

Pruebalo! ;)

continua el movimiento con las nuevas velocidades en las mismas variables.
 cada vez que haya una colisión agrega en efecto de sonido, si visualmente es muy rápido y no se nota.


el efecto del rozamiento esta bastante bien logrado, si aumentas la aceleracion se frena mas rápido, de lo contrario mas lento.


Saludos  \(\mathbb {R}^3\)

23 Noviembre, 2024, 06:26 pm
Respuesta #5

Tachikomaia

  • $$\Large \color{#5b61b3}\pi\,\pi\,\pi\,\pi\,\pi$$
  • Mensajes: 1,297
  • País: uy
  • Karma: +0/-0
  • Sexo: Masculino
Lo que me propones ¿es distinto de lo que ya hice? No veo la diferencia ^^u más allá de que calculas la posición basado en el tiempo y yo simplemente le sumo la velocidad:
NuevaPosicion = Antigua+Velocidad

Lo que dices es mejor, pero de momento tengo otras prioridades. Iba a hacer un tema:
Cuando el personaje camina, se mueve 0.2 pixeles.

Pero si así tocará un barril delante, se moverá menos y el resto de su movimiento empujará al barril.

No me sale hacer el cálculo xP

Lo empujará, determinar cuánto:
Máxima Distancia < 14+12
Mínima Distancia  > 0

Cuando está a distancia 0
// 0 -> 100% de 0.2
// 28 -> 0% de 0.2

lo empujará ¿cuánto? Depende de qué tan cerca estuviera. Si está muy cerca
pero creo que ya sé cómo hacer eso.