Orologio Analogico

Post on 07-Jun-2015

698 views 0 download

Transcript of Orologio Analogico

Lezione di Build & Script

Come costruire un orologio analogico

Salahzar Stenvaag

Agosto 2008

La lezione non è difficile ma prevede la conoscenza almeno base della costruzione e dello scripting.

Per intenderci dovreste sapere come costruire box, cilindri tagliarli e linkarli assieme (lato build) e

come costruire uno script base e aver visto almeno la base della comunicazione llSay/listen.

0. Il progetto

1. la parte di build (3 lancette + la base)

2. lo script per le ore

3. per i minuti

4. per i secondi

5. lo script che fa ticcare il tutto

Scopo della lezione è insegnarvi a costruire un orologio analogico, utile da mettere in costruzioni (campanili), orologi da polso,

ed in genere per dimostrarvi:

la comunicazione all'interno di oggetti linkati (llMessageLinked/link_message)

istruzioni di movimentazione di oggetti linkati (llSetLocalRot)

accesso alle funzioni di data/ora utilizzo di un timer

0. Il progetto.

La nostra idea è semplice: costruiamo 3 lancette di dimensioni diverse e le poniamo sopra una base circolare.

Abbiamo un "ticker", un contatore che ogni secondo verifica l'ora e manda alle 3 lancette un segnale in modo che le lancette si dispongano in maniera conveniente.

Il ticker è un semplice timer che ogni secondo prende la data/ora, estra le informazioni relative a HH MM SS ed invia

HH => alla lancetta delle ore MM => alla lancetta dei minuti SS => alla lancetta dei secondi

1. la parte di build.

Le lancette devono poter essere facilmente ruotate attorno al perno centrale. Questo ci conduce ad un piccolo problema:

se le lancette le faccio con un box appiattito (es. 3m x 20cm x 1 cm) l'istruzione di rotazione lo muoverebbe attorno al suo centro e non avrei chiaramente indicazione di dove sta puntanto (si potrebbe mettere una texture trasparente per metà), ma io ho trovato una soluzione più elegante:

useremo dei box "tagliati" in modo che il centro stia ad una estremità.

Questo si ottiene con il seguente trucchetto:

- step 0: facciamo un normale box parallelepipoidale (10x.5x.5)

- step 1: se tagliamo il box fra 0.75 e 1.00 otteniamo una specie di spicchio.

- step 2: riducendo lo spessore lungo la Y al minimo possibile abbiamo una lamina rettangolare

Che può essere ruotata attorno all'asse Y facilmente per produrre le ore volute

La lancetta in questione la duplichiamo 3 volte cambiando la Z in modo da avere larghezza diversa.

Noi abbiamo utilizzato larghezza 0.10 per i secondi (lunghezza 4.9), 0.15 per i minuti (lunghezza 4.5) 0.25 per le ore (2.5). A questo punto le lancette vanno accostate con lo stesso centro, costruite un cilindro 5x5x0.01, usando

una texture opportuna linkiamo tutto assieme avendo cura di avere il cilindro come root prim (ultimo a essere cliccato) e voilà dal punto di vista costruttivo abbiamo fatto il nostro orologione. :)

2. Lo script per le ore

Come dicevo le lancette si limitano ad "ascoltare" sul canale dei messaggi interni finchè non compare un messaggio.

I messaggi vengono inviati come llMessageLinked all'intero oggetto linkato specificando "H" o "M" o "S" sul campo "key" e nel campo str il valore con la virgola di dove si deve mettere la lancetta es 5.4. Questo per avere uno spostamento molto

lineare delle lancette (eccetto la lancetta dei secondi che si muoverà a scatti).

Lo script per le ore è il seguente (TickHour):

default {

link_message(integer sendnum, integer channel, string str, key id) {

if((string)id=="H") {

// use str as the number to tick hour

float hour=(float)str;

vector myrotation=<90,270 -360 * (hour/12.0),0 >;

llSetLocalRot(llEuler2Rot(DEG_TO_RAD* myrotation));

} } }

* Come vedete risponde solo quando il parametro id vale "H" (così le lancette non si confondono).

* Prende il valore con la virgola estratta dal dato passato e lo mette in un float.

