Jump to content
Sign in to follow this  
nomoregames

ANSWERED incremento con while

Recommended Posts

Hola a todos

:90_wave:

Estoy intentando,que cuando mantienes el botón derecho de el ratón  , mediante while, que una variable float, incremente de manera "pausada", pero no se por que no estoy consiguiendo absolutamente nada....

  while (ArrowAddForce != 30)
        {
            ArrowAddForce += 1;
            print(ArrowAddForce);
           // yield return new WaitForSeconds(0.4f); e probado con esto pero sigo sin conseguir nada
            
        }

estoy seguro de que tiene una respuesta muy sencilla, pero no llego a mas y es desesperante

 

Editado: en el código, donde pongo while(ArrowAddForce....) ponía originalmente  while(Input.GetMouseButtonDown(1)).


  

 

Share this post


Link to post
Share on other sites
Quote

Estás usando el Input.GetMouseButton( 1 ) no??

Sip

(joder me ha dado un huelco el corazón, siempre que apareces en alguno de mis posts me arreglas la vida)

Share this post


Link to post
Share on other sites
2 hours ago, nomoregames said:

Sip

(joder me ha dado un huelco el corazón, siempre que apareces en alguno de mis posts me arreglas la vida)

Jajaja, bueno me imagino que estás haciendo esto dentro de una corrutina. Quizás podrías subir el código entero así se ve mejor la cosa.

 

Share this post


Link to post
Share on other sites

Yo recomiendo usar tiempo siempre que puedas, en lugar de contadores arbitrarios que luego nunca nos acordamos de qué unidades contaban, y además nos arriesgamos a que funcionen diferente en diferentes ordenadores.

Yo en el Update() o FixedUpdate() simplemente usaría:

if (Input.GetMouseButton(1)) {
    buttonActionPressedTime = buttonActionPressedTime + Time.fixedDeltaTime;  // o deltaTime, pero esto yo lo pondría en FixedUpdate así que fixedDeltaTime
    this.UpdateBowTension();  // supongamos que este método existe por ahora
} else {
    pressedTime = 0.0f;
}

Y luego cuando necesites interpretar eso ya dividirás pressedTime por lo que toque, o le aplicas la función que quieras (lineal, cuadrática, una spline a tu gusto...). Igual necesitas caparla (clampearla) para que no crezca demasiado pero eso también puedes hacerlo al interpretarla, eso ya a tu gusto.

En otra parte (desde Update o FixedUpdate depende de lo que vayas a hacer), la usaría:

public void UpdateBowTension() {
    float bowTensionTime = 2.0f;  // esto bien podría ser una constante o ponerlo como parámetro de tu controller o tus globals
    float bowTension = Mathf.Clamp(buttonActionPressedTime / bowTensionTime, 0.0f, 1.0f);  // la tensión normalizada entre 0 y 1 (siempre mejor! :))

    // Y aquí lo usas para lo que quieras, por ejemplo actualizar la imagen o una barra, o si vas a disparar, usarlo como multiplicador de la fuerza.
}

De esta forma sabes exactamente que tu acción toma 2 segundos, y puedes cambiarlo fácilmente.

Es verdad que seguram1ente necesitarás un boolean para expresar también que estás de hecho disparando el arco, y lidiar con el sonido, y demás, pero espero que te inspire un poco lo de arriba.

Fíjate también que así es fácil cambiar la "respuesta" del arco, si quisieras. No te preocupes ahora pero estamos usando "buttonActionPressedTime / bowTensionTime" que es lineal, pero si quisieras que la tensión fuese acelerando podrías usar por ejemplo una cuadrática (elevando eso al cuadrado para que llegue antes al tope) o, tratándose de un arco, una función que decaiga como 1 - (x - 1)^2, aunque realmente no sé qué hace la gente.  También puedes crear una spline en el editor y llamo a su método para interpolar el tiempo, así tienes un control de las curvas, si necesitas algo tan fino.

