JavascriptProva

martedì 22 gennaio 2013

Collisioni: facciamo i conti con l'ostacolo

A quest'ultima funzione, che mi blocca l'oggetto per tutta la parte di schermo che supera 400
 //CODICE CHE MUOVE L'OGGETTO
 if(MoveRight) MuoviADestra();
 if(MoveLeft) MuoviASinistra();
 if (destro(oggetto)>400) {
  oggetto.style.left=(400-larghezza(oggetto))+"px";
  MoveRight=false;
 }else{
  MoveRight=true;
 }
ora sostituisco la funzione daSinistra().
 //CODICE CHE MUOVE L'OGGETTO
 if(MoveRight) MuoviADestra();
 if(MoveLeft) MuoviASinistra();
 if (daSinistra(oggetto,ostacolo)) {
  oggetto.style.left=(sinistro(ostacolo)-larghezza(oggetto))+"px";
  MoveRight=false;
 }else{
  MoveRight=true;
 }
E ottengo la possibilità di aggirare l'ostacolo, ossia l'oggetto impatta contro il limite dell'ostacolo solo nel punto in cui l'ostacolo è presente, altrimenti arriva fino in fondo allo schermo.

No! Correzione:
 //CODICE CHE MUOVE L'OGGETTO
 if(MoveRight) MuoviADestra();
 if(MoveLeft) MuoviASinistra();
 if (prevDex<=sinistro(ostacolo) && daSinistra(oggetto,ostacolo)) {
  oggetto.style.left=(sinistro(ostacolo)-larghezza(oggetto))+"px";
  MoveRight=false;
 }else{
  MoveRight=true;
 }
Così funziona, altrimenti mi porta l'oggetto sulla sinistra dell'ostacolo anche quando si trova sulla destra.

Se muovo l'oggetto da destra, invece, esso attraversa ancora l'ostacolo. Inseriamo anche il reciproco della funzione da destra.
 //CODICE CHE MUOVE L'OGGETTO
 if(MoveRight) MuoviADestra();
 if(MoveLeft) MuoviASinistra();
 if (prevDex<=sinistro(ostacolo) && daSinistra(oggetto,ostacolo)) {
  oggetto.style.left=(sinistro(ostacolo)-larghezza(oggetto))+"px";
  MoveRight=false;
 }else{
  MoveRight=true;
 }
 if (prevSin>=destro(ostacolo) && daDestra(oggetto,ostacolo)) {
  oggetto.style.left=destro(ostacolo)+"px";
  MoveLeft=false;
 }else{
  MoveLeft=true;
 }
E funziona altrettanto.

Collisioni: nuovo modo per bloccare l'oggetto.

Ecco: anzichè muovere l'oggetto che poi mi viene continuamente rispinto indietro, adesso pongo una condizione perchè lo spostamento sia possibile: in questo caso dico al codice che se lo spostamento è verso destra, non deve essere fatto, mentre se è verso sinistra si può fare:
 //CODICE CHE MUOVE L'OGGETTO
 if (event.clientX-MouseX<0) oggetto.style.left=(BaseX+event.clientX-MouseX)+"px";;
 
 oggetto.style.top=(BaseY+event.clientY-MouseY)+"px"; 
}
Funziona: così facendo, sono possibili solo gli spostamenti negativi, verso sinistra. Ora facciamo il contrario:
 //CODICE CHE MUOVE L'OGGETTO
 if (event.clientX-MouseX>0) oggetto.style.left=(BaseX+event.clientX-MouseX)+"px";;
 
 oggetto.style.top=(BaseY+event.clientY-MouseY)+"px"; 
} 
Ecco, bene. Ovviamente funziona anche questo!
Ora facciamo che se il margine destro dell'oggetto arriva a 400 l'oggetto non si può spostare più a destra.
if(destro(oggetto)>400){
  if (event.clientX-MouseX<0) oggetto.style.left=(BaseX+event.clientX-MouseX)+"px";
 }else{
  oggetto.style.left=(BaseX+event.clientX-MouseX)+"px";
 }
Ecco...
Adesso proviamo a svilupparlo con le funzioni che esprimono la sovrapposizione a un ostacolo...

 if(daSinistra(oggetto,ostacolo)){
  if (event.clientX-MouseX<0) oggetto.style.left=(BaseX+event.clientX-MouseX)+"px";
 }else{
  oggetto.style.left=(BaseX+event.clientX-MouseX)+"px";
 }
 oggetto.style.top=(BaseY+event.clientY-MouseY)+"px"; 
