View Full Version : [CICLO 15] Storia 1
Storia 1: Introduzione del menu principale, in cui selezionare la modalità di gioco. Lo sfondo del menu sarà una jpg fissa (in gfx/common), e le voci evidenziabili saranno sei (Story Mode, Versus, Advanced, Custom, Options, Quit), grazie ad una png suddivisa in 6 caselle (in verticale), di dimensione 512x60 px ciascuna, ed ognuna contenente la grafica per la corrispondente voce evidenziata. Con le frecce direzionali su e giù, verrà cambiata la casella della png da mostrare, ovviamente nelle coordinate corrispondenti allo sfondo, insieme ad una variabile capace di assumere valori tra 1 e 5 (ognuno corrisponderà ad una delle prime 5 modalità). Premendo giù sull’ultima voce si selezionerà la prima, premendo su sulla prima si selezionerà l’ultima. Confermando con invio su Versus si accederà al gioco, confermando su Quit il gioco verrà terminato.
Punti cardine da tenere a mente durante i lavori:
* Mai fare a gara a chi finisce il task per primo, meglio procedere con calma, altrimenti perderemo molto più tempo in seguito
* Evitiamo di complicarci la vita, esiste di certo una soluzione più semplice di quella che abbiamo pensato di implementare
* MAI aggiungere elementi non richiesti esplicitamente dai task: se mai serviranno, se ne parlerà nelle prossime storie
* Comunichiamo il più possibile, se qualcosa non è chiaro discutiamone tutti i dettagli fino ad eliminare ogni dubbio, anche il più insignificante
* Postare sempre la test list PRIMA di mettere mano al codice
Task
15.1.1: Vifani: completato
Modificare GameLoop e Game in modo che una volta avviato il gioco mostri lo sfondo del menù nella finestra. Il file da caricare per Background è gfx/common/main.jpg. La finestra e l'enviroment deve essere creato solo una volta.
15.1.2: Ufo13: completato
Creare un MenuBox da visualizzare sopra al background del menù alle coordinate x=0 y=244. Le dimensioni del MenuBox devono essere 512x360. Il box è diviso in 6 aree di 512x60 che corrispondono ad una voce del menù. Quando una voce è selezionata la si deve evidenziare disegnando la parte corrispondente che è contenuta nella texture gfx/common/main_menu.png.
15.1.3: Bonfo: completato
Gestire la pressione dei tasti su e giù nella schermata del menù. Quando si preme il tasto Su nella prima voce si deve selezionare l'ultima e viceversa quando si preme giù nell'ultima voce si deve seleziona re la prima.
15.1.4: Jappilas: 4 giorni
Aggiungere la gestione del tasto invio nei menù. Quando questo viene premuto e la modalità "Versus" è selezionata si deve nascondere il menù e mostrare il normale gioco con le due griglie. Quando si preme su Quit il gioco deve uscire.
15.1.5: Jappilas + cdimauro: 3 giorni
Rendere selezionabili solo le voci "Quit" e "Versus mode" nel menù. La voce predefinita deve essere la modalità Versus.
Ricordate la modalità di svolgimento dei task è:
- Ci si prenota.
- Si guarda il codice e si propone sul forum dei refactoring se questi sono molto grandi altrimenti si procede direttamente.
- Si propone una piccola test list da discutere con il coach e gli altri.
- Si svolge il task.
- Si fa il commit.
ciao ;)
Task 15.1.1 preso!
Tre giorni per farlo visti gli impegni.
^TiGeRShArK^
02-05-2006, 09:51
doh...
vorrei farne uno...
però se prima non finisco il web start il merge sarà da suicidio...
quindi vedo se stasera finisco tutto e domani mi prendo qualcuno di quelli che restano....
prendo il 2, posso cominciare a farlo mercoledì sera, impiego 2 giorni :)
E io prendo il 3 :D
Finito il 2 ci metto 4 giorni (come al solito sto molto largo ;) )
Ufo13, Bonfo: Assegnati. :)
ciao ;)
Cerchiamo di non stare troppo larghi però, così se facciamo in tempo introduciamo un'altra storiella sfiziosa sfiziosa!
Cerchiamo di non stare troppo larghi però, così se facciamo in tempo introduciamo un'altra storiella sfiziosa sfiziosa!
Non ti preoccupare che sono veloci. :)
ciao ;)
jappilas
02-05-2006, 15:58
il numero 4 sembra la continuazione del 3 e un' estensione della macchina a stati iniziata nel 3, quindi potrei farlo io appena bonfo ha finito il 3 :)
Tbonfo + 4gg :D
il numero 4 sembra la continuazione del 3 e un' estensione della macchina a stati iniziata nel 3, quindi potrei farlo io appena bonfo ha finito il 3 :)
Tb + 4gg
Estensione della macchina a stati?
if (EnterWasPressed())
game.Run();
Keep It Simple :)
Non ti preoccupare che sono veloci. :)
ciao ;)
So benissimo che sono veloci, ma darsi una deadline larga porta inevitabilmente a procedere più lentamente (anche inconsciamente, si è consapevoli che c'è ancora tempo). Visto che alcuni task dipendono dal completamento di altri, però, questo porta a fare le stesse cose (il tempo richiesto dal task in fondo è sempre lo stesso) in maniera più lenta, e di conseguenza possiamo realizzare meno cose per ciclo.
Rispetto alle altre cose che abbiamo implementato, questa storia dovrebbe essere piuttosto banalotta, e magari potremmo approfittarne per aggiungere anche qualcosa di diverso. Ovviamente, però, per iniziare a lavorarci dobbiamo chiuderla prima ;)
Stando alla metodologia di sviluppo che usiamo, il Customer (Jocchan) non puo' chiedere al team di aumentare la sua Velocita' per poter produrre piu' Storie. Questa richiesta non e' in suo potere.
Il Customer puo' solo proporre un certo numero di Storie e il team, in base alla sua Velocita', decidere quante ne puo' garantire. Il Customer poi decide quali Storie hanno priorita' e quali no (non e' il team a decidere questo).
Ora, questo meccanismo pero' funziona se i dati sulla Velocita' del team sono accurati e i dati sono accurati se non li sovraestimate. Di solito in questi casi si tiene per ognuno uno "slack value" basato sulla sua storia passata: ad esempio, se Pippo tende a sovrastimare i suoi task del doppio, gli si applica un fattore di 0.5 ed una previsione di 4gg diventa automaticamente 2gg e dopo 2gg il task viene riassegnato. Se Pluto sottostima, il fattore puo' diventare 2.0 magari ed una previsione di 1gg diventa 2gg.
Aiutateci a calcolare la Velocita' del team dando stime il piu' accurate possibili e non "tenetevi larghi", cosi' possiamo sapere con buona precisione quando concluderemo il gioco.
Ovviamente preciso che la mia intenzione non era affatto quella di chiedere di aumentare la velocità, ma semplicemente di far notare che il "tenersi larghi" può essere controproducente, in quanto è molto probabile che finisca - in maniera del tutto involontaria - col farci perdere tempo inutilmente, e con il "falsare" i tempi che stimiamo siano necessari per proseguire il progetto.
Ciclo per ciclo, durante la fase di elaborazione delle storie, è necessario valutare se rientriamo nei tempi per implementare tutto quello che scriviamo, ed ovviamente avere un'idea più precisa della nostra velocità non può che essere un aiuto in questi termini, ed in fase di previsione delle deadline per le varie versioni che rilasceremo.
Quindi cambiano in 2gg per Bonfo e 2gg per Jappilas. Potete garantire queste stime? Da notare che Raffaele non va modificato perche' la sua previsione non e' per tenersi largo, ma e' in base ai suoi impegni, quindi e' cio' che garantisce.
jappilas
02-05-2006, 18:12
Estensione della macchina a stati?
if (EnterWasPressed())
game.Run();
pensavo dal task 3 (che ero tentato di prendere), sarebbe venuta fuori una specie di macchina a stati per gestire i tasti premuti finche' si è nel menu, del tipo:
while(!EscWasPressed())
{
if (( highlightedChoice == VSMode) && (UpWasPressed()))
{ highlightedChoice = Options;}
if (( highlightedChoice == Options) && (DownWasPressed()))
{highlightedChoice = VSMode;}
...}
quindi una semplice modifica sarebbe stata:
if (( highlightedChoice == VSMode) {
if (UpWasPressed()) { highlightedChoice = Options;}
if (EnterWasPressed()) {game.Run();}
}
Keep It Simple :)non era per violare il KISS principle, pensavo l' algoritmo che avevo in testa fosse semplice e limpido :O
ma probabilmente, come di mio solito, penso troppo, quindi non fateci caso e scusatemi :stordita:
Quindi cambiano in 2gg per Bonfo e 2gg per Jappilas. Potete garantire queste stime?
spero
stimavo qualche giorno perche' potro' mettermici solo alla sera :O
stimavo qualche giorno perche' potro' mettermici solo alla sera :O
Allora la stima iniziale va benissimo, purchè ovviamente sia realistica :)
Quindi cambiano in 2gg per Bonfo e 2gg per Jappilas. Potete garantire queste stime? Da notare che Raffaele non va modificato perche' la sua previsione non e' per tenersi largo, ma e' in base ai suoi impegni, quindi e' cio' che garantisce.
Sinceramente io penso di metterci meno di 4 giorni...ma so anche che sono impegnato e che ho sempre l'imprevisto dietro l'angolo.
2 giorni va benissimo...anzi...forse ci metterei anche meno.
Facciamo che passo a 2....e come ho problemi li comunico.
@Fek: porcaccia miseria...che bello poter calcolare la "velocità" di un team. Che fisica è??? Fisica del software :D :D :D
Scusate, sbaglio o il server è down? Ho difficoltà a sincronizzarmi.
NOOOOOOOOOOO CATTIVI, NON ME NE AVETE LASCIATO MANCO UNO :cry: :cry: :cry: :cry:
vabbè, vorra dire che mi divertirò con la storia 2 -.-'
(sgrunt, tutto refactoring)
Scusate, sbaglio o il server è down? Ho difficoltà a sincronizzarmi.
Ho controllato ora ed il repository sembra essere up.
Hai risolto, o hai ancora problemi a sincronizzarti col server?
NOOOOOOOOOOO CATTIVI, NON ME NE AVETE LASCIATO MANCO UNO :cry: :cry: :cry: :cry:
vabbè, vorra dire che mi divertirò con la storia 2 -.-'
(sgrunt, tutto refactoring)
Sono dei lupi famelici :D
P.S.: noto con piacere che hai rimesso il buon vecchio avatar "Coding Horror" :sofico:
Attenzione, modificati leggermente i task 2 e 4.
Nel primo dei due le voci saranno sei e non cinque (aggiunto Quit... si vede che sono un consolaro, su console non esiste e me ne sono bellamente scordato), e nell'altro - come prevedibile - bisognerà attivare anche questa nuova voce.
Dunque ragazzi.
La test list elaborata è la seguente:
testMenuLoopFinishedAfterEnterPressed
testGameLoopStartedAfterMenuLoopStopped
Secondo me completato il tutto salteranno una serie di altri test da risistemare in GameLoop.
Comunque attendo l'avvallo.
Task 15.1.1 committato :)
Ottimo ;)
Ho committato le modifiche a main.jpg e main_menu.png (che riguardano solo il task di Ufo) :)
Task 15.1.1 committato :)
Perfetto! Comincio :)
Scusa Vifani...ho un paio di dubbi filosofici:
public void notifyKeyEvent(int code, boolean state)
{
if(((code == KeyEvent.ESCAPE) || (code == KeyEvent.QUIT)) && inGameLoop)
{
finished = true;
}
if ((code == KeyEvent.ENTER) || (code == KeyEvent.ENTER))
{
finishedMenu = true;
}
}
Qual'è la differenza tra ESCAPE e QUIT?? Cioè perchè è stato aggiunto QUIT?? :eek: :eek:
Ma ancora di più...quel'è la differenza tra ENTER e ENTER?? :eekk: :eekk:
Scusa Vifani...ho un paio di dubbi filosofici:
public void notifyKeyEvent(int code, boolean state)
{
if(((code == KeyEvent.ESCAPE) || (code == KeyEvent.QUIT)) && inGameLoop)
{
finished = true;
}
if ((code == KeyEvent.ENTER) || (code == KeyEvent.ENTER))
{
finishedMenu = true;
}
}
Qual'è la differenza tra ESCAPE e QUIT?? Cioè perchè è stato aggiunto QUIT?? :eek: :eek:
Ma ancora di più...quel'è la differenza tra ENTER e ENTER?? :eekk: :eekk:
Riguardo il discorso di ESCAPE e QUIT non ho approfondito la cosa. Suonava strano anche a me, ma stava già lì, non l'ho aggiunto io.
Riguardo ENTER hai ragione. E' un doppione che si può eliminare :)
Comunque so che a livello aereospaziale poiché le radiazioni solari non schermate dall'atmosfera possono far svarionare i computer usano elettronica ridondante (cioè doppi, tripli, quadrupli controlli) e anche software fatto ad hoc.
Al limite lo si può lasciare e certifichiamo che il tasto ENTER in Diamond Crush è SPACE CERTIFIED :D
Riguardo il discorso di ESCAPE e QUIT non ho approfondito la cosa. Suonava strano anche a me, ma stava già lì, non l'ho aggiunto io.
Se c'e' una duplicazione, va tolta immediatamente, non mi interessa chi l'ha aggiunta: puo' essere chiunque visto che tutti scriviamo ovunque :)
Al limite lo si può lasciare e certifichiamo che il tasto ENTER in Diamond Crush è SPACE CERTIFIED :D
LOL
Ah l'avete notata anche voi :P
L'avevo già tolta ma non posso fare commit :P
Ah l'avete notata anche voi :P
L'avevo già tolta ma non posso fare commit :P
OK....allora è già tutto a posto ;)
Se c'e' una duplicazione, va tolta immediatamente, non mi interessa chi l'ha aggiunta: puo' essere chiunque visto che tutti scriviamo ovunque :)
Se non l'ho tolta è solo perché non avevo il tempo per approfondire e non sapevo esattamente perché chi l'aveva aggiunta all'epoca, l'aveva fatto.
Se non l'ho tolta è solo perché non avevo il tempo per approfondire e non sapevo esattamente perché chi l'aveva aggiunta all'epoca, l'aveva fatto.
Tranquillo, è responsabilità di tutti rimuovere la duplicazione :)
Al limite lo si può lasciare e certifichiamo che il tasto ENTER in Diamond Crush è SPACE CERTIFIED :D
Se non ricordo male i robottini della Nasa che girano su marte sono controllati tramite java e hanno una JavaVM. Potremmo contattare qualche agenzia spaziale ed essere il primo gioco ad andare su un pianeta alieno :D
ciao ;)
Se non l'ho tolta è solo perché non avevo il tempo per approfondire e non sapevo esattamente perché chi l'aveva aggiunta all'epoca, l'aveva fatto.
Questo lo capisco. In quel caso segnalalo sul forum cosi' un lupo famelico puo' lancarsi sulla duplicazione. E' importante non lasciare le duplicazioni cosi' nell'anonimato...
cdimauro
05-05-2006, 11:28
Scusa Vifani...ho un paio di dubbi filosofici:
public void notifyKeyEvent(int code, boolean state)
{
if(((code == KeyEvent.ESCAPE) || (code == KeyEvent.QUIT)) && inGameLoop)
{
finished = true;
}
if ((code == KeyEvent.ENTER) || (code == KeyEvent.ENTER))
{
finishedMenu = true;
}
}
Qual'è la differenza tra ESCAPE e QUIT?? Cioè perchè è stato aggiunto QUIT?? :eek: :eek:
Fa parte del refactoring che sto operando su Engine: l'ho introdotto ai tempi del porting di SDL per indicare l'evento di "chiusura applicazione" (chiusura finestra, attualmente).
L'idea è quella di togliere di mezzo il metodo isWindowClosed da Engine e sostituirlo con un generico checkForEvents, che eventualmente inserisce gli eventi presenti in Engine nel "flusso" dei tasti premuti (che in realtà dovrebbe diventare un più generico flusso di eventi ;)).
In soldoni: la chiusura della finestra dovrebbe scatenare un evento QUIT.
L'idea del flusso di eventi dovrebbe portare a un'interfaccia col metodo checkForEvents, che verrebbe implementata da Engine, Audio, Keyboard, ecc. (anche Timer, se ha senso farlo), e richiamata a ogni game loop: in questo modo qualunque dispositivo avesse "qualcosa da dire", avrebbe il modo per poterlo fare, e in maniera completamente trasparente all'applicazione.
Mi spiace per l'assenza di commenti, ma il refactoring non è ancora finito, perché richiede un bel po' di tempo e modifiche al sorgente.
Ma ancora di più...quel'è la differenza tra ENTER e ENTER?? :eekk: :eekk:
Io non c'entro, eh! :D D'altra parte sono pure sinistroide... :asd:
cdimauro
05-05-2006, 11:29
Questo lo capisco. In quel caso segnalalo sul forum cosi' un lupo famelico puo' lancarsi sulla duplicazione. E' importante non lasciare le duplicazioni cosi' nell'anonimato...
ESCAPE e QUIT non sono un duplicazione. ;)
In soldoni: la chiusura della finestra dovrebbe scatenare un evento QUIT.
Ho perfettamente capito la logica....ma QUIT non è un KeyEvent. Semmai è un ApplicationEvent. Ovvero Quit non rappresenta la pressione di alcun tasto...quindi ESCAPE e QUIT sono una duplicazione.
Anzi, forse sarebbe giusto eliminare ESCAPE e tenere QUIT, perchè in realtà non è detto che il tasto che genera l'uscita dal gioco sia proprio ESCAPE, dipende dove lo si vuol mappare.
cdimauro
05-05-2006, 12:06
Ho perfettamente capito la logica....ma QUIT non è un KeyEvent. Semmai è un ApplicationEvent.
Ma infatti:
"(che in realtà dovrebbe diventare un più generico flusso di eventi )"
;)
Ovvero Quit non rappresenta la pressione di alcun tasto...quindi ESCAPE e QUIT sono una duplicazione.
Ho capito quello che vuoi dire, e hai perfettamente ragione.
Anzi, forse sarebbe giusto eliminare ESCAPE e tenere QUIT, perchè in realtà non è detto che il tasto che genera l'uscita dal gioco sia proprio ESCAPE, dipende dove lo si vuol mappare.
Esattamente. ESCAPE va intercettato dalle sezioni del gioco che ne fanno uso e dovrebbe essere scatenato un evento di uscita dal gioco.
Fatemi finire il refactoring! :p
Mi fate un aggiornamento sui task? Secondo la tabella siamo indietro su questa Storia.
Finisco oggi pomeriggio per rientrare nei 2 giorni :)
15.1.2: Ufo13: 2 giorni
Creare un MenuBox da visualizzare sopra al background del menù alle coordinate x=0 y=244. Le dimensioni del MenuBox devono essere 512x360. Il box è diviso in 6 aree di 512x60 che corrispondono ad una voce del menù. Quando una voce è selezionata la si deve evidenziare disegnando la parte corrispondente che è contenuta nella texture gfx/common/main_menu.png.
Con coordinate x=0, y=244 risulta un po' sfalsato
Il metodo in GameLoop:
public void menuLoop()
non è testato!
task completato :)
Che ne dite invece di tutti quei get un bel metodo che accetta in ingresso un enumerativo MenuItem.
Ed inoltre aggiungere un getSelectedItem() ??? ;)
EDIT:
Oppure mettere all'interno di MainMenu dei campi public static final come per i KeyEvent.
Anzi....forse è pure meglio....opero con la seconda ;)
EDIT2:
Decisone finale: Enumerativo. :D
Il metodo in GameLoop:
public void menuLoop()
non è testato!
Ragazzi, per favore, sempre prima i test e poi il codice. Non voglio fare il poliziotto e fare il revert del codice che mi accorgo scritto prima dei test. Aiutatemi ad aiutarvi :)
Che ne dite invece di tutti quei get un bel metodo che accetta in ingresso un enumerativo MenuItem.
Ed inoltre aggiungere un getSelectedItem() ??? ;)
EDIT:
Oppure mettere all'interno di MainMenu dei campi public static final come per i KeyEvent.
Anzi....forse è pure meglio....opero con la seconda ;)
EDIT2:
Decisone finale: Enumerativo. :D
Direi che è proprio il caso :)
Fatto il refactoring.
Ecco la test list:
- aggiungere un metodo getSelectedItem a MainMenu.
- controllare che la pressione del tasto su e giù cambi il selectedItem (probabilmente li scorro tutti)
- test per il passaggio dal primo item all'ultimo
- test per il passaggio dall'ultimo item al primo
Se va bene la test list....c'è il rischio che domanimattina i trovate il task fatto :sofico:
Fatto il refactoring.
Ecco la test list:
- aggiungere un metodo getSelectedItem a MainMenu.
- controllare che la pressione del tasto su e giù cambi il selectedItem (probabilmente li scorro tutti)
- test per il passaggio dal primo item all'ultimo
- test per il passaggio dall'ultimo item al primo
Se va bene la test list....c'è il rischio che domanimattina i trovate il task fatto :sofico:
Va bene :)
Ragazzi, per favore, sempre prima i test e poi il codice. Non voglio fare il poliziotto e fare il revert del codice che mi accorgo scritto prima dei test. Aiutatemi ad aiutarvi :)
Aggiunto il test che verifica il disegno della texture per il background del menu.
I test sono stati fatti prima del codice, anche perché altrimenti non avrei realizzato tutto il discorso del tasto ENTER in quel modo. Il test sulla verifica del funzionamento del rendering evidentemente non era necessario per lo sviluppo del task anche perché la stessa background del gioco settata in GameLoop non ha alcun test che ne verifichi l'effettivo disegno, ma solo un test che verifica il suo ordine di disegno rispetto al punteggio.
Dire che menuloop non era testata non è esatto. Tutto ciò che serve per entrare in gameloop e la sua uscita (cioè la pressione di ENTER) è testato e il suo interno è lo stesso di loop (ci sono i vari processWindows, processInput, ecc...).
TASK 15.1.3 Completato.
Ma non va :( :(
Sembra che GameLoop non riceva i notifyKeyEvent dalla tastiera.
Altri problemi:
- se si chiude la finestra si sente la musica del gioco partire e poi chiudersi l'applicazione
- non è stato specificato come comportarsi se il tasto giù, o su, sono lasciati premuti durante la visualizzazione del menù: si fa scorrere all'impazzata oppure si aspetta il realase??
Risolto ;)
Semplicemente mancava il mapping di UP e DOWN in public static KeyMappings createForGameLoop()
Ma è normale che non esista nessun test per i KeyMappings??
Nessuno di questi metodi di KeyMappings è testato:
-createForPlayerOne()
-createForPlayerTwo()
-createForGameLoop()
In più ho aggiunto i test relativi al Press&Realease, altrimenti era considerato 2 volte il tasto.
Per come è realizzato ora la pressione continuata del tasto non fa cambiare il menù.
Notte ;)
A che punto siamo? Manca solo il task 4?
A che punto siamo? Manca solo il task 4?
Vorrei che il 4 fosse fatto in pair. Jappilas vs ?
Vorrei che il 4 fosse fatto in pair. Jappilas vs ?
Jappilas mi ha fatto vedere la lista dei test ed il loro codice poco fa in chat e sta procedendo bene. Secondo me può procedere anche da solo :)
ciao ;)
Jappilas mi ha fatto vedere la lista dei test ed il loro codice poco fa in chat e sta procedendo bene. Secondo me può procedere anche da solo :)
ciao ;)
Allora e' ok, meglio postare la test list comunque, cosi' abbiamo tutti un'idea.
jappilas
07-05-2006, 14:56
I test di cui parlavo con Vic prima erano essenzialmente
- selezione 2a item del menu, notificare ENTER premuto, testare se parte il gioco
- selezione 6a item del menu, notificare ENTER premuto, testare se il gioco esce
- selezione item unhandled, testare che per ora la 1, 3, 4, e 5 non alterino lo stato ( non entrino nel gioco e non quittino), anche notificando la pressione del tasto ENTER
con un test o un serie di piccoli test, eliminabili "safely" man mano che le item restanti vengono implementate nei cicli futuri, non essendo quindi più unhandled
avevo però delle perplessità sull' effettiva traduzione delle condizioni da verificare.. Il seg test vi sembra corretto?
public void testSelectVersusModeMenuItem()
{
gameLoop.menuLoop();
MainMenu mainMenu = gameLoop.getMainMenu();
mainMenu.selectMenuItem(MenuItem.VERSUS_MODE);
gameLoop.notifyKeyEvent(KeyEvent.ENTER, KeyEvent.PRESSED);
gameLoop.notifyKeyEvent(KeyEvent.ENTER, KeyEvent.RELEASED);
assertTrue("The Menu Loop must be stopped", gameLoop.isMenuFinished());
assertTrue("The GameLoop must be running", gameLoop.inGameLoop());
}
jappilas
07-05-2006, 21:28
testGameLoopStartedAfterMenuLoopStopped() fallisce: comprensibilmente, perchè testa un comportamento che, con le modifiche alla gestione di KeyEvent.ENTER, ora si verifica: una volta su 6, da un punto di vista puramente statistico, e mai se il versus mode non viene selezonato tramite chiamate esplicita
invece passa la versione del test contenente le righe di codice evidenziate in verde:
public void testGameLoopStartedAfterMenuLoopStopped()
{
assertFalse("The GameLoop must be stopped", gameLoop.inGameLoop());
assertFalse("The Menu Loop must be running", gameLoop.isMenuFinished());
gameLoop.menuLoop();
MainMenu mainMenu = gameLoop.getMainMenu();
mainMenu.selectMenuItem(MenuItem.VERSUS_MODE);
gameLoop.notifyKeyEvent(KeyEvent.ENTER, KeyEvent.RELEASED);
gameLoop.initBeforeGameLoop();
assertTrue("The GameLoop must be running", gameLoop.inGameLoop());
assertTrue("The Menu Loop must be stopped", gameLoop.isMenuFinished());
}
jappilas
08-05-2006, 11:40
Vorrei che il 4 fosse fatto in pair. Jappilas vs ?
ad essere sincero, non e' che un po' di aiuto mi dispiacerebbe eh :D
pero' il problema adesso non e' tanto far passare i test, quanto ridurre la complessita' ciclometrica di un metodo in cui la verifica sulle condizioni e' tutto, senza alterare lo stato attuale (ad es, la duplicazione del quit/escape, va mentenuta?) e senza modificare il codice scritto da chi ha svolto i task precedenti...
ad essere sincero, non e' che un po' di aiuto mi dispiacerebbe eh :D
pero' il problema adesso non e' tanto far passare i test, quanto ridurre la complessita' ciclometrica di un metodo in cui la verifica sulle condizioni e' tutto, senza alterare lo stato attuale (ad es, la duplicazione del quit/escape, va mentenuta?) e senza modificare il codice scritto da chi ha svolto i task precedenti...
un pattern state?
ad essere sincero, non e' che un po' di aiuto mi dispiacerebbe eh :D
pero' il problema adesso non e' tanto far passare i test, quanto ridurre la complessita' ciclometrica di un metodo in cui la verifica sulle condizioni e' tutto, senza alterare lo stato attuale (ad es, la duplicazione del quit/escape, va mentenuta?) e senza modificare il codice scritto da chi ha svolto i task precedenti...
Nessuna duplicazione va mantenuta. Qui hai diverse strade, dallo State al Command pattern per la GUI. Il secondo mi sembra un'opzione interessante nel nostro codice, ma la scelta sta a te. Anche gli Action, ad esempio, assomigliano a tutti gli effetti a dei Command.
jappilas
08-05-2006, 12:41
un pattern state?
ci puo' stare, ma ho la netta sensazione che implichi un refactoring del codice scritto da ufo e bonfo, che al momento mi sembrava prematuro :stordita:
Nessuna duplicazione va mantenuta.
se elimino la duplicazione mi libero di una condizione sotto if, e me ne resta da limare solo un' altra per accontentare checkstyle (che e' il mio obiettivo contingente) :D
Qui hai diverse strade, dallo State al Command pattern per la GUI.
intendi per il menu ?
Il secondo mi sembra un'opzione interessante nel nostro codice, ma la scelta sta a te. Anche gli Action, ad esempio, assomigliano a tutti gli effetti a dei Command.
come pattern e' un po' complesso (per le capacita' attuali dei miei neuroni bruciati, intendo) ma siccome sono uno dei piu' vecchi "qui dentro", non posso tirarmi indietro... stasera vedo di metterlo in pratica :D
jappilas
08-05-2006, 13:00
doppio sorry :O
se elimino la duplicazione mi libero di una condizione sotto if, e me ne resta da limare solo un' altra per accontentare checkstyle (che e' il mio obiettivo contingente) :D
Perfetto, eliminala :)
intendi per il menu ?
Sicuramente per i menu, il Command Patter e' praticamente nato con le GUI. Ma anche le nostre Action, a mio avviso, non sono altro che dei Command. Il punto e': fai il refactoring solo se porta ad una semplificazione del menu, non tanto per usare un pattern. E non implementarlo tutto che non ci serve.
come pattern e' un po' complesso (per le capacita' attuali dei miei neuroni bruciati, intendo) ma siccome sono uno dei piu' vecchi "qui dentro", non posso tirarmi indietro... stasera vedo di metterlo in pratica :D
Stasera sono a disposizione se necessario :)
jappilas
08-05-2006, 20:17
Perfetto, eliminala :)
eliminando quella e una condizione che reputavo necessaria per gestire ENTER, i test passano e ant builda
solo che... ehm... si va in crash subito dopo il menu :stordita:
e in bugreport è annotata una nullPointerException (null pointer? in java? :mbe: ) :fagiano:
Sicuramente per i menu, il Command Patter e' praticamente nato con le GUI. Ma anche le nostre Action, a mio avviso, non sono altro che dei Command. Il punto e': fai il refactoring solo se porta ad una semplificazione del menu, non tanto per usare un pattern.
dont worry, se lo implemento è per rendere un po' più pulita una parte di codice che al momento mi sembra un po' contorta
però ehm, ora che vedo il bug mi sa che è contingente eliminare quello :( :fagiano:
Stasera sono a disposizione se necessario :)mi sa che approfitterò volentieri :)
cdimauro
09-05-2006, 08:56
eliminando quella e una condizione che reputavo necessaria per gestire ENTER, i test passano e ant builda
solo che... ehm... si va in crash subito dopo il menu :stordita:
e in bugreport è annotata una nullPointerException (null pointer? in java? :mbe: ) :fagiano:
Puoi postare lo stack trace che porta all'errore?
jappilas
09-05-2006, 12:55
Stacktrace:
java.lang.NullPointerException
at it.diamonds.GameLoop.processInput(GameLoop.java:299)
at it.diamonds.GameLoop.menuLoop(GameLoop.java:384)
at it.diamonds.Game.start(Game.java:35)
at it.diamonds.Game.main(Game.java:71)
La linea incriminata è
if(environment.getEngine().isWindowClosed())
Metti un breakpoint e controlla se enviroment o engine dentro ad enviroment sono sono settati a valori non null
ciao ;)
cdimauro
09-05-2006, 13:18
Mi posti anche il codice del tuo test?
A naso sembra che tu non abbia creato qualche istanza delle classi "principali" (Engine, Audio, Keyboard, Timer, che si creano con environment.createEngine, environment.createAudio, ecc.), per cui al momento del bisogno il puntatore è nullo e quindi salta fuori l'errore.
jappilas
09-05-2006, 14:03
il test è lo stesso di 12 post fa ;)
essenzialmente scritto sulla falsariga di quelli per testare KeyEvent.UP e KeyEvent.DOWN
public void testSelectVersusModeMenuItem()
{
assertFalse("The GameLoop must be stopped", gameLoop.inGameLoop());
assertFalse("The Menu Loop must be running", gameLoop.isMenuFinished());
gameLoop.menuLoop();
MainMenu mainMenu = gameLoop.getMainMenu();
mainMenu.selectMenuItem(MenuItem.VERSUS_MODE);
gameLoop.notifyKeyEvent(KeyEvent.ENTER, KeyEvent.PRESSED);
gameLoop.notifyKeyEvent(KeyEvent.ENTER, KeyEvent.RELEASED);
assertTrue("The Menu Loop must be stopped", gameLoop.isMenuFinished());
assertTrue("The GameLoop must be running", gameLoop.inGameLoop());
assertFalse("The GameLoop must be running", gameLoop.isFinished());
}
no, non ho aggiunto creazioni nel test perchè pensavo:
il test precedente funzionava io devo solo cambiare una variabile di stato che faccia uscire dal loop => non servirà ricreare l' environment premendo enter... :stordita:
per lo stesso motivo, ed anche visto che il task consisteva nel far sì che quel che KeyEvent.ENTER prima faceva sempre e comunque, lo faccia solo se la scelta selezionata è la seconda
non ho fatto modifiche in tal senso nemmeno nel codice
avevo invece aggunto una variabile che tenesse memoria del KeyEvent precedente, in modo da triggerare KeyEvent.ENTER solo al secondo evento consecutivo (che si presume in rilascio), questo per mantenere il comportamento di ESCAPE e non far fallire
testEscKeyMustBePressedAfterEnterKeyToWork()
cdimauro
09-05-2006, 14:23
Qual è il file di test?
jappilas
09-05-2006, 14:39
La linea incriminata è
if(environment.getEngine().isWindowClosed())
Metti un breakpoint e controlla se enviroment o engine dentro ad enviroment sono sono settati a valori non null
ciao ;)
sono non null prima e dopo
jappilas
09-05-2006, 14:41
Qual è il file di test?
testGameLoop.java, ma il mio test non lo vedi perchè non mi sogno di committare :stordita:
cdimauro
09-05-2006, 14:47
Infatti NON devi committare, altrimenti fek al posto della caccia alla volpe dà la caccia a Jappilas. :D
Ho appena lanciato il test e non dà nessun NullPointer Exception. Ecco il trace:
junit.framework.AssertionFailedError: The GameLoop must be running
at junit.framework.Assert.fail(Assert.java:47)
at junit.framework.Assert.assertTrue(Assert.java:20)
at it.diamonds.tests.TestGameLoop.testSelectVersusModeMenuItem(TestGameLoop.java:369)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at junit.framework.TestCase.runTest(TestCase.java:154)
at junit.framework.TestCase.runBare(TestCase.java:127)
at junit.framework.TestResult$1.protect(TestResult.java:106)
at junit.framework.TestResult.runProtected(TestResult.java:124)
at junit.framework.TestResult.run(TestResult.java:109)
at junit.framework.TestCase.run(TestCase.java:118)
at junit.framework.TestSuite.runTest(TestSuite.java:208)
at junit.framework.TestSuite.run(TestSuite.java:203)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:478)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:344)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)
Fallisce questo assert:
assertTrue("The GameLoop must be running", gameLoop.inGameLoop());
Che è già molto meglio del precedente problema. :D
jappilas
09-05-2006, 14:58
Infatti NON devi committare, altrimenti fek al posto della caccia alla volpe dà la caccia a Jappilas. :D
ma poi, se non riesce a spezzarmi le ditine lui, mi tocca spezzarmele da solo :stordita:
Fallisce questo assert:
assertTrue("The GameLoop must be running", gameLoop.inGameLoop());
Che è già molto meglio del precedente problema. :D
per farlo passare ho aggiunto questo codice (provvisorio, in attesa di passagio a Command pattern) in notifyKeyEvent(int code, boolean state)
if (code == KeyEvent.ENTER)
{
if(lastKey == KeyEvent.ENTER)
{
performSelection(mainMenu.getSelectedItem().ordinal());
}
}
lastKey = code;
e questa funzione (uno switch)
private void performSelection(int choice)
{
switch(choice)
{
case 0:
finishedMenu = false;
finished = false;
break;
case 1:
finished = false ;
inGameLoop = true;
finishedMenu = true;
break;
case 2:
finished = false;
finishedMenu = false;
break;
case 3:
finished = false;
finishedMenu = false;
break;
case 4:
finished = false;
finishedMenu = false;
break;
case 5:
inGameLoop = false;
quit();
finished = true ;
finishedMenu = true;
break;
}
}
tra l'altro per qualche motivo, se finishedMenu non veniva eplicitamente settata false, n test fallivano... :stordita:
cdimauro
09-05-2006, 15:05
Bene. A questo punto lancia la build con Ant e se è verde committa pure. ;)
jappilas
09-05-2006, 15:11
Bene. A questo punto lancia la build con Ant e se è verde committa pure. ;)
ehm, è proprio con queste modifiche che si manifesta il baco :D
(tra l' altro ho anche testAllTexturesLoaded... e un warning:junit.framework.AssertionFailedError: No tests found in it.diamonds.tests.gems.GemsPairTestCase che fanno fallire Junit ma non ant
)
in effetti andando passo passo in eclipse, l' ultimo stack visibile è questo, poi termina... sembra si "perda" qualcosa nella gestione di un evento
Thread [main] (Suspended)
Keyboard.next() line: 426
Keyboard.update() line: 44
GameLoop.processInput() line: 288
GameLoop.menuLoop() line: 380
Game.start() line: 55
Game.main(String[]) line: 91
adesso mi uccidi lo so :stordita:
if (code == KeyEvent.ENTER)
{
if(lastKey == KeyEvent.ENTER)
{
performSelection(mainMenu.getSelectedItem().ordinal());
}
}
lastKey = code;
e questa funzione (uno switch)
private void performSelection(int choice)
{
switch(choice)
{
case 0:
finishedMenu = false;
finished = false;
break;
case 1:
finished = false ;
inGameLoop = true;
finishedMenu = true;
break;
case 2:
finished = false;
finishedMenu = false;
break;
case 3:
finished = false;
finishedMenu = false;
break;
case 4:
finished = false;
finishedMenu = false;
break;
case 5:
inGameLoop = false;
quit();
finished = true ;
finishedMenu = true;
break;
}
}
Ullalla', c'e' uno switch grosso con numeri che setta flag :D
Urge un bel refactoring ed un bel Command pattern qui ;)
Sistema i test, fai pure il commit e poi passa dritto al refactoring.
"Make it work, make it nice, make it fast"
jappilas
09-05-2006, 15:27
Ullalla', c'e' uno switch grosso con numeri che setta flag :D
Urge un bel refactoring ed un bel Command pattern qui ;)
non credere che non lo sappia ;)
ma non capisco da dove venga fuori il crash :cry:
Sistema i test, fai pure il commit e poi passa dritto al refactoring.
"Make it work, make it nice, make it fast"
ok, stavo pensando a una cosa del genere
public interface MenuAction
{
void execute();
void changeSelectionToPrevious();
void changeSelectionToNext();
}
e 6 classi che derivino da questa e implementino i rami dello switch
però ehm, si tratterebbe di rifattorizzare il codice scritto dagli altri, cosa che preferivo evitare... :O
cdimauro
09-05-2006, 15:32
ehm, è proprio con queste modifiche che si manifesta il baco :D
(tra l' altro ho anche il testAllTexturesLoaded... che fallisce, più un warning:junit.framework.AssertionFailedError: No tests found in it.diamonds.tests.gems.GemsPairTestCase)
in effetti andando passo passo in eclipse, l' ultimo stack visibile è questo, poi termina... sembra si "perda" qualcosa nella gestione di un evento
Thread [main] (Suspended)
Keyboard.next() line: 426
Keyboard.update() line: 44
GameLoop.processInput() line: 288
GameLoop.menuLoop() line: 380
Game.start() line: 55
Game.main(String[]) line: 91
adesso mi uccidi lo so :stordita:
Ho capito. Aggiungo quelle righe di codice a GameLoop e vedo cosa succede...
cdimauro
09-05-2006, 15:36
Incollando il codice relativo a notifyKeyEvent Eclipse s'arrabbia perché non trova la variabile lastKey: 'ndo sta?
public interface MenuAction
{
void execute();
void changeSelectionToPrevious();
void changeSelectionToNext();
}
Si', puo' andare. Pensi che si possa fare anche solo con il metodo execute() e implementare la logica di selezione a parte?
e 6 classi che derivino da questa e implementino i rami dello switch
però ehm, si tratterebbe di rifattorizzare il codice scritto dagli altri, cosa che preferivo evitare... :O
E perche' mai evitarlo? La metodologia che usiamo non solo permette di rifattorizzare il codice scritto da altri, ma te lo impone. Devi rifattorizzarlo quando necessario.
jappilas
09-05-2006, 15:39
Incollando il codice relativo a notifyKeyEvent Eclipse s'arrabbia perché non trova la variabile lastKey: 'ndo sta?
ah ops...
l' avevo messa (temporaneamente) come membro di gameLoop
private int lastKey
cesare, grazie e scusami , ultimamente vivo di disattenzioni :fagiano:
jappilas
09-05-2006, 15:45
E perche' mai evitarlo? La metodologia che usiamo non solo permette di rifattorizzare il codice scritto da altri, ma te lo impone. Devi rifattorizzarlo quando necessario.
volevo evitare di disfare il codice appena scritto da altri (in qs caso bonfo) per la gestione degli eventi, per non dare l' impressione di vanificare il loro task :O
Si', puo' andare. Pensi che si possa fare anche solo con il metodo execute() e implementare la logica di selezione a parte?
sì, ma allora non avrei ben chiaro come sincronizzare lo stato "interno" (oggetto menuaction effttivamente istanziato) con la menuselection ,senza fare modifiche al codice che farebbero saltare n test
cdimauro
09-05-2006, 15:54
ah ops...
l' avevo messa (temporaneamente) come membro di gameLoop
private int lastKey
cesare, grazie e scusami , ultimamente vivo di disattenzioni :fagiano:
E di che? Forse è nella natura dei programmatori l'esser distratti. Per questo mia moglie è disperata... :p
cdimauro
09-05-2006, 15:59
Con le tue modifiche al codice il tuo test passa, ma ne fallisce un altro:
public void testGameLoopStartedAfterMenuLoopStopped()
{
assertFalse("The GameLoop must be stopped", gameLoop.inGameLoop());
assertFalse("The Menu Loop must be running", gameLoop.isMenuFinished());
gameLoop.notifyKeyEvent(KeyEvent.ENTER, KeyEvent.RELEASED);
gameLoop.initBeforeGameLoop();
assertTrue("The GameLoop must be running", gameLoop.inGameLoop());
assertTrue("The Menu Loop must be stopped", gameLoop.isMenuFinished());
}
junit.framework.AssertionFailedError: The Menu Loop must be stopped
at junit.framework.Assert.fail(Assert.java:47)
at junit.framework.Assert.assertTrue(Assert.java:20)
at it.diamonds.tests.TestGameLoop.testGameLoopStartedAfterMenuLoopStopped(TestGameLoop.java:159)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at junit.framework.TestCase.runTest(TestCase.java:154)
at junit.framework.TestCase.runBare(TestCase.java:127)
at junit.framework.TestResult$1.protect(TestResult.java:106)
at junit.framework.TestResult.runProtected(TestResult.java:124)
at junit.framework.TestResult.run(TestResult.java:109)
at junit.framework.TestCase.run(TestCase.java:118)
at junit.framework.TestSuite.runTest(TestSuite.java:208)
at junit.framework.TestSuite.run(TestSuite.java:203)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:478)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:344)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)
Non digerisce l'ultimo assert.
jappilas
09-05-2006, 16:00
E di che? Forse è nella natura dei programmatori l'esser distratti. Per questo mia moglie è disperata... :p
che ti sto sfruttando (meglio: succhiando a mo' di zanzara) per svolgere il mio task :O :p
cdimauro
09-05-2006, 16:05
http://www.movieconnection.it/schede/attimo_fuggente1.jpg
Carpe diem: succhia il midollo della vita. ;)
jappilas
09-05-2006, 16:10
Con le tue modifiche al codice il tuo test passa, ma ne fallisce un altro:
public void testGameLoopStartedAfterMenuLoopStopped()
Non digerisce l'ultimo assert.
ah sì, quello :p
quel test si aspetta che MenuLoop sia settato a false e inGameLoop a true dopo la notifica di keyEvent.ENTER, senza altre precondizioni
ma visto che il task prevede proprio di passare al gioco solo in certi casi a seconda della selezione del menu, quel test d' ora in avanti fallirà sempre :p
per cui, a me sembrava ragionevole... modificare il test :stordita:
public void testGameLoopStartedAfterMenuLoopStopped()
{
assertFalse("The GameLoop must be stopped", gameLoop.inGameLoop());
assertFalse("The Menu Loop must be running", gameLoop.isMenuFinished());
/*Added to make the test work for menu option #2, VS mode*/
gameLoop.menuLoop();
MainMenu mainMenu = gameLoop.getMainMenu();
mainMenu.selectMenuItem(MenuItem.VERSUS_MODE);
/*end of lines added by Jappilas*/
gameLoop.notifyKeyEvent(KeyEvent.ENTER, KeyEvent.RELEASED);
gameLoop.initBeforeGameLoop();
assertTrue("The GameLoop must be running", gameLoop.inGameLoop());
assertTrue("The Menu Loop must be stopped", gameLoop.isMenuFinished());
}
PS: "Capitano, mio Capitano" (bellissimo l' Attimo Fuggente e grande Robin Williams ) :)
volevo evitare di disfare il codice appena scritto da altri (in qs caso bonfo) per la gestione degli eventi, per non dare l' impressione di vanificare il loro task :O
Non abbiamo alcuna connessione emotiva con il codice. Il codice che scriviamo e' di tutti e tutti possono e devono modificarlo. Quando X scrive il codice che Y rifattorizza, lo sforzo di X ha permesso a Y di arrivare ad una soluzione migliore per tutto il team, quindi non e' stato vanificato.
sì, ma allora non avrei ben chiaro come sincronizzare lo stato "interno" (oggetto menuaction effttivamente istanziato) con la menuselection ,senza fare modifiche al codice che farebbero saltare n test
Hmmm, dovrei guardare il codice per rispondere. Prova a farlo comunque senza quei due metodi, vedi che ne esce.
jappilas
09-05-2006, 16:13
Non abbiamo alcuna connessione emotiva con il codice. Il codice che scriviamo e' di tutti e tutti possono e devono modificarlo. Quando X scrive il codice che Y rifattorizza, lo sforzo di X ha permesso a Y di arrivare ad una soluzione migliore per tutto il team, quindi non e' stato vanificato.
ah, ok :)
Hmmm, dovrei guardare il codice per rispondere. Prova a farlo comunque senza quei due metodi, vedi che ne esce.
ah ok, ci provo :)
dai un' occhiata al mio ultimo post :D
cdimauro
09-05-2006, 16:17
ah sì, quello :p
quel test si aspetta che MenuLoop sia settato a false e inGameLoop a true dopo la notifica di keyEvent.ENTER, senza altre precondizioni
ma visto che il task prevede proprio di passare al gioco solo in certi casi a seconda della selezione del menu, quel test d' ora in avanti fallirà sempre :p
per cui, a me sembrava ragionevole... modificare il test :stordita:
public void testGameLoopStartedAfterMenuLoopStopped()
{
assertFalse("The GameLoop must be stopped", gameLoop.inGameLoop());
assertFalse("The Menu Loop must be running", gameLoop.isMenuFinished());
/*Added to make the test work for menu option #2, VS mode*/
gameLoop.menuLoop();
MainMenu mainMenu = gameLoop.getMainMenu();
mainMenu.selectMenuItem(MenuItem.VERSUS_MODE);
/*end of lines added by Jappilas*/
gameLoop.notifyKeyEvent(KeyEvent.ENTER, KeyEvent.RELEASED);
gameLoop.initBeforeGameLoop();
assertTrue("The GameLoop must be running", gameLoop.inGameLoop());
assertTrue("The Menu Loop must be stopped", gameLoop.isMenuFinished());
}
Sì, i requisiti sono cambiati e se quel test cozza contro di essi puoi benissimo modificarlo affinché rifletta il nuovo comportamento che deve avere il gioco.
I test non sono del codice immutabile che deve mantenere per forza il "contratto" stabilito. ;)
PS: "Capitano, mio Capitano" (bellissimo l' Attimo Fuggente e grande Robin Williams ) :)
:)
public void testGameLoopStartedAfterMenuLoopStopped()
{
assertFalse("The GameLoop must be stopped", gameLoop.inGameLoop());
assertFalse("The Menu Loop must be running", gameLoop.isMenuFinished());
/*Added to make the test work for menu option #2, VS mode*/
gameLoop.menuLoop();
MainMenu mainMenu = gameLoop.getMainMenu();
mainMenu.selectMenuItem(MenuItem.VERSUS_MODE);
/*end of lines added by Jappilas*/
gameLoop.notifyKeyEvent(KeyEvent.ENTER, KeyEvent.RELEASED);
gameLoop.initBeforeGameLoop();
assertTrue("The GameLoop must be running", gameLoop.inGameLoop());
assertTrue("The Menu Loop must be stopped", gameLoop.isMenuFinished());
}
PS: "Capitano, mio Capitano" (bellissimo l' Attimo Fuggente e grande Robin Williams ) :)
A me sta bene. Togli solo i commenti :)
jappilas
09-05-2006, 16:39
adesso, se cesare ha applicato le mie modifiche al codice, dovrebbe avere anche lui una build perfettamente... buggata, ma con tutti (o quasi) i test che passano
:sofico: :p :D
cdimauro
09-05-2006, 16:44
I test di TestGameLoop passano, ma lanciando la build con Ant:
[checkstyle] C:\Documents and Settings\Cesare\workspace\Diamonds\src\it\diamonds\GameLoop.java:591:5: Cyclomatic Complexity is 9 (max allowed is 8).
CheckStyle non gradisce notifyKeyEvent con quelle modifiche...
P.S. Odio CheckStyle!!!
jappilas
09-05-2006, 16:47
CheckStyle non gradisce notifyKeyEvent con quelle modifiche...
P.S. Odio CheckStyle!!!
ah giusto, io avevo anche con la benedizione di fek, eliminato la condizione su QUIT, per ora commentandola via (ennesima dimenticanza ops :p ): limandola via, checkstyle era contento
if(((code == KeyEvent.ESCAPE) /*|| (code == KeyEvent.QUIT)*/) && inGameLoop)
PS: ultimamente pure io
cdimauro
09-05-2006, 16:59
OK, con quella modifica la build è verde: puoi pure committare. :)
Hai bene a commentare per il momento, perché in futuro utilizzeremo soltanto l'evento QUIT per uscire dall'applicazione (che sarà generato ANCHE dalla pressione ESCAPE sotto determinate condizioni). ;)
jappilas
09-05-2006, 17:06
OK, con quella modifica la build è verde: puoi pure committare. :)
ehm... e il bug di prima? vuoi dire che anche se il gioco va in crash selezionando la seconda o l' ultima opzione del menu, le mie ditine non verranno spezzate? :D
Hai bene a commentare per il momento, perché in futuro utilizzeremo soltanto l'evento QUIT per uscire dall'applicazione (che sarà generato ANCHE dalla pressione ESCAPE sotto determinate condizioni). ;)
io, ehm, nella mia ingenuità pensavo a un comportamento inverso: l' uscita dal gioco avverebbe solo da menu, e con il tasto ESC si passerebbe dal gioco al menu (quello principale o un "in game menu" che permetta di variare le opzioni di gioco senza abbandonare la partita e di tornare al gioco), e da un eventuale 2o livello di menu (ad es la schermata delle opzioni) al primo
l' idea mi veniva guardando altri giochi, ma se avevate intenzioni diverse me ne sto :O
io, ehm, nella mia ingenuità pensavo a un comportamento inverso: l' uscita dal gioco avverebbe solo da menu, e con il tasto ESC si passerebbe dal gioco al menu (quello principale o un "in game menu" che permetta di variare le opzioni di gioco senza abbandonare la partita e di tornare al gioco), e da un eventuale 2o livello di menu (ad es la schermata delle opzioni) al primo
l' idea mi veniva guardando altri giochi, ma se avevate intenzioni diverse me ne sto :O
In-game menu tutta la vita ;)
ehm... e il bug di prima? vuoi dire che anche se il gioco va in crash selezionando la seconda o l' ultima opzione del menu, le mie ditine non verranno spezzate? :D
scrivi 2 test che presuppongano che selezionando quelle 2 opzioni il gioco vada in crash(intercetta l'eccezione). Questi test verranno tolti quando implmenteremo quelle 2 opzioni :)
cdimauro
09-05-2006, 17:16
ehm... e il bug di prima? vuoi dire che anche se il gioco va in crash selezionando la seconda o l' ultima opzione del menu, le mie ditine non verranno spezzate? :D
Pork. Chiaramente no, qualcuno te le spezzerebbe. :asd:
Aspetta che riapplico quelle modifiche al codice (avevo già fatto il revert) e controllo... ;)
cdimauro
09-05-2006, 17:17
scrivi 2 test che presuppongano che selezionando quelle 2 opzioni il gioco vada in crash(intercetta l'eccezione). Questi test verranno tolti quando implmenteremo quelle 2 opzioni :)
Giustissimo. Avevo dimenticato l'equazione bug -> test relativo. :angel:
Pork. Chiaramente no, qualcuno te le spezzerebbe. :asd:
Aspetta che riapplico quelle modifiche al codice (avevo già fatto il revert) e controllo... ;)
in effetti e meglio cosi :asd:
Giustissimo. Avevo dimenticato l'equazione bug -> test relativo. :angel:
il meglio sarebbe testare non che crashi, ma che non faccia nulla(come dicevi tu)
jappilas
09-05-2006, 17:26
il meglio sarebbe testare non che crashi, ma che non faccia nulla(come dicevi tu)
però mi perplime parecchio in entrambi i casi... modifico le stesse flag che modificavo prima, solo in un subset dei casi in base a delle condizioni testate... non dovrebbe andare in crash :cry:
che dipenda da quel lastKey che uso come variabile di memoria...? :mc:
jappilas
09-05-2006, 17:29
il meglio sarebbe testare non che crashi, ma che non faccia nulla(come dicevi tu)
già dall' inizio stavo pensando anche a un test (meglio, una serie di test) per verificare che le flag non vengano cambiate notificando ENTER quando sono selezionate le opzioni del menu non implementate... lo aggiungo?
cdimauro
09-05-2006, 17:38
Ho provato a effettuare il tracing e incredibilmente mi ritrovo coi due playfield a null dopo la pressione di ENTER, senza aver visto eseguito alcun pezzo di codice che potesse farlo.
Adesso devo staccare. Domani provo con un'altra sessione di debug, ma prima devo finire il mio task.
jappilas
09-05-2006, 17:47
Ho provato a effettuare il tracing e incredibilmente mi ritrovo coi due playfield a null dopo la pressione di ENTER, senza aver visto eseguito alcun pezzo di codice che potesse farlo.
allora anche tu sei perplesso quanto me? :D
Adesso devo staccare. Domani provo con un'altra sessione di debug, ma prima devo finire il mio task.
non pretendo certo che tu sottrai tempo al tuo task e al tuo lavoro per fare anche il mio, anzi ti ringrazio per l' assistenza e la pazienza di oggi :)
intanto ho anche da pensare a come rifattorizzare con i command ... :sofico:
Il codice fa sempre rifattorizzato....anche se è appena stato scritto :D
In ogni caso questo task sta assorbendo sforzi che nn dovrebbe assorbire...cìè qualcosa che stiamo sbagliando.
Do 2 idee...forse sbagliate ;)
1) Lo switch si dovrebbe basare sul MenuItem più che su un intero ...e il command Pattern di conseguenza :D
2) Questo codice
if (code == KeyEvent.ENTER)
{
if(lastKey == KeyEvent.ENTER)
{
performSelection(mainMenu.getSelectedItem().ordinal());
}
}
lastKey = code;
Porterà problemi...non si fa alcuna differenziazione in funzione dello stato.
Non basterebbe un
if ((code == KeyEvent.ENTER) && (state == KeyEvent.Pressed)) ???
3) O esiste KeyEvent.QUIT o KeyEvent.ESCAPE.
Non capisco Cesare perchè dovrebbero esistere tutti e due !?! :mbe:
La pressione di un detreminato tasto genera il KeyEvent di Uscita.
Chiamatelo come vi pare...ma sempre uno e solo un KeyEvent resta.
4) Prima di fare le cose serie...nell'ottica "fallo funzionare e basta" io avrei aggiunto solamente
if((code == KeyEvent.ENTER) && (mainMenu.getSelectedItem()==MenuItem.VERSUS_MODE))
{
finishedMenu = true;
}
Così il task è completato in 0 sec ;)
jappilas
09-05-2006, 20:51
Il codice fa sempre rifattorizzato....anche se è appena stato scritto :D
ok, allora penso ai menucommand senza rimpianti :)
In ogni caso questo task sta assorbendo sforzi che nn dovrebbe assorbire...cìè qualcosa che stiamo sbagliando.
lo so, e ammetto di aver sottostimato la difficoltà del task che si sta rivelando forse superiore alle mie capacità :( (anche se il codice che ho postato era pronto domenica sera, non immaginavo che avrebbe provocato un crash che ora come ora non capisco da cosa sia innescato e come possa essere risolto)
e di questo, mi scuso
1) Lo switch si dovrebbe basare sul MenuItem più che su un intero ...e il command Pattern di conseguenza :D
vero, infatti ho appena sotituito i case numerali e l' int choice con un menuitem e le relative stringhe
ed è tutto il pomeriggio che mi spremo le meningi per pensare a un comportamento delle menucommand che tenga conto di quale menuitem è effettivamente selezionata
2) Non basterebbe un
if ((code == KeyEvent.ENTER) && (state == KeyEvent.Pressed)) ???
avevo provato una cosa simile, ma fallisce testEscKeyMustBePressedAfterEnterKeyToWork() ;)
ho provato varie soluzioni, quella che ho scritto è per ora quella che fa passare tutti i test, anche se come codice non piace moltissimo nemmeno a me
ah, da specifica la selezione deve funzionare al rilascio di ENTER
4) Prima di fare le cose serie...nell'ottica "fallo funzionare e basta" io avrei aggiunto solamente
if((code == KeyEvent.ENTER) && (mainMenu.getSelectedItem()==MenuItem.VERSUS_MODE))
{
finishedMenu = true;
}
Così il task è completato in 0 sec ;)
avevo provato anche così, ma falliscono, tra gli altri:
testEscKeyMustBePressedAfterEnterKeyToWork
testMenuLoopFinishedAfterEnterPressed
;)
lo so, e ammetto di aver sottostimato la difficoltà del task che si sta rivelando forse superiore alle mie capacità :( (anche se il codice che ho postato era pronto domenica sera, non immaginavo che avrebbe provocato un crash che ora come ora non capisco da cosa sia innescato e come possa essere risolto)
e di questo, mi scuso
E di che ti scusi...hai e stai lavorando benissimo. :D
avevo provato anche così, ma falliscono, tra gli altri:
testEscKeyMustBePressedAfterEnterKeyToWork
testMenuLoopFinishedAfterEnterPressed
;)
Ma siamo sicuri che questi test definiscono un comportamento corretto :confused: :confused:
jappilas
09-05-2006, 22:22
E di che ti scusi...hai e stai lavorando benissimo. :D
:)
Ma siamo sicuri che questi test definiscono un comportamento corretto :confused: :confused:
public void testMenuLoopFinishedAfterEnterPressed()
{
assertFalse("The Menu Loop must be running", gameLoop.isMenuFinished());
gameLoop.notifyKeyEvent(KeyEvent.ENTER, KeyEvent.RELEASED);
gameLoop.doOneStep();
assertTrue("The Menu Loop must be stopped", gameLoop.isMenuFinished());
}
almeno questo mi sembra ok (piu' o meno)
per l' altro mi vengono dei dubbi , alla luce delle nuove considerazioni sulla nuova gestione degli eventi
cdimauro
10-05-2006, 08:35
allora anche tu sei perplesso quanto me? :D
Anche più: non capire come funziona il codice neppure seguendo passo passo l'esecuzione è una cosa che non mi piace assolutamente. :rolleyes:
Ai tempi del C64 realizzare un menù come quello e la scelta di un'opzione si realizzava con una manciata di istruzioni, come pure la logica dei giochi: non posso credere che non si possa trovare una maniera altrettanto semplice, leggibile e "sotto controllo" per Diamonds.
Forse ci stiamo complicando troppo la vita...
non pretendo certo che tu sottrai tempo al tuo task e al tuo lavoro per fare anche il mio, anzi ti ringrazio per l' assistenza e la pazienza di oggi :)
Non ti preoccupare. Se non avessi avuto tempo non avrei avuto modo di aiutarti: hai beccato il periodo giusto. :p
intanto ho anche da pensare a come rifattorizzare con i command ... :sofico:
E io spero di completare il mio task. :D
Niente grandi rivoluzioni del codice, andrò a toccare soltanto l'implementazione di Engine/Texture e relativi test, per cui si può procedere benissimo "in parallelo". ;)
cdimauro
10-05-2006, 08:46
3) O esiste KeyEvent.QUIT o KeyEvent.ESCAPE.
Non capisco Cesare perchè dovrebbero esistere tutti e due !?! :mbe:
La pressione di un detreminato tasto genera il KeyEvent di Uscita.
Chiamatelo come vi pare...ma sempre uno e solo un KeyEvent resta.
Hanno motivo di esistere perché sono due eventi diversi: il primo determina la chiusura dell'applicazione, il secondo invece può farlo, ma a determinate condizioni.
Il problema qui è che per il momento vediamo il tutto soltanto come eventi generati/legati d/alla tastiera
Ad esempio, nel caso dell'ESCAPE che genera una condizione di terminazione del programma, a mio avviso sarebbe meglio generare in risposta un evento QUIT.
Per fare un altro esempio, per i menù può darsi che una via per semplificare e rendere più leggibile il tutto sia quella di introdurre degli eventi in risposta alla selezione delle opzioni del menù.
Sono idee che mi frullano per la testa.
Se per adesso non vedi bene la coesistenza di QUIT ed ESCAPE, per me puoi benissimo eliminare il primo.
In ogni caso, alla rifattorizzazione degli eventi che ho in mente, salterà di nuovo fuori sotto forma di Event.QUIT (mentre ESCAPE diventerà Event.ESCAPE) per segnalare anche l'avvenuta chiusura della finestra di gioco.
Ad esempio, nel caso dell'ESCAPE che genera una condizione di terminazione del programma, a mio avviso sarebbe meglio generare in risposta un evento QUIT.
Per fare un altro esempio, per i menù può darsi che una via per semplificare e rendere più leggibile il tutto sia quella di introdurre degli eventi in risposta alla selezione delle opzioni del menù.
Sono idee che mi frullano per la testa.
Se ho capito bene mi sa che abbiamo avuto le stesse idee :) sto aspettando la fine del task di Jappilas per cominciare
E di che ti scusi...hai e stai lavorando benissimo. :D
Perche' si deve scusare non l'ho mai capito :)
Se jappilas pensa di trovare sempre la soluzione piu' semplice elegante e funzionante per un task al primo colpo, non solo e' al di la' delle sue capacita', ma e' al di la' delle mie e di quelle di chiunque altro qui dentro. Per questo collaboriamo e discutiamo sul forum.
(Ed e' anche per questo che spesso non intervengo nelle vostre discussioni, di modo che arriviate alle soluzioni fra di voi)
jappilas
10-05-2006, 10:39
Perche' si deve scusare non l'ho mai capito :)
in questo caso, perche' mi pareva di "approfittare" degli altri, soprattutto cesare, ma visto che non e' un problema sono il primo a gioire :)
Se jappilas pensa di trovare sempre la soluzione piu' semplice elegante e funzionante per un task al primo colpo, non solo e' al di la' delle sue capacita', ma e' al di la' delle mie e di quelle di chiunque altro qui dentro. Per questo collaboriamo e discutiamo sul forum.
dont worry, per ste menuAction ho in testa un tale garbuglio che: 1 non ho dormito, 2 ne verra' fuori sicuramente un capolavoro di codice bizantino e complesso ( pero' leggibile eh :p ) :D
(Ed e' anche per questo che spesso non intervengo nelle vostre discussioni, di modo che arriviate alle soluzioni fra di voi)
adesso pero' ho bisogno di te, quindi non scappare :D
... please :cry:
jappilas
10-05-2006, 11:00
Allora, secondo l' abbozzo concettuale che avevo in mente:
1) L' introduzione del Command Pattern originerebbe da una classe astratta MenuAction e dal suo metodo fondamentale execute(...) <-non void, e ci arrivo dopo
6 classi erediterebbero da Menuaction e implementerebbero execute in modo specifico, e fin qui va bene
Primo dilemma: implementare come pura interfaccia o abstract class?
nel primo caso si otterrebbe un disaccoppiamento pressoche' totale, nel secondo sfrutterei caratteristiche dello state (incapsulazione di variabili di stato, come l' ultimo KeyEvent ricevuto, che ho visto essere utile) o dello strategy pattern
2) L' oggetto di tipo MainMenu in gameLoop conterrebbe almeno un oggetto ManuAction, istanziato da mainMenu stesso o da se' tramite il sempreverde costruttore statico privato :D
3) Istanziazione di MenuAction alternative in reazione alla selezione menu precedente /successivo:
terzo dilemma: istanziazione "interna" (l' istanza attuale si occupa di istanziare un oggetto di tipo derivato diverso) o "esterna" (da parte dell' oggetto client, in questo caso il menu)?
nel secondo caso avrei probabilmente bisogno di un metodo factory nel MainMenu
4) MenuItem: i test attuali si appoggiano all' enumerativo e al metodo di selezione diretta della Item in base a un indice esportato dal menu, quindi entrambi i dettagli vanno mantenuti e al piu' aggiunti, ai metodi selectnext() e selectprevious() che pensavo all' inizio
Ma, domanda: come si puo' fare una selezione a runtime , non di un oggetto ma di un tipo di dato da istanziare, con un accesso diretto su indice, senza usare uno switch?
la prima cosa che mi viene in mente e' di riciclare una hashmap, mettervi delle coppie <MenuItem,MenuActionGenerator>
pero' mi sembra tutto meno che KISS (come tutto il refactoring ad essere sincero) :(
5) Execute (se unico membro pubblico dell' interfaccia) non potra' essere void, questo perche' ha bisogno di un riferimento all' oggetto gameLoop di cui chiamare finishMenuLoop() e Quit()
quindi in fase di creazione della MenuAction mi servira' passare un puntatore this da gameloop a mainmenu e da mainmenu alla action, o al suo costruttore, si puo' fare vero? :mbe:
in c++ non ero particolarmente amante dei callback, pero' sto iniziando a rimpiangerli... :stordita:
cdimauro
10-05-2006, 12:33
Se ho capito bene mi sa che abbiamo avuto le stesse idee :) sto aspettando la fine del task di Jappilas per cominciare
Fai pure. Avevo intenzione di metterci mano io in futuro, ma ho tante di quelle rifattorizzazioni in mente che non so se finirò da qui al rilascio del gioco. :p
cdimauro
10-05-2006, 12:43
Allora, secondo l' abbozzo concettuale che avevo in mente:
1) L' introduzione del Command Pattern originerebbe da una classe astratta MenuAction e dal suo metodo fondamentale execute(...) <-non void, e ci arrivo dopo
6 classi erediterebbero da Menuaction e implementerebbero execute in modo specifico, e fin qui va bene
Primo dilemma: implementare come pura interfaccia o abstract class?
nel primo caso si otterrebbe un disaccoppiamento pressoche' totale, nel secondo sfrutterei caratteristiche dello state (incapsulazione di variabili di stato, come l' ultimo KeyEvent ricevuto, che ho visto essere utile) o dello strategy pattern
Ci sono dei pro e dei contro per ogni scelta, ma per Diamonds abbiamo deciso di utilizzare le interfacce e non le classi astratte proprio per disaccoppiare il più possibile il codice.
Questo porta in alcuni casi a della duplicazione del codice (e a checkstyle che rompe le scatole, per cui bisogna mettere dei commenti ad hoc per zittirlo. :p), ma per il momento è la soluzione che abbiamo preso in considerazione.
4) MenuItem: i test attuali si appoggiano all' enumerativo e al metodo di selezione diretta della Item in base a un indice esportato dal menu, quindi entrambi i dettagli vanno mantenuti e al piu' aggiunti, ai metodi selectnext() e selectprevious() che pensavo all' inizio
Ma, domanda: come si puo' fare una selezione a runtime , non di un oggetto ma di un tipo di dato da istanziare, con un accesso diretto su indice, senza usare uno switch?
la prima cosa che mi viene in mente e' di riciclare una hashmap, mettervi delle coppie <MenuItem,MenuActionGenerator>
pero' mi sembra tutto meno che KISS (come tutto il refactoring ad essere sincero) :(
In Delphi utilizzavo dei tipi costruttori di classe derivati dalla superclasse, creando un array che ad ogni indice assegnasse il rispettivo costruttore di classe della classe figlia. Mi documento e vediamo come si può fare con Java...
5) Execute (se unico membro pubblico dell' interfaccia) non potra' essere void, questo perche' ha bisogno di un riferimento all' oggetto gameLoop di cui chiamare finishMenuLoop() e Quit()
quindi in fase di creazione della MenuAction mi servira' passare un puntatore this da gameloop a mainmenu e da mainmenu alla action, o al suo costruttore, si puo' fare vero? :mbe:
in c++ non ero particolarmente amante dei callback, pero' sto iniziando a rimpiangerli... :stordita:
Tranquillo: utilizziamo già un meccanismo di callback per la notifica degli eventi. ;)
Allora, secondo l' abbozzo concettuale che avevo in mente:
1) L' introduzione del Command Pattern originerebbe da una classe astratta MenuAction e dal suo metodo fondamentale execute(...) <-non void, e ci arrivo dopo
6 classi erediterebbero da Menuaction e implementerebbero execute in modo specifico, e fin qui va bene
Primo dilemma: implementare come pura interfaccia o abstract class?
nel primo caso si otterrebbe un disaccoppiamento pressoche' totale, nel secondo sfrutterei caratteristiche dello state (incapsulazione di variabili di stato, come l' ultimo KeyEvent ricevuto, che ho visto essere utile) o dello strategy pattern
2) L' oggetto di tipo MainMenu in gameLoop conterrebbe almeno un oggetto ManuAction, istanziato da mainMenu stesso o da se' tramite il sempreverde costruttore statico privato :D
3) Istanziazione di MenuAction alternative in reazione alla selezione menu precedente /successivo:
terzo dilemma: istanziazione "interna" (l' istanza attuale si occupa di istanziare un oggetto di tipo derivato diverso) o "esterna" (da parte dell' oggetto client, in questo caso il menu)?
nel secondo caso avrei probabilmente bisogno di un metodo factory nel MainMenu
4) MenuItem: i test attuali si appoggiano all' enumerativo e al metodo di selezione diretta della Item in base a un indice esportato dal menu, quindi entrambi i dettagli vanno mantenuti e al piu' aggiunti, ai metodi selectnext() e selectprevious() che pensavo all' inizio
Ma, domanda: come si puo' fare una selezione a runtime , non di un oggetto ma di un tipo di dato da istanziare, con un accesso diretto su indice, senza usare uno switch?
la prima cosa che mi viene in mente e' di riciclare una hashmap, mettervi delle coppie <MenuItem,MenuActionGenerator>
pero' mi sembra tutto meno che KISS (come tutto il refactoring ad essere sincero) :(
5) Execute (se unico membro pubblico dell' interfaccia) non potra' essere void, questo perche' ha bisogno di un riferimento all' oggetto gameLoop di cui chiamare finishMenuLoop() e Quit()
quindi in fase di creazione della MenuAction mi servira' passare un puntatore this da gameloop a mainmenu e da mainmenu alla action, o al suo costruttore, si puo' fare vero? :mbe:
in c++ non ero particolarmente amante dei callback, pero' sto iniziando a rimpiangerli... :stordita:
Jappilas, non entro nello specifico, ma ad una prima lettura tutto questo mi sembra estremamente complicato solo per gestire un menu con una manciata di opzioni. Keep It Bloody Simple. Resetta e prova a ripensare al problema dall'inizio, in maniera piu' semplice. Non devi usare un pattern per forza, ma solo se semplifica il design. Io ti consiglierei di fare un revert di tutto il task e di ripartire da zero con quello che hai imparato al primo tentativo.
Sono d'accordo con Fek....
...e non solo jappilas deve fare revert e riaprtire da zero. Ma pure tutti noi !!! (ovvaimente per ciò che riguarda questo task :D)
Pe la question ESCAPE e QUIT.
Ho capito perfettamente e avete ovvaimente ragione. Ma secondo me si sta facendo confusione.
Il primo è un KeyEvent. Quindi un determinato tasto definito nel mapping genererà il KeyEvent.BUTTON_SPECIAL (o come vogliamo chiamarlo)
A questo punto, sotto determinate condizioni, si genererà l'Event.QUIT.
Se incominciamo a fare che un tasto genera più keyEvent o che più KeyEVent trattono lo stesso tasto....la confusione dilagherà ;)
Sottolineo:
uno è il KEY_EVENT (generato dalla pressione del tasto definto nel mapping) e altra cosa è l'EVENT di quit sotto determinate condizioni.
EDIT: anche perchè sembra che il tasto ESCAPE, ovvero il BUTTON_SPECIAL, non farà sempre e e solo il QUIT ;)
cdimauro
10-05-2006, 14:29
Nessuna confusione: è proprio quello che stiamo dicendo da un pezzo. :)
L'eventuale confusione sparirà a seguito di una rifattorizzazione in questo senso. ;)
cdimauro
10-05-2006, 14:36
In Delphi utilizzavo dei tipi costruttori di classe derivati dalla superclasse, creando un array che ad ogni indice assegnasse il rispettivo costruttore di classe della classe figlia. Mi documento e vediamo come si può fare con Java...
Niente da fare: da quel che ho visto (ma mi potrebbe anche esser sfuggito qualcosa), in Java non si può fare.
Se qualcuno volesse controllare, qui (http://homepages.borland.com/abauer/archives/2003_10_05_archive.php) c'è una descrizione (per Delphi, ma è comprensibilissimo) di quello che stiamo cercando di fare in Java.
jappilas
10-05-2006, 14:38
Jappilas, non entro nello specifico, ma ad una prima lettura tutto questo mi sembra estremamente complicato
lo è, infatti nn mi ha fatto dormire stanotte :D
Resetta e prova a ripensare al problema dall'inizio, in maniera piu' semplice. Non devi usare un pattern per forza, ma solo se semplifica il design.
#reset *click*
System going down for a reboot NOW
trrr trrr trr...
JappyBrain 1.0
16 NUMA neurons at default state
ready
# cd \MemoryPool15\HWUP\it.diamonds\15.1.4\
# revert "MenuAction" | mem_sync hwupgrade.it/forum/newreply.php
# runlevel 7
brain simple mode activated
#
....
allora, rianalisi del problema:
- applicando le modifiche che avevo fatto alla notifyKeyEvent, e ad un test che richiede un adeguamento per cambio di specifiche, il gioco crasha
e non so ancora perchè
e sono sempre più perplesso perchè "si perde" qualcosa per strada subito dopo la pressione del tasto, ma non veniva perso prima, quando cioè si settava la stessa flag, ma nella stessa funzione invece che in una secondaria, chiamata
- sembra necessario rifattorizzare il codice di gestione dei menu, con pattern o senza pattern, presumibilmente il nuovo codice dovrebbe essere più pilito ed elegante, sicuramente deve far passare tutti i test attuali (quindi deve interfacciarsi con l' attuale MainMenu) e la chiamata selectMenuItem (se non ricordo male) che prende in ingresso un MenuItem
Fin qui il problema
Niente da fare: da quel che ho visto (ma mi potrebbe anche esser sfuggito qualcosa), in Java non si può fare.
Se qualcuno volesse controllare, qui (http://homepages.borland.com/abauer/archives/2003_10_05_archive.php) c'è una descrizione (per Delphi, ma è comprensibilissimo) di quello che stiamo cercando di fare in Java.
ho dato una scorsa veloce, non si puo fare con la reflection?
Con la reflection puoi costruire un oggetto passandogli dei parametri, avendo il l'oggetto class che la rappresenta.
jappilas
10-05-2006, 14:43
io posso anche creare 6 oggetti di tipo MenuAction (o quello che sarà, MenuAction mi sembrava appropriato) , incapsularli nel MainMenu e far fare alla execute( GameLoop loop) di ognuno quello che serve quando genero un evento ENTER
non sarebbe complicato di per sè
quello che non ho ancora ben chiaro è come selezionarli (o istanziarne uno nuovo del tipo selezionato) prendendo il tipo da un array statico: si può fare con la reflection?
una volta che ho capito questo dovrebbe essere discesa
PS: possibile epifania: il costruttore di MainMenu istanzia staticamente i 6 oggetti e li mette in un array
io posso anche creare 6 oggetti di tipo MenuAction (o quello che sarà, MenuAction mi sembrava appropriato) , incapsularli nel MainMenu e far fare alla execute( GameLoop loop) di ognuno quello che serve quando genero un evento ENTER
non sarebbe complicato di per sè
quello che non ho ancora ben chiaro è come selezionarli (o istanziarne uno nuovo del tipo selezionato) prendendo il tipo da un array statico: si può fare con la reflection?
una volta che ho capito questo dovrebbe essere discesa
Esercizio: implementa il task in meno di 20 righe di codice. Poi vediamo come rifattorizzarlo. Keep It Simple. Hai 20 righe di codice a disposizione, usale bene :)
ho dato una scorsa veloce, non si puo fare con la reflection?
Con la reflection puoi costruire un oggetto passandogli dei parametri, avendo il l'oggetto class che la rappresenta.
Ragazzi, per fare un menu con una manciata di opzioni da selezionare non c'e' bisogno di tirare in ballo la reflection. Keep It Simple.
jappilas
10-05-2006, 14:47
Hai 20 righe di codice a disposizione, usale bene :)
O_o
ci provo...
O_o
ci provo...
Dimenticavo: hai anche due ore a disposizione, pensa veloce ;)
Il segreto per riuscire in quest'impresa e' uno solo: Keep It Simple.
io posso anche creare 6 oggetti di tipo MenuAction (o quello che sarà, MenuAction mi sembrava appropriato) , incapsularli nel MainMenu e far fare alla execute( GameLoop loop) di ognuno quello che serve quando genero un evento ENTER
non sarebbe complicato di per sè
quello che non ho ancora ben chiaro è come selezionarli (o istanziarne uno nuovo del tipo selezionato) prendendo il tipo da un array statico: si può fare con la reflection?
una volta che ho capito questo dovrebbe essere discesa
PS: possibile epifania: il costruttore di MainMenu istanzia staticamente i 6 oggetti e li mette in un array
Class.forName(className)
per avere da una stringa l'oggetto classe corrispondente(se esiste).
per il resto nn sono riuscito a trovare codice, cmq
Member Interface
The classes Field, Method and Constructor implement the Member interface. The methods of Member are used to query a reflected member for basic identifying information. Identifying information consists of the class or interface that declared the member, the name of the member itself, and the Java language modifiers (such as public, protected, abstract, synchronized, and so on) for the member.
Devi usare questi 3 oggetti per creare oggetti e accedere ai relativi metodi e field.
Non è il max della comodità, ma dovrebbe funzionare.
ps.lascia perdere sta roba e segui il consiglio di fek
Nessuna confusione: è proprio quello che stiamo dicendo da un pezzo. :)
L'eventuale confusione sparirà a seguito di una rifattorizzazione in questo senso. ;)
ALE'....allora ero solo io che non avevo capito niente :stordita: :stordita:
Ora che so che siamo allineati con le idee...non vedo l'ora di vedere che succede :D :D
cdimauro
10-05-2006, 14:58
ho dato una scorsa veloce, non si puo fare con la reflection?
Con la reflection puoi costruire un oggetto passandogli dei parametri, avendo il l'oggetto class che la rappresenta.
Grazie per l'indicazione. :) Appena potrò mi documenterò.
cdimauro
10-05-2006, 15:01
io posso anche creare 6 oggetti di tipo MenuAction (o quello che sarà, MenuAction mi sembrava appropriato) , incapsularli nel MainMenu e far fare alla execute( GameLoop loop) di ognuno quello che serve quando genero un evento ENTER
non sarebbe complicato di per sè
quello che non ho ancora ben chiaro è come selezionarli (o istanziarne uno nuovo del tipo selezionato) prendendo il tipo da un array statico: si può fare con la reflection?
una volta che ho capito questo dovrebbe essere discesa
PS: possibile epifania: il costruttore di MainMenu istanzia staticamente i 6 oggetti e li mette in un array
Per fare le cose semplici, dai un'occhiata a CrushBox e a come gestisce l'array crushBoxTexture... ;)
jappilas
10-05-2006, 15:34
per pensare un po' più veloce non ho letto i post successivi...:D
allora quello che ho accrocchiato finora è :
interfaccia MenuAction, righe di codice poche
package it.diamonds;
import it.diamonds.GameLoop;
public interface MenuAction
{
void execute(GameLoop loop);
}
classe concreta MenuActionVersusMode
package it.diamonds;
public class MenuActionVersusMode implements MenuAction
{
public void execute(GameLoop loop)
{
GameLoop gameloop = loop;
gameloop.finishMenuLoop();
}
}
classe concreta MenuActionQuit
package it.diamonds;
public class MenuActionQuit implements MenuAction
{
public void execute(GameLoop loop)
{
GameLoop gameloop = loop;
gameloop.quit();
gameloop.finishLoop();
}
}
Aggiunto a MainMenu.java:
gli import;
tra i membri:
private MenuAction[] menuAction;
private MenuAction selectedAction;
nel costruttore:
menuAction[0] = new MenuActionStoryMode();
menuAction[0] = new MenuActionVersusMode();
menuAction[0] = new MenuActionAdvancedMode();
menuAction[0] = new MenuActionCustomMode();
menuAction[0] = new MenuActionOptions();
menuAction[0] = new MenuActionQuit();
selectedAction = menuAction[0];
modificate le righe evidenziate in selectMenuItem
public void selectMenuItem(MenuItem menuItem)
{
this.menuItem = menuItem;
int menuIndex = menuItem.ordinal();
int offSet = 60 * menuIndex;
sprite.setOrigin(0, offSet);
sprite.moveTo(0f, offSet + 227f);
selectedAction = menuAction[menuIndex];
}
aggiunto metodo performSelectedItem
public boolean performSelectedItem(GameLoop loop)
{
selectedAction.execute(loop);
return true;
}
public boolean performSelectedItem(GameLoop loop)
{
selectedAction.execute(loop);
return true;
}
Perche' stai ritornando sempre true?
jappilas
10-05-2006, 15:51
Perche' stai ritornando sempre true?
perchè mi sono sbagliato
in quel momento pensavo mi sarebbe potuto servire tenere traccia se il menu ha fallito oppure no, ma è yagni :fagiano:
il resto della soluzione come ti sembra? :fagiano:
perchè adesso devo tornare in lab a combinare qualcosa e non avendo eclipse da lì posso solo leggere il forum
:stordita:
perchè mi sono sbagliato, in quel momento pensavo mi sarebbe potuto servire tenere traccia se il menu ha fallito oppure no, ma è yagni :fagiano:
il resto della soluzione come ti sembra? :fagiano:
perchè adesso devo tornare in lab a combinare qualcosa e non avendo eclipse da lì posso solo leggere il forum
:stordita:
E' ok, magari riusciamo a togliere qualche riga di codice qua e la' e scendere sotto le venti :D
jappilas
10-05-2006, 16:01
E' ok, magari riusciamo a togliere qualche riga di codice qua e la' e scendere sotto le venti :D
:)
a tra poco allora (casa -> lab 10 min circa :D)
comunque vada, sono felice: sto imparando tantissimo in poco tempo (e studia tutti i pattern che non ti ricordi piu'... e vai a vedere come funziona la famigerata reflection e se e come si applica al caso in esame...) e sto raffinando il mio modo di intervenire sul codice :)
jappilas
10-05-2006, 16:21
mi veniva in mente una cosa: quando tornero' a casa a lanciare junit, sicuramente alcuni test falliranno:
nel caso di testEscMustBePressedAfterEnterKeyToWork, e' pensabile un riesame del test stesso in previsione di un nuovo modo di uscire e un nuovo comportamento in seguito a Escape?
jappilas
10-05-2006, 20:50
sicuramente alcuni test falliranno: nel caso di testEscMustBePressedAfterEnterKeyToWork...
aggiornamento: con il refactoring adesso il mainmenu si comporta come prima, tutti i test che passavano prima passano di nuovo dopo l' introduzione dell' array di MenuAction, tranne... il mio
cioè, sembra che gameloop.finishMenuLoop, sebbene chiamata dalla MenuActionVersusMode, non faccia nulla e le flag non vengano cambiate :(
jappilas
11-05-2006, 00:14
La situazione è migliorata notevolmente con l' aggiunta del pattern:
il codice che fa passare i miei due test passando solo attraverso oggetti esterni MenuAction istanziati dentro il MainMenu, apparentemente risolve anche il crash che si manifestava in precedenza... (sia selezionando il versus mode, sia uscendo con il quit, sia premendo esc durante il gioco, la perfida finestra "crash detected", non fa la sua temuta comparsa - spero non sia solo una combinazione casuale ma il segno che le cose vanno come devono)
dettagli implementativi :
la MenuActionVersusMode chiama da fuori il metodo finishMenuLoop dell' oggetto Gameloop che lo ha chiamato (era questo concetto che mi sembrava astruso in origine)
ma per far passare il test che verifica che la flag di uscita non sia attiva, ho dovuto aggiungere un metodo a gameloop che in caso, la forzi a false, e far chiamare anche questa dalla Action
note:
- ho reintrodotto le boolean a scopo di debug: i valori di ritorno finiscono in due livelli di flag a loro volta testati, quindi si sa con certezza se l' esecuzione entra nel menu e nel metodo esportato della Action
- anche se la build di ant riesce , Junit non mi dà barra verde per causa di un warning (No tests found in it.diamonds.tests.gems.GemsPairTestCase.. :mbe: ) e del famigerato testAllTexturesLoadedBeforeStartPlaying()
- riguardo al codice del mio test che passa, è questo (posto il codice in modo che se ci sono correzioni da fare....):
per i motivi precedenti aspetto prima di committare (ed anche perchè avendo reinstallato Eclipse un po' di tempo fa, non sono sicuro di avere diritti di commit)
public void testSelectVersusModeMenuItem()
{
assertFalse("The GameLoop must be stopped", gameLoop.inGameLoop());
assertFalse("The Menu Loop must be running", gameLoop.isMenuFinished());
gameLoop.menuLoop();
MainMenu mainMenu = gameLoop.getMainMenu();
mainMenu.selectMenuItem(MenuItem.VERSUS_MODE);
gameLoop.notifyKeyEvent(KeyEvent.ENTER, KeyEvent.PRESSED);
gameLoop.notifyKeyEvent(KeyEvent.ENTER, KeyEvent.RELEASED);
assertTrue("The MenuAction method must have been entered",mainMenu.checkMenuActionEntered());
assertTrue("The MenuAction must have returned successfully",gameLoop.checkMenuActionPerformed());
assertTrue("The Menu Loop must be stopped", gameLoop.isMenuFinished());
assertFalse("The GameLoop must be running", gameLoop.isFinished());
gameLoop.initBeforeGameLoop();
assertTrue("The GameLoop must be running", gameLoop.inGameLoop());
}
public void testSelectQuitMenuItem()
{
assertFalse("The GameLoop must be stopped", gameLoop.inGameLoop());
assertFalse("The Menu Loop must be running", gameLoop.isMenuFinished());
gameLoop.menuLoop();
MainMenu mainMenu = gameLoop.getMainMenu();
mainMenu.selectMenuItem(MenuItem.QUIT);
gameLoop.notifyKeyEvent(KeyEvent.ENTER, KeyEvent.PRESSED);
gameLoop.notifyKeyEvent(KeyEvent.ENTER, KeyEvent.RELEASED);
assertTrue("The MenuAction method must have been entered",mainMenu.checkMenuActionEntered());
assertTrue("The MenuAction must have returned successfully",gameLoop.checkMenuActionPerformed());
assertTrue("The Menu Loop must be stopped", gameLoop.isMenuFinished());
assertTrue("The GameLoop must be stopped", gameLoop.isFinished());
}
- attualmente la classe Menu istanzia in modo harcoded i 6 oggetti corrispondenti al menu iniziale
ma non escluderei che con qualche altra modifica (che lo farebbe assomigliare di più alla CrushBox, magari :D ) possa diventare una classe generica per gestire "set" di dimensioni varibili (a seconda di cosa si passa al costruttore) di menu options, adattandosi quindi ad essere usata anche per un menu secondario
PS: mi scuso per aver un po' "sporcato" il topic con un raffica di post... :O
cdimauro
11-05-2006, 09:55
- anche se la build di ant riesce , Junit non mi dà barra verde per causa di un warning (No tests found in it.diamonds.tests.gems.GemsPairTestCase.. :mbe: ) e del famigerato testAllTexturesLoadedBeforeStartPlaying()
Ehi, cos'hai contro il mio test? :D
A volte è necessario un cleanup del progetto per sistemare questi problemi.
P.S. Non devi scusarti. ;)
cdimauro
11-05-2006, 09:56
mi veniva in mente una cosa: quando tornero' a casa a lanciare junit, sicuramente alcuni test falliranno:
nel caso di testEscMustBePressedAfterEnterKeyToWork, e' pensabile un riesame del test stesso in previsione di un nuovo modo di uscire e un nuovo comportamento in seguito a Escape?
Se è cambiato il contratto, certamente: puoi cambiare il test in questione.
jappilas
11-05-2006, 10:20
Se è cambiato il contratto, certamente: puoi cambiare il test in questione.
quando torno a casa provo a modificare il test e postare il nuovo codice, per adesso ho lasciato i test come stavano, reintrodotto la variabile di memoria lastKeyEvent ed eseguita la MenuAction solo se anche l' evento precedente era di tipo ENTER (il che dovrebbe dare problemi solo in caso di pressione contemporanea di piu' senza rilasciarli)
pero' ho notato un'altra cosa: se seleziono il vs mode aspetta circa 3 secondi prima di mostrare i due field e iniziare la partita (e nel frattempo la musica era partita subito), se seleziono quit ho di nuovo 3 secondi di delay accompagnati da rock_bg.ogg prima che la finestra si chiuda
e' normale?
Ehi, cos'hai contro il mio test? :D
nulla contro il tuo test, e' che all' inizio l' avevo preso per una delle tante "idisiosincrasie" che eclipse ha dato nel tempo sul mio sistema e che capitavano solo a me ;)
era anche per sapere se voialtri li avevate risolti tutti in un modo "standard", per non , magari, dover creare io un fake test che passi per eliminare il warning
tornando alle cose serie: vi interessano due funzioncine carine carine e implementabili a costo zero (previo test of course) enterSubMenu() e Back() ? :D
cdimauro
11-05-2006, 10:38
pero' ho notato un'altra cosa: se seleziono il vs mode aspetta circa 3 secondi prima di mostrare i due field e iniziare la partita (e nel frattempo la musica era partita subito), se seleziono quit ho di nuovo 3 secondi di delay accompagnati da rock_bg.ogg prima che la finestra si chiuda
e' normale?
Penso di sì, perché la musica viene fatta partire proprio all'inizio del codice di GameLoop.initBeforeGameLoop(), mentre successivamente sono presenti dei Timer.advance() che mettono in attesa il timer.
Basterebbe spostare quella riga di codice alla fine di GameLoop.initBeforeGameLoop(), ma fino a quando il customer non cambia le specifiche io non mi azzardo. :D
nulla contro il tuo test, e' che all' inizio l' avevo preso per una delle tante "idisiosincrasie" che eclipse ha dato nel tempo sul mio sistema e che capitavano solo a me ;)
Purtroppo il codice era troppo ballerino prima, perché utilizzava delle strutture statiche. :(
era anche per sapere se voialtri li avevate risolti tutti in un modo "standard", per non , magari, dover creare io un fake test che passi per eliminare il warning
Niente fake, se possibile.
tornando alle cose serie: vi interessano due funzioncine carine carine e implementabili a costo zero (previo test of course) enterSubMenu() e Back() ? :D
Se fanno parte delle specifiche o derivano direttamente dall'implementazione di qualche test / funzionalità, sono le benvenute. Se arrivano da qualche rifattorizzazione, idem. Altrimenti... YAGNI! :p
jappilas
11-05-2006, 10:46
Penso di sì, perché la musica viene fatta partire proprio all'inizio del codice di GameLoop.initBeforeGameLoop(), mentre successivamente sono presenti dei Timer.advance() che mettono in attesa il timer.
quindi posso dire che il menu fa quello che deve fare e il resto e' un comportamento "atteso" in base alla situazione nota del codice? :)
Se fanno parte delle specifiche o derivano direttamente dall'implementazione di qualche test / funzionalità, sono le benvenute. Se arrivano da qualche rifattorizzazione, idem. Altrimenti... YAGNI!
per implementabili a costo zero intendevo appunto dall' implementazione dell' array di Action ;)
del codice che segue quello che ho impiegato piu' secondi a crivere e' il test :D
guarda:
Test (abbozzo) per il passaggio da story mode a una nuova action (in realta' a un nuovo livello di menu con un unica scelta, e selezione automatica dell' unica che e' la prima del nuovo livello)
che se eseguita() , chiama la Back() di mainmenu
public void testEnterSubMenuAndBack()
{
assertFalse("The GameLoop must be stopped", gameLoop.inGameLoop());
assertFalse("The Menu Loop must be running", gameLoop.isMenuFinished());
gameLoop.menuLoop();
MainMenu mainMenu = gameLoop.getMainMenu();
mainMenu.selectMenuItem(MenuItem.STORY_MODE);
gameLoop.notifyKeyEvent(KeyEvent.ENTER, KeyEvent.PRESSED);
gameLoop.notifyKeyEvent(KeyEvent.ENTER, KeyEvent.RELEASED);
assertTrue("The MenuAction method must have been entered",mainMenu.checkMenuActionEntered());
assertTrue("The MenuAction must have returned successfully",gameLoop.checkMenuActionPerformed());
assertTrue("The Menu Loop must be stopped", gameLoop.isMenuFinished());
assertFalse("The GameLoop must be running", gameLoop.isFinished());
gameLoop.initBeforeGameLoop();
assertEquals("The currently selected Action must now be the one labeled Unimplemented", mainMenu.getSelectedItem(),MenuItem.UNIMPLEMENTED);
gameLoop.notifyKeyEvent(KeyEvent.ENTER, KeyEvent.PRESSED);
gameLoop.notifyKeyEvent(KeyEvent.ENTER, KeyEvent.RELEASED);
assertEquals("The currently selected Action must now be the one labeled Story Mode", mainMenu.getSelectedItem(),MenuItem.STORY_MODE);
}
abbozzo di enterSubMenu(int newMenuLevelBase, int newMenuLevelTop)
{
previousMenuLevelBase = currentMenuLevelBase;
previousMenuLevelTop = currentMenuLevelTop;
previousSelectedAction = selectedActionIndex;
currentMenuLevelBase = newMenuLevelBase;
currentMenuLevelTop = newMenuLevelTop;
currentSelectedAction = menuaction[currentMenuLevelBase];
}
abbozzo di Back()
{
currentMenuLevelBase = prevousMenuLevelBase;
currentMenuLevelTop = previousMenuLevelTop;
currentSelectedAction = menuaction[previousSelectedAction];
}
public MenuActionUnimplemented implements MenuAction
{
public boolean execute (Gameloop loop, MainMenu menu)
{
menu.Back;
return true;
}
}
public MenuActionStoryMode implements MenuAction
{
public boolean execute (Gameloop loop, MainMenu menu)
{
menu.enterSubMenu(6,6);
return true;
}
}
alla pratica serve aggiungere qualche variabile intera in piu' dentro a MainMenu, la relativa classe (copia/incolla delle preesistenti), un elemento in piu' al vettore delle MenuAction e all' enumerativo che conterra' una nuova stringa, una modifica alla execute di MenuActionStorymode
notare che se invece di due variabili temporanee per salvare lo stato precedente del menu (indice della prima scelta, indice dell' ultima, action selezionata precedentemente) usassi uno stack e dei push e pop, avrei un menu a n livelli :D
PS: non vi spaventate se cliccando enter sulla story mode, poi non reagiscono piu' i tasti su e giu': semplicemente il menu principale "perde il focus" perche' quello attuale diventa un sottorange di un solo elemento: up e down in effetti funzionano ma fanno tornare sempre sullo stesso
dovrebbe bastare premere enter di nuovo per tornare a quello di prima
cdimauro
11-05-2006, 11:52
quindi posso dire che il menu fa quello che deve fare e il resto e' un comportamento "atteso" in base alla situazione nota del codice? :)
Per quanto mi riguarda, sì. ;)
per implementabili a costo zero intendevo appunto dall' implementazione dell' array di Action ;)
del codice che segue quello che ho impiegato piu' secondi a crivere e' il test :D
guarda:
Test (abbozzo) per il passaggio da story mode a una nuova action (in realta' a un nuovo livello di menu con un unica scelta, e selezione automatica dell' unica che e' la prima del nuovo livello)
che se eseguita() , chiama la Back() di mainmenu
abbozzo di enterSubMenu(int newMenuLevelBase, int newMenuLevelTop)
{
previousMenuLevelBase = currentMenuLevelBase;
previousMenuLevelTop = currentMenuLevelTop;
previousSelectedAction = selectedActionIndex;
currentMenuLevelBase = newMenuLevelBase;
currentMenuLevelTop = newMenuLevelTop;
currentSelectedAction = menuaction[currentMenuLevelBase];
}
abbozzo di Back()
{
currentMenuLevelBase = prevousMenuLevelBase;
currentMenuLevelTop = previousMenuLevelTop;
currentSelectedAction = menuaction[previousSelectedAction];
}
public MenuActionUnimplemented implements MenuAction
{
public boolean execute (Gameloop loop, MainMenu menu)
{
menu.Back;
return true;
}
}
public MenuActionStoryMode implements MenuAction
{
public boolean execute (Gameloop loop, MainMenu menu)
{
menu.enterSubMenu(6,6);
return true;
}
}
alla pratica serve aggiungere qualche variabile intera in piu' dentro a MainMenu, la relativa classe (copia/incolla delle preesistenti), un elemento in piu' al vettore delle MenuAction e all' enumerativo che conterra' una nuova stringa, una modifica alla execute di MenuActionStorymode
notare che se invece di due variabili temporanee per salvare lo stato precedente del menu (indice della prima scelta, indice dell' ultima, action selezionata precedentemente) usassi uno stack e dei push e pop, avrei un menu a n livelli :D
Per me va bene, visto che è un dettaglio implementativo: il codice per far passare il test e aggiungere il requisito richiesto dal task lo puoi organizzare come meglio credi. ;)
PS: non vi spaventate se cliccando enter sulla story mode, poi non reagiscono piu' i tasti su e giu': semplicemente il menu principale "perde il focus" perche' quello attuale diventa un sottorange di un solo elemento: up e down in effetti funzionano ma fanno tornare sempre sullo stesso
dovrebbe bastare premere enter di nuovo per tornare a quello di prima
OK
Visto il comportamento con le voci "non disponibili", aggiungiamo un task dell'ultim'ora (abbiamo ancora un paio di giorni... Vic, lo formalizzi tu per favore?) per fare in modo che solo le voci Versus e Quit siano, per ora, evidenziabili con su o giù (ovviamente la predefinita sarà Versus).
Chi se ne occupa? Jappilas e Cesare in pair?
Visto il comportamento con le voci "non disponibili", aggiungiamo un task dell'ultim'ora (abbiamo ancora un paio di giorni... Vic, lo formalizzi tu per favore?) per fare in modo che solo le voci Versus e Quit siano, per ora, evidenziabili con su o giù (ovviamente la predefinita sarà Versus).
Chi se ne occupa? Jappilas e Cesare in pair?
Fate questo task in pair in TDD in forma pura: ad ogni test cambiate una sola linea di codice per farlo passare.
cdimauro
11-05-2006, 12:44
Visto il comportamento con le voci "non disponibili", aggiungiamo un task dell'ultim'ora (abbiamo ancora un paio di giorni... Vic, lo formalizzi tu per favore?) per fare in modo che solo le voci Versus e Quit siano, per ora, evidenziabili con su o giù (ovviamente la predefinita sarà Versus).
Chi se ne occupa? Jappilas e Cesare in pair?
Va bene. Per domattina come sei messo Marco (se ricordo bene il tuo vero nome)?
jappilas
11-05-2006, 12:50
Va bene. Per domattina come sei messo Marco (se ricordo bene il tuo vero nome)?
Marco (piu' altri 3 , dovuti alla moda dell' epoca :D), giusto :)
il problema e' che di mattina non ho Eclipse sottomano (lab dell' uni...gia' tanto che abbiano lasciato installato firefox e aperto l' accesso oltre il router dipertimentale :( ), che e' purtroppo il motivo per cui all' inizio dicevo che avrei potuto dedicarmici solo alla sera (per un totale di 15 ore davanti a un crt, i neuroni ringraziano :D)
se ti va bene un task in pair "asimmetrico" , in cui l' unico che ha davanti eclipse applica le modifiche al codice suggerite dall' altro , di mattina sono comunque sul forum :sofico:
cdimauro
11-05-2006, 13:17
Mumble mumble. E' un bel problema: io sono disponibile soltanto la mattina... :(
Un pair "asimmetrico", come suggerisci, è troppo incasinato e non aiuta come dovrebbe nell'apprendimento del TDD.
cdimauro
11-05-2006, 13:20
Il coach dice che va bene anche così. :D
Domattina appena sei disponibile apri un apposito thread, che si comincia. ;)
Aspettiamo comunque VICIUS per la definizione del task.
jappilas
11-05-2006, 13:21
oppure potrei scompattare Eclipse sul pc del lab... :Perfido:
jappilas
11-05-2006, 13:23
Il coach dice che va bene anche così. :D
e meno male che l' avevo buttata lì quasi scherzando (immaginavo pure io che non fosse una soluzione ottima) :D
Domattina appena sei disponibile apri un apposito thread, che si comincia. ;)
ok ;)
cdimauro
11-05-2006, 14:08
oppure potrei scompattare Eclipse sul pc del lab... :Perfido:
Se puoi farlo è sempre meglio, è un aiuto in più.
oppure potrei scompattare Eclipse sul pc del lab... :Perfido:
potrebbe andare anche con una chiavetta usb, anche se forse sarebbe lento....
jappilas
11-05-2006, 16:03
PS: non vi spaventate se cliccando enter sulla story mode, poi non reagiscono piu' i tasti su e giu': semplicemente il menu principale "perde il focus" perche' quello attuale diventa un sottorange di un solo elemento: up e down in effetti funzionano ma fanno tornare sempre sullo stesso
dovrebbe bastare premere enter di nuovo per tornare a quello di prima
aggiornamento : nella pausa pranzo sono tornato a casa e ho provato a implementare le funzioni di cui parlavo prima ... oltre a sfruttare il redraw dello sprite per accendere/spegnere il menu principale
essenzialmente MainMenu ha subito un "major revamping" e nonostante ciò è codice testato (il test è quello postato prima, cge mi pareva corretto) e funziona :)
l' unico problema che vedo (che si potrebbe quasi mettere tra i bug noti a meno che non mi si autorizzi a modificare i test che fallivano già in origine) è legato alla memoria del KeyEvent:
dopo due eventi ENTER, pressione e rilascio, si esegue la menuaction
ma se viene di nuovo premuto e rilasciato ENTER senza eventi UP e DOWN nel frattempo, le menuaction vengono eseguite due volte (la prima entra in un sottomenu fake, la seconda ritorna)
quindi ribadisco:
se mi fate committare e il menu scompare o lampeggia premendo enter, non spaventarsi, premere su o giù una volta e ripremere enter per tornare al menu principale
potrebbe andare anche con una chiavetta usb, anche se forse sarebbe lento....
hm, cavolo... ho visto che non posso installare nulla di nulla senza chiedere il consenso dell' admin
e la mia ultima chiavetta usb ha dato forfait qualche giorno fa... infatti aspettavo la fiera dell' elettronica che si tiene qui tra 10 gg per comprarne un altro paio
:( :( :(
cdimauro
11-05-2006, 16:18
Eclipse non ha bisogno di installarsi: basta decomprire l'archivio e lanciare l'eseguibile. Funziona benissimo anche con utenze limitate, e in teoria potrebbe anche funzionare lanciandolo da una chiavetta USB (e forse da CDROM, se non va a scrivere nella sua cartella).
jappilas
11-05-2006, 17:45
ora enter e' gestito solo se il KeyEvent e' di tpo RELEASED, quindi il menu non dovrebbe piu' sfarfallare
per far passare i test ho adeguato anche altri 2 test che mostravano la stessa caratteristica di quello discusso a meta' thread: prima dipendevano indistintamente da KeyEvent.Enter
Ora da KeyEvent.Enter, SE la Action attiva e' quella del versus mode
funziona :)
jappilas
12-05-2006, 14:35
come da approvazione di vic, committato e task 4 completato
A cosa servono i subMenu nella soluzone del task???
Esistono... ??? :mbe: :mbe:
YAGNI :nonsifa:
:D :D :D
Direi che questo metodo non serve più:
selectMenuItem()
Se ce la faccio stasera lo faccio saprire ;)
jappilas
13-05-2006, 10:45
A cosa servono i subMenu nella soluzone del task???
Esistono... ??? :mbe: :mbe:
YAGNI :nonsifa:
:D :D :D
già che alla fine si maneggiano degli indici di un array, era un' aggiunta "infrastrutturale" a costo implementativo pressochè nullo, almeno riguardo l' implementazione attuale
inoltre mi è servito per creare un code path che reagisse a una serie di soli Event.ENTER consecutivi, facendo qualcosa "all' andata" e al "ritorno": senza un semplice meccanismo che all'esecuzione della MenuAction faccia passare il menu in un nuovo stato, probabilmente non mi sarei accorto che il funzionamento di ENTER con una varibile di memoria lastKey (messo per far passare dei test e non per altro) aveva un difetto inerente e non avrei pensato che erano i 3 test ad aver bisogno di un adeguamento
inoltre, per come è implementato, è servito per appurare la solidità del codice di ridisegno dello sprite: funziona tutto nonostante venga eseguito esplicitamente sprite.setOrigin() e moveTo() su una zona al di là delle dimensioni dello sprite stesso, quindi non visibile
ma visto che sono così controversi vorrà dire che verranno tolti quanto prima ;)
e mi scuso per il mio modo di lavorare non proprio ortodosso :O :p
jappilas
13-05-2006, 10:46
Direi che questo metodo non serve più:
selectMenuItem()
svariati test ne hanno bisogno se non ricordo male... se hai voglia di rimettere mano a tutti quelli che la chiamano... ;)
ma visto che sono così controversi vorrà dire che verranno tolti quanto prima ;)
e mi scuso per il mio modo di lavorare non proprio ortodosso :O :p
Come al solito ti scusi...ma non devi :D :D
Era solo per capire :stordita:
Ho notato che il selectMenuItem è usato ovunque....ma se non serve a nessuno nel codice, i test posono usare altri metodi.
Vediamo che riesco a fare più tardi ;)
jappilas
13-05-2006, 14:49
Come al solito ti scusi...ma non devi :D :D
Era solo per capire :stordita:
sai, magari mi viene da fare a modo mio quando voi adottate pratiche assodate e consolidate... :)
Ho notato che il selectMenuItem è usato ovunque....ma se non serve a nessuno nel codice, i test posono usare altri metodi.
Vediamo che riesco a fare più tardi ;)
il Menu è mmmmmio :sofico:
scherzi a parte, credo sarebbe meglio fare tutto "da una sola parte", invece che replicare il coding per ritrovarsi con versioni in conflitto di testgameloop , mainmenu e gameloop...
per il task 15.1.5 ho modificato svariati test (quelli che provano il comportamento con gli eventi UP e DOWN : ora invece che da story mode a versus mode si deve passare da versus mode a quit), e in alcuni la selectMenuItem era chiamata per posizionarsi esplicitamente sulla prima o ultima voce del menu; nel codice mi pare sia chamata solo dalla setMenu(), per posizionarsi sulla prima opzione
quello che farei sarebbe:
per intanto, modificare il costruttore del MainMenu in modo che la prima scelta selezionata sia versus mode - fatto :)
commentare via le select dai test che iniziano da versus (prima story) - fatto :)
testare che tutto funzioni di nuovo
update: se si elimina la select bisogna anche far sì che lo sprite venga disegnato alla 2a posizione dal costruttore del mainmenu...
ma così facendo saltano dei test sulle coordinate iniziali dello sprite all' avvio
comncio a pensare che sia meglio lasciare come sta il codice coinvolto, anche perchè quando le opzioni verranno implementate andrebbe di nuovo modificato
sai, magari mi viene da fare a modo mio quando voi adottate pratiche assodate e consolidate... :)
il Menu è mmmmmio :sofico:
scherzi a parte, credo sarebbe meglio fare tutto "da una sola parte", invece che replicare il coding per ritrovarsi con versioni in conflitto di testgameloop , mainmenu e gameloop...
per il task 15.1.5 ho modificato svariati test (quelli che provano il comportamento con gli eventi UP e DOWN : ora invece che da story mode a versus mode si deve passare da versus mode a quit), e in alcuni la selectMenuItem era chiamata per posizionarsi esplicitamente sulla prima o ultima voce del menu; nel codice mi pare sia chamata solo dalla setMenu(), per posizionarsi sulla prima opzione
quello che farei sarebbe:
per intanto, modificare il costruttore del MainMenu in modo che la prima scelta selezionata sia versus mode - fatto :)
commentare via le select dai test che iniziano da versus (prima story) - fatto :)
testare che tutto funzioni di nuovo
update: se si elimina la select bisogna anche far sì che lo sprite venga disegnato alla 2a posizione dal costruttore del mainmenu...
ma così facendo saltano dei test sulle coordinate iniziali dello sprite all' avvio
comncio a pensare che sia meglio lasciare come sta il codice coinvolto, anche perchè quando le opzioni verranno implementate andrebbe di nuovo modificato
Ok...occupatene tu.
Però ora che il task è finito e funziona bisogna rifattorizzare sia il codice che i test.
Io inizierei tolgiendo i commenti da MainMenu (:nonsifa:)... :D :D
Poi qualcuno mi spiega il warning che c'è in MainMenu???
jappilas
13-05-2006, 22:28
Ok...occupatene tu.
Però ora che il task è finito e funziona bisogna rifattorizzare sia il codice che i test.
ok ;)
Io inizierei tolgiendo i commenti da MainMenu (:nonsifa:)... :D :D
il commento in mainmenu era un pezzetto di codice che ho estratto in un funzione redrawSprite(int) che ridisegna la sezione iesima dello sprite del menu ;)
tolto :)
Poi qualcuno mi spiega il warning che c'è in MainMenu???
non ho capito a quale warning ti riferisci .... se è nel codice, mi diresti nome file e riga? :O :fagiano:
jappilas
13-05-2006, 22:51
più o meno ( rivedo se è il caso di rifattorizzare i test e più tardi posto sia i test che il codice )
però, ehm, non l' ho fatto in pair con cesare e in tdd puro (un test => una riga di codice) come voleva fek... :stordita:
quindi potrei aspettare se cesare ritiene opportuno postare altre versioni dei test coinvolti, per migliorare la soluzione passo a passo: comunque intanto posto i passaggi che ho seguito finora:
- riadattato il testMainMenuReactionToDownInput() come segue:
public void testMainMenuReactionToDownInput()
{
gameLoop.menuLoop();
MainMenu mainMenu = gameLoop.getMainMenu();
mainMenu.selectMenuItem(MenuItem.VERSUS_MODE);//previously STORY MODE
gameLoop.notifyKeyEvent(Event.DOWN, Event.PRESSED);
assertEquals(MenuItem.QUIT, mainMenu.getSelectedItem());//previously VERSUS MODE
gameLoop.notifyKeyEvent(Event.DOWN, Event.PRESSED);
assertEquals(MenuItem.VERSUS_MODE, mainMenu.getSelectedItem());//previously ADVANCED MODE
}
- aggiunto un ciclo
do ... while(!selectedAction[SelectedActionIndex].isAvailable) che contenesse le 3 righe di codice che passano all' opzione successiva in selectNetxItem,
- aggiunto un metodo isAvailable all' interfaccia MenuAction,
- aggiunto l' implementazione che ritorna true da versus_mode e quit, false dalle altre
- ripetuto i passaggi per i test complementari e la selectPreviousMenuItem
- alla fine, riportato il costruttore com' era prima e lasciata selectMenuItem per i motivi descritti nel precedente post
Jappi, non fare il commit di codice che ha a che fare con Menu e MenuItem. Fai un update e aspetta domattina.
Domani io e te si fa lezione su come fare le cose semplici e non complicarsi la vita per vivere felici.
Jappi, non fare il commit di codice che ha a che fare con Menu e MenuItem. Fai un update e aspetta domattina.
Domani io e te si fa lezione su come fare le cose semplici e non complicarsi la vita per vivere felici.
Una cosa sola...in MainMenu secondo mè c'è il rischio di fare confusione tra l'indice dell'array privato dei MenuItem e il valore di index() di un MenuItem.
Addesso "accidentalmente" sono coerenti...ma per come è implementato il tutto non è detto.
O si unificano le cose oppure si separano nettamente. ;)
Una cosa sola...in MainMenu secondo mè c'è il rischio di fare confusione tra l'indice dell'array privato dei MenuItem e il valore di index() di un MenuItem.
Addesso "accidentalmente" sono coerenti...ma per come è implementato il tutto non è detto.
O si unificano le cose oppure si separano nettamente. ;)
E' vero. E non e' mica finito li' il refactoring :)
Era l'una di notte mi sono preso una pausa. Stamattina concludo.
jappilas
14-05-2006, 10:25
Jappi, non fare il commit di codice che ha a che fare con Menu e MenuItem.
certo che no, finchè non ho via libera ufficiale ;)
Fai un update e aspetta domattina.
ok
Domani io e te si fa lezione su come fare le cose semplici e non complicarsi la vita per vivere felici.
lo sapevo, ho sbagliato tutto... :cry:
Jappi, non fare il commit di codice che ha a che fare con Menu e MenuItem. Fai un update e aspetta domattina.
:eek: Ho fatto un piccolo commit in GameLoop. Spero di non averti distrutto ore di lavoro.
ciao ;)
lo sapevo, ho sbagliato tutto... :cry:
La maggior parte del lavoro è buono. Ci sono solo alcuni punti da sistemare. La cosa importante è che hai fatto il tuo lavoro e ti sei impegnato :mano:
ciao ;)
jappilas
14-05-2006, 10:47
:eek: Ho fatto un piccolo commit in GameLoop. Spero di non averti distrutto ore di lavoro.
ciao ;)
se non hai modificato la notifyKeyEvent, e non hai rimosso il selectMenuItem (Versus_Mode) in setMenu, credo di no :)
La maggior parte del lavoro è buono. Ci sono solo alcuni punti da sistemare. La cosa importante è che hai fatto il tuo lavoro e ti sei impegnato :mano:
ciao ;)
:):):)
certo che a vedere quanto sta diventando lungo il thread, sto menu è praticamente un parto ... :D :D :D
certo che no, finchè non ho via libera ufficiale ;)
ok
lo sapevo, ho sbagliato tutto... :cry:
Smettila subito di piagnucolare che non abbiamo tempo :)
Non hai sbagliato tutto. Hai solo commesso un paio di errori, non ti nascondo abbastanza gravi, mentre lavoravi. Il primo errore e' stato ragionare in C e non in Java. Tu hai implementato il menu in C, non in Java e si vede perche' hai scritto molto piu' codice di quanto fosse necessario. Il secondo errore e' stato non tenere a mente i principi che usiamo nel progetto che sono essenzialmente due: semplicita' ed eliminare le duplicazioni.
Sembrano due principi stupidi e astratti, ma sono molto concreti, infatti: perche' far restituire un boolean ad execute quando tutte le implementazioni restituiscono true? Puo' magari anche andare bene scriverlo di getto, come tentativo di design, ma il principio della semplicita' ti avrebbe dovuto suggerire che al momento non serviva, e lo avresti dovuto eliminare. Perche' avere tre classi che implementano MenuAction il cui metodo execute() non fa altro che ritornare true?
Ovvero, se vai da un datore di lavoro e gli suggerisci di assumere tre persone e metterle a fare niente e pagarle, che ti risponde? E allora perche' tenere treu classi uguali che non fanno nulla?
Il resto riguarda il C contro Java: gli enum possono anche andare bene per descrivere, appunto, delle enumerazioni. Usare gli enum per selezionare comportamenti diversi non e' Java, e' C. Abbiamo strumenti piu' efficaci per risolvere il problema, le classi, vanno usate. Ed ecco che MenuItem grida per essere trasformato in una classe ed e' lui a svolgere le azioni.
Ricorda l'esempio di Hello World scritto con i pattern, duecento righe di codice per scrivere:
printf("Hello World!");
Impara a non complicarti la vita inutilmente, fai le cose semplici. Il mondo ti sorridera' :)
certo che a vedere quanto sta diventando lungo il thread, sto menu è praticamente un parto ... :D :D :D
Quel menu si implementa in 15 righe di codice: i parti avvengono quando ci si complica la vita ;)
Infine, perche' gestire due livelli di menu quando non c'e' alcun menu che lo richieda? Via. Quel codice non serve.
jappilas
14-05-2006, 11:15
Sembrano due principi stupidi e astratti, ma sono molto concreti, infatti: perche' far restituire un boolean ad execute quando tutte le implementazioni restituiscono true?
Puo' magari anche andare bene scriverlo di getto, come tentativo di design, ma il principio della semplicita' ti avrebbe dovuto suggerire che al momento non serviva, e lo avresti dovuto eliminare. Perche' avere tre classi che implementano MenuAction il cui metodo execute() non fa altro che ritornare true?
è vero, mi è servita in fase di sviluppo per testare che effettivamente l' esecuzione entrasse nel metodo della MenuAction () : infatti all' inizio sembrava non facesse nulla (non veniva settata isMenufinished, nonostante la flag di ritorno della funzioen fosse true) e sono stato un po' a domandarmi cosa potesse essere, finchè non mi sono accorto di non aver importato gameLoop in tutte le MenuAction
poi, ammetto di aver fatto copy/paste, quindi sono venute tutte uguali... cmq le tolgo asap ;)
Il resto riguarda il C contro Java: gli enum possono anche andare bene per descrivere, appunto, delle enumerazioni. Usare gli enum per selezionare comportamenti diversi non e' Java, e' C. Abbiamo strumenti piu' efficaci per risolvere il problema, le classi, vanno usate. Ed ecco che MenuItem grida per essere trasformato in una classe ed e' lui a svolgere le azioni.
ehm, l' enum l' ho ereditato da chi ha svolto i task precedenti, e partivo dal presupposto di dover "aggiungere" più che sostituire, "incastonando" il nuovo codice in ciò che già esisteva :O
però a metà thread avevo chiesto lumi su come realizzare nel modo migliore una struttura di menuactions, sincronizzata con l' enumerativo da usare per gli identificatori... siccome nessuno mi ha detto nulla allora, la cosa più semplice che sono stato capace di mettere insieme è stato l' array statico con l' enum come indice ... :O
Ricorda l'esempio di Hello World scritto con i pattern, duecento righe di codice per scrivere:
printf("Hello World!");
pensa che stavo per riscrivere anche i sottomenu a classi, meno male che mi hai fermato :D
jappilas
14-05-2006, 11:18
Infine, perche' gestire due livelli di menu quando non c'e' alcun menu che lo richieda? Via. Quel codice non serve.
;_;
allora elimino anche i due test che li stressano?
ehm, l' enum l' ho ereditato da chi ha svolto i task precedenti, e partivo dal presupposto di dover "aggiungere" più che sostituire, "incastonando" il nuovo codice in ciò che già esisteva :O
Devi aggiungere, sostituire, soprattutto togliere, vendere l'anima al diavolo se necessario, basta che finisci il tuo task con il codice piu' semplice possibile :)
Ora fai un update del mio refactoring. Guarda mamma, senza codice :)
Adesso un esercizio: implementa l'ultima richiesta di Jocchan, le opzioni disabilitate vanno saltate. Fallo senza aggiungere una riga di codice. Solo togliendo codice.
Devi aggiungere, sostituire, soprattutto togliere, vendere l'anima al diavolo se necessario, basta che finisci il tuo task con il codice piu' semplice possibile :)
Ora fai un update del mio refactoring. Guarda mamma, senza codice :)
Adesso un esercizio: implementa l'ultima richiesta di Jocchan, le opzioni disabilitate vanno saltate. Fallo senza aggiungere una riga di codice. Solo togliendo codice.
beh i test vanno aggiunti :D
beh i test vanno aggiunti :D
No, basta modificarne uno per testare la nuova condizione :p
ahhh :P
Fra non ti trovo su MSN :P
Non facciamo il refactoring oggi?
jappilas
14-05-2006, 12:14
rimosse le return true dalle execute()
rimossi i sottomenu, la menuActionBack e i relativi test
rimosso il MenuItem da membro della classe menu , adesso viene usato dalle singole Action per ritornare il proprio ID a scopo di testing
devo togliere anche i while nella selectPrevious (Next) Item() ? :fagiano:
jappilas
14-05-2006, 12:36
...passato , grazie al cielo e all' aiuto di vic
jappilas
14-05-2006, 13:07
Devi aggiungere, sostituire, soprattutto togliere, vendere l'anima al diavolo se necessario, basta che finisci il tuo task con il codice piu' semplice possibile :)
Ora fai un update del mio refactoring. Guarda mamma, senza codice :)
bel refactoring, ho imparato molte cose nuove vedendolo (in effetti gli oggetti statici che istanziano se stessi, mi perplimevano anche all' inizio :stordita: ) :ave:
Adesso un esercizio: implementa l'ultima richiesta di Jocchan, le opzioni disabilitate vanno saltate. Fallo senza aggiungere una riga di codice. Solo togliendo codice.
per ora solo cambiate 4 assegnazioni in MenuItem, se vuoi cancello quelle inutilizzate
MenuItem.VERSUS_MODE.previousItem = MenuItem.QUIT;
MenuItem.VERSUS_MODE.nextItem = MenuItem.QUIT;
MenuItem.QUIT.previousItem = MenuItem.VERSUS_MODE;
MenuItem.QUIT.nextItem = MenuItem.VERSUS_MODE;
modificata la chiamata selectMenuItem in setMenu in GameLoop, ora setta a versus mode lo stato iniziale
aggiornati i test di reazione ad UP e DOWN per ciclare su versus mode -> quit -> versus mode
funziona di nuovo, e mi hai fatto fare un altro reset mentale trasformandomi in uno zealot della code simplicity :D
funziona di nuovo, e mi hai fatto fare un altro reset mentale trasformandomi in uno zealot della code simplicity :D
:D
vBulletin® v3.6.4, Copyright ©2000-2026, Jelsoft Enterprises Ltd.