Stratos: Punto de Encuentro de Desarrolladores

¡Bienvenido a Stratos!

Acceder

Foros





Ayuda con cálculos para que la trayectoria de una pelota cumpla ciertas condicio

Iniciado por Tachikomaia, 29 de Abril de 2023, 07:45:19 AM

« anterior - próximo »

Tachikomaia

Nota: Esto lo escribí en noviembre, puede que haya cambiado algunas cosas, perdón pero no le veo sentido a revisar todo.

1- Su velocidad de caída aumenta 0.01 por segundo (segundo es un decir, es más bien una centésima de segundo).

2- Sus velocidades hacia los costados (X), adelante (Y, arriba) y arriba (Z, distancia con respecto al suelo) deben ser acordes a la fuerza del jugador que realiza el tiro. La velocidad hacia abajo aumentará, pero me refiero a las velocidades iniciales. Si por ejemplo tiene fuerza 4 y aplicó 3 para que la pelota avance 3 pixeles (es un decir) por segundo entonces no puede ser que la pelota se eleve 2 pixeles por segundo, ya que la fuerza que queda disponible es sólo 1.

3- Cuando llega a la red la Z de la pelota debe ser igual o mayor a cierto valor, es decir, se debe preestablecer un valor que represente la mínima Z con la que la pelota pasa por encima de la red sin tocarla, y cuando llegue a la red debe tener ese valor o uno mayor. En mi caso es 17.5 pero elijan el que gusten.

4- Debe caer en la cancha rival.

5- Las velocidades deben ser tales que la pelota caiga en cierto punto. Por ejemplo:


6- Su velocidad hacia adelante (Y) debe ser la máxima posible.


Es decir, se intenta que se cumpla una condición en tanto eso no cause que no se cumplan las otras.
3- Se quiere que la pelota pase por encima de la red, pero sin que ello implique que haya caído más/menos de lo que debe (condición 1) ni que se le haya aplicado más fuerza de la que se estableció como posible (condición 2). Si el jugador no tiene suficiente fuerza como para que se cumpla esta condición, no se cumple.
4- La oración anterior.
5- Lo mismo. Si para cumplir las condiciones anteriores es necesario que el tiro no vaya tan diagonal como se quiere, entonces no irá tan así, irá más bien verticalmente.
6- En tanto se cumplan las condiciones anteriores... Si la fuerza es 10 la velocidad Y no debe ser mayor que eso. Si queriendo asignar determinada fuerza a Y luego sin importar cuánta se asigne a Z la pelota no pasa la red o no cae en la cancha rival, entonces habrá que reducir la velocidad Y...


Por si los necesitan o quieren, les dejo los datos del caso (pero pueden inventar otros, lo que sí debe tenerse en cuenta es que no necesito simplemente averiguar 3 numeritos basados en otros, sino un método para averiguarlos teniendo en cuenta que los otros pueden variar, por ejemplo se puede elegir hacer un saque hacia al medio o puede que el personaje tenga distinta fuerza):
NOTA: Ignoren lo de "_level0."
  Variable _level0.AlexFuerza = 10
  Variable _level0.BallX = 417
  Variable _level0.BallY = 548
  Variable _level0.BallZ = 43.8
  Variable _level0.DistanciahastaDestinoX = 136.9
  Variable _level0.DistanciahastaDestinoY = 368
  Variable _level0.DistanciahastaRed = 248
  Variable _level0.DistanciahastaMinsafeBallZ = 26.3


Gracias.

Ah: El incremento de Y está invertido, es decir, entre más abajo más valor.
0,0________600,0
0,800______600,800


