|
1
|
Programación / .NET (C#, VB.NET, ASP) / Re: Bordes redondeado de un cuadrado o rectáncugo.
|
en: 27 Octubre 2024, 20:07 pm
|
Lo que pasa es que los únicos códigos realmente ASCII son los del 0-127. Los demás son una extensión no estándar y sus caracteres varían según la página de códigos configurada. Para usarlos necesitas configurar la consola con la codificación correcta, pero como estamos en 2024, no tiene sentido seguir usando ASCII (extendido) para eso, así que olvídate de esa tabla y mejor usa Unicode, que sí es universal. Vas a necesitar buscar los códigos (o puntos de código, como se les conoce) Unicode de esos caracteres que quieres usar, y por suerte, son tan comunes que tienen su propia entrada en la Wikipedia: https://en.wikipedia.org/wiki/Box_DrawingAsí que lo primero que debes hacer es asegurarte de que tu consola use alguna codificación Unicode. La más recomendable y universal es UTF-8, y la configuras así: Console.OutputEncoding = Encoding.UTF8;
a partir de aquí, ya puedes imprimir caracteres especiales Unicode, usando el prefijo \u. Por ejemplo, en la tabla que hay en el link de la Wikipedia, puedes ver que el caracter ╔ tiene asignado el punto de código U+2554, por lo que lo puedes imprimir así: System.Console.Write("\u2554");
|
|
|
2
|
Programación / .NET (C#, VB.NET, ASP) / Re: Salir de un void
|
en: 31 Agosto 2024, 02:50 am
|
En cuanto al return, me imagino que te refieres que justo antes que acabe un void o función, tenga return true; o el return false;
Sí, pero las void no pueden devolver valores, así que tendrías que cambiar las funciones de los submenús a bool. Te pongo un ejemplo genérico (y medio en pseudocódigo) de cómo podrías hacerlo: void MenuPrincipal() { bool salir = false; do { dibujar menu principal; leer opcion; switch (opcion) { case 1: Ajustes(); break; case 2: SubMenuB(); break; etc ... case N: salir = true; break; } } while (!salir); } bool AjustesPrincipal() { // La variable inicio indicara si se selecciono volver al inicio bool salir = false, inicio = false; do { dibujar menu; leer opcion; switch (opcion) { case 1: salir = inicio = Volumen(); break; case 2: salir = inicio = SubMenuB(); break; etc ... case Atras: salir = true; break; case Inicio: salir = inicio = true; break; } } while (!salir); return inicio; }
Con Volumen y todos los demás submenús harías esencialmente lo mismo que con AjustesPrincipal: bool Volumen() { bool salir = false, inicio = false; do { dibujar menu; leer opcion; switch (opcion) { case 1: instrucciones; break; case 2: // Si volumen llamara a un submenu, habria que hacerlo tambien asi: salir = inicio = SubMenu(); break; etc ... case Atras: salir = true; break; case Inicio: salir = inicio = true; break; } } while (!salir); return inicio; }
Puede que tengas que reestructurar un poco tu código, pero eso debería funcionar. Como mencionaste lo de los goto, si acaso necesitaras que cuando se seleccione "Atrás" o "Inicio", la función retorne inmediatamente sin pasar por el while, podrías hacerlo así: case 2: // Si volumen llamara a un submenu, habria que hacerlo tambien asi: inicio = SubMenu(); if (inicio) return true; break; etc ... case Atras: return false; break; case Inicio: return true; break; } } while (!salir);
Así que ni siquiera en este caso hay necesidad de gotos. De hecho, prácticamente nunca hay que usarlos (hay poquísimas excepciones donde pueden ser útiles).
|
|
|
3
|
Programación / .NET (C#, VB.NET, ASP) / Re: Salir de un void
|
en: 30 Agosto 2024, 16:54 pm
|
Primero que nada, deberías repasar los fundamentos, porque te estás complicando mucho con cosas más bien triviales, además de que la sugerencia de quitar el bucle era tan disparatada, y tan obvio lo que iba a suceder, que no sé cómo se te ocurrió siquiera probarla.
En cuanto al problema, en general, si tienes una secuencia de llamadas de funciones tipo:
A --> B --> C --> D
deberías intentar evitar que cualquiera de esas funciones llame a alguna de las anteriores (B no debería llamar a A, C no debería llamar ni a A ni a B, etc.). Si por ejemplo, estando en D, quieres volver al submenú anterior (C), la solución NO es llamar a C, sino simplemente dejar que D termine su ejecución, retornando de forma normal.
Si también quieres que, por ejemplo, desde D o C sea posible volver al menú inicial (A), lo único que cambia es que estas funciones deberían devolver un valor que indique que se seleccionó la opción del menú principal. Suponiendo que sea un bool, lo que harías sería que cuando desde una función se desea volver al inicio, ésta termine con un return true (y en todos los demás casos, retornar false). Asimismo, todas las funciones, al invocar a otra, deberán verificar el valor que retorne, y si es true, deberán terminar su ejecución, devolviendo a su vez true, es decir, este valor se propaga a lo largo de la secuencia de llamadas, lo cual hará que termines volviendo al menú inicial de forma limpia.
Para que todo esto funcione, tienes que cambiar tus funciones de manera que los menús se impriman dentro de los bucles.
|
|
|
4
|
Programación / Programación C/C++ / Re: alguien me puede decir en que falla
|
en: 6 Agosto 2024, 21:31 pm
|
Es verdad que no es recomendable usar eñes o acentos en los nombres de identificadores. Y eso que desde hace más de 10 años los estándares de C y C++ definen un buen rango de caracteres Unicode válidos, entre los cuales están vocales con acento y la ñ, por lo que no tiene nada de extraño que los compiladores modernos los acepten, de hecho es lo esperado. El problema viene más bien con los editores de código y los IDEs, pues aunque la mayoría trabajan sin problemas con Unicode, hay que asegurarse de que usen exactamente la misma codificación que el compilador que vamos a usar. En cambio, si nos limitamos únicamente a los caracteres ASCII estándar de toda la vida, nunca tendremos problemas.
Y por cierto, no confundamos compiladores con IDEs, que son cosas completamente diferentes. Eso ocasiona muchos problemas entre principiantes. Aquí mismo en el foro he visto cualquier cantidad de hilos donde el problema es justo ése, y luego les dan "soluciones" completamente erróneas debido a que ni quien preguntó ni quien contestó entendían esa diferencia. CLion es sólo un IDE. Los compiladores son GCC, Clang, Visual C++, MinGW, entre otros, y los IDEs simplemente los invocan, evitándonos teclear comandos. Si en Windows CLion incluye MinGW, es sólo para conveniencia del usuario, ya que son herramientas completamente independientes. La idea es que cada uno configure su IDE para que use el compilador que prefiera. Incluso en el caso del propio CLion, si lo usamos con MSVC, es casi seguro que el código con eñes así, de inicio, no va a compilar, ya que, a diferencia de MinGW, MSVC espera que los archivos fuente, si tienen caracteres no ASCII, incluyan marca de orden de bytes, pero los editores/IDEs no suelen ponerla de forma predeterminada, por lo que habría que cambiar manualmente eso en la configuración.
Pero reitero, si omitimos caracteres "especiales", nos facilitamos mucho las cosas y ni siquiera necesitamos saber nada de lo anterior. Bueno, salvo la distinción IDE/compilador: eso sí es indispensable tenerlo bien claro, especialmente si programamos en C o C++.
|
|
|
5
|
Programación / Programación General / Re: ¿Cómo la PC usa los códigos?
|
en: 2 Marzo 2024, 00:09 am
|
Lo que te aconsejaría es que simplemente programes como te sea a ti más conveniente. Incluso al crear programas en lenguajes que generan código nativo, como C y C++, determinar a priori si llamar a una función es más/menos rápido, genera código más/menos grande, etc. que escribir directamente el código, es prácticamente imposible, y si en algún lugar lees lo contrario, quien lo escribió no tiene idea de lo que habla. Únicamente analizando el código exacto en cada caso se pueden hacer estimaciones, y aún así es muy complejo y depende de muchas cosas.
Además, tú programas en Flash, el cual hasta donde sé, no compila el ActionScript a código nativo sino a byte code que el reproductor (ya sea el independiente o el que se incluye en los .exe) ejecuta, por lo que casi cualquier explicación general que te den, sea ChatGPT o una persona, te servirá de poco o nada. Sólo alguien que conozca a fondo cómo funciona internamente Flash 5 podría contestar bien tus preguntas. Yo te podría contestar cómo es en los programas nativos, pero es casi 100% seguro que nada de eso aplica para Flash, por lo que no le veo mucho caso.
Lo que podrías hacer es probar escribiendo código de una y otra forma y comparar su ejecución. A menos que notes una diferencia importante (y realmente lo dudo), lo mejor es, como te dije al inicio, que programes como te guste a ti.
|
|
|
6
|
Programación / Programación C/C++ / Re: ayudaaa tengo un problema con ERROR: Id returned 1 exit status
|
en: 7 Diciembre 2023, 05:08 am
|
Como te dijo MAFUS, es error del enlazador o linker. En este caso me imagino que será porque en la línea 15 pusiste prinf en lugar de printf (falta la 't').
Como referencia futura, siempre hay que poner los mensajes de error completos, pues eso de "ld returned..." por sí solo no sirve de mucho. Por fuerza el compilador/linker debe haberte dado más información (algo tipo "undefined reference to prinf"). Si usas un IDE, probablemente eso lo encuentras en una pestaña llamada output, build log, build messages o similar.
|
|
|
7
|
Programación / Programación C/C++ / Re: campos de bits
|
en: 5 Octubre 2023, 19:42 pm
|
Sí, además de su función principal, volatile puede ser útil al depurar, y en casos como éste, también puede ser válido. Ojo, en ningún momento pretendo decir que todos los ejemplos de los primeros mensajes estén "mal". Se entiende que son cosas que uno normalmente no usaría para cosas más reales (aunque no está de más decir que, aún en códigos simples de ejemplo, violar las reglas nos puede traer más de una sorpresa desagradable). Pero hay gente, incluso aquí en el foro, que a veces intenta ya no sólo experimentar sino implementar cosas de bajo nivel en sus programas. Por ejemplo, hace poco un usuario estaba haciendo algo similar a un editor hexadecimal. Mis recomendaciones, y lo que sigue, son sobre todo para quien quiera hacer cosas así, "reales". Primero, para saber más sobre el tema, se puede googlear "strict aliasing" que es como se conoce a la regla de la que hablo en mi mensaje anterior. Y hay unas cosas que es fundamental entender: 1) Esto lo recalco de nuevo, cuando un programa hace cosas que el estándar cataloga como "undefined behaviour", el resultado, y las acciones del compilador, se vuelven impredecibles y éste puede hacer lo que quiera y a menudo hace cosas distintas en versiones distintas. Otra referencia más en FAQ de C: https://c-faq.com/ansi/undef.html . 2) Las optimizaciones que el compilador hace son totalmente dependientes del contexto. Dado un conjunto de líneas, su optimización puede ser totalmente distinta si las metemos en un for, o en dos for anidados, o si hay un if, o si las variables a las que acceden son globales o locales, o parámetros recibidos, o si la función es inline, etc., casi cualquier cosa lo altera. 3) Si el programa está escrito correctamente, un compilador jamás va a cambiar su comportamiento observable y su funcionamiento. Los ejemplos anteriores fallan únicamente porque violan el strict aliasing. Si se cambian de manera que respeten esta regla (usando unsigned char*, por ejemplo) se arreglan de forma permanente. El calificador volatile no es realmente solución; en todo caso, es un parche temporal. De nuevo, si se googlea sobre el tema, van a salir muchos resultados de fuentes confiables, ninguno de los cuales sugiere siquiera a volatile como solución (los pocos que lo mencionan básicamente dicen: "no arregla el problema. Si te sirve es suerte"). El propio Linus Torvalds dijo lo siguiente cuando alguien supuso que volatile servía para arreglar estos problemas: "sí, volatile podría funcionar, pero es como matar una mosca con una bomba atómica (...) y no hay garantía de que el compilador no haga las optimizaciones, aún con acceso volatile, así que de todas formas es un punto irrelevante". En términos prácticos, con volatile el compilador desactiva optimizaciones relacionadas con el acceso a las variables calificadas de esta manera (ya no las elimina, y para cada lectura, se traen sus valores de la memoria, etc.), pero eso no tiene nada que ver con el aliasing, lo que pasa es que en algunos contextos, como mis ejemplos, la única optimización que hace el compilador al encontrar UB coincide, de forma fortuita, con las que deshabilita volatile. Pero hay toda una gama de cosas que el compilador puede hacer (eliminar instrucciones que producen UB, reordenarlas, etc.) que vuelven a romper los programas a pesar de usar este calificador. No quiero que salga un mensaje aún más largo de lo que es, y no le veo sentido a poner más ejemplos (siempre se puede encontrar un "parche" que arregle de momento el programa, y luego poner un nuevo ejemplo con las instrucciones reacomodadas/cambiadas de manera que el parche no funcione, y luego otro parche, y así nos pasamos la vida, porque no estamos arreglando el problema) pero nada de esto es hipotético, pasa en la realidad. Por no hablar de otros problemas, como la alineación incorrecta. De esto también hay ejemplos reales, incluso en x86-64 (donde algunas instrucciones producen errores de violación de acceso si los datos no tienen una alineación específica), y derivados de violar el strict aliasing. La única solución general es seguir las reglas del lenguaje, en este caso, respetar el strict aliasing. Usar punteros char o memcpy (con ciertas precauciones) son maneras válidas. De esta manera nos quitamos de cualquier preocupación. Los programas van a funcionar siempre, en cualquier compilador que acepte la versión del lenguaje elegido, y con cualquier nivel de optimización. Si forzosamente necesitamos acceder a datos mediante punteros a tipos incompatibles (en unas pocas ocasiones puede ser conveniente), lo que se debe hacer es compilar con -fno-strict-aliasing o equivalente. Esto le dice al compilador que vamos a violar el strict aliasing, y así sabe exactamente que debe desactivar las optimizaciones específicas a esta regla (y no otras que podrían o no arreglar estos problemas en un contexto dado). Y todo esto sin los problemas de rendimiento que trae volatile.
|
|
|
8
|
Programación / Programación C/C++ / Re: campos de bits
|
en: 3 Octubre 2023, 02:48 am
|
Como aquí estamos poniendo sólo ejemplos ilustrativos, creo que es válido ver la representación interna de las variables de esa manera, pero reitero que lo mejor es usar un unsigned char* y recorrer con él los bytes de la estructura, ya que, en general, en C y C++ no es válido acceder a una variable mediante un puntero a un tipo distinto. Una excepción son los punteros a char (con o sin signo), los cuales sí se pueden usar con variables de otros tipos. Hay otras excepciones (por ejemplo, un puntero unsigned/signed puede acceder a datos signed/unsigned, siempre que sean del mismo tipo) pero son muy pocas. Romper esa regla resulta en comportamiento indefinido o UB, y en ese caso los compiladores pueden hacer prácticamente lo que quieran. Pudiera parecer estos son sólo problemas teóricos, pero no es así, pues constantemente se encuentran problemas derivados de estos malos usos. Aquí pongo unos ejemplos: #include <stdio.h> typedef struct { unsigned char codigo : 4; unsigned short cantidad : 9; unsigned char procedencia : 1; unsigned char basura : 2; } producto_t; producto_t* prod; int main() { unsigned base[2] = { 0 }; prod = (producto_t*)&base; prod->codigo = 5; prod->procedencia = 1; prod->cantidad = 4; prod->basura = 3; printf("base : %08x %08x\n", base [1], base [0]); }
En GCC o MinGW, si se compila con -O2 o superior, la salida es: Lo que pasó es que el compilador decidió optimizar el programa y dejar sólo esto: printf("base : %08x %08x\n", 0, 0);
es decir, directamente imprime los valores con los que base fue inicializado. Puesto que *prod y base tienen tipos distintos e incompatibles, no es válido modificar base mediante ese puntero, así que el compilador decide que base jamás fue modificado luego de su inicialización. Otro ejemplo casi igual pero con un resultado todavía peor: #include <stdio.h> typedef struct { unsigned char codigo : 4; unsigned short cantidad : 9; unsigned char procedencia : 1; unsigned char basura : 2; } producto_t; producto_t* prod; int main() { unsigned base[2] = { 0 }; prod = (producto_t*)&base; prod->codigo = 5; prod->procedencia = 1; prod->cantidad = 4; prod->basura = 3; base[0] = base[0]; base[1] = base[1]; printf("base : %08x %08x\n", base [1], base [0]); printf("codigo: %u\n", prod ->codigo ); printf("procedencia: %u\n", prod ->procedencia ); printf("cantidad: %u\n", prod ->cantidad ); printf("basura: %u\n", prod ->basura ); }
de nuevo, GCC y MinGW arrojan esta salida: base : 00000000 00000000 codigo: 0 procedencia: 0 cantidad: 0 basura: 0 por las mismas razones de antes. Y esto no se limita a GCC, sino que cada compilador tiene sus "detalles". Por ejemplo, hace años alguien reportó un posible bug en clang. El ejemplo que puso era más o menos así: #include <stdio.h> int main() { int par[2] = { 1 }; int k = 0; for (int i = 0; i < 1; i++) { if (par[1] > 0) { *(short*)&par[0] = 5; } par[k++] = 0; } printf("Esto deberia ser 0: %d\n", par [0]); }
con -O1 o superior, en clang da esta salida: Edit: corrijo números de línea se supone que siempre debería ser 0 porque la última instrucción que se ejecuta antes del printf es la de la línea 12, pero el compilador hace lo que quiere, porque la línea 10 contiene UB (¡a pesar de que nunca se va a ejecutar, ya que la condición del if forzosamente será falsa!). Si se cambia el short* por char*, ahí la modificación ya es válida y el programa imprime 0, como se esperaba. Estos ejemplos pueden parecer muy rebuscados o "artificiales", pero la realidad es que normalmente ese tipo de problemas se encuentran al estar trabajando en programas reales. Obviamente uno no va poner programas enteros en los foros o en reportes de bugs, así que se busca crear un ejemplo lo más básico y simplificado posible que muestre el problema, pero estas cosas ocurren todo el tiempo en programas de todo tipo y tamaño, y de hecho hay tanto debate al respecto, que hay muchas conferencias hablando sobre el tema y justificando (o no) lo que hacen los compiladores. Como muchos otros programadores, no soy fan de optimizaciones tan agresivas como éstas, y para mí, el caso de clang debería considerarse un bug (si experimentamos un poco con el código, obtenemos resultados aún más raros), pero sus desarrolladores no piensan así, y nunca lo arreglaron. Técnicamente, el estándar de C (y C++) les da la razón. El caso es que esté o no uno de acuerdo, los compiladores hacen este tipo de cosas cuando encuentran código que viola el estándar, así que es mejor intentar apegarse a las reglas.
|
|
|
9
|
Programación / Programación C/C++ / Re: campos de bits
|
en: 29 Septiembre 2023, 05:00 am
|
Como ya te recomendaron, es mejor que evites los campos de bits si puedes, ya que no tienes casi ningún control sobre la manera en que el compilador los almacena. También hay unas cosas que creo que vale la pena comentar. Los compiladores tienen ciertas libertades con las estructuras, pero lo que hacen no es aleatorio, y además hay reglas que tienen que seguir. Si dejamos de lado de momento los campos de bits, tenemos algunas garantías con las estructuras: el compilador siempre colocará en memoria los campos en el orden en que los declaramos. Puede haber relleno (padding) entre algunos, pero el orden siempre se respeta. Y la dirección del primer campo es la misma que la de la estructura, es decir, está exactamente al inicio. Luego, hay otras reglas no oficiales, pero que los compiladores en general siguen. Por ejemplo, los compiladores normalmente acomodan los campos de acuerdo a su alineación natural, es decir, en qué direcciones de memoria conviene que estén. Si para lograrlo deben meter bytes de relleno (padding), lo hacen. Esto en general se puede evitar declarándolos de manera que ya estén alineados (no basta con sólo agruparlos por tipo). No sé si quisieras información más detallada, pero como estás empezando en estos temas, a lo mejor te podría confundir. Con los campos de bits es más complicado y depende del compilador y la arquitectura, pero tampoco es totalmente arbitrario. De nuevo, sin entrar en detalles, baste decir que tiene sentido la manera en que los está organizando y ordenando el compilador en este caso y que, aunque acostumbramos leer de izquierda a derecha, en realidad los dígitos se enumeran de derecha a izquierda. En los últimos ejemplos, el problema principal es, como ya te dijeron, el hecho de usar union. Y esto no sólo aplica a las estructuras, sino que, en general, se supone que sólo uno de sus miembros es válido en un momento dado: el último que hayas modificado. Es decir, si haces esto: vec.producto.codigo = 5;
lo más correcto sería que, a partir de ahí, consideres a vec.empaquetado como inactivo o "inválido" y no accedas a él. Si después modificaras el otro miembro: vec.empaquetado = loquesea;
ahora este miembro es el activo y vec.producto se inactiva, y así sucesivamente. De hecho, en C++ es incorrecto acceder al miembro "inactivo" (aunque compila y en general funciona, técnicamente no es válido). En C se permite y a veces se hace, pero no se recomienda, pues puede dar pie a errores. Finalmente, para ver la representación interna de una estructura, es mejor usar punteros a unsigned char, no unions, y menos mediante un miembro entero, pues ¿qué tipo de dato debería tener empaquetado, si no sabemos a priori cuál es el tamaño de la estructura producto_t? Eso es parte del problema que se está dando, ya que en el ejemplo la estructura ocupa 6 bytes, pero empaquetado es unsigned short int (2 bytes) o unsigned int (4 bytes). No es que procedencia y basura estén escondidos o perdidos; están ahí, pero empaquetado no tiene el tamaño suficiente para mostrarlos. Se podría cambiar a un tipo de dato de 64 bits (aunque ya no se podría usar el especificador %X para imprimirlos sino que habría que recurrir a la macro PRIX64), pero de nuevo, esta no es una manera aconsejable de usar union y estamos adivinando qué tamaño tendrá la estructura. Lo mejor, reitero, sería usar un unsigned char* que apunte a la dirección de vec.producto, y vaya recorriendo por sus bytes y mostrándolos. O en todo caso, si no quieres usar punteros, puedes hacer que empaquetado sea arreglo de caracteres como lo hacías originalmente: unsigned char empaquetado[sizeof(s_producto)];
y vas iterando, desde 0 hasta sizeof(s_producto) - 1: printf("%02X ", vec. empaquetado[i ]);
aunque, dado que la arquitectura x86 (y x86-64) es little-endian (es decir, se almacena primero el byte menos significativo, o más a la derecha), los datos te aparecerían de manera inversa a la que probablemente esperarías, por lo que tal vez sea mejor mostrarlos al revés, iterando desde sizeof(s_producto) -1 hasta 0.
|
|
|
10
|
Programación / Programación General / Re: Ayuda con cálculos para que la trayectoria de una pelota cumpla ciertas condiciones.
|
en: 17 Mayo 2023, 03:01 am
|
Pienso lo mismo pero en mis ejemplos no parece ocurrir. ¿No? Pues es que si el método y la gravedad no son correctos, los resultados tampoco lo serán. Debes que imaginar que el jugador es perfecto en cuanto a inteligencia y puntería y quiere que la bola caiga en cierto punto, para lo cual usará toda la fuerza que pueda (según la que tenga, en ese sentido no es perfecto), no la mínima necesaria; no hará globitos si puede hacer que el tiro sea rápido y pase cerca de la red. No sé si has entendido eso.
Claro. Pero el párrafo de donde sacaste esa frase es hipotético. Ya sé que no buscas la fuerza mínima necesaria, pero lo usé como ejemplo para explicar la relación entre el ángulo la y distancia recorrida. En cuanto a tu código, tienes varios errores. Fíjate bien lo que te puse, y de ser necesario, ve las explicaciones de mensajes anteriores, porque además te estás saltando algún paso. Por ejemplo, aquí: DistanciahastaRed = DistanciahastaDestinoXY*Math.abs(RedZ-BallZ)/Math.abs(DistanciahastaDestinoY); En vez de RedZ-BallZ va RedY - BallY. Luego, como te comenté (y expliqué con más detalle en mi segundo mensaje), si Disc es negativo, no puedes hacer el tiro, no tienes la fuerza necesaria, así que ya ni siquiera tiene sentido calcular los ángulos y todo lo demás. En todo caso, podrías escoger un nuevo destino más cercano, como lo mencionaste en relación al punto 5, y repetir el procedimiento a ver si este sí lo puedes hacer. Además, fíjate que después de calcular AlturaEnRedTheta y AlturaEnRedPhi puse: Si ambos pasan por encima, elige el más alto o bajo, según prefieras Pero tú ya directamente supones que ambos lo hacen y pasas a elegir el ángulo más bajo. Primero debes comprobar si alguno de los ángulos pasa por arriba de la red. Si sólo uno de los ángulos lo hace, obviamente lo tienes que usar, no hay otra opción. Únicamente si ambos pasan sobre la red, toca elegir el más bajo o alto. Y naturalmente, si ninguno lo consigue, toca aquí también elegir nuevo destino o lo que quieras. Ah, el tema del pique se me complica, mejor luego del pique vuelvo al método simple de sumar ¿no? Pues sí, podrías probar en ese caso tu método simple. Al final lo que estás haciendo es un juego y no una simulación perfecta, así que puede que con eso tengas un resultado aceptable. En relación a lo anterior, este cálculo no es correcto: BallZSpeed = BallZ-BallZAnterior; porque simplemente te daría la velocidad promedio a lo largo del último intervalo de tiempo, en este caso, el último segundo (porque creo que incrementas el tiempo un segundo a la vez, ¿no?), pero tú lo que buscas es el valor de la velocidad en el instante actual, que es distinto. La forma de hacerlo sería esta: BallZSpeed = VelocidadZ - Gravedad * Tiempotranscurridodeltiro; Una última cosa: supongo que estás usando escalas adecuadas, ¿no? Por ejemplo, suponiendo que quisieras modelar una cancha con longitud de 20 m, y que en el juego mida 400 pixels, esto significaría que cada metro equivale a 20 pixels (400 / 20 = 20). Si eliges arbitrariamente la gravedad y le pones 1 pixel/s 2, por ejemplo, vas a tener resultados absurdos, porque eso significaría que la gravedad equivale a 1/20 m/s 2 = .05 m/s 2. ¡Más débil incluso que en la luna! Para tener resultados coherentes, debes elegir valores realistas para la gravedad, fuerza, altura inicial y altura de la red, y multiplicarlos por este factor de escala. Siguiendo con este ejemplo, sería: Gravedad = 9.8 m/s 2 * 20; AlexFuerzadetiros = 25 m/s * 20; etc.
|
|
|
|
|
|
|