martedì 27 gennaio 2015

Creare delle funzioni che identifichino la posizione del mobile rispetto a un ostacolo.
Innanzitutto, identificare sinistra, destra, alto e basso.
function sinistra(oggetto){
 return oggetto.x;
}

function destra(oggetto){
 return oggetto.x+oggetto.w;
}

function alto(oggetto){
 return oggetto.y;
}

function basso(oggetto){
 return oggetto.y+oggetto.h;
}

Con queste funzioni, adesso definiamo la posizione relativa di un mobile rispetto a un ostacolo:
function ASinistra(mobile, ostacolo){
 if(destra(mobile)<sinistra(ostacolo) && alto(mobile)<basso(ostacolo) && basso(mobile)>alto(ostacolo)) return true;
 return false;
}

function ADestra(mobile ostacolo){
 if(sinistra(mobile)>destra(ostacolo) && alto(mobile)>basso(ostacolo) && basso(mobile)>alto(ostacolo)) return true;
 return false;
}

function InAlto(mobile, ostacolo){
 if(basso(mobile)<alto(ostacolo) && destra(mobile)>sinistra(ostacolo) && sinistra(mobile)<destra(ostacolo)) return true;
 return false;
}

function InBasso(mobile, ostacolo){
 if (alto(mobile)>basso(ostacolo) && destra(mobile)>sinistra(ostacolo) && sinistra(mobile)<destra(ostacolo)) return true;
 return false;
} 
E adesso facciamo la prova... modificando il codice di OnMouseMove:
function OnMouseMove(evt){
 rettangolo.x=evt.pageX;
 rettangolo.y=evt.pageY;

 scrivi(InBasso(rettangolo,ost));
}
provando via via con InAlto, ADestra, ASinistra, e cambiando ost con ost2 (due diversi ostacoli disegnati sul canvas) funziona tutto!


Alla fine ho fatto tutto, definendo sia le posizioni del mobile, sia le posizioni delm mobile virtuale dato dalla posizione del cursore...
function sinistra(oggetto){
 return oggetto.x;
}

function destra(oggetto){
 return oggetto.x+oggetto.w;
}

function alto(oggetto){
 return oggetto.y;
}

function basso(oggetto){
 return oggetto.y+oggetto.h;
}


//_________________________________________________________________________________________________

function ASinistra(mobile, ostacolo){
 if(destra(mobile)<sinistra(ostacolo) && alto(mobile)<basso(ostacolo) && basso(mobile)>alto(ostacolo)) return true;
 return false;
}

function ADestra(mobile, ostacolo){
 if(sinistra(mobile)>destra(ostacolo) && alto(mobile)<basso(ostacolo) && basso(mobile)>alto(ostacolo)) return true;
 return false;
}

function InAlto(mobile, ostacolo){
 if(basso(mobile)<alto(ostacolo) && destra(mobile)>sinistra(ostacolo) && sinistra(mobile)<destra(ostacolo)) return true;
 return false;
}

function InBasso(mobile, ostacolo){
 if (alto(mobile)>basso(ostacolo) && destra(mobile)>sinistra(ostacolo) && sinistra(mobile)<destra(ostacolo)) return true;
 return false;
}

//________________________________________________________________________________________________

function sinistraVirtuale(evt,mobile){
 return evt.pageX;
}

function destraVirtuale(evt,mobile){
 return evt.pageX+mobile.w;
}

function altoVirtuale(evt,mobile){
 return evt.pageY;
}

function bassoVirtuale(evt,mobile){
 return evt.pageY+mobile.h;
}

//________________________________________________________________________________________________

function ASinistraDelMargineDestro(evt,mobile, ostacolo){
 if(sinistraVirtuale(evt,mobile)<destra(ostacolo) && altoVirtuale(evt,mobile)<basso(ostacolo) && bassoVirtuale(evt,mobile)>alto(ostacolo)) return true;
 return false;
}
 
function ADestraDelMargineSinistro(evt,mobile, ostacolo){
 if(destraVirtuale(evt,mobile)>sinistra(ostacolo) && altoVirtuale(evt,mobile)<basso(ostacolo) && bassoVirtuale(evt,mobile)>alto(ostacolo)) return true;
 return false;
}
function InAltoDelMargineBasso(evt,mobile, ostacolo){
 if(altoVirtuale(evt,mobile)<basso(ostacolo) && destraVirtuale(evt,mobile)>sinistra(ostacolo) && sinistraVirtuale(evt,mobile)<destra(ostacolo)) return true;
 return false;
}

function InBassoDelMargineAlto(evt,mobile, ostacolo){
 if (bassoVirtuale(evt,mobile)>alto(ostacolo) && destraVirtuale(evt,mobile)>sinistra(ostacolo) && sinistraVirtuale(evt,mobile)<destra(ostacolo)) return true;
 return false;
}

sabato 17 gennaio 2015

Collisioni

Lo scopo è far rimanere il rettangolo entro la metà sinistra del canvas.

La logica è che il margine sinistro del rettangolo è pari al pageX del mouse se non supera un determinato valore di coordinata x.

function OnMouseMove(evt){
 if (evt.pageX<300) rettangolo.x=evt.pageX;
 rettangolo.y=evt.pageY;
}




mercoledì 14 gennaio 2015

Oggetti rettangolo sul canvas.

Trasformo un rettangolo in un oggetto.
function rect(x,y,w,h,colore){
 ctx.fillStyle=colore;
 ctx.beginPath();
 ctx.rect(x,y,w,h);
 ctx.closePath();
 ctx.fill();
 this.x=x;
 this.y=y;
 this.w=w;
 this.h=h;
}
Così quando voglio disegnare un rettangolo sul canvas:
 rettangolo=new rect(100,100,50,20,"dodgerblue"); 
 alert(rettangolo.x);
Che mi restituisce una messageBox con il valore 100.

Ancora:
function draw(){
  rect(0,0,WIDTH,HEIGHT,sfondo);
  
 rettangolo=new rect(100,100,50,20,"dodgerblue"); 
 alert(rettangolo.x);
 
 rettangolo2=new rect(50,150,200,10,"green");
 alert("Area = "+rettangolo2.x*rettangolo2.y);
}


Ed ecco i successivi sviluppi...

<!DOCTYPE html>
<html>
<script src="funzioniCanvas.js"></script>
<script>
var sfondo;
var rettangolo;
var rettangolo2;

function init(){
  initContext("canvas");
  
  
  //istanziazione di rettangoli
  
  sfondo=new rect(0,0,WIDTH,HEIGHT,"black");
 rettangolo=new rect(100,100,50,20,"dodgerblue"); 
 rettangolo2=new rect(50,150,200,10,"green");

 
 
  intervallo=setInterval(draw,1);
}

function draw(){
  
  sfondo.disegna();
 rettangolo.disegna();
 rettangolo2.disegna();
 rettangolo2.y+=.1
 rettangolo.x+=.1;

}

window.addEventListener("load",init);
</script>
<body>
<canvas id="canvas" width=500 height=500></canvas>
<textarea id="testo" style="float:right;height:500px""></textarea>
<div id="delta"></div>
</body>
</html> 


Così ottengo anche il movimento dei rettangoli.
Essi vengono istanziati prima della funzione draw(), e vengono solo disegnati a ogni ripetizione della funzione.

sabato 10 gennaio 2015

Collisioni perfezionate (in attesa del prossimo bug)

Ecco le collisioni su tutti i lati, ancora perfezionato, in attesa che vengano fuori degli altri bugghetti a farmi imprecare un po'...
<!DOCTYPE html>
<html>
<script src="funzioniCanvas.js"></script>
<script>
var x=200;
var dx=4;
var y=200;
var dy=3;
var w=30;
var h=30;
var sfondo="black";
var colore="green";

var immagine;

function init(){
 initContext("canvas");
 intervallo=setInterval(draw,1);
}

function draw(){
 rect(0,0,WIDTH,HEIGHT,sfondo);
 rect(x,y,w,h,colore);
 
 rect(350,100,1,250,"#FFFF00");
 rect(50,100,1,250,"#FFFF00");
 //rect(100,50,300,1,"#FF0000");
 rect(100,400,300,1,"#FF0000");
 immagine=ctx.getImageData(x+w,y-1,dx,h+2);
 immagine2=ctx.getImageData(x-1,y-1,dx,h+2);
 immagineGiu=ctx.getImageData(x-1,y+h,w+2,dy)
 immagineSu=ctx.getImageData(x-1,y-1,w+2,dy)
 
 
 
 XDetect(immagine,0,255);
 XDetect(immagine2,0,255);

 YDetect(immagineGiu,0,255);
 YDetect(immagineSu,0,255);
 
 if(x+w>WIDTH || x<0) dx=-dx;
 if(y+h>HEIGHT || y<0) dy=-dy;
 
 x+=dx;
 y+=dy;
}

function XDetect(img,colByte, colore){
  for(var n=0;n<img.data.length;n+=4){ 
  if(img.data[n+colByte]==colore) {
   dx=-dx; 
   break;
  } 
 }
}

function YDetect(img,colByte, colore){
  for(var n=0;n<img.data.length;n+=4){ 
  if(img.data[n+colByte]==colore) {
   dy=-dy; 
   break;
  } 
 }
}

window.addEventListener("load",init);
</script>
<body>
<canvas id="canvas" width=500 height=500></canvas>
<textarea id="testo" style="float:right;height:500px""></textarea>
<div id="delta"></div>
</body>
</html>
Ecco il risultato:



Il movimento a scatti è una questione di browser. Non solo per questo, Firefox mi rallenta dopo un po' di uso, e per ripristinare la velocità devo riavviarlo... Boh?

Detezione delle collisioni su tutto il perimetro del rettangolo con il canvas.

Fatto! Realizzata la detezione delle collisioni su tutto il perimetro del rettangolo!
Ecco il codice:
<!DOCTYPE html>
<html>
<script src="funzioniCanvas.js"></script>
<script>
var x=200;
var dx=1;
var y=200;
var dy=1;
var w=50;
var h=50;
var sfondo="black";
var colore="green";

var immagine;

function init(){
 initContext("canvas");
 intervallo=setInterval(draw,1);
}

function draw(){
 rect(0,0,WIDTH,HEIGHT,sfondo);
 rect(x,y,w,h,colore);
 
 rect(350,100,1,250,"#FFFF00");
 rect(50,100,1,250,"#FFFF00");
 rect(100,50,300,1,"#FF0000");
 rect(100,400,300,1,"#FF0000");
 immagine=ctx.getImageData(x+w,y,1,h);
 immagine2=ctx.getImageData(x-1,y,1,h);
 immagineGiu=ctx.getImageData(x,y+h,w,1)
 immagineSu=ctx.getImageData(x,y-1,w,1)
 
 
 
 XDetect(immagine,0,255);
 XDetect(immagine2,0,255);

 YDetect(immagineGiu,0,255);
 YDetect(immagineSu,0,255);
 
 if(x+w>WIDTH || x<0) dx=-dx;

 x+=dx;
 y+=dy;
}

function XDetect(img,colByte, colore){
  for(var n=0;n<img.data.length;n+=4){ 
  if(img.data[n+colByte]==colore) {
   dx=-dx; 
   break;
  } 
 }
}

function YDetect(img,colByte, colore){
  for(var n=0;n<img.data.length;n+=4){ 
  if(img.data[n+colByte]==colore) {
   dy=-dy; 
   break;
  } 
 }
}

window.addEventListener("load",init);
</script>
<body>
<canvas id="canvas" width=500 height=500></canvas>
<textarea id="testo" style="float:right;height:500px""></textarea>
<div id="delta"></div>
</body>
</html>
Le due funzioni chiave sono XDetect e YDetect.

Ecco il risultato:

Detezione delle collisioni sull'asse X bilateralmente col canvas.

Ecco il codice per le collisioni bilaterali sull'asse X.
Ho preferito creare due rettangolini-spia, l'uno sul lato destro e l'altro sul lato sinistro, in quanto la creazione di un rettangolo-spia delle dimensioni del rettangolo più qualche pixel accessorio che costituisse la zona-spia si è rivelata molto più lenta, verosimilmente perché deve trascrivere nella variabile immagine tutti i dati dei pixel del rettangolo, molti di più rispetto a quelli dei rettangolini.

La funzione di "detezione" (esisterà questa parola in italiano?) l'ho isolata in una funzione a parte:
function XDetect(img,colByte, colore){
		for(var n=0;n&>lt;img.data.length;n+=4){	
		if(img.data[n+colByte]==colore) {
			dx=-dx;	
			break;
		}	
	}
}
...che accetta come parametri il rettangolino (img), il numero di byte del quale si vuole eseguire la detezione dopo quello iniziale del colore rosso (se è 0 si farà la detezione dal byte del rosso, se 1 da quello del verde, se 2 da quello del blu e se 3 da quello della trasparenza), e come terzo parametro il colore da "detectare".
<!DOCTYPE html>
<html>
<script src="funzioniCanvas.js"></script>
<script>
var x=200;
var dx=1;
var y=21;
var dy=.1;
var w=80;
var h=10;
var sfondo="black";
var colore="green";
var osx=100;
var osy=10;
var osw=1;
var osh=200;
var oscolore="#FFFF00";
var immagine;

function init(){
	initContext("canvas");
	intervallo=setInterval(draw,1);
}

function draw(){
	rect(0,0,WIDTH,HEIGHT,sfondo);
	rect(x,y,w,h,colore);
	rect(osx,osy,osw,osh, oscolore);
	rect(300,0,1,50,"#FF0000");
	immagine=ctx.getImageData(x+w,y,1,h);
	immagine2=ctx.getImageData(x-1,y,1,h);
	XDetect(immagine,0,255);
	XDetect(immagine2,0,255);

	if(x+w>WIDTH || x<0) dx=-dx;

	x+=dx;
	y+=dy;
}

function XDetect(img,colByte, colore){
		for(var n=0;n<img.data.length;n+=4){	
		if(img.data[n+colByte]==colore) {
			dx=-dx;	
			break;
		}	
	}
}
window.addEventListener("load",init);
</script>
<body>
<canvas id="canvas" width=500 height=500></canvas>
<textarea id="testo" style="float:right;height:500px""></textarea>
<div id="delta"></div>
</body>
</html> 
Ed ecco il risultato:

venerdì 9 gennaio 2015

Collisioni con spostamenti superiori a un pixel

Se però il rettangolo si sposta con una velocità maggiore di 1 pixel alla volta, può accadere che la collisione non venga individuata.



Con un rettangolino-spia della larghezza di un solo pixel, lo spostamento di due pixel alla volta può far "saltare" un ostacolo della larghezza di un solo pixel.
Così conviene fare un rettangolino-spia di due pixel di larghezza.
Faccio in modo che il rettangolo si muova di due pixel alla volta, per fare una prova:
<!DOCTYPE html>
<html>
<script src="funzioniCanvas.js"></script>
<script>
var x=145;
var dx=2;

var y=50;
var w=100;
var h=10;
var sfondo="black";
var colore="green";
var osx=350;
var osy=50;
var osw=1;
var osh=100;
var oscolore="#FFFF00";
var immagine;

function init(){
 initContext("canvas");
 intervallo=setInterval(draw,10);
}

function draw(){
 rect(0,0,WIDTH,HEIGHT,sfondo);
 rect(x,y,w,h,colore);
 rect(osx,osy,osw,osh, oscolore);
 
 immagine=ctx.getImageData(x+w,y,1,h);
 
 $("testo").value="";
 for(var n=0;n<immagine.data.length;n+=4){
  $("testo").value+=immagine.data[n]+" "+immagine.data[n+1]+" "+immagine.data[n+2]+" "+immagine.data[n+3]+"\n";
  if(immagine.data[n]==255) {
   dx=-dx;
   
   break;
  }
  
  
 }
 x+=dx;
}
window.addEventListener("load",init);
</script>
<body>
<canvas id="canvas" width=500 height=500></canvas>
<textarea id="testo" style="float:right;height:500px""></textarea>
<div id="delta"></div>
</body>
</html> 
Ecco, lo spostamento istantaneo del rettangolo è di 2 pixel, mentre il rettangolino-spia ha ancora una larghezza di un pixel.
Se la teoria è giusta, cambiando la posizione di partenza del rettangolo, si alternano posizioni in cui la collisione viene vista e posizioni in cui non viene vista, alternate.
E infatti così succede:
Con questa posizione (x = 145),...
var x=145;
var dx=2;

.....

 immagine=ctx.getImageData(x+w,y,1,h);
...la collisione non viene individuata e l'ostacolo viene attraversato tranquillamente dal rettangolo.

Aumentiamo di 1 la posizione del rettangolo:
var x=146;
var dx=2;
(il rettangolino-spia è sempre di 1)
... la collisione c'è, e il rettangolo torna indietro non appena "toccato" l'ostacolo.

Aumentiamo ancora di 1
var x=147;
var dx=2;
e la collisione adesso non c'è: l'ostacolo viene attraversato.

Ancora:
var x=148;
var dx=2;
...e la collisione c'è!
Questo conferma in pieno la mia teoria illustrata con l'immagine sopra!

Adesso proviamo ad aumentare di 1 la larghezza del rettangolino-spia:
var x=145;
var dx=2;

....

 immagine=ctx.getImageData(x+w,y,2,h);
...e stiamo a vedere, variando di nuovo la posizione del rettangolo...
E la collisione c'è!

Aumentiamo:
var x=146;
var dx=2;
...e la collisione c'è!

Ancora:
var x=147;
var dx=2;
e la collisione c'è ancora!

Ancora:
var x=148;
var dx=2;
E la collisione c'è ancora!

La teoria è esatta!