ACTUALIZADO:
Intenté seguir un método que me recomendaron pero la persona desapareció, así que a ver si alguien lo puede completar. Esto es lo que tengo:
Código completo:
[spoiler]// La mínima BallZ que no toca la red es 18.6.
fscommand ("fullscreen", "true");
Fuerzaderebotedepelota = -0;
// En ese caso menos es más.
Influenciadelrozamiento = 0.02;
AlexFuerzadebrazos = 2000;
Alextimetodownracket = (10-Math.floor(AlexFuerzadebrazos/1000))*2+5;
Alextimetoupracket = Alextimetodownracket*2;
AlexFuerzadepiernas = 1000;
AlexFuerzadetiros = (AlexFuerzadebrazos/1000+AlexFuerzadepiernas/5000)*1;
Alexrunspeed = AlexFuerzadepiernas/10000;
Alexrunspeedonserving = AlexFuerzadepiernas/1000;
AlexMinXposonserving = 408+Alexrunspeedonserving;
AlexMaxXposonserving = 512-Alexrunspeedonserving;
// ///////////////////////////////////////////////////////
// ////////////////////  Saca Alex  //////////////////////
// ///////////////////////////////////////////////////////
AlexX = 460;
AlexY = 548;
attachMovie("AlexMovie", "Alex", 100);
setProperty (Alex, _x, AlexX);
setProperty (Alex, _y, AlexY);
MaxBallZwhenstriked = 0;
Teclafuesoltada = 0;
// ///////////////////////////////////////////////////////
// ///////////////////////  Alex  ////////////////////////
// ///////////////////////////////////////////////////////
function Alexmovetoserve () {
// Se asume que el jugador elevó la pelota y no soltó la tecla, o que quizá empezó el juego con la tecla presionada.
// Hasta que se capte que la tecla no está presionada no se podrá elevar la pelota.
// Es para evitar que en caso de mantener la tecla presionada se eleve la pelota a penas vuelva a la mano.
if (Key.isDown(37)) {
// Se mueve a la izquierda, si no se sale del límite.
if (AlexX>AlexMinXposonserving) {
AlexX = AlexX-Alexrunspeedonserving;
} else {
AlexX = AlexMinXposonserving-Alexrunspeedonserving;
}
setProperty (Alex, _x, AlexX);
} else if (Key.isDown(39)) {
// Se mueve a la derecha, si no se sale del límite.
if (AlexX<AlexMaxXposonserving) {
AlexX = AlexX+Alexrunspeedonserving;
} else {
AlexX = AlexMaxXposonserving+Alexrunspeedonserving;
}
setProperty (Alex, _x, AlexX);
}
if (Teclafuesoltada == 0) {
if (Key.isDown(65)) {
} else {
Teclafuesoltada = 1;
// Ahora al presionar la tecla de nuevo Alex elevará la pelota.
}
} else if (Key.isDown(65)) {
// Tecla A, eleva la pelota.
Funcencurso = "Alexelevandoball";
Teclafuesoltada = 0;
// Qué tan arriba está la pelota y a qué Velocidad sube (todo al revés).
BallZ = -37.6;
BallZSpeed = -0.4;
Alex.gotoAndStop(2);
gotoAndStop (3);
}
}
//
function Alexelevandoball () {
if (Teclafuesoltada == 1 && Key.isDown(65)) {
// La tecla fue soltada y vuelta a presionar; Alex saca.
// La pelota y su sombra, que estaban en la movie Alex (para que se pudieran mover simplemente con mover a Alex), ahora son attached al lv0.
Funcencurso = "Alexserving";
BallX = AlexX+9;
BallY = AlexY;
attachMovie("BallShadowMovie", "BallShadow", 50);
setProperty (BallShadow, _x, BallX);
setProperty (BallShadow, _y, BallY);
BallZ = BallZ*-1;
BallZoom = 100+BallZ;
attachMovie("BallMovie", "Ball", 99);
setProperty (Ball, _x, BallX);
setProperty (Ball, _y, BallY-BallZ);
setProperty (Ball, _xscale, BallZoom);
setProperty (Ball, _yscale, BallZoom);
Timesincebeginserve = -1;
Alex.gotoAndStop(3);
setProperty (Alex.Chispa, _y, BallZ*-1-getProperty("Ball", _height)/2);
setProperty (Alex.Chispa, _xscale, AlexFuerzadetiros*10);
setProperty (Alex.Chispa, _yscale, AlexFuerzadetiros*10);
// Datos para determinar velocidades del tiro.
DistanciahastaDestinoX = 280.1-BallX;
DistanciahastaDestinoY = 180-BallY;
DistanciahastaMinsafeBallZ = BallZ-18.6;
BallZwhenstriked = BallZ;
DistanciahastaDestinoXY = Math.sqrt(DistanciahastaDestinoX*DistanciahastaDestinoX+DistanciahastaDestinoY*DistanciahastaDestinoY);
DistanciahastaRed = DistanciahastaDestinoXY * Math.abs(BallY-300) / DistanciahastaDestinoY;
// Determinando velocidades del tiro.
BallXSpeed = DistanciahastaDestinoX/DistanciahastaDestinoXY*AlexFuerzadetiros;
BallYSpeed = DistanciahastaDestinoY/DistanciahastaDestinoXY*AlexFuerzadetiros;
BallZSpeed = 0;
// Datos para determinar posiciones de la pelota.
Tiempotranscurridodeltiro = 0;
BallXwhenstriked = BallX;
BallYwhenstriked = BallY;
Ballreachedred = 0;
gotoAndStop (4);
} else {
if (Teclafuesoltada == 0) {
// Aún no se soltó la tecla.
if (Key.isDown(65)) {
} else {
Teclafuesoltada = 1;
// Ahora al presionarla de nuevo Alex saca.
}
}
// Disminuye la velocidad de subida y varía la altura.
BallZSpeed = BallZSpeed+0.01;
BallZ = BallZ+BallZSpeed;
if (BallZ<MaxBallZwhenstriked) {
MaxBallZwhenstriked = BallZ;
}
setProperty (Alex.Ball, _y, BallZ);
// Varía el tamaño de la pelota.
BallZoom = 100+BallZ*-1;
setProperty (Alex.Ball, _xscale, BallZoom);
setProperty (Alex.Ball, _yscale, BallZoom);
if (BallZ>=-37.6) {
// Si queda muy abajo (BallZ muy alto), vuelve a la etapa Alexmovetoserve.
Teclafuesoltada = 0;
Funcencurso = "Alexmovetoserve";
Alex.gotoAndStop(1);
gotoAndStop (2);
}
}
}
//
function Ballmoving () {
Tiempotranscurridodeltiro = Tiempotranscurridodeltiro+1;
BallX = BallXwhenstriked+BallXSpeed*Tiempotranscurridodeltiro;
setProperty (BallShadow, _x, BallX);
setProperty (Ball, _x, BallX);
BallY = BallYwhenstriked+BallYSpeed*Tiempotranscurridodeltiro;
setProperty (BallShadow, _y, BallY);
DistanciaXYrecorrida = AlexFuerzadetiros * Tiempotranscurridodeltiro * C;
Senodelangulodeltiro = Math.sqrt(1-C*C);
BallZ = BallZwhenstriked + AlexFuerzadetiros * Tiempotranscurridodeltiro * Senodelangulodeltiro;
BallZ = BallZ - 0.01 * Tiempotranscurridodeltiro*Tiempotranscurridodeltiro /2;
// BallZSpeed = BallZSpeed-0.01;
// BallZ = BallZ+BallZSpeed;
if (BallZ<=0) {
// Si la pelota llega al suelo, BallZSpeed se invierte con disminución según la cancha.
BallZ = 0;
BallZSpeed = BallZSpeed*Fuerzaderebotedepelota;
// Si BallZSpeed es menor que 0.01: Queda en 0.
if (BallZSpeed<0.01) {
BallZSpeed = 0;
}
// La pelots, al rozarse con el suelo, disminuye sus velocidades.
// BallXSpeed = BallXSpeed+Influenciadelrozamiento;
if (BallXSpeed>0) {
BallXSpeed = 0;
}
// BallYSpeed = BallYSpeed+Influenciadelrozamiento;
if (BallYSpeed>0) {
BallYSpeed = 0;
}
}
setProperty (Ball, _y, BallY-BallZ);
BallZoom = 100+BallZ;
setProperty (Ball, _xscale, BallZoom);
setProperty (Ball, _yscale, BallZoom);
if (Ballreachedred == 0) {
if (BallY <= 300) {
        // Si llegó a la red.
        Ballreachedred = 1;
        BallZwhenreachedred = BallZ;
attachMovie("BallShadowMovie", "BallShadow2", 49);
setProperty (BallShadow2, _x, BallX);
setProperty (BallShadow2, _y, BallY);
attachMovie("BallMovie", "Ball2", 98);
setProperty (Ball2, _x, BallX);
setProperty (Ball2, _y, BallY-BallZ);
setProperty (Ball2, _xscale, BallZoom);
setProperty (Ball2, _yscale, BallZoom);
        }
    }
}
//
function Alexserving () {
Ballmoving();
Timesincebeginserve = Timesincebeginserve+1;
if (Timesincebeginserve == Alextimetodownracket) {
// Desaparece la chispa y Alex queda con la raqueta abajo.
Alex.gotoAndStop(5);
} else if (Timesincebeginserve == 5) {
// Deaaparece la chispa.
Alex.gotoAndStop(4);
} else if (Timesincebeginserve == Alextimetoupracket) {
// Alex queda listo para moverse, etc.
Alex.gotoAndStop(6);
gotoAndStop (5);
// Funcencurso = ""; hay q ver si el saque toca la red.
}
}
// falta indicar dirección
// El rozamiento funciona mal, uno se reduce a 0 antes que el otro.
// El tamaño de la chispa debería depender de cuánta fuerza se use, no de la usable.
// Asignar demasiada fuerza hace que la animación no ocurra bien
Funcencurso = "Alexmovetoserve";
[/spoiler]

