JavascriptProva

martedì 15 gennaio 2013

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!

domenica 16 dicembre 2012

Linee animate in Processing

Proviamo a disegnare una linea animata, adesso.
int x=0;
void setup(){
  background(100);
  size(1000,800);
  frameRate(200);
  fill(100);
}
void draw(){
  x++;
  line(0,0,x,500);
}
Ecco, la linea non si muove, ma disegna un triangolo. Per far disegnare un cerchio, dovrei usare le funzioni trigonometriche...
Ma se io voglio che la linea si sposti, posso procedere a quell'artifizio col background... Proviamo.
int x=0;
void setup(){
  background(100);
  size(1000,800);
  frameRate(10);
  fill(100);
}
void draw(){
  x++;
  line(0,0,x,500);
  background(100);
}
...che non funziona!
Vediamo con il contatore di frames...

Ecco: un buon artifizio è questo!
int x=0;
void setup(){
  background(100);
  size(1000,800);
  frameRate(100);
  fill(100);
}
void draw(){
  line(0,0,x,500);
  if(frameCount%5==0) {
    background(100);
    x++;
  }
}
Funziona! ...anche se la linea si muove un po' lentamente.
Ho appreso un artifizio per fare i loop. Fare l'operazione frameCount % [numero di frames che compongono il loop]. Ogni volta che il numero di frames eseguiti è divisibile per il numero di frames che compongono il loop, il risultato dell'operazione MODULO è zero, e questa viene posta come condizione per ottenere un effetto.

Primi rudimenti con Processing

Dunque...

Iniziamo con il metodo (o funzione) void setup...

Ecco:
void setup(){
  size(500,500);
}
Così facendo, con il comando size() imposto l'area del mio canvas. Ci provo con l'editor di Processing.
Ottengo una finestra del calibro voluto.

Ora ci disegno una linea:
void setup(){
  size(500,500);
}
void draw(){
  line(10,10,400,400);
}
Benissimo! Ci sono riuscito.

Ora divaghiamo...

Caricare un'immagine. Cerchiamo su Google "load image"...
PImage img;
void setup(){
  size(500,500);
  stroke(0);
  img=loadImage("bella.jpg");
}
void draw(){
  image(img,0,0,img.width/2,img.height/2);
}
Risultato:

Bene...

Quindi il caricamento dell'immagine è indipendente dalla sua visualizzazione.
L'immagine è stata preventivamente messa nella cartella "data" del file .pde.

martedì 11 dicembre 2012

Canvas: per prima cosa rendiamo un canvas trascinabile, potrebbe servire.

Bene... Sono riuscito a creare una libreria dragdrop.js che contiene l'essenziale per trascinare elementi sulla pagina web.
Essa viene chiamata semplicemente dando all'evento window.onload istruzione di eguagliare l'evento document.onmousedown alla funzione OnMouseDown e l'evento document.onmouseup alla funzione OnMouseUp, e di impostare la proprietà di stile position a "absolute" per gli elementi che si vuole trascinabili.

Ora occupiamoci del canvas.
Dato che sto lavorando con Internet Explorer a causa del fatto che è l'unico browser che mi consente di salvare files su disco fisso, e quindi di mantenere e modificare archivi xml, devo imparare la sintassi del canvas per IE.

Anche il canvas può essere soggetto a DragDrop, impostando le giuste proprietà:
<!DOCTYPE HTML>
<html>
<head>
<style>
#mycanvas{
   border:1px solid red;
   position:absolute;
}
</style>
<script src="funzioni.js"></script>
<script src="dragdrop.js"></script>
<script>
function main(){
 document.onmousedown=OnMouseDown;
 document.onmouseup=OnMouseUp;
}
window.onload=main;
</script>
</head>
<body>
   <canvas id="mycanvas" width="100" height="100">
</body>
</html>
Ecco: con il richiamo delle librerie "dragdrop.js" e "funzioni.js", e impostando quei semplici comandi, il canvas si muove se trascinato.

lunedì 5 novembre 2012

Incapsulamento

Ecco uno schema per creare delle interfacce istanziando oggetti e incapsulando, anzichè creando noiosi innerHTML nei quali mi perdo:

Questo è il costruttore dell'oggetto interfaccia:
function interfaccia(){
 var Me;
 var Notizie;
 var creaMe=function(){
  Me=document.createElement("div");
  Me.setAttribute("className","interfaccia");
  document.body.appendChild(Me); 
  
  var Notizie=new notizie();
  Me.appendChild(Notizie.Me);
 
 }
 creaMe();
 
 this.Me=Me; 
}
Nel contesto di questo costruttore viene istanziato l'oggetto notizie da un altro costruttore, in cui è prevista anche la presenza di una textarea:
function notizie(){
 var Me;
 var Testo
 
 var creaMe=function(){
  //Crea l'oggetto
  Me=document.createElement("div");
  Me.setAttribute("className","bordatoblu");
  
  //Crea la Textarea
  var testo=document.createElement("textarea");
  Testo=testo
  Me.appendChild(testo);
  
 }
 creaMe();
 this.Me=Me;
 
}
Di questo secondo oggetto viene resa pubblica soltanto l'interfaccia Me, ma aggiungendo un this.Testo=Testo potrei rendere pubblica anche la textarea, facendo sì che possa essere gestita anche da altre aree del programma.