Funziona ancora. E ovviamente aggira l'ostacolo.
Però è impreciso perchè a seconda della velocità del movimento l'oggetto si arresta in un punto variabile.

Organizziamo diverse istruzioni, una che muove a destra, una che muove a sinistra...

Creando queste due funzioni:
function MuoviADestra(){
 if(event.clientX-MouseX>0) oggetto.style.left=(BaseX+event.clientX-MouseX)+"px";
}
function MuoviASinistra(){
 if(event.clientX-MouseX<0) oggetto.style.left=(BaseX+event.clientX-MouseX)+"px";
} 
E creando queste due variabili booliane:
var MoveRight=true;
var MoveLeft=true;
io riesco a interrompere il movimento dell'oggetto quando il suo margine destro supera 400 in questo modo:
 //CODICE CHE MUOVE L'OGGETTO
 if(MoveRight) MuoviADestra();
 if(MoveLeft) MuoviASinistra();
 if (destro(oggetto)>400) {
  oggetto.style.left=(400-larghezza(oggetto))+"px";
  MoveRight=false;
 }else{
  MoveRight=true;
 }
In questo modo l'oggetto non si sposta virtualmente, come accadeva prima. Almeno credo...

Collisioni: prendiamo di petto la cosa...

Per prima cosa, creiamo una serie di funzioni DragDrop secondo la mia tecnica, complete delle righe di codice che memorizzano le coordinate prima del movimento

function OnMouseMove(){
 
 //CODICE CHE MEMORIZZA LE COORDINATE PRIMA DELLO SPOSTAMENTO
 prevSin=sinistro(oggetto);
 prevAlt=alto(oggetto);
 prevDex=destro(oggetto);
 prevBas=basso(oggetto);
 
 oggetto.style.left=(BaseX+event.clientX-MouseX)+"px";;
 
 oggetto.style.top=(BaseY+event.clientY-MouseY)+"px"; 
}


Quando l'oggetto viene mosso, prima che si abbia lo spostamento vengono memorizzate le coordinate che l'oggetto deteneva prima dello spostamento stesso.
Adesso, voglio che all'ascissa 400 il movimento a destra si arresti.
Come fare?

Ho pronte alcune funzioni:
//FUNZIONI CHE ESPRIMONO LE SOVRAPPOSIZIONI DELL'OGGETTO ALL'OSTACOLO.
function daSinistra(obj,ost){
 if(overH(obj,ost) && destro(obj)>sinistro(ost)){
  return true;
 } else {
  return false;
 }
}

function daDestra(obj,ost){
 if(overH(obj,ost) && sinistro(obj)<destro(ost)){
  return true;
 } else {
  return false;
 }
}

function daAlto(obj,ost){
 if(overV(obj,ost) && basso(obj)>alto(ost)){
  return true;
 } else {
  return false;
 }
}