Un saludo,

Edited by J Montes
  • Like 1

Share this post


Link to post
Share on other sites
Quote

 Quizás podrías subir el código entero así se ve mejor la cosa.


    float ArrowAddForce;
    private void Update()
    {
    if (Input.GetMouseButtonDown(1))
        {
            StartCoroutine(tensiontime()); 
        }
    }

    IEnumerator tensiontime()
    {
        while (Input.GetMouseButtonDown(1))  
        {
            ArrowAddForce += 1;
            print(ArrowAddForce);
            yield return new WaitForSeconds(0.4f);


        }
    }

 

J Montes ...

es triste... pero es la unica parte que e logrado entender....

16 hours ago, J Montes said:

if (Input.GetMouseButton(1)) {     buttonActionPressedTime = buttonActionPressedTime + Time.fixedDeltaTime;

 

 

16 hours ago, J Montes said:

Y luego cuando necesites interpretar eso ya dividirás pressedTime por lo que toque, o le aplicas la función que quieras (lineal, cuadrática, una spline a tu gusto...).

con que lo tengo que dividir

 

16 hours ago, J Montes said:

// la tensión normalizada entre 0 y 1 (siempre mejor! :))

normalizar no era hacer que un numero fuera -1, 0 o 1, por que lo clampeas....

 

Como puedes ver, hablo desde una ignorancia... casi absoluta

Share this post


Link to post
Share on other sites

Para esta práctica necesitas 2 "eventos", MouseUp y MouseDown.

private void Update()
{
	if (Input.GetMouseButton(0)) // Si fuera DOWN se ejecutaria 1 vez. De esta menera detecta si el mouse esta siendo presionado.
	{
	}

	if (Input.GetMouseButtonUp(0))
	{
	}
}

Teniendo esto ahora necesitarás un factor, número del 0 al 1 que será utilizado para multiplicar el valor máximo que desees.
Para esto la forma más simple y de alguna manera "segura" es utilizando Time.deltaTime para incrementar una variable.

Dentro de el bloque IF del mouse "DOWN".

time_amount += Time.deltaTime;

Dentro de el bloque IF del mouse UP

OnFinishEvent(time_amount);
time_amount = 0;

La función OnFinishEvent es donde ejecutaras la mecanica necesario, multiplicando time_amount normalizado * el maximo valor permitido.

Edited by francoe1
Modifique un error lógico.
  • Like 1

Share this post


Link to post
Share on other sites

No usarías corrutinas para esto, porque Unity está orientado a que este tipo de lógica no necesite corrutinas: en cada frame, tienes un evento Update() para ocuparte de la lógica que necesites ejecutar. 

Podríamos hacerlo en una corrutina, claro, pero sería más lioso que como te ha dicho @francoe1.

Una corrutina la usas cuando precisamente quieres ejecutar instrucciones a lo largo de varios frames. Por ejemplo, las uso mucho para demorar algo o secuenciar cosas (ejemplo: termina una partida, emito un sonido, paro reloj y controles, espero 2 segundos, y muestro un mensaje de Final. Para esperar esos dos segundos, podríamos usar una variable y en el Update comprobar si han pasado esos 2 segundos, pero sería engorroso hacer eso para cada secuencia, y rompe la linealidad del código. En ese caso, yo suelo hacer algo como:

void Update() {
  if (finished) {
    gameStopped = true;  // ejemplo: marcamos el juego como parado
    StartCoroutine(EndGameCoroutine);  // arrancamos nuestra secuencia de fin de juego
  }
}

private IEnumerator EndGameCoroutine(float waitTime) 
{
            endSound.Play();  // ejemplo: sonido de fin de juego
            timer.Stop();  // ejemplo: en este ejemplo, paro el reloj del juego ya mismo ya que ha acabado la partida
            yield return new WaitForSeconds(2.0f);  // esperamos un rato, me gusta que el jugador contemple su éxito o fracaso
            endGameBanner.SetActive(true);  // ejemplo: mostramos un mensaje de fin de partida
            yield return new WaitForSeconds(3.0f); // esperamos un rato, para que el jugador pueda ver el mensaje anterior
            restartRound();  // ejemplo: y reiniciamos
}

Ves que en este ejemplo sería engorroso tener condiciones el Update() para cada una de esas esperas de 2 segundos, en cambio con una corrutina se expresa de forma secuencial.

En todo momento, puede haber una o más corutinas ejecutándose. Éstas se ejecutan durante el Update(), de forma que puedes ir arrancándolas y se ejecutarán concurrentemente (en "paralelo") al resto de tus updates. Ojo a no dejar corrutinas perdidas. Fíjate también que en realidad las corutinas pendientes se ejecutan en realidad, en orden, al final del Update de la escena (no corren en hilos, sino que utilizan un modelo de programación asíncrona y de ahí que se llamen corrutinas). En resumen si lanzas una corutina en Update(), ésta se ejecutará al final del Update de ese frame para todos los objetos. Si una corrutina está esperando 2 segundos, se ejecutará la línea siguiente al final del Update cuando terminen esos 2 segundos.

La manera que tiene una corrutina de "parar y esperar a algún evento" es declarándose como IEnumerator y usando ese "yield return". Esto es una peculiaridad del lenguaje y no vamos a entrar en detalles por ahora.

Las corrutinas son útiles para muchas más cosas que temporizar algo. Por ejemplo, para díalogos de tipo "Aceptar / Cancelar". El código que espera la respuesta usa:

bool confirmed = yield return new ShowConfirmationDialog("Are you sure?");  // esta función no es estándar, es un ejemplo

Y se queda por tanto esperando a que el usuario responda a ese mensaje (es posible decirle a una corutina que "ya ha llegado su evento"). También se usan para peticiones de red o cargas de recursos (que se ejecutan por detrás, de forma asíncronas).

Mi consejo es que pienses por ahora en corrutinas para secuencias de acciones programadas. Por ejemplo, al soltar tu arco, podrías querer una corrutina para:

  1. Bloquear el movimiento del jugador
  2. Sonido de disparo
  3. Preparar la flecha y lanzarla
  4. (ESPERAR) al impacto de la flecha y/o timeout  <- este sería el motivo de usar una corrutina para esto
  5. comprobar el impacto (terreno válido, etc) y salir si es inválido
  6. sonido de "enganchar la flecha"
  7. crear el puente
  8. reestablecer el movimiento del jugador

Igualmente, podrías hacer esto usando varios scripts en la flecha. Usar una corrutina para este tipo de secuencias depende del contexto, y de tus preferencias y estilo personal. Pero de todas formas, esto sería una vez se decide soltar la flecha... en general para gestionar los controles yo te recomiendo que no pienses en corrutinas. Igual alguien tiene otra opinión, pero yo no veo su utilidad aquí, ya que el mecanismo de Update() está pensado exactamente para esa parte de la lógica -controles, movimientos de objetos, lógica que se ejecuta en cada frame...-).

 

En otro orden de cosas:

Normalizar no es hacer que algo valga "-1, 0, o 1". Normalizar significa "regularizar" algo y normalmente a lo que nos referimos depende del contexto.

Pero para empezar, es habitual referirse a valores entre  -1.0 y 1.0 (con todos los números reales intermedios). Quizá en algún contexto normalizar se refiera a "-1, 0 o 1" (valores enteros discretos) pero no en este caso. 

En otros casos nos referimos a valores positivos entre 0 y 1 , como en este caso, donde el tiempo de tensión puede ser "0" o "máximo" pero no puede ser negativo evidentemente. Si lo normalizamos, en general, la mayoría entendemos ponerlo entre 0 y 1 (es decir, dividir por el máximo).

En mi ejemplo, además lo clampeo porque si el usuario deja el ratón pulsado más tiempo entiendo que consideramos que está en el "máximo", por eso lo clampeo entre 0 y 1 (una vez dividido por el máximo: es decir, "normalizado").

Por supuesto, podrías clampear entre [0, maxTime] y luego dividir, o dividir primero y clampear entre [0, 1]... esto ya tienes que tener tú claro qué unidades y qué representa cada una de tus variables.

Y yo por eso sugiero contar tiempo, y hacer las cuentas al final: así tienes siempre el dato inequívoco (tiempo pulsado) y luego con un par de cuentas (como una división y un clamp) ya lo tienes entre 0 y 1 (disparar flojísimo - máxima tensión). Al estar normalizado, lo puedes usar para multiplicar por tu fuerza, para tu animación... entre 0 y 1. Por eso todo el mundo te aconseja que intentes trabajar así y no con valores absolutos, porque luego cualquier cambio te obligará a cambiar varias cosas. Pero... ¡todos metemos constantes en el código durante las pruebas!.

...en estadística, normalizar se refiere a normalizar los valores de una serie respecto a unos parámetros estadísticos. En álgebra lineal, normalizar un vector significa hacer que su magnitud sea 1 conservando su dirección (en Unity: Vector3.normalize() y muchas otras funciones), normalizar una matriz es hacer que la transformación que representa no escale el espacio, y etc etc...

 

Edited by J Montes
  • Like 1

Share this post


Link to post
Share on other sites

Por lo que explicas, tenia una idea totalmente equivocado sobre las corrutinas ... como bes aun me queda mucho por aprender (aun tengo miedo a los while ), a partir de lo que me as contado intentare llegar a entenderlas completamente

 

Gracias a todos por la ayuda, y en especial a la explicación de J Montes :96_ok_hand:

Share this post


Link to post
Share on other sites

Buenas tardes, estoy leyendo por encima todos los comentarios y como siempre termino abrumado con todo lo que saben en este foro, pero creo que lo que intentas hacer es mucho mas sencillo que todo lo que te están explicando y se soluciona sin usar while (que está para otros casos).

Según como yo lo he entendido, tu problema es que Unity no tiene nada que detecte mientras la tecla está pulsada, tan solo cuando la pulsas una vez o cuando dejas de pulsarla y lo que pretendes hacer es que cuando está la tecla pulsada una variable sume para hacer algo que tengas en mente con esa variable y es muy facil de resolver:

- Creas una variable booleana que te devolverá true o false y la puedes llamar por ejemplo Tecla_Pulsada.

- Cuando oprimas la tecla que tu quieras, por medio de un If (. . .) indicas que la booleana que has creado antes sea true y con else que sea false.

- De nuevo en otro If (. . .) indicas que cuando la booleana sea true, la variable a sumar empiece a hacerlo, si la booleana es false, no sumará nada a la variable. Por tanto mientras la tecla esté pulsada esa variable que habias creado va a sumar y en cuanto sueltes la tecla dejará de hacerlo.

No se si he entendido bien cual era tu problema...

Un saludo.

Share this post


Link to post
Share on other sites

Buenas tardes Jhonatan

Lo mismo que estas explicando tu, se puede lograr mediante el script de el compañero francoe 

private void Update()
{
	if (Input.GetMouseButton(0)) // Si fuera DOWN se ejecutaria 1 vez. De esta menera detecta si el mouse esta siendo presionado.
	{
	}

	if (Input.GetMouseButtonUp(0))
	{
	}
}

en el que cuando presiono el ratón (sin poner "down", por que entonces solo se ejecuta un frame) pues se empieza a sumar 1 a el flotante, y cuando se suelta (

Input.GetMouseButtonUp(0)

)

pues se aplica ese flotante a la cantidad de fuerza que tendrá el rigidbody... no se si me explico muy bien :7_sweat_smile:

 

Share this post


Link to post
Share on other sites
6 hours ago, Jhonatan00_00 said:

Buenas tardes, estoy leyendo por encima todos los comentarios y como siempre termino abrumado con todo lo que saben en este foro, pero creo que lo que intentas hacer es mucho mas sencillo que todo lo que te están explicando y se soluciona sin usar while (que está para otros casos).

Según como yo lo he entendido, tu problema es que Unity no tiene nada que detecte mientras la tecla está pulsada, tan solo cuando la pulsas una vez o cuando dejas de pulsarla y lo que pretendes hacer es que cuando está la tecla pulsada una variable sume para hacer algo que tengas en mente con esa variable y es muy facil de resolver:

- Creas una variable booleana que te devolverá true o false y la puedes llamar por ejemplo Tecla_Pulsada.

- Cuando oprimas la tecla que tu quieras, por medio de un If (. . .) indicas que la booleana que has creado antes sea true y con else que sea false.

- De nuevo en otro If (. . .) indicas que cuando la booleana sea true, la variable a sumar empiece a hacerlo, si la booleana es false, no sumará nada a la variable. Por tanto mientras la tecla esté pulsada esa variable que habias creado va a sumar y en cuanto sueltes la tecla dejará de hacerlo.

No se si he entendido bien cual era tu problema...

Un saludo.

Cuando todos empezamos a programar creamos este tipo de lógicas, esto crea algo que llamamos código espagueti.
No hay una forma 100% correcta para realizarlo con el sistema actual de inputs de UNITY,  es lamentable que se requiera un IF que sea comprobado constantemente para detectar un evento de teclado.

Los BOOL-FLAG no siempre son buena idea, es decir, de alguna manera el FLAG se asigna con un valor, esto quiere decir que el evento que esperamos se está realizando pero desconocemos de qué manera tratarlo.

¿Es necesario incrementar una variable?
No, claramente este es el error de inicio al intentar solucionar el problema.

¿Entonces cómo lo hago?
Simple, al detectar el evento KeyDown guardamos una referencia de tiempo de ejecución, esto puede ser DataTime.Now, o Time.time de unity, luego al detectar el evento KeyUp restamos el valor del tiempo actual con el tiempo guardado, esto nos va a dar un valor que no dependerá del FrameRate actual.

CODIGO

public class DetectKeyTime : MonoBehaviour
{
    public Action<float> EventFinish;
    public KeyCode Key = KeyCode.F;
    private float m_lastTime { get; set;}    
    
    private void Update()
    {
        if (Input.GetKeyDown(Key))
            m_lastTime = Time.time;
        if (Input.GetKeyUp(Key))
            EventFinish?.Invoke(Time.time - m_lastTime);
    }
}

Esto estaría correcto, pero aún eliminar la función Update y tener un Sistema de eventos para los inputs evitando así que cada instancia del componente realice la misma comprobación. 

Share this post


Link to post
Share on other sites

Buenas tardes, yo desde lo poco que se de programación puedo decir que hagamos lo que hagamos el PC siempre va a estar constantemente haciendo comprobaciones, es mas, todas las funciones que nos proporciona un engine o un lenguaje de programación son operaciones como la que yo he dicho antes pero simplificadas, para hacerlo mas sencillo, pero comprobaciones al fin de al cabo con sus If detrás solo que no los ves. De hecho, yo he programado muchísimas cosas (primero en Div Game Studio 2, después en Blitz3D y por último en Unity) sin saber muchos comandos del lenguaje y usando instrucciones básicas porque todo empieza con 0 y 1 y todo empieza con If, Else y poco mas... Las instrucciones son esas cosas simplificadas en un comando, pero están ahí detrás igualmente y no van a consumir mas recursos a no ser que uses la misma comprobación mas veces de las que sean necesarias.

En este último código que ha puesto Francoe1 ya hay montones de comprobaciones por cada frame lo quiera o no y tampoco entiendo por que a los programadores mas avanzados les gusta tanto crear variables para llamar a las cosas como quieren y no por su nombre, por ejemplo, en lugar de poner Input.GetKeyDown(KeyCode.F) y ya está, primero crea una variable para llamar a KeyCode.F como Key (lo que es mas trabajo tanto para el programador como para el PC y es mas complicado) y después usa esa variable para un If que no es una operación matemática ni nada complejo.

Yo pienso que la solución mas sencilla y práctica, si funciona, es la mejor, aunque es bueno saber comandos para facilitar muchas operaciones matemáticas (sobre todo), pero para esto tan simple creo que no es necesario tanto jaleo.

Un saludo.

 

Share this post


Link to post
Share on other sites
3 hours ago, Jhonatan00_00 said:

Buenas tardes, yo desde lo poco que se de programación puedo decir que hagamos lo que hagamos el PC siempre va a estar constantemente haciendo comprobaciones, es mas, todas las funciones que nos proporciona un engine o un lenguaje de programación son operaciones como la que yo he dicho antes pero simplificadas, para hacerlo mas sencillo, pero comprobaciones al fin de al cabo con sus If detrás solo que no los ves. De hecho, yo he programado muchísimas cosas (primero en Div Game Studio 2, después en Blitz3D y por último en Unity) sin saber muchos comandos del lenguaje y usando instrucciones básicas porque todo empieza con 0 y 1 y todo empieza con If, Else y poco mas... Las instrucciones son esas cosas simplificadas en un comando, pero están ahí detrás igualmente y no van a consumir mas recursos a no ser que uses la misma comprobación mas veces de las que sean necesarias.

En este último código que ha puesto Francoe1 ya hay montones de comprobaciones por cada frame lo quiera o no y tampoco entiendo por que a los programadores mas avanzados les gusta tanto crear variables para llamar a las cosas como quieren y no por su nombre, por ejemplo, en lugar de poner Input.GetKeyDown(KeyCode.F) y ya está, primero crea una variable para llamar a KeyCode.F como Key (lo que es mas trabajo tanto para el programador como para el PC y es mas complicado) y después usa esa variable para un If que no es una operación matemática ni nada complejo.

Yo pienso que la solución mas sencilla y práctica, si funciona, es la mejor, aunque es bueno saber comandos para facilitar muchas operaciones matemáticas (sobre todo), pero para esto tan simple creo que no es necesario tanto jaleo.

Un saludo.

 

No esperaba que conteste semejante brutalidad.

1 - Es muy raro ver lógicas basadas en bloques de IF, la programación no solo se basa en comparaciones lógicas.

2 - Crear variables para ser utilizada es una costumbre "buena" para ahorrar memoria. Esto es algo que con los años vas aprendiendo, es común ver string dentro de un bloque Update sin estar conscientes de que se está creando un nuevo objeto por cada iteración.

3 - La idea no es discutir, si no, darte información para que armes tu propio camino a una solución. 
La programación no es algo "simple" aunque lo parezca, cuando comienzas crees que se trata únicamente de operaciones lógicas simples, luego empiezas a estudiar múltiples casos y soluciones te das cuenta el ¿por qué? de dichas implementaciones.

"hagamos lo que hagamos el PC siempre va a estar constantemente haciendo comprobaciones"
Esta frase deja mucho que decir sobre tu conocimiento, para entender qué tipos de comprobaciones, formas y orden se deben seguir tendrás que estudiar varios años, como muchos de los que estamos acá, C# es un lenguaje compilado intermedio, esto quiere decir que todo lo que programes se pasa a MSIL para ser interpretado. MSIL tiene muchas pautas para lograr un funcionamiento óptimo, las vas aprendiendo con el tiempo, con los errores y los fracasos.
Tu frase es recíproca, la magia o el conocimiento te lleva a saber distinguir qué maneras son las óptimas para trabajar.

 

 

Share this post


Link to post
Share on other sites
Sign in to follow this  

×
×
  • Create New...