Sólo lo relevante:
[spoiler] // La mínima BallZ que no toca la red es 18.6.
// Datos para determinar velocidades del tiro.
DistanciahastaDestinoX = 280.1-BallX;
DistanciahastaDestinoY = 180-BallY;
DistanciahastaMinsafeBallZ = BallZ-18.6;
BallZwhenstriked = BallZ;
DistanciahastaDestinoXY = Math.sqrt(DistanciahastaDestinoX*DistanciahastaDestinoX+DistanciahastaDestinoY*DistanciahastaDestinoY);
DistanciahastaRed = DistanciahastaDestinoXY * Math.abs(BallY-300) / DistanciahastaDestinoY;
// Determinando velocidades del tiro.
BallXSpeed = DistanciahastaDestinoX/DistanciahastaDestinoXY*AlexFuerzadetiros;
BallYSpeed = DistanciahastaDestinoY/DistanciahastaDestinoXY*AlexFuerzadetiros;
BallZSpeed = 0;
// Datos para determinar posiciones de la pelota.
Tiempotranscurridodeltiro = 0;
BallXwhenstriked = BallX;
BallYwhenstriked = BallY;
function Ballmoving () {
Tiempotranscurridodeltiro = Tiempotranscurridodeltiro+1;
BallX = BallXwhenstriked+BallXSpeed*Tiempotranscurridodeltiro;
BallY = BallYwhenstriked+BallYSpeed*Tiempotranscurridodeltiro;
        DistanciaXYrecorrida = AlexFuerzadetiros * Tiempotranscurridodeltiro * C;
        Senodelangulodeltiro = Math.sqrt(1-C*C);
        BallZ = BallZwhenstriked + AlexFuerzadetiros * Tiempotranscurridodeltiro * Senodelangulodeltiro;
        BallZ = BallZ - 0.01 * Tiempotranscurridodeltiro*Tiempotranscurridodeltiro /2;
}
[/spoiler]