function daBasso(obj,ost){
 if(overV(obj,ost) && alto(obj)<basso(ost)){
  return true;
 } else {
  return false;
 }
}
...costruite su queste altre funzioni che esprimono la sovrapposizione dell'oggetto alla proiezione orizzontale o verticale dell'ostacolo (un po' cervellotico):
function overH(obj,ost){
 if(basso(obj)>alto(ost) && alto(obj)<basso(ost)){
  return true;
 } else {
  return false;
 }
}

function overV(obj,ost){
 if(destro(obj)>sinistro(ost) && sinistro(obj)<destro(ost)){
  return true;
 } else {
  return false;
 }
}


Bene, comunque le funzioni che dobbiamo considerare per verificare la sovrapposizione da destra, sinistra, alto e basso sono queste:
daDestra(obj,ost), daSinistra(obj,ost), daAlto(obj,ost) e daBasso(obj,ost).
Anzi quasi quasi le metto su un modulo a parte così non ci confondiamo le idee...
Sì, lo faccio subito così le tolgo dalle balle.

Fatto. E inserisco il collegamento:
<script src="overlap.js"></script> 
Fatto... Adesso si può ragionare, tenendo sempre presenti i nomi delle funzioni.

venerdì 18 gennaio 2013

E se io creassi una mappa di limiti oltre i quali viene meno...? No, c'è sempre la questione dell'affondamento iniziale dell'oggetto nell'ostacolo. Per rilevare la collisione, cioè, l'oggetto deve superare il limite dell'ostacolo, in modo da esserne poi respinto ai margini. E nel momento in cui affonda, come accade nel caso di cui parlavo prima, può sfuggire al rilevamento di altri ostacoli.
La questione sembra proprio insolubile...

Si può porre praticamente per tutte le volte che ci siano due ostacoli posti ad angolo. Il sistema dovrebbe verificare prima, ad esempio, l'ostacolo 2, ma poi verificare immediatamente l'ostacolo 1... E se si creasse una condizione generale di "sovrapposizione"? Una volta respinto in alto dall'ostacolo 2, non perderebbe la sua condizione di "sovrapposto", e quindi questo vanificherebbe lo stesso respingimento.
Da sviluppare... Potrebbe essere l'idea buona...???

Se io spingo l'oggetto contro l'ostacolo 2, ottengo come risultato di una funzione il fatto che l'oggetto sia ancora "non libero" e quindi lo spostamento non si fa, e si passa ad esaminare altri ostacoli... fino a quando si ottiene la condizione di "libero" e si verifica effettivamente lo spostamento.

Analisi del bug...

come fare a ricacciare l'oggetto nella stessa direzione da cui è venuto?
Un momento, però! Non devo mica riportarlo nel punto di entrata? è sufficiente che lo riporti, alla stessa altezza, sul margine.
Che succede quando io porto l'oggetto su un ostacolo e poi mi passa attraverso l'altro ostacolo messo a breve distanza?

Ora faccio in modo che la funzione esamini dapprima l'ostacolo 1 (marrone) e poi l'ostacolo 2 (rosso).


In questo caso, dopo aver portato l'oggetto (celeste) sull'ostacolo2, spostandolo verso l'ostacolo1, sia che il cursore del mouse rimanga sull'oggetto sia che venga spostato in sotto l'oggetto non attraversa l'ostacolo 1.
In questo caso, la funzione esamina dapprima l'ostacolo 1: quando porto l'oggetto sull'ostacolo 2 il codice non trova nulla da eccepire sull'ostacolo 1 e quindi esamina l'ostacolo 2 trovando che l'oggetto si è avvicinato dall'alto e quindi respingendolo in alto.
Quando poi avvicino l'oggetto all'ostacolo 1, il codice esamina di nuovo l'ostacolo 1 e trova l'eccezione, così respinge l'oggetto a sinistra. Quindi esamina l'ostacolo 2 e trovando l'eccezione respinge l'oggetto in alto.

Adesso inverto la sequenza degli ostacoli esaminati.
Quando avvicino l'oggetto sull'ostacolo 2 il codice esamina l'ostacolo 2 trovando l'eccezione e portandomi l'oggetto in alto. Quindi esamina l'ostacolo 1 e non trova nessuna eccezione.
Successivamente, all'avvicinamento all'ostacolo 1 il codice esamina l'ostacolo 2 e trova un'eccezione spingendomi in alto l'oggetto anche qualora l'oggetto avesse giè superato il limite dell'oggetto 1. Questo fa sì che l'oggetto rispunti fuori dall'oggetto 2 quando già ha superato il limite che non dovrebbe attraversare, creando il problema.
Se invece il cursore resta sull'oggetto, l'oggetto viene spinto fuori dall'oggetto 2, ma successivamente viene anche esaminato l'oggetto 1 perchè nel momento in cui l'oggetto viene respinto non si trova fuori dall'area dell'oggetto 1 e quindi può sollevare l'eccezione anche a carico dell'oggetto 1.

martedì 15 gennaio 2013

Una scatola di DIV...

Come generare una scatola di DIV?

Maledette collisioni!

Voglio vedere una volta per tutte come risolvere questa maledetta storia delle collisioni di un oggetto mosso manualmente.

Inizio con la pagina nuovamente vergine. Adesso non dovrei fare più gran fatica per ricostruire lo schema che permette l'individuazione delle collisioni.
function OnMouseMove(){

 oggetto.style.left=(event.clientX-spiazzamentoX)+"px";
 oggetto.style.top=(event.clientY-spiazzamentoY)+"px";
}
Questa è la funzione che va modificata.
In pratica, devo riscrivere da capo il semplice codice che mi fa individuare le collisioni, che ormai credo di aver imparato a sufficienza...
Ci provo...

Mi dichiaro le variabili globali che mi servono per memorizzare la posizione precedente delle coordinate dell'oggetto:
var prevDex;
var prevSin;
var prevAlt;
var prevBas;
E poi vado alla funzione per modificarla.
Innanzitutto memorizzo la posizione dell'oggetto prima del movimento.
function OnMouseMove(){
 prevDex=destro(oggetto);
 prevSin=sinistro(oggetto);
 prevAlt=alto(oggetto);
 prevBas=basso(oggetto);
 
 oggetto.style.left=(event.clientX-spiazzamentoX)+"px";
 oggetto.style.top=(event.clientY-spiazzamentoY)+"px";
}
Ora devo individuare i "corridoi", ossia le sovrapposizioni...
Spezziamo queste in due funzioni: una che individua la posizione nell'ambito della proiezione dell'ostacolo e una che individua lo sconfinamento dell'oggetto oltre il margine dell'ostacolo.
Funzione overH, che individua la sovrapposizione sul piano orizzontale, e overV, sul piano verticale
function overH(obj,ost){
 if(basso(obj)>=alto(ost) && alto(obj)<=basso(ost)){
  return true;
 } else {
  return false;
 }
}

function overV(obj,ost){
 if(destro(obj)>=sinistro(ost) && sinistro(obj)<=destro(ost)){
  return true;
 } else {
  return false;
 }
} 

Ho costruito, valendomi di overH e overV, le funzioni daAlto, daBasso, daDestra e daSinistra:
function daSinistra(obj,ost){
 if(overH(obj,ost) && destro(obj)>sinistro(ost)){
  return true;
 } else {
  return false;
 }
}

function daDestra(obj,ost){
 if(overH(obj,ost) && sinistro(obj)<destro(ost)){
  return true;
 } else {
  return false;
 }
}

function daAlto(obj,ost){
 if(overV(obj,ost) && basso(obj)>alto(ost)){
  return true;
 } else {
  return false;
 }
}

function daBasso(obj,ost){
 if(overV(obj,ost) && alto(obj)<basso(ost)){
  return true;
 } else {
  return false;
 }
} 
E adesso passo a modificare tutta la funzione OnMouseMove:
function OnMouseMove(){
 prevDex=destro(oggetto);
 prevSin=sinistro(oggetto);
 prevAlt=alto(oggetto);
 prevBas=basso(oggetto);
 
 oggetto.style.left=(event.clientX-spiazzamentoX)+"px";
 oggetto.style.top=(event.clientY-spiazzamentoY)+"px";
 
 
 if(prevDex<=sinistro(ostacolo) && daSinistra(oggetto,ostacolo)){
  oggetto.style.left=(sinistro(ostacolo)-larghezza(oggetto))+"px";
 }
 else if(prevSin>=destro(ostacolo) && daDestra(oggetto,ostacolo)){
  oggetto.style.left=(destro(ostacolo))+"px";
 }
 else if(prevAlt<=alto(ostacolo) && daAlto(oggetto,ostacolo)){
  oggetto.style.top=(alto(ostacolo)-altezza(oggetto))+"px";
 }
 else if(prevBas>=basso(ostacolo) && daBasso(oggetto,ostacolo)){
  oggetto.style.top=(basso(ostacolo))+"px";
 } 
} 
che funziona egregiamente! L'ostacolo è solido come un mattone, l'oggetto non gli passa assolutamente attraverso!

Il bug si manifesta quando gli ostacoli sono più di uno, e forse ragionando ho capito bene perchè

martedì 1 gennaio 2013

Esperimenti sulle collisioni

Ecco, adesso potrei approfittare dei diversi pattern di vero e falso delle due funzioni per decidere il comportamento dell'oggetto nelle diverse posizioni in cui impatta l'ostacolo.
Devo dividere la funzione OnMouseMove in diverse sezioni:
c'è una sezione in cui si possono leggere le impostazioni sullo stato precedente, quindi l'atto del movimento dell'oggetto e una sezione successiva in cui viene rilevato il nuovo stato dell'oggetto, prendendo eventualmente le impostazioni precedenti.

Primo esercizio:
Prima del movimento si deve rilevare se l'oggetto si trova in posizione orizzontale rispetto all'ostacolo o in posizione verticale. Nel primo caso verrà fissato attaccato all'ostacolo sulla sinistra, nel secondo attaccato all'ostacolo in alto.
Proviamo...

Ho avuto una qualche difficoltà in relazione alla nomenclatura delle funzioni che ho già creato.
La funzione overHor, secondo il nome, dovrebbe esprimere la sovrapposizione orizzontale, ma in realtà è positiva, per come l'ho scritta, solo se l'oggetto si trova sulla verticale dell'ostacolo, e non sull'orizzontale.
Reciprocamente, overVert secondo il nome, dovrebbe esprimere la sovrapposizione verticale, ma risulta positiva solo se l'oggetto si trova sull'orizzontale dell'ostacolo.
Sostituisco la nomenclatura delle due funzioni, altrimenti la cosa è fonte di confusione:

//funzione overHor: è positiva se l'oggetto si trova sull'orizzontale dell'ostacolo
function overHor(){
 if(basso(oggetto)>alto(ostacolo) && alto(oggetto)<basso(ostacolo)){
  return true;
 }else{
  return false;
 }
}

//funzione overVert: è positiva se l'oggetto si trova sulla verticale dell'ostacolo
function overVert(){
 if(destro(oggetto)>sinistro(ostacolo) && sinistro(oggetto)<destro(ostacolo)){
  return true;
 }else{
  return false;
 }
} 
Ecco, così va meglio...
Ora scrivo la funzione OnMouseMove con le sue sezioni: una sezione in cui si legge lo stato precedente, una in cui si effettua il movimento e una successiva in cui si prendono decisioni in relazione al raffronto fra lo stato precedente e lo stato successivo al movimento.
function OnMouseMove(){
 $("testo").innerHTML=overHor()+" "+overlap();
 
 //sezione di lettura stato precedente
 stato=overHor();
 
 
 oggetto.style.left=(event.clientX-spiazzamentoX)+"px";
 
 //sezione decisioni
 if(overlap()) {
  if(stato==true) oggetto.style.left=(sinistro(ostacolo)-larghezza(oggetto))+"px";
 }
  
 oggetto.style.top=(event.clientY-spiazzamentoY)+"px"; 
}
E così funziona: ossia se l'oggetto, prima di impattare con l'ostacolo, si trova sulla sua "banda" orizzontale, viene attaccato all'ostacolo sulla sinistra.

Individuazione della sovrapposizione fra due elementi di un documento.

Insisto a cercare di costruirmi una serie di funzioni completamente da solo.

Innanzitutto definiamo una funzione di nome sovrapposto o qualcosa di simile che dovrebbe essere una variabile booleana la quale esprime lo stato di sovrapposizione fra due oggetti.

E cerchiamo di verificarla nella pagina-laboratorio.

Ecco, per il momento ho creato una funzione di nome overHor che esprime la sovrapposizione dell'oggetto all'ostacolo in senso orizzontale:
function overHor(){
 if(destro(oggetto)>sinistro(ostacolo) && sinistro(oggetto)<destro(ostacolo)){
  return true;
 }else{
  return false;
 }
}

Testata sulla pagina, in questo modo:
function OnMouseMove(){
 $("testo").innerHTML=overHor();
 oggetto.style.left=(event.clientX-spiazzamentoX)+"px";
 oggetto.style.top=(event.clientY-spiazzamentoY)+"px";
}
funziona: nella casella "testo" appare "false" se l'oggetto non si sovrappone in senso orizzontale all'ostacolo, mentre appare "true" soltanto nel momento in cui l'oggetto venga trascinato sulla banda verticale corrispondente alle coordinate X dell'ostacolo.

Ora creo anche un'analoga funzione per la direzione verticale:
function overVert(){
 if(basso(oggetto)>alto(ostacolo) && alto(oggetto)<basso(ostacolo)){
  return true;
 }else{
  return false;
 }
}
e funziona, parimenti.

Ora le sintetizzo insieme, e dovrei avere un valore true soltanto quando ci sia una sovrapposizione dell'oggetto all'ostacolo.
function overlap(){
 if(overHor() && overVert()){
  return true;
 }else{
  return false;
 }
}
Perfetto! Funziona benissimo! Ottengo un true solo se l'oggetto si sovrappone perfettamente all'ostacolo!