Jump to content
UnitySpain

Aceptamos donaciones vía Paypal.

UnitySpain.com es un servicio gratuito, pero mantener la Comunidad conlleva una serie de gastos.

Fondo Anual Unityspain: Donados 51,34€ de 150,00€

  • Servidor: Dominio.com y Hosting Web
  • Mantenimiento de los Foros
  • Contenido y Servicios Extras
  • Mantenimiento para Redes Sociales

Leaderboard


Popular Content

Showing most liked content since 05/17/2019 in all areas

  1. 3 likes
    Creo que todos los niños de mi época han visto la película Twister al menos una vez. Claro que no era perfecta pero dió a conocer por el mundo a los cazadores de tormentas. A mi me encantó... Me llamo Manuel, vivo en Madrid y desde ese momento me empecé a interesar por los tornados. Hace unos tres años, iba por Castilla La Mancha con el coche en pleno verano y vi unos cuantos remolinos de polvo (dust devil en inglés) debido a la tierra caliente y pensé.... "con lo que molan los tornados, qué raro que no haya ningún videojuego sobre ellos". Acababa de publicar mi primer juego en Steam (City Z) y decidí empezar a probar tornados en Unity 3D para ver si había algún potencial. Tan sólo encontré una demo visual que me gustó y empecé a modificarla añadiendo física y mejores efectos. En ese momento me pareció bastante impresionante y decidí crear el primer videojuego (que yo sepa) sobre cazadores de tormentas. Desde entonces, el juego ha evolucionado muchísimo cómo habéis podido ver en el vídeo y creo que ya ha llegado a la calidad suficiente para poder ser lanzado en acceso anticipado en Steam. Queda mucho por mejorar o añadir pero el núcleo del juego ya parece bastante divertido. Características del juego: Modos de juego - Misiones en solitario para aprender las bases del juego - Multijugador online 1 vs 1, 2 vs 2 or 4 vs 4 para jugar contra otros cazadores de tormentas - Tipos de juego variados: Fotografía, Brote de tornados, Controla el tornado... etc. Entorno - Física realista de los tornados con fuertes vientos y destrucción de objetos cercanos - Mapa grande y detallado inspirado en los paisajes de la Tornado Alley - Condiciones climáticas cambiantes y distintas horas del día Gameplay - Algoritmo complejo para evaluar la calidad de las fotos: distancia, focus, escombros visibles... etc. - Distintos coches equipados con radares meteorológicos para medir la actividad de las tormentas - Pods de monitorización para medir la velocidad del viento y su dirección en el suelo Otros - Galería de imagen para gestionar tus fotos y compartirlas en Steam - Emisoras de radio FM modificables para que escuches tu radio favorita en el coche - Posibilidades de ver vacas volando Poco más, éste es el enlace del juego en Steam: Ficha del juego en Steam El lanzamiento en acceso anticipado está previsto para principios de junio y ando retocando cosillas y arreglando errores. Pues nada, aquí me despido, muchas gracias por vuestro interés y no dudéis en comentar dudas o sugerencias. Os dejo con una captura de pantalla que he tomado ayer para que veáis los últimos avances en cuanto a representación de las superceldas:
  2. 2 likes
    Yo mismo después de un rato solucione mi problema por si a alguien le pasa en alguna ocasión. El error se debía a que cuando guarde el archivo en excel .csv lo guarde con separaciones por medio de ' ; ' y después desde el código lo estaba identificando por medio de ' , '. Espero alguna vez le sirva a alguien mi caso :)
  3. 2 likes
    La acción sería que baje de 1 en 1, pero de 1 en 1 no nos dice absolutamente nada, que es de 1 en 1, 60 veces por segundo? 200 veces por segundo? cada 1 segundo ? ... como te dice leocub con un "stay" podrías verificar una y otra vez, pero eso sí, va a bajar horriblemente rápido si no hacés algo al respecto, por ejemplo con un simple flag podés hacer algo así, con una corrutina: public float duracion = 1f; Coroutine perderVidaCoroutine; void OnCollisionStay( Collision col ) { if( personajeDisponible ) perderVidaCoroutine = StartCoroutine( PerderVida() ); } IEnumerator PerderVida() { vida--; personajeDisponible = false; //con esto no re-disparás la corrutina una y otra vez yield return new WaitForSeconds( duracion ); //termina en 1 segundo por defecto personajeDisponible = true; } Creo que podés ver si X corrutina se está reproduciendo, eso en este caso sería ideal, nunca lo usé.
  4. 2 likes
    Perdón por tardar en contestar, pero gracias a todos! Al final he conseguido el efecto que quería ayudado por vuestros consejos. En respuesta a @pioj he de decir que leí que muchas veces se abusa del lerp cuando se puede usar MoveTowards que es más eficiente para la cpu. Toda la razón, @lightbug Gracias, @Cappa, me guardo tu script. Me vendrá bien más adelante. Os dejo con el código con el que al final lo he solucionado por si le viene bien a alguien en un futuro. public class CameraController : MonoBehaviour { // Vars assigned in inspector (public) public Transform firstPersonCamera = null; public Transform thirdPersonCamera = null; // Private vars private Transform target = null; void Update () { if (Input.GetKeyUp("v")) { if (transform.position == thirdPersonCamera.position) { target = firstPersonCamera; } else { target = thirdPersonCamera; } } if (target) { transform.position = Vector3.MoveTowards(transform.position, target.position, 5 * Time.deltaTime); } } }
  5. 1 like
    Buenas, despues de tanto tiempo y varios juegos aplazados JeicoGames presenta Factory Cubes, pruebenlo, califiquen y comenten en play store y me avisan si les sale banners o publicidad, Gracias, https://play.google.com/store/apps/details?id=com.jeicogames.FactoryCubes
  6. 1 like
    Our new editor for Linux (in preview for Ubuntu and CentOS) brings the benefits of real-time to a whole new platform. For years, we’ve offered an unofficial, experimental Unity Editor for Linux. A growing number of developers using the experimental version, combined with the increasing demand of Unity users in the Film and Automotive, Transportation, […] Ver artículo completo...
  7. 1 like
    Requiem for Erich Sann Actualizamos post con información de todo lo nuevo de Requiem for Erich Sann. Enlace Play Store: Enlace Apple Store: Juego en primera persona, realizado con Unity 3D. El objetivo del juego consiste en salir vivo de la casa con el preciado instrumento que obsesiona al protagonista. Os dejo un video introductorio y se agradece cualquier tipo de review, crítica, opinión... https://www.microsoft.com/en-us/p/requiem-for-erich-sann/9p8lwl0lwcdf El juego es totalmente gratuito y está disponible de momento en la Microsoft Store para X64, X86 y ARM Espero que os guste.
  8. 1 like
    Hola perdón por la espera xD, ya lo solucioné para que se cumpliera la condición si o si lo que hice fué establecer la posición del objeto con anterioridad. Pero gracias de todas formas ahora entiendo que si quiero que pase algo (por ejemplo: si el personaje llega a un sitio que salte una cinemática) es mejor seleccionar un rango que poner medidas exactas, lo que no se si es mejor hacerlo como me dijistes con vector3.Distance o que si el personaje entra en contacto con un collider que salte la cinemática.
  9. 1 like
    Hola Marianito, Lo que intentas hacer es muy sencillo te explico: En primer lugar, un Canvas es solo el receptaculo donde pondrás objetos "Text", que no son más que Objetos "Empty" pero con una serie de componentes adicionales que te permiten añadir textos en pantalla. 1 Por un lado necesitarás crear un script en C# (no hay otra manera de hacerlo), y este código lo que hará es buscar el valor (string) que ha de pintar en pantalla. Desde este script, has de conseguir la referencia al componente de texto de la siguiente manera: void Awake() { //Obtener referencia del componente. private Text text = gameObject.GetComponent<Text>(); //Ponemos 123456 en el Texto del Canvas. text.text = "123456"; ... } 2 Seguramente habrás de leerlo de otro script donde recoges los valores y los operas. También lo has de hacer en C#, y hay varias maneras de hacerlo. Lo mejor es que mires un tutorial de principiante, pero no es dificil. Un saludo!
  10. 1 like
    Podés hacer dos cosas (que se me ocurren): 1 - Usar LightProbes, con esto podés samplear puntos en el espacio y la luz resultante es aplicada al objeto dinámico. Busca en youtube hay mucha infromación al respecto, yo solamente los probé hace tiempo pero nunca más los usé. Aca te dejo un vid: https://www.youtube.com/watch?v=pzbebc0Ryv8 2 - Usar GI de tiempo Real, por supuesto la idea de hacer un bake es evitar esto (para no sacrificar tanta performance) pero bueno, sigue siendo una solución valida. 3 - Hacer un fake, pone una luz falsa que simule la iluminación del entorno en ese volumen que querés, sin sombras ni nada. Eso sí, tenés que tener cuidado con los objetos que pueden bloquear la luz. Una válida es emitir la luz con una spot desde debajo del suelo, en el ejemplo de la foto funcionaría parecido, aunque no igual, y la fuente estaría fuera del volumen. Para casos rapiditos funciona muy bien y no cuesta nada. Dependerá de tu objeto animado, si es un objeto animado pero que siempre está en un mismo lugar (un arbol por ej) no pasa nada, si tu objeto animado es el player iría por 1 o por 2 (o 3 con cuidado).
  11. 1 like
    Windows tiene una configuración para todo este tipo de cosas, desde la configuración de Idioma y teclado podes encontrar todo este tipo de cosas, el carácter de separación de decimales, el signo de la moneda etc..
  12. 1 like
    Y como es que sabés que "en teoría" funciona si no te sale nada en consola (en realidad en teoría es poco probable que se cumpla). Yo tenía un amigo que cada vez que poniamos un break en código él quería hacer una variable para comprobar que en realidad X cosa pasara porque por alguna razón u otra sospecha que el lenguaje de programación lo podía estar traicionando , como que era algo maleable y dependía del clima... aca pasa algo similar pero con el Debug.Log, el lenguaje es así y si no ves lo que imprime en memoria pasa una de las dos: No tenés habilitado la impresión o el log de mensajes (que ojo! puede ser, me ha pasado), lo habilitas con el boton dentro de la consola (al lado de los errores) No se cumple la condición del if (probablemente sea esta). Osea que volviste al punto inicial , Lee de vuelta esto: Estás usando = en vez de == (no se si es así en tu código o pasa acá) --> Usar == para float's no es recomendable usá Mathf.Approximately ---> Aun así verificar igualdad no queda lindo en este caso (aclaro que no se como es que el objeto se mueve), la matemática de punto flotante tiene errores, que un objeto se mueva libremente, tenga la posición <x,y,z> y que vos termines por verificar eso en un if y sea correcto es muy poco pobrable, ah no ser que antes hayas impuesto que ese valor sea <x,y,z> en un momento dado, cosa que no se si estás haciendo. Osea, si querés verificar la posición asegurate que el objeto que vas a mover llegue a la posición (no más o menos, sino que lo haga --> =), para esto podés usar vector3.MoveTowards o verificar si está cerca de la posición con Vector3.Distance (la cercanía la elegís vos). ---> Un error que tuve anteriormente, puse que uses Mathf.Aproximately, para floats está bien, pero para vectores el mismo operador "==" hace uso de esto! (Vector3.Equals no lo hace)... ups! https://docs.unity3d.com/ScriptReference/Vector3-operator_eq.html No cometas el típico error de la soberbia de programación, lo digo porque es extremadamente común si arrancás a programar pensar de la siguiente manera "No importa lo que haga, esto tiene que andar y si no anda el problema no es lo que yo hice, el problema tiene que ser esto otro (Debug.Log en tu caso)". Trata de evitar esos valores super exactos de posición que nunca se van a dar, probá métodos como Vector3.distance, incluso si desde afuera del script especificas la posición exacta para el objeto en cuestión "Vector3(-114.15f, 2.04f, -95.61f)" intenta reemplazar eso por un transform que haga de posicion objetivo (por supuesto asegurandote que al final al objeto lo movés a esa posición objetivo), el if te quedaría así: if (evento.transform.position == objetivo.transform.position ) { Debug.Log("Evento"); } Saludos!
  13. 1 like
    si lo metes en OnColliderStay o OnTriggerStay seguirá bajando.
  14. 1 like
    No es tan sencillo de hacer, por lo menos a lo primero, yo lo veo así: Cuadro 1: BOLA: Movimiento Normal de la bola Situación: cayó sobre la plataforma (suelo = true) Registras los datos de la plataforma, transform sobretodo, con esto vas a poder sacar dos datos importantes en el cuadro que sigue (y en los que le siguen a este)-> diferencias de posiciones y diferencias de quaternions (ángulos!!) ... no te preocupes por la posición si querés, ignorala cada vez que la mencione. Calculas distancia desde bola hasta centro de la plataforma y la guardás. Yo siempre le pongo "deltaReference", es mi convención. Cuadro 2: PLATAFORMA: Se mueve y rota ponele, hace lo suyo BOLA: La plataforma ya se movió y rotó, ahora recalculas los datos anteriores (nueva posicion de esta y nuevo quaternion de esta ) Hacés la diferencia entre los datos de este cuadro y los datos anteriores -> tenés dif de pos y dif de ángulos Aplicás la dif de ángulos a "deltaReference", esto te da donde debería estar la bola con el efecto de rotación de la plataforma Aplicás la dif de posición a "deltaReference", esto te da donde debería estar la bola con el efecto de posición + rotación de la plataforma A todo esto todavía el movimiento normal de la bola no se aplicó, acá es donde seguís haciendo lo de siempre, el movimiento "Normal", (AddForce o MovePosition o Translate o lo que sea) Finalmente Actualizas/Pisás todos los datos anteriores, pos de plataforma, quaternion de plataforma, distancia bola-plataforma, esto es para reutilizarlos en el siguiente cuadro, los datos que en este cuadro eran "actuales" pasan a ser "previos", se van pasando la posta. Lo expliqué muy por arriba pero en general las famosas Moving/Rotating platforms funcionan algo así, si le querés dar toques vas a tener que meter algún que otro paso intermedio, como por ej que la orientación respecto al centro sea la misma (idéntico a enparentar) o que se mantenga la orientación con la que contactas con la bola, etc.
  15. 1 like
    Hola, algunas cositas: Estás usando = en vez de == (no se si es así en tu código o pasa acá) --> Usar == para float's no es recomendable usá Mathf.Approximately ---> Aun así verificar igualdad no queda lindo en este caso (aclaro que no se como es que el objeto se mueve), la matemática de punto flotante tiene errores, que un objeto se mueva libremente, tenga la posición <x,y,z> y que vos termines por verificar eso en un if y sea correcto es muy poco pobrable, ah no ser que antes hayas impuesto que ese valor sea <x,y,z> en un momento dado, cosa que no se si estás haciendo. No es necesario hacer GetComponent<Transform>() para eso existe ".transform" que es mucho mejor en terminos de performance. Te recomendaría no usar valores tan crudos en el código (si fue de prueba vaya y pase), usá más bien un "public Vector3 miValor;" y elegilo vos en el inspector. Ver cosas como -114.15f, 2.04f, -95.61f puede no ser tan descabellado en 5 líneas de código, probá tener 50 de estos datos crudos todos diferentes y distribuidos en 2000 líneas de código , y ni hablemos si algun día alguien tiene que leer eso, colega o alguien de algún foro. Te recomendaría usar nombres intuitivos, "objeto" es un método? porque por el nombre parecería que fuera un objeto o instancia de algo. Osea, si querés verificar la posición asegurate que el objeto que vas a mover llegue a la posición (no más o menos, sino que lo haga --> =), para esto podés usar vector3.MoveTowards o verificar si está cerca de la posición con Vector3.Distance (la cercanía la elegís vos). Está muy bien que lo hiciste con un Debug.Log, muchos a lo primero se tiran 500 líneas de código en vez de hacer un simple print ... Saludos
  16. 1 like
    Hola gente, la consulta es la siguiente, estoy haciendo un juego de carrera de karts, y me encuentro en el problema que no tengo forma en los circuitos de hacer colliders para detectar cuando un auto se sale del camino, actualmente lo resuelvo generando box colliders, que estiro y roto hasta que ocupen el espacio necesario, pero esto me resulta muy engorroso y asumo que debe existir una forma mas facil de hacer algo parecido. Exite en 3d algo parecido a lo que es el polygon collider en el 2d? buscando en foros en ingles recomiendan algo llamado Pro builder Basic , pero ya no lo encuentro en el assets store. Cualquier ayuda que me puedan dar, estare muy agradecido.
  17. 1 like
    Ah, muchas gracias, lo voy a probar. Sabes desde que versión? Yo estoy en la 2018.2.16f1. Edit: En la versión 2018.2.16f1 ya esta, muchas gracias.
  18. 1 like
    El ProBuilder ahora forma parte de Unity3D y lo tienes disponible en el Package Manager.
  19. 1 like
    Eso es como el valle inquietante que pasa con los robots humanoides, es algo complicado que no se si incluso dentro de 25 años y con toda la tecnologia del mundo se conseguirá, aunque van en buen camino, juegue al "DETROIT BECOME HUMAN" y había partes y movimientos muy realistas que parecian casi actores de verdad, pero aun asi seguia ese valle inquietante... Al personaje le gusta usar brillo de labios Ahora fuera de coñas, la evolución del principio a como esta ahora esta muy bien, muy buen trabajo. Yo en el 3D todavía no me atrevo ni con los humanos ni con cosas muy organicas, no paso de escenarios y robots, jaja. Coincido en que tiene una buena tocha (nariz) y quizas demasiada comisura en los labios, se la reduciria un poco, hasta donde acaban los labios mas o menos. ¡¡Por lo demás esta muy bien!! saludos
  20. 1 like
    Hola, sí, es totalmente posible, aunque para eso no necesitas un objeto por planeta orbitando, con algebra vectorial lo podés lograr. Osea, si conocés la posición de todos los planetas (con tenerlos referenciados alcanza) podés crear un vector centro-órbita y de ahí rotar dicho vector. Podrías hacer (espero que funcione): //supongo que cada planeta tiene uno de estos [SerializeField] float orbitDistance = 10f; Vector3 targetOrbitPoint; //quien controle a la nave puede pedir este valor, no modifcarlo, es un getter public Vector3 TargetOrbitPoint{ get{ return targetOrbitPoint; } } Vector3 centerToOrbit; void Start() { centerToOrbit = Vector3.right * orbitDistance (por ej, a la derecha alejado lo que le pongas) } void Update() { //Para rotar un vector se hace lo siguiente (algebra matricial pura) //angle es tu angulo final, por ej con angular speed, en tu ejemplo sería = 360.0f / (timeAround / factor) angle = angularSpeed * Time.deltaTime; Quaternion rotation = Quaternion.AngleAxis( angle , Vector3.forward ); //le puse forward pero ponele el eje que quieras //rotás el vector centerToOrbit = rotation * centerToOrbit; // actualizar el dato de interés targetOrbitPoint = transform.position + centerToOrbit; //Para debuguear <--- Debug.DrawRay( transform.position , centerToOrbit , Color.Magenta ); } a lo que subiste lo toqué un poco, no arreglé ni vi mucho, solamente cambié que algunas variables se llamaban "___Pos" cuando eran GameObjects (difícil de leer, sobretodo si tenés cosas como "camPos.transform.position") y ese GetComponent<Camera> lo podés catchear antes, por lo menos para este caso, no es que haga mucho pero igual. public class controler : MonoBehaviour { public Camera cam; //<---MOD public Transform camTransform; //<---MOD public Transform camPos;//empty object associated with the camera to track public GameObject targetTransform; //por qué se llamaba "Pos" si era un GameObject? public GameObject eyeTransform; //IDem anterior public GameObject ostaculeTransform;//IDem anterior //Seguramente uses mucho más el transform que el gameObject, por eso son transforms Vector3 newpos; bool moving; void start() { moving = false; cam = camTransform.GetComponent<Camera>(); } void update() { if (Input.GetMouseButtonDown(0)) { RaycastHit hitplanet; RaycastHit hitsun; Ray ray = cam.ScreenPointToRay(Input.mousePosition); //<---MOD if (Physics.Raycast(ray, out hitplanet)) { if (hitplanet.collider.CompareTag("planetas")) { newpos = hitplanet.point; targetTransform.position = newpos; camTransform.SetParent(null); transform.LookAt(new Vector3(newpos.x, transform.position.y, newpos.z)); camTransform.SetParent(transform); if (Physics.Raycast(eyeTransform.position, newpos - eyeTransform.position, out hitsun, Vector3.Distance(transform.position, newpos))) { if (hitsun.collider.CompareTag("sol")) { ostaculeTransform.position = hitsun.point; Debug.Log("Sun in the middle of the path"); } else { moving = true; } } else { moving = true; } } } } if (moving == true) { transform.Translate(new Vector3(0, 0, 100f)); if (Vector3.Distance(transform.position, newpos) < 50f) { moving = false; } } camTransform.position = Vector3.Lerp(camTransform.position, camTransform.position,0.1f); } } Saludos
  21. 1 like
    Lo mio también era sarcasmo XDXD
  22. 1 like
    Yo me apunto para probarlo tambien, tiene muy buena pinta!
  23. 1 like
    Se ve muy bien! cuando pueda lo pruebo y te cuento!
  24. 1 like
    Como Emperador magnánimo que soy, te lo permito . Puedes pasar links a tu web o a tu página de SoundCloud o lo que uses. Lo que no quiero es que colguéis canciones aquí directamente, porque se llena el server y porque fomenta a que la gente "vaga" suba porrocientos megas de archivos por vagueza...
  25. 1 like
    Trigonometría con Mathf Hola a todos, Me dispongo a hacer unas explicaciones de trigonometría Mathf y como funciona, y algo de explicaciones matematicas al respecto. Explicare los metodos mas importantes de la trigonometría. Explicare primero los arcos de coseno, seno y tangente. explicando en ellos el coseno, seno y tangente a su vez. luego mostrare como funciona Mathf.cos, Mathf.sin y Mathf.tan aparte sin explicar matematicamente cada uno, ya que han sido explicados junto a sus arcos. Mathf.Abs Este es sencillo y facil de entender asi que no me entretengo, Abs retorna el valor absoluto de un valor X Debug.Log(Mathf.Abs(-2045.34f)); //Vemos que estamos pasando el valor -2045.34f, el valor retornado sera 2045.34 //Si el valor que le pasamos a Mathf.Abs() es -10, este nos retornara 10. //En definicion, Abs retornara el valor positivo. Mathf.Acos Esta devuelve el Arcocoseno de un valor, recordar que lo devuelve en radianes. Que es coseno: Quiero explicar antes el coseno para poder entender mejor el arcocoseno. (Al igual que haré con seno, el codigo de ejemplo lo pondre para Mathf.Cos()) el coseno es la razon entre: El cateto adyacente (b) a dicho ángulo y la hipotenusa (c) en un triangulo rectangulo. esto quiere decir que cos α = b / c donde α es el valor angular con un dominio de [0,π]. (cuando hablamos de dominio, queremos decir un rango entre un minimo y un maximo, en este caso el minimo es 0 y el maximo 3.14159265359) Esta es la grafica de coseno: Que es Arcocoseno: Por definicion es la funcion recíproca de coseno, Esta es el arco cuyo coseno es alfa. arcocoseno restringe el dominio de la funcion coseno a (x) [-1,1] donde su codominio (α) [0, π]. Donde x es el valor comprendido entre -1 y 1 de la linea que vemos en la imagen, y α es la aceleración angular por unidad de tiempo. float x = ; //0 es exactamente es exactamente la bisectriz del primer y el tercer cuadrante de la grafica de arcocoseno. Debug.Log(Mathf.Acos(x)); //Devolvera (1/2)π radianes, que es 1,57 radianes. que en grados es 0. //Si X fuese 0.7, Devolveria (1/4)π radianes, que es 0,785 radianes. que son 45 grados. La tabla de valores comunes es: Valor dominio X: -1 -√2/2 -1/2 0 1/2 √2/2 1 Angulos: 180 135 120 90 60 45 0 Radianes: π 3/4π 5/6π 1/2π 1/3π 1/4π 0 Que son Radianes: El radian es la unidad de ángulo plano, en el sistema de medidas, 1rad = r. donde r es el radio de la circunferencia. y la circunferencia siempre vale 2π radianes. Esto quiere decir que 1 radian en valor decimal es equivalente la la longitud del radio. os dejo una imagen que aclara bastante la mente. Mathf.Approximately Segun la referencia oficial de unity: (Este metodo lo añado por que me parecia interesante) //En vez de: if(1.0f == 10.0f / 10.0f)... //Hacer esto: if(Mathf.Aproximately( 1.0f, 10.0f / 10.0f )... (Supongo que esto es mejor usarlo con valores float largos como pueda ser π.) Mathf.Asin Este metodo devuelve el arcoseno de un valor, Recordar que lo devuelve en Radianes. Que es seno: Como con arcocoseno ya explique el coseno, con arcoseno explicare el seno. el seno es la razon entre: El cateto opuesto (a) a dicho ángulo y la hipotenusa (c) en un triangulo rectangulo. esto quiere decir que sen α = a / c (La diferencia con coseno es que coseno usa cateto adyacente, y este usa el opuesto al ángulo) donde α es el valor angular con un dominio de [0,π]. Esta es la grafica de seno: Ahora que sabemos que es el seno: Que es Arcoseno: Al igual que arcocoseno es la funcion recíproca de coseno, arcoseno es la funcion recíproca de seno. Lo que quiere decir que: SI arcsen x = α ENTONCES sen α = x recordar tambien que se escribe arcsen o sen-1 Es el arco cuyo seno es α. (Es como el espejo de arcocoseno antes explicado) arcoseno restringe el dominio de la funcion seno a (x) [-1,1] donde su codominio (α) [-π/2, π/2]. Os mostrare ahora una imagen de como se comportan seno y arcoseno en una grafica: La gráfica de la función arcoseno es simétrica a la de la función seno respecto a la recta bisectriz del primer y tercer cuadrante (y=x) float x = .5f; //.5f es el equivalente a 1/2 Debug.Log(Mathf.Asin(x)); //Devolvera 1/6π radianes que es 0,52 y son 30 grados. Mathf.Atan El metodo devuelve en arcotangente de un valor, recordar que lo devuelve en radianes. Que es la Tangente: La tangente la razon entre los catetos de un triangulo rectangulo. tan α = a / b Siempre como dividendo es el cateto opuesto, y como divisor el cateto adyacente. Vamos a recordar que sen α = a / c y que cos α = b / c por lo tanto la tangente de α se puede expresar como tan α = sen α / cos a Para comprender el concepto de tangente, graficamente vista en la imagen anterior, imagina una linea que su punto 0 nace desde D y tiende a infinito. El dominio de la tangente es (x) [-∞,∞], donde su codominio (α) [-π/2, π/2]. (Tranquilos esta funcion no estan necesaria en un principio como seno y coseno, asi que no os preocupeis si os resulta mas compleja) Que es Arcotangente: En este caso es la función recíproca de tangente. Al igual que con arcoseno y arcocoseno, arcotangente es el arco cuya tangente es α. En notacion matematica se puede escribir arctan o tan-1. Uso con unity de estas funciones Vale, ahora que sabemos la teoria, queda lo mas interesante que es la practica de estos conceptos en unity, y aplicaciones varias. El metodo que utilizare para mostrar los ejemplos sera con imagenes y codigo para que veamos la facilidad del asunto. (Recordar tambien que el objetivo es entender estos conceptos, para que podais usarlos a vuestro libre albederio) En este ejemplo, vamos a ver como saber los grados que tiene que rotar un objeto para mirar a otro. (Aunque esta funcion ya trae incorporada unity como Transform.LookAt() aquí explicare como funciona internamente) Lo primero que hay que saber es como conseguir la distancia entre dos puntos del plano de unity. (Yo trabajare con Vectores de dos dimensiones, "Vector2") Vector2.Distance(Vector2 a, Vector2 b); //Distancia entre los dos vectores. //Es lo mismo que hacer: Vector2 a = new Vector2(10, 11); Vector2 b = new Vector2(5, 8); float dist = (a - b).magnitude; Debug.Log(dist); Ahora en el proyecto creamos dos objetos, recuerdo que estoy trabajando en 2D, en 3D seria lo mismo pero jugando con Vector3, recordar que solo rotamos en el eje Y. Como vemos he creado dos objetos en un plano bidimensional, son dos sprites, el azul llamado objeto1 su posicion es: X=0 Y=-3.5, el negro y rojo llamado objeto2 su posicion es X=4 Y=-1. Como veis he dibujado un triangulo rectangulo a partir del punto A (Objeto1) y punto B (Objeto2) ahora tenemos la incognita de C que es sencilla, es la posicion Y de A y la posicion X de B Para encontrar la posición de C en Unity: public Transform A, B; //Aqui añadiremos los objetos de nuestra escena desde el inspector. void Start () { Vector2 C = new Vector2(B.position.x, A.position.y); //C es la posicion X del objeto2 y la posicion Y del objeto 1 } Ahora ya tenemos los 3 puntos de nuestro triangulo imaginario. Ahora hay que saber la distancia de h, de ca y de co Aunque para sacar el coseno que es lo que necesitamos, no nos hacefalta co, ya que solo necesitamos cateto adyacente e hipotenusa. public Transform A, B; //Aqui añadiremos los objetos de nuestra escena desde el inspector. void Start () { Vector2 C = new Vector2(B.position.x, A.position.y); //C es la posicion X del objeto2 y la posicion Y del objeto 1 float h = (A.position - B.position).magnitude; //Distancia de hipotenusa float ca = (new Vector2(A.position.x, A.position.y) - C).magnitude; //distancia cateto adyacente float co = (new Vector2(B.position.x, B.position.y) - C).magnitude; //distancia cateto opuesto. } Sacaremos ahora el coseno del triangulo, para que nos de los radianes. public Transform A, B; //Aqui añadiremos los objetos de nuestra escena desde el inspector. void Start () { Vector2 C = new Vector2(B.position.x, A.position.y); //C es la posicion X del objeto2 y la posicion Y del objeto 1 float h = (A.position - B.position).magnitude; //Distancia de hipotenusa float ca = (new Vector2(A.position.x, A.position.y) - C).magnitude; //distancia cateto adyacente float co = (new Vector2(B.position.x, B.position.y) - C).magnitude; //distancia cateto opuesto. //Sabiendo que; cos α = ca / h float a = ca / h; //Ya tenemos alfa. float rad = Mathf.Cos(a); //ahora sacamos con Mathf el coseno de alfa y lo pasamos a una variable float, que sera el valor en radianes. Debug.Log(rad); //Nos dara 0.66 } Vale ahora tenemos el valor en radianes, ahora lo pasaremos a grados. public Transform A, B; //Aqui añadiremos los objetos de nuestra escena desde el inspector. void Start () { Vector2 C = new Vector2(B.position.x, A.position.y); //C es la posicion X del objeto2 y la posicion Y del objeto 1 float h = (A.position - B.position).magnitude; //Distancia de hipotenusa float ca = (new Vector2(A.position.x, A.position.y) - C).magnitude; //distancia cateto adyacente float co = (new Vector2(B.position.x, B.position.y) - C).magnitude; //distancia cateto opuesto. //Sabiendo que; cos α = ca / h float a = ca / h; //Ya tenemos alfa. float rad = Mathf.Cos(a); //ahora sacamos con Mathf el coseno de alfa y lo pasamos a una variable float, que sera el valor en radianes. //Para pasar de radianes a grados es aplicar la regla de 3 //-> Pi / 180 = rad / X despejamos la x // y la ecuacion es-> x=180*rad/Pi float grados = (180 * rad) / Mathf.PI; Debug.Log(grados); } No os equivoqueis por que estos no son los grados que hay que rotar, estos son los a los que se encuentra el punto B respecto al punto A, os muestro una imagen para que lo comprendais. Si nuestro sprite mirase a la derecha por defecto (que es donde comienda el grado 0) entonces 37.9 grados serian los que tendria que rotar a su izquierda, pero nosotros tenemos el offset de 90 grados por que nuestro sprite mira hacia arriba. (Por eso hay que hacer un pequeño arreglo) Y ahora si por fin lo rotaremos lo necesario para que mire hacia el otro objeto. void Start () { Vector2 C = new Vector2(B.position.x, A.position.y); //C es la posicion X del objeto2 y la posicion Y del objeto 1 float h = (A.position - B.position).magnitude; //Distancia de hipotenusa float ca = (new Vector2(A.position.x, A.position.y) - C).magnitude; //distancia cateto adyacente float co = (new Vector2(B.position.x, B.position.y) - C).magnitude; //distancia cateto opuesto. //Sabiendo que; cos α = ca / h float a = ca / h; //Ya tenemos alfa. float rad = Mathf.Cos(a); //ahora sacamos con Mathf el coseno de alfa y lo pasamos a una variable float, que sera el valor en radianes. //Para pasar de radianes a grados es aplicar la regla de 3 //-> Pi / 180 = rad / X despejamos la x // y la ecuacion es-> x=180*rad/Pi float grados = (180 * rad) / Mathf.PI; float offset = 90; //Este es el offset de nuestro sprite, por que por defecto deberia de mirar a izquierda y no arriba. //Ahora ya si, lo rotamos A.Rotate(new Vector3(,,-(offset-grados))); } Recordar que el offset cambia segun si esta a izquierda o derecha de nosotros, tambien segun este arriba o abajo. Esto es un ejemplo de una de las muchas utilidades de la trigonometría en los videojuegos, esta claro que para muchos unity ya da herramientas, pero para otros no, por eso estos conceptos son necesarios saberlos. Un saludo y espero que les sirva esta pequeña explicación!
×