* Calcola la rotazione Euleriana in gradi lungo i 3 assi.

* In maniera empirica ho visto che se hour=0, la rotazione da fargli assumere è 270 gradi (verifica sul campo).

270-360*(hour/12.0) server per avere una rotazione espressa in gradi corretta, dove ogni incremento di hour corrisponde a 1/12 di angolo giro (360 gradi).

* la rotazione euleriana in gradi viene ricondotta in radianti e come di rotazione elementare

* Infine si setta la rotazione rispetto al root prim

Per provare questo script avevo messo:

1\ una llListen solo all'owner nello state_entry

2\ una listen che rimandava il dato ascoltato come message linked con chiave H

state_entry(){

llListen(0,"",llGetOwner(),"");

}

listen(integer channel,string name, key id, string data)

{

llMessageLinked(LINK_SET,0,data,"H");

}

ed alcuni llSay(0, ) in posizioni strategiche dello script :)

3. Lo script per i minuti

Avendo in mano lo script per le ore già testato, lo replichiamo per rispondere ai minuti. Attenzione che le ore sono espresse in dodicesimi di angolo, ma i minuti sono in sessantesimi.

Da qui lo script (TickMinute):

default {

link_message(integer sendnum, integer channel, string str, key id) {

if((string)id=="M") {

// use str as the number to tick hour

float minute=(float)str;

vector myrotation=<90,270-360*(minute/60.0),0>;

llSetLocalRot(llEuler2Rot(DEG_TO_RAD*myrotation)); }

}} Notate la divisione per 60.

4. Lo script per i secondi.

E' identico a quello dei minuti:

default {

link_message(integer sendnum, integer channel, string str, key id) {

if((string)id=="S") {

// use str as the number to tick hour

integer second=(integer)str;

vector myrotation= <90,270 – 360 * ((float) second/60.0),0>;

llSetLocalRot(llEuler2Rot(DEG_TO_RAD*myrotation));

}}}

5. Il cuore: il ticker centrale che istruisce le lancette:

default {

state_entry() {

llSetTimerEvent(1);

}

timer() {

// ottiene ora/minuti/secondi e calcola lo spostamento delle ore e minuti

list timestamp = llParseString2List( llGetTimestamp(), ["T",":","Z"] , [] );

float hour= llList2Float(timestamp,1) + llList2Float (timestamp,2) / 60.0;

float minutes= llList2Float(timestamp,2)+ llList2Float(timestamp,3) / 60.0;

// manda il segnale alle ore “H”, minuti “M” e secondif “S”

llMessageLinked(LINK_SET,0,(string)hour,(key)"H");

llMessageLinked(LINK_SET,0,(string)minutes,(key)"M");

llMessageLinked(LINK_SET,0,llList2String( timestamp, 3 ),(key)"S");

// visualizza comunque la data come testo flottante

llSetText(llList2String(timestamp,1)+":"+llList2String(timestamp,2)+":"+llGetSubString(llList2String(timestamp,3),0,2),<1,1,0>,1); }}

* Lo state_entry si limita ad impostare il timer ogni secondo

* il timer va a vedere che ore sono (llGetTimeStamp() espresso in tempo UTC (quello di Greenwich), anche chiamato ZULU time

* parsifica la data estraendone i vari pezzettini dentro una lista [ xx, v1, v2, v3 ]

* v1 contiene le ore, v2 i minuti, v3 i secondi

* l'ora viene calcolata come ora + minuti/60 per avere lo spostamento "dolce" delle ore

* i minuti vengono calcolati come minuti + secondi/60 analogamente

* le tre informazioni vengono inviate alle lancette che "obbediscono".

6. Conclusioni.

Avete in mano un freebie semplice e funzionale.

E' migliorabile in molti modi, a partire dalla texture per le ore.

Si potrebbe anche usare in luogo delle lancette dei cilindri con alpha channel con sopra dipinte le frecce.

Il problema però è che secondlife quando si usa troppa trasparenza non capisce più niente. :)

NOTA: A causa di alcuni problemi di refresh del Browser è possibile che non vediate le lancette dei minuti e delle ore muoversi se state immobili davanti. E’ comunque un ottimo esercizio per capire gli oggetti linkati e la comunicazione fra di essi.

Salahzar Stenvaag