Si el personaje tiene poca fuerza:
https://drive.google.com/file/d/1bY60WE73Gvh7eUFoRX8NAeuBoWIaYtNJ/view?usp=share_link

Algún error cometí o cometió porque el personaje está aplicando más fuerza de la que tiene y además la pelota debe pasar más cerca de la red.

Con un poco más:
https://drive.google.com/file/d/1YEhAz8nrcztWpttScLOeMekfXlZHUVZ9/view?usp=share_link

¿Qué está mal en el código? ¿o qué falta, qué hago?

mariahcarey

Asegúrate de que la velocidad hacia abajo también cumpla con la restricción de aumento de 0.01 por segundo.

FelipeAguilar

Para ayudarte con este problema, te ofrezco un resumen claro de cómo podrías abordar la física detrás del movimiento de la pelota en tu simulación y algunas sugerencias para implementar las condiciones que mencionas.

Resumen de las condiciones que debes cumplir:
Velocidad de caída: La pelota debe caer aumentando su velocidad vertical (hacia abajo) de manera constante, como una simulación de la aceleración de la gravedad. Tienes definido que aumenta 0.01 por "segundo" (aunque realmente es en centésimas de segundo). Esto se puede implementar como:

js
Copiar código
BallZSpeed += 0.01;  // Incremento constante de velocidad hacia abajo
BallZ += BallZSpeed;  // Actualizar la posición de la pelota en Z
Distribución de la fuerza: Debes asegurarte de que la velocidad en las direcciones X, Y, y Z no exceda la fuerza disponible del jugador. Es decir, la suma de las componentes de la velocidad no puede exceder la fuerza máxima del jugador. Si la fuerza en el eje Y es grande, entonces debe quedar menos disponible para Z y X.

Puedes calcular las velocidades en función de la fuerza total del jugador con algo como:

js
Copiar código
let fuerza_disponible = AlexFuerza;
BallXSpeed = (fuerzaX / fuerza_disponible) * AlexFuerza;  // Proporcional a la fuerza aplicada en X
BallYSpeed = (fuerzaY / fuerza_disponible) * AlexFuerza;  // Proporcional a la fuerza aplicada en Y
BallZSpeed = (fuerzaZ / fuerza_disponible) * AlexFuerza;  // Proporcional a la fuerza en Z
Altura mínima al pasar la red: Debes asegurarte de que cuando la pelota llegue a la red, la altura de la pelota (Z) sea al menos igual a una altura mínima establecida, por ejemplo, 17.5 o 18.6 en tu caso. Esto se puede verificar con una condición:

js
Copiar código
if (BallY >= DistanciahastaRed && BallZ < 18.6) {
    // La pelota no pasa la red, aplicar una corrección o fallo.
}
La pelota debe caer en la cancha rival: Para asegurar que la pelota caiga en la cancha rival, puedes establecer un objetivo para la posición final (X, Y) de la pelota y calcular las velocidades iniciales de manera que la pelota aterrice en el punto deseado:

js
Copiar código
BallXSpeed = DistanciahastaDestinoX / tiempo_total;
BallYSpeed = DistanciahastaDestinoY / tiempo_total;
Prioridad de la velocidad Y (horizontal hacia adelante): La velocidad en Y debe ser lo más alta posible, siempre y cuando se cumplan las otras condiciones. Esto significa que puedes intentar maximizar BallYSpeed en función de la fuerza disponible y luego ajustar las velocidades en X y Z para cumplir con la altura de la red y la distancia objetivo.

Si después de asignar la velocidad en Y, la pelota no cumple las demás condiciones (por ejemplo, no pasa la red o no cae en la cancha), deberás ajustar la velocidad en Y para respetar esas restricciones.

Método sugerido:
Inicializar variables: Define las variables que vas a utilizar, como fuerza del jugador, posiciones y velocidades iniciales de la pelota.

Calcular la trayectoria de la pelota: Basado en la fuerza del jugador y las distancias hacia la red y la cancha rival, distribuye las velocidades entre los ejes X, Y, y Z. Utiliza las fórmulas de cinemática para asegurarte de que la pelota pase por encima de la red y caiga en la cancha rival.

Actualizar la posición de la pelota: Usa un loop de simulación (cada "frame" o centésima de segundo) para actualizar las posiciones de la pelota con base en sus velocidades en X, Y, y Z.

Revisar las condiciones: En cada actualización, verifica que las condiciones se sigan cumpliendo (altura en la red, caída en la cancha, fuerza utilizada, etc.).

Con estos pasos, deberías poder implementar una simulación realista del comportamiento de la pelota cumpliendo con las condiciones que has definido.

telldesigner

Los problemas realmente difíciles requieren conocimientos para dar respuestas adecuadas. Disfrute de las diversas actualizaciones de conocimientos. Experimenta más!






Stratos es un servicio gratuito, cuyos costes se cubren en parte con la publicidad.
Por favor, desactiva el bloqueador de anuncios en esta web para ayudar a que siga adelante.
Muchísimas gracias.