Jump to content

lightbug

Registrados
  • Content Count

    2,447
  • Joined

  • Last visited

  • Days Won

    218

Everything posted by lightbug

  1. Creo que debes importar el 2D sprite package por separado (antes venía incluido en cada proyecto nuevo).
  2. Revisa si abriendo el sprite con el sprite editor (en las opciones de importación) te permite cambiar esto. Creo que podés hacerlo cambiando el "physics shape". https://docs.unity3d.com/Manual/CustomPhysicsShape.html No estoy seguro con tiles, pero me parece que Unity simplemente crea el collider en base a la forma del mismo tile. La otra solución (si fuera posible y queda bien en tu juego) es rellenar esos pixeles que faltan usando un editor. En este caso esos pixeles transparenetes no forman parte del collider, creo que por esto los está ignorando.
  3. Acá dejo un lindo artículo al respecto (ingles): https://blog.unity.com/technology/1k-update-calls Lo que primero tendrías que plantearte es si el "overhead" que implica tener este sistema centralizado vs descentralizado es significante para tu proyecto (usa el profiler o usá las stats de Unity, fps). Porque si no lo es, no tiene sentido que le prestes atención de entrada. Un ejemplo bien simple, tener un sistema centralizado (1 solo Update para todos los aviones) tarda 0.2ms (por frame), uno descentralizado (muchos scripts) consume 1ms, mientras que la parte gráfica de tu juego tarda 50ms. En este caso, si le das bola al update vas a pasar de un frame time (scripts + gráficos, me olvidé del resto) de 50.2 ms (centralizado) vs 51 ms(descentralizado), cuando en realidad la parte gráfica es tu problema. Como todo loop, el cuerpo del loop es muy importante. En mi caso, para un asset mio usé un "scene controller" (típico script maestro que actualiza a otros) durante algunos años, este se encargaba de iterar sobre rigidbodies que hacían todo tipo de raycast, sphereCast y capsuleCast por frame. Con el tiempo dejé de usar esto y me incliné al clásico monobehaviour + FixedUpdate. En mi test de performance (una escena que había dentro del asset) la diferencia entre el centralizado vs descentralizado era de 0 fps. La demanda de las físicas + scripts era tal, que compararlos no tenía sentido (en este caso en particular).
  4. La posicion del editor (component Transform) es la posición local. Por ejemplo, si tu objeto es hijo de otro objeto, este puede tener pos = <0,0,0> y estar globalmente ubicado en <1,2,3> (ya que el padre está en <1,2,3>).
  5. Hola @Alex Ametlle, algunas consejos que quizás ayuden: 1. Evita los GetComponent en Update/FixedUpdate. Si es posible cachea dichos componentes: Rigidbody rb; void Awake() { rb = GetComponent<Rigidbody>(); } void FixedUpdate() { // Ejemplo rb.velocity = ...; } 2. Nunca modificar propiedades físicas en Update (o LateUpdate). La razón por la que debés usar FixedUpdate es porque este callback corre antes de la simulación física (está preparado para brindarte esa "lógica" previa a la simulación). La otra es por un tema de estabilidad, en general los motores usan pasos fijos (fixed step) para mejorar la "estabilidad" en los resultados. Además, si tu framerate es bajo, es posible que FixedUpdate (+ simulación) corran varias veces para compensar este tiempo de frame grande. En resumen, físicas/movimiento de cuerpos = FixedUpdate , inputs/transforms puros = Update/LateUpdate. 3. Esto: rb.AddForce(new Vector2(velocidad, 0f * Time.deltaTime)); ...está fundamentalmente mal, por dos razones: 3.1 estás multiplicando un valor por cero. 3.2 Siempre tienes que incluir el dt, incluso para FixedUpdate (ni hablar para Update como en tu caso, vas a encontrar que depende del framerate) rb.AddForce(new Vector2(velocidad * Time.deltaTime , 0f )); (Por cierto, usar deltaTime o fixedDeltaTime es lo mismo dentro de FixedUpdate) Si necesitas ignorar la componente y podés multiplicar por Vector2.right ( = <1,0>) rb.AddForce( Vector2.right * velocidad * Time.deltaTime ); velocidad * dt te va a dar aceleración, pero el modo de la fuerza está en Force (por defecto), es decir que la masa del objeto va a influir en tus calculos. https://docs.unity3d.com/ScriptReference/ForceMode2D.Force.html Un objeto de masa 1 no va a acelerar lo mismo que uno con masa 10 (diez veces menos aceleración). Así que, incluye la masa en los calculos, al menos si quieres coherencia en tus resultados. rb.AddForce( Vector2.right * velocidad * Time.deltaTime * rb.mass ); Para 3D podés optar por usar un ForceMode.acceleration (2D no tiene un modo así 😞 ) 4. Usa los ejes (axis) para las inputs. Esto: if (Input.GetKey("right")) { rb.AddForce(new Vector2(velocidad, 0f * Time.deltaTime)); animator.SetBool("moving", true); spriteRenderer.flipX = false; } if (Input.GetKey("left")) { rb.AddForce(new Vector2(-velocidad, 0f * Time.deltaTime)); animator.SetBool("moving", true); spriteRenderer.flipX = true; } Se puede transformar en esto: float horizontalAxis = Input.GetAxis("Horizontal"); float acceleration = velocity * Time.deltaTime; rb.AddForce( Vector2.right * horizontalAxis * acceleration ); // horizontalAxis != 0 = true si es distinto de cero, false caso contrario. animator.SetBool("moving", horizontalAxis != 0 ); if( horizontalAxis != 0f ) spriteRenderer.flipX = horizontalAxis < 0; 5. Grounding, o detección de suelo. El tema es complejo, pero siempre debés tener una variable grounded dando vueltas, te va a ayudar para todo el código (físicas, animaciones, sonidos, etc), es una parte vital de todo character. Siendo 100% amigables con las físicas (podés hacerlo de otras maneras), la forma de detectar un suelo es mediante los contactos. Basicamente, si uno de tus contactos (puede haber muchos) es parte del suelo, entonces estás "grounded". El "es parte del suelo" se resuelve de forma simple. Una vez que tengas la normal del contacto, tienes que hacer lo siguiente (en OnCollisionXXX): float slopeAngle = Vector3.Angle( Vector3.up , contact.normal ); //slope = pendiente del suelo // Es parte del suelo? // puse 85f como ej, puede ser menos si queres, siempre que sea menor a 90 está bien if( slopeAngle < 85f ) grounded = true;
  6. Normalmente se recomienda arrancar con una escala apropiada ya que hay constantes (tales como el contact offset, y otras más a las que no tienes acceso) que van a influir en el resultado. Si bajando el valor de 0.01 a 0.002 no te ocasiona inconvenientes, entonces puede que no necesites cambiarlo. El tema es que el contact offset también se usa como buffer para prevenir "jitter". Es probable que un valor alto te de más rango de estabilidad, es decir, que no pase de "está en el suelo" a "está en el aire" de un frame a otro. Por esto mismo, en el tooltip del contact offset te dice que un valor cercano a cero puede causar "jitter".
  7. No es recomendable cambiar ese valor. Te recomendaría que cambies la escala en general del juego, es probable que este sea el principal problema (o quizás el collider está mal seteado). Como dato curioso, en 3D esto no pasa, 3D usa algo muy inteligente que detecta colisiones + "depenetra" los cuerpos casi a la perfección (algo de physx de nvidia).
  8. Perdón por responder tan tarde! No, no es requerido, las referencias a componentes se buscan automaticamente. La estructura que yo propongo es una estructura óptima, es decir que puedes hacer varias cosas interesantes separando la parte visual de la parte física (collider + rigidbody). Lo que sí o sí es requerido es que todo lo relacionado al personaje esté contenido dentro de un "root" u objeto maestro (padre). No, de hecho CCP no hace referencia a los huesos de ninguna manera. En la "Demo" mi personaje es un humanoide, gracias a esto puedo usar el avatar que Unity ofrece para acceder a los IK (por ejemplo). Por ejemplo (estado LadderClimbing ) public override void UpdateIK( int layerIndex ) { if( !useIKOffsetValues ) return; UpdateIKElement( AvatarIKGoal.LeftFoot , leftFootOffset ); UpdateIKElement( AvatarIKGoal.RightFoot , rightFootOffset ); UpdateIKElement( AvatarIKGoal.LeftHand , leftHandOffset ); UpdateIKElement( AvatarIKGoal.RightHand , rightHandOffset ); } void UpdateIKElement( AvatarIKGoal avatarIKGoal , Vector3 offset ) { CharacterStateController.Animator.SetIKPositionWeight( avatarIKGoal , 0f ); Vector3 originalRightFootPosition = CharacterStateController.Animator.GetIKPosition( avatarIKGoal ); CharacterStateController.Animator.SetIKPositionWeight( avatarIKGoal , 1f ); CharacterStateController.Animator.SetIKPosition( avatarIKGoal , originalRightFootPosition + offset ); } Ahora mismo el método usado para movimiento es muy pero muy simple, un MoveTowards que modifica la velocidad linealmente con el tiempo. El base speed limit indica el target del MoveTowards (función de Vector3) del walk (no de run). Este valor será el valor final de velocidad obtenido, es decir que técnicamente no es posible, ya que mayor límite de velocidad + aceleración implica obtener una velocidad mayor. Ya que es un MoveTowards (incluso si fuese un Lerp), quizás lo que más te importe a la hora de modificarlo es su "t factor" (el tercer argumento de este método). Si tienes el control de "t" entonces puedes controlar la velocidad como quieras, independientemente de sus límites. En mi caso uso acceleration/deceleration como variables "t". Jugar entre los valores de velocidad y los umbrales (threshold) del animator es fundamental. Quizás tratar de cubrir varios tipos de movimiento (parada, arranque suave, trote, correr, etc) todos al mismo tiempo (usando una simple funcion lineal) no sea una buena solución en tu caso. Si realismo en las animaciones es lo que necesitas se pueden hacer dos cosas: Mejorar el script de movimiento. Meter curvas para lograr un movimiento menos lineal y más personalizable es algo que voy a introducir en 2.0.0. Ya esto pasa por el lado de la implementación de la lógica (por parte del usuario) y escapa al alcance del asset. De todas formas siempre trato de meter este tipo de cosas, de manera de facilitar un poco la parte del gameplay. Usar root motion, piensa en GTA 4/5 por ejemplo. No hay scripts ni nada de eso, el clip contiene la información de movimiento y solamente se lee el input del player. Con 1.3.3 puedes usar root motion para planar velocity y seguir usando la gravedad de NormalMovement.
  9. Gracias! 😀 No me quedó bien claro si no supiste/pudiste hacer funcionar este asset o ese "FPS" (?). Gracias Bydark! Espero que siga funcionando 😄 Ya que estoy, la version 1.3.3 debería estar lista dentro de algunas horas. Una cosa que no he mencionado aquí es la existencia de un bug que imposibilita descargar versiones actualizadas de asset (afecta a todos sus asset). Versiones con el fix incluido: 2021.1.0b3 o mayor 2020.2.3f1 o mayor 2019.4.19f1 o mayor Fix manual: Ir a C:/Users/***your-user-name***/AppData/Roaming/Unity/Asset Store-5.x/ Encontrar al autor del asset (/Lightbug/) Borrar "Character Controller Pro.unitypackage" Ir al package manager y descargar el asset nuevamente.
  10. Hola, así es, un trigger no debería generar colisiones de ningun tipo (lo que hace que un rigidbody dinámico responda). Te recomiendo que uses Physics2D.queriesHitTriggers para esto. https://docs.unity3d.com/ScriptReference/Physics2D-queriesHitTriggers.html Si lo pones en true cada query (raycast, sphereCast, etc) va a detectar triggers (cosa que en este caso no querés, debe ser falso). El tema es que cada vez que lo usas lo tenés que restablecer (es static!). Por ejemplo: // Guardas el estado actual queriesHitTriggers bool previousQueryHitTriggers = Physics2D.queriesHitTriggers; // Usas lo que vos quieras (en este caso falso) Physics2D.queriesHitTriggers = false; // Hacés el query RaycastHit2D hitInfo = Physics2D.Raycast(...) // Lo repones Physics2D.queriesHitTriggers = previousQueryHitTriggers;
  11. Genial lo del outline! Como lo dije en su momento, el outline sienta mejor con el juego, además de (creo) ayudar en el gameplay 😉. Para el caso del fill, una alternativa podría ser implementar un blend entre el fill y el color original (50-50 por ej). El script de animación está muy bueno también, me encantan ese tipo de enfoque, sobretodo porque soy pésimo animando 🙃. Tengo pensado implementar la famosa rueda (sacada de aquí). No solo podés controlar la velocidad de animación sino también la sincronización con el movimiento. Por ej, en un momento dado determinas la rotación de la rueda, definis la pose objectivo (ej el frame "i") y luego usas el "ease" que quieras desde el frame actual al target.
  12. Es muy probable, igual si tenés el código sería mucho mejor. Podrías definir un flag (bool) que simplemente se ponga en true si algun rayo colisiona. bool stopFlag = false; for(int i = 0; i < numero_rayos; i++) { ... mismo que antes if( hit ) stopFlag = true; } if( stopFlag ) Stop(); // velocity = 0 esto que puse acá podés replicarlo así: bool stopFlag = false; for( ... ) { ... stopFlag |= hit; } Que básicamente significa "si algún hit es true, stopFlag será siempre true, solamente si todos los hit son falsos stopFlag será falso"
  13. Hola, sí eso pasa porque efectivamente "colisiona_rayo" se llama después del del Debug.DrawRay. Podrías organizarlo un poco mejor así:
  14. Ostia! Vine a actualizar el hilo del asset, y me di cuenta que nunca lo había creado 😅 ... bueno aquí va... Links: Asset store Demo (Desktop) Demo (webGL) Features Documentación (en ingles) Breve descripción: Character Controller Pro es un controlador de personaje (o character controller) de tipo dinámico que funciona con físicas 2D/3D, y tiene forma de cápsula. El paquete se separa en 3 partes: Core: El character controller con todo lo necesario para que exista y funcione por si solo [Lógica no implementada] Implementation: incluye un sistema construido encima del controlador que ayuda a 1) administrar inputs (sin importar su origen, viejo sistema de Unity, nuevo sistema, Rewired, etc) para luego convertirlas en acciones, y 2) proveer de una maquina de estados (FSM). [Lógica no implementada] Demo: Dentro del paquete se incluyen escenas de demostración, estados (implementaciones de lógica de gameplay), acciones predefinidas (movement, jump, crouch, etc), y más. [Lógica implementada]
  15. Ahhh claro, perdón ni me avivé de la parte 2D.
  16. Bueno depende de cómo los NPC se muevan, cosa que no sabemos. Asumiendo que usas un NavMeshAgent para los NPC, ¿Probaste con un NavMeshObstacle en tu personaje? https://docs.unity3d.com/Manual/class-NavMeshObstacle.html
  17. Todo eso me suena a que no estás haciendo 2 cosas: Seteando la prioridad de las transiciones, Selecciona un estado y fijate que en el inspector te figuran en order, de arriba (más prioridad) a abajo (menos). Configurando la fuente de interrupción de cada estado (https://docs.unity3d.com/Manual/class-Transition.html#TransitionInterruption), ya que se puede dar que una transición esté pasando, pero un estado (el actual o el siguente) tenga una transición valida al mismo tiempo. Respecto a 2, esto dice la doc: Value Function None Don’t add any more transitions. Current State Queue the transitions from the current state. Next State Queue the transitions from the next state. Current State then Next State Queue the transitions from the current state, then queue the ones from the next state. Next State then Current State Queue the transitions from the next state, then queue the ones from the current state. Ejemplo de un personaje que está en el estado "caida" y pasa a "suelo" al caer (isGrounded = true). En plena transición le das a la tecla de salto, es decir, deberías pasar de "suelo" a "salto". Volviendo al isGrounded = true, un trigger se llama, ahora está en plena transicion a "suelo". Vamos a suponer que todavía no estás en "suelo" (que es el proximo estado, el "next"), entonces sigues en "caida" (el actual o "current"), por lo que si presionas la tecla de salto no pasa nada (a nivel animación, probablemente el objeto físico salte, eso no nos importa de momento). La cosa que la animación no cambia, todo termina en "suelo" eventualmente. Si configuras que la fuente de interrupción sea "Next", lo que va a pasar es lo siguiente: Hay una transición que require accionarse ya mismo ("suelo -> salto" dió válida) Dicha transición pertenece al estado siguiente "suelo" (next). Recordar que los estados contienen a las transiciones si tienen su cola (no su punta). En este caso suelo contiene "suelo -> salto", salto tendrá "salto -> caida", caida tendra "caida -> suelo" , y así... El estado actual (caida) tiene como fuente de interrupción el estado Next ("suelo", quien contiene la transición a salto y encima es válida) El sistema suma dos más dos y termina interrumpiendo la transición actual de inmediato, en base a la "interruption source" de arriba. Todo esto no hubiera terminado bien si tuvieras current como fuente de interrupción. Si no estás seguro metele "Current state then next state". Documentación. Como dijiste, esas son las dos más usadas, Play reproduce de una, Crossfade te da una transición de donde estés hacia el estado target. Pasa que eso es muy confuso, que pasa si estás saltando (que se yo, 100 metros en el aire) y a los 3 segundos (llegaste al pico) no presionas nada? tenés que andar leyendo el estado actual, y en base a eso determinar si das Play/Crossfade a X animación... terminas creandote la misma herramienta dentro del código. Creeme que yo vengo puteando con Mecanim desde hace años, y todos los problemas (excepto los más estúpidos y fáciles de solucionar) tienen su vuelta. Te recomiendo lo de las prioridades y las fuentes de interrupciones.
  18. Imposible: void Update() { Vector3 Direccion = new Vector3(0.0f , Random.Range(0.1f, 1.0f) , 0.0f); print( Direccion.normalized ); } Te imprime solo <0,1,0> Probablemente se entendió mal, quise decir que "Direccion" siempre lo vas a tener que normalizar sí o sí, si lo que esperas de resultado es una dirección. Dicho de otro modo, la dirección será <0,1,0> simpre, "Dirección" (la variable) sí va a cambiar (no siempre <0,1,0>).
  19. Claro, por eso mencioné que el resultado final es siempre <0,1,0>, tu random no hace nada.
  20. lightbug

    GUI

    Acordate de los colliders! no hay nada más feo que el cursor no capte el UI porque se metió dentro de una "O". Podés usar el mismo UI para esto, no es necesario que pongas texto en pantalla (Unity). Pregunto, ¿Usar TextMeshPro no era posible? (es que veo que estás haciendo todo en Blender). O quizás es todo parte del menu y listo?
  21. Una cosita (se que es viejo, pero igual lo menciono): Direccion = new Vector3(0.0f , Random.Range(0.1f, 1.0f) , 0.0f); En teoría una dirección debe estar siempre normalizada (imagina una variable cantidadDeManzanas = -5, no tiene sentido). Por lo que el resultado final debería ser siempre <0,1,0> (más alla de cómo utilices el vector "Direccion"). Esto va más allá de las capacidades del lenguaje, es más bien una forma de evitar bugs innecesarios.
  22. ¿No es esto lo que estás haciendo (pasando ambos como argumento)? Está bien, por lo menos la dirección es una dirección (normalizada), y la fuerza hace de magnitud (similar a la forma polar de un vector). AddForce agrega (importante, no setea, suma cuadro a cuadro) la fuerza que le pases. Fuerza es masa x aceleración, la masa es la fija que tenés en el rigidbody, así que terminas tocando la aceleración de una manera u otra (por lo menos usando el modo Force que viene por defecto). Pasar una dirección como vector te va a agregar una fuerza de magnitud 1 en la dirección especificada. Ejemplo: m = 2 , F = 1 ... F = m x a --> a = F / m --> a = 0.5 --> acelerar 0.5 m/s por cada segundo que le apliques esto. Me parece que el problema no tiene que ver ni con la fuerza, ni con la dirección, me juego a que AddForce (Force mode) o no es la herramienta que necesitas, o directamente necesitas más información a la hora de saber si necesitas variar la fuerza o no (y así controlar mejor tu RB). Probá con cambiar la velocidad directamente, usando rbPelota.velocity , o directamente el modo VelocityChange de AddForce. Quizás de esta forma puedas controlar el rb como deseas.
  23. Usar una maquina de estados, quizás separando la lógica por estados puedas habilitar/bloquear diferentes funcionalidades dependiendo del estado del personaje o juego en general. Por ejemplo, separando el clásico "Locomotion" (movimiento básico) del "ataque especial", de esta menera usar uno no influye en el otro.
  24. Es probable que puedas "engañar" al sistema creando events por código. https://docs.unity3d.com/Packages/com.unity.inputsystem@1.0/manual/Events.html El ejemplo de la página (necesitas usar el namespace InputSystem.LowLevel) // Send event to update leftStick on the gamepad. InputSystem.QueueDeltaStateEvent(Gamepad.current.leftStick, new Vector2(0.123f, 0.234f) ); Quizás puedas reemplazar esto por Mouse.current, recuerdo que lo hice en su momento. De argumento le pasas la posición actual. No se si sea la mejor solución, es probable que si necesitas actualizar frame a frame UI no sea lo más efectivo, no lo se.
  25. Muy buena atmósfera! Hay demo??? 😬
×
×
  • Create New...