Visualizzazione dei risultati da 1 a 6 su 6
  1. #1

    [C#] Rimanere in attesa dell'azione dell'utente...

    Mi spiego meglio:
    sto programmando un giochino, e quello che devo fare è poter "mettere in pausa" un ciclo while fino a quando il giocatore non ha fatto la sua mossa. Il ciclo while è, detta in parole povere, una cosa del tipo:

    While (qualcuno non ha vinto)
    {
    Gioco io;
    Gioca il computer;
    }

    Il problema è quel "Gioco io". Non so come fermare il ciclo e fargli aspettare che io abbia mosso. Ho provato con il ThreadPool.QueueUserWorkItem e un AutoResetEvent, ma il problema persiste: avvio il nuovo thread e fermo il thread principale in attesa dell'evento che lo sblocchi. Ma il nuovo thread a sua volta termina subito, dato che anche lui deve aspettare la mia mossa, e non so come fargliela aspettare...

    Immagino che sia una banalità, ma non mi viene in mente come risolvere la cosa...

    L'alternativa sarebbe quella di eliminare il ciclo while, e collegare le due azioni (gioco io e gioca il computer) con una chiamata alla successiva azione al termine della precedente (con il controllo che nel mentre non sia finita la partita).
    Però ormai mi sono fissato, e voglio capire se esiste un modo per fare questa cosa...

    Grazie a tutti.

    Ciao.

  2. #2
    Moderatore di Programmazione L'avatar di alka
    Registrato dal
    Oct 2001
    residenza
    Reggio Emilia
    Messaggi
    24,472
    Che tipo di applicazione stai realizzando?

    E' una Windows Application o una Console Application (per il prompt)?
    MARCO BREVEGLIERI
    Software and Web Developer, Teacher and Consultant

    Home | Blog | Delphi Podcast | Twitch | Altro...

  3. #3
    Originariamente inviato da alka
    Che tipo di applicazione stai realizzando?

    E' una Windows Application o una Console Application (per il prompt)?
    Si tratta di una windows application, per la precisione è per windows mobile.

    Ho fatto una gran quantità di prove, ed ho notato che il problema è ricorrente anche in altre situazioni. Per esempio quando visualizzo su schermo un'animazione, realizzata con un timer allo scadere del quale viene sostituito il frame precedente con il successivo. Si verifica sempre lo stesso problema: se eseguo l'animazione dal thread principale, non c'è modo di "fermare" l'esecuzione del codice durante la visualizzazione dell'animazione. Se la eseguo da un altro thread, mettendo in wait il principale con il metodo AutoResetEvent.WaitOne(), il thread si conclude subito e dell'animazione mi va bene se riesco a vedere il primo frame... in questo modo tra l'altro, non concludendosi l'operazione, non arrivo neanche a chiamare l'evento che sblocca il thread principale, e quindi mi rimane tutta l'applicazione bloccata.

    La conclusione a cui sono giunto è che l'unico modo per inserire dei "tempi morti" è quello di farlo nel thread principale, dato che l'applicazione rimane viva anche quando tutto il codice è stato eseguito, e collegare le azioni in sequenza solo tramite eventi, lasciando perdere il ciclo while...

    Probabilmente sono stato un po' poco chiaro... appena ho il tempo inserisco qualche frammento di codice come esempio.

  4. #4
    Utente di HTML.it L'avatar di U235
    Registrato dal
    Mar 2006
    Messaggi
    1,539
    non so se ho capito bene ma mi pare che
    non c'è modo di "fermare" l'esecuzione del codice durante la visualizzazione dell'animazione
    non sia corretto... cosa intendi esattamente?

    osserva questo codice sotto, il form principale cambia colore in maniera indipendente dai cicli nel thread separato che gestisce un eventuale logica di gioco. nel particolare si tratta di un ciclo continuo che in caso risulti il turno del giocatore entra in un ciclo annidato dove attende la pressione del bottone da parte dell'utente, quando questa avviene esce dal ciclo annidato per eseguire il codice per il turno del computer.
    codice:
    using System;
    using System.Linq;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Text;
    using System.Windows.Forms;
    using System.Threading;
    
    namespace SmartDeviceProject1
    {
        
        public partial class Form1 : Form
        {
            bool giocoAvviato;
            bool GiocoAvviato
            {
                get
                {
                    lock (lockThis) { return giocoAvviato; }
                }
                set 
                {
                    lock (lockThis) { giocoAvviato = value; }
                }
            }
    
            bool attesaInput;
            bool AttesaInput
            {
                get
                {
                    lock (lockThis) { return attesaInput; }
                }
                set
                {
                    lock (lockThis) { attesaInput = value; }
                }
            }
    
            int numero=-1;
            int Numero
            {
                get
                {
                    lock (lockThis) { return numero; }
                }
                set
                {
                    lock (lockThis) { numero = value; }
                }
            }
    
            object lockThis = new object();
            
            public Form1()
            {
                InitializeComponent();
                timer.Interval = 2000;//imposto il timer a 2 secondi
                timer.Tick += new EventHandler(timer_Tick);
                timer.Enabled = true;
                this.label1.Text = "Avvio gioco";
                GiocoAvviato = true; //avvio il gioco
                Thread t = new Thread(avviaGioco);//mando l'esecuzione in un thread separato dall'interfaccia
                t.Start();
                //da questo punto in poi il thread principale è in attesa di input e simula il funzionamento del tuo cambio del frame 
                //indipendente dal thread secondario che rimane in attesa di input dall'utente o della simulazione di attesa nel turno del computer
            }
    
            void timer_Tick(object sender, EventArgs e)
            {
                //cambio colore al form come prova di concetto della separazione dei thread
                if (this.BackColor == Color.Red)
                {
                    this.BackColor = Color.Yellow;
                }
                else
                {
                    this.BackColor = Color.Red;
                }
            }
    
            void avviaGioco()
            {
                //inizia il gioco
                while (GiocoAvviato)
                {
                    //se è in attesa di input dall'utente entra nel ciclo
                    while (AttesaInput)
                    {
                        //il ciclo continua finchè l'utente non preme il bottone che chiama Button1_Click ponendo numero = 1
                        if (Numero > -1)
                        {
                            //necessario per modificare il form da thread separato
                            if (this.InvokeRequired)
                            {
                                //eseguo il codice riguadante il turno del giocatore attraverso un delegato
                                this.Invoke(new cambio(turnoGiocatore));
                            }
                            else
                            {
                                //eseguo il codice riguadante il turno del giocatore
                                turnoGiocatore();
                            }
                        }
                    }
                    //se il codice non è nel primo loop significa che non è il turno del giocatore, ma se numero non è ancora -1 ma 0 
                    //significa che il turno è già stato "passato" al codice del turno del computer che è fermo (simulato con Thread.Sleep(1000)
                    //questo serve a fare in modo che si riesca a leggere la label quando è il turno del computer 
                    //se no è talmente veloce che si vede solo il turno del giocatore
                    if (Numero < 0)
                    {
                        //necessario per modificare il form da thread separato
                        if (this.InvokeRequired)
                        {
                            //eseguo il codice riguadante il turno del computer attraverso un delegato
                            this.Invoke(new cambio(turnoComputer));
                        }
                        else
                        {
                            //eseguo il codice riguadante il turno del computer
                            turnoComputer();
                        }
                    }
                }
            }
    
            delegate void cambio();
    
            void turnoComputer()
            {
                this.label1.Text = "Turno del giocatore";
                //tuo codice di gioco per Giocatore ovvero il tuo "Gioco io"
                Numero = 0;//imposto a 0 in modo che non entri nella condizione del turno del computer  e nemmeno nel loop di attesa del turno del giocatore
                Thread.Sleep(1000);//simulo un elaborazione di 1 secondo
                AttesaInput = true;//faccio entrare il controllo del codice nel loop dell'attesa di input da parte del giocatore
                this.button1.Enabled = true;//abilito il bottone per il turno del giocatore
                
            }
    
            void turnoGiocatore()
            {
                //se il numero è maggiore di 0 significa che l'utente ha premuto il bottone
                if (Numero > 0)
                {
                    //tuo codice di gioco per Computer ovvero il tuo "Gioca il computer;"
                    Numero = -1;//riporto numero a -1 per fare in modo che nel ciclo principale passi il turno del computer
                    AttesaInput = false;//faccio in modo che lesecuzione non si fermi sul turno del giocatore
                    this.button1.Enabled = false;//disabilito il bottone del giocatore
                    this.label1.Text = "Turno del computer";
                }
            }
    
            private void button1_Click(object sender, EventArgs e)
            {            
                Numero = 1;
            }
    
            private void button2_Click(object sender, EventArgs e)
            {
                GiocoAvviato = !GiocoAvviato;
            }
        }
    }

  5. #5
    Utente di HTML.it L'avatar di rsdpzed
    Registrato dal
    Aug 2001
    Messaggi
    764
    Lascia stare il while e i thread se è solo quello il problema. Usa gli eventi, per esempio se il giocatore interagisce con il gioco tramite pulsanti avrai:

    codice:
    protected void Button1_OnClick(object sender, EventArgs e)
    {
       Gioca(1);
    }
    protected void Button2_OnClick(object sender, EventArgs e)
    {
       Gioca(2);
    }
    //e via dicendo...Non è il miglior modo ma per ora va bene cosi
    
    //qui la logica del gioco... di regola dovrebbe essere in una classe a parte. Ma questo è un altro discorso.
    //In ogni modo questa funzione non è in un while ma viene chiamata solo ogni volta che il player esegue una mossa.
    public void Gioca(int mossaPlayer)
    {
         if (!ThereIsAWinner)
            GiocoIo(mossaPlayer);
    
        if (!ThereIsAWinner)
            GiocaIlComputer();
    
        if (ThereIsAWinner)
        {
            MessageBox.Show("HA VINTO: " + WhoIsTheWinner() + "!");
            ResettaAlloStatoIniziale();
        }
    }
    EDIT:
    ovviamente non per smentire U235. Puoi sempre usare i thread se vuoi ma ho come l'impressione che questa tua idea di usare il while (che ti costringe poi a maneggiare i thread), giusta in caso di ConsoleApplication, sia solo un retaggio di un modo di programmare per Console Application.

  6. #6
    Utente di HTML.it L'avatar di U235
    Registrato dal
    Mar 2006
    Messaggi
    1,539
    Originariamente inviato da rsdpzed
    EDIT:
    ovviamente non per smentire U235. Puoi sempre usare i thread se vuoi ma ho come l'impressione che questa tua idea di usare il while (che ti costringe poi a maneggiare i thread), giusta in caso di ConsoleApplication, sia solo un retaggio di un modo di programmare per Console Application.


    hai pienamente ragione, e anche se lo avessi detto per smentirmi lo avresti fatto con cognizione di causa, e per fortuna siamo in democrazia ed ognuno può esprimere liberamente il suo parere.
    La mia era una prova di concetto.
    A volte però è necessario agire attraverso cicli in thread separati sopratutto in applicazioni mobile per diverse cause. basta pensare ad esempio su ce.net al controllo della carica della batteria o all'uso di alcuni tasti hardware di cui il .net non fornisce eventi specifici, l'unico modo per conoscere se ad esempio è stato premuto quel bottone e quello di interrogare continuamente lo stato (che oltretutto ho scoperto essere più rapido di un evento del .net!).


Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved.