Digital Toys sviluppati con Box2d

Una parola che usano spesso quelli di Disney Online per descrivere tutte quelle piccole applicazioncine flash che appaiono un po' come giocattoli all'interno del sito. Ma forse di giocattolo c'è veramente poco... Ricordo quando da piccolo con mio fratello passavo giornate intere a costruire astronavi o robot usando le mollette come fossero costruzioni.
Io ho pensato di creare dei giocattolini che ammiccano ai giochi della realtà, quelli che i nostri figli forse non vedranno mai.

L system - Animazione

Ed ecco un'animazione completa. Un amico agronomo mi ha fatto notare che la forma dell'albero non può essere definita così meccanicamente.
Tanto per iniziare, come per ogni forma di vita, esistono delle fasi, (chissà com'è la pubertà dell'albero?).

L System (rappresentazioni grafiche)

Ecco alcune delle immagini ottenute:




Ed ecco la classe completa:


// Fern Fractal Nicola Sirago - an - Jim Bumgardner 2008 -port
package 
{
 import flash.geom.*;
 import GeomUtil;
 import flash.events.Event;
 import flash.display.DisplayObject;
 import flash.display.Sprite;

 public class FernSprite2 extends Sprite
 {
  var maxLevels:Number// = 6;
  var initBendAngle:Number// = 15;
  var initBranchAngle:Number// = 37;
  var trunkRatio:Number// = .1;
  var branchRatio:Number// = .4;
  var heightScale:Number// = 2.5;
  var regularity:Number// = 1;
  var offshoot:Number// = 1;
  
  public function FernSprite2(initObj)
  {
   maxLevels = initObj.maxLevels;
   initBendAngle = initObj.initBendAngle;
   initBranchAngle = initObj.initBranchAngle;
   trunkRatio = initObj.trunkRatio;
   branchRatio = initObj.branchRatio;
   heightScale = initObj.heightScale;
   regularity = initObj.regularity;
   offshoot = initObj.offshoot;
   initObj.parMC.addChild(this);
  }
  public function drawFern(p,a,rad,level)
  {
   var c:Point = new Point(p.x + Math.cos(a) * rad * trunkRatio, p.y + Math.sin(a) * rad * trunkRatio);
   p.height = Point.distance(new Point (p.x,p.y), c);
   p.width = (level + 1)*trunkRatio*30
   p.rotation = GeomUtil.radToGrad(a)-90;
   this.addChild(p);
   if (level > 0) {
    a += bendAngle;
    level--;
    var b1:ramo = new ramo;
    var b2:ramo = new ramo;
    var b3:ramo = new ramo;
    b1.x = b2.x = b3.x = c.x;
    b1.y = b2.y = b3.y = c.y;
    if(randRange(0,offshoot))
    drawFern(b1, a - branchAngle * randRange2(1, regularity), rad * branchRatio * randRange2(1, regularity), level);
    if(randRange(0,offshoot))
    drawFern(b2, a + branchAngle * randRange2(1, regularity), rad * branchRatio * randRange2(1, regularity), level);
    if(randRange(0,offshoot))
    drawFern(b3,a * randRange2(1, regularity),rad*antiTrunkRatio * randRange2(1, regularity),level);
   }else {
    var f:foglie = new foglie; 
    f.x = c.x;
    f.y = c.y;
   // f.rotation = p.rotation
    if(randRange(0,offshoot))
    this.addChild(f);
   }
  }
  public function redrawFern()
  {
   bendAngle = initBendAngle*Math.PI/180;
   branchAngle = initBranchAngle*Math.PI/180;
   lastMaxLevels = maxLevels;
   antiTrunkRatio = 1-trunkRatio;
   startAngle = -Math.PI/2;
   var b:t2 = new t2;
   drawFern(b, startAngle, heightScale, maxLevels);
  }
  public static function randRange(min:Number, max:Number):Number {
   var randomNum:Number = Math.floor(Math.random() * (max - min + 1)) + min;
   return randomNum;
  }
  public static function randRange2(min:Number, max:Number):Number {
   if (min == max)
   return min
   var d = 0
   while (d == 0) { d = randRange( -1, 1) }
   var randomNum:Number =Math.abs( Math.random() * (max - min) + min * d);
   return randomNum;
  }
 }
}

Per modificare le texture basta modificare i disegni all'interno dei movieclip "ramo" e "foglie"

L system MovieClip texturization

Ora che abbiamo trovato l'algoritmo di base le variazioni possono essere infinite.
Con Flash ad esempio si può texturizzare il nostro albero come ci piace distorcendo delle figure ed adattandole alla nostra struttura.
Ho preparato un esempio per consentire a chiunque di inserire le proprie texture all'interno dell'albero.
public function drawFern(p,a,rad,level)
  {
   var c:Point = new Point(p.x + Math.cos(a) * rad * trunkRatio, p.y + Math.sin(a) * rad * trunkRatio);
   p.height = Point.distance(new Point (p.x,p.y), c);
   p.width = (level + 1)*trunkRatio*30
   p.rotation = GeomUtil.radToGrad(a)-90;
   this.addChild(p);
   if (level > 0) {
    a += bendAngle;
    level--;
    var b1:tronco = new tronco;
    var b2:tronco = new tronco;
    var b3:tronco = new tronco;
    b1.x = b2.x = b3.x = c.x;
    b1.y = b2.y = b3.y = c.y;
    drawFern(b1, a - branchAngle, rad * branchRatio, level);
    drawFern(b2, a + branchAngle, rad * branchRatio, level);
    drawFern(b3,a, rad*antiTrunkRatio, level);
   }else {
    var f:foglie = new foglie; 
    f.x = c.x;
    f.y = c.y;
    f.rotation = p.rotation
    this.addChild(f);
   }
  }
Questa volta gli input iniziali non sono le coordinate di un punto (px, py) ma un MovieClip.
Ora abbiamo 2 differenti texture (tronco, foglie).
A differenza del primo esempio, foglie viene posizionato solo quando la variabile level è scesa a zero, quindi nell'ultima recursione.
Inoltre ho inserito una funzione radToGrad, che effettua una conversione da radianti a gradi (non ho mai capito come mai la proprietà rotation si esprime in scomodissimi gradi.)
public static function radToGrad(rad:Number) {
   return rad/Math.PI*180;
  }
Domani cerco di postare la classe completa e qualche immagine di esempio.

Sempre su L system (Un po' di codice)

Ciao, dopo aver smanettato alla ricerca di un buon syntax highliter, ovvero di un programino che stampa codice come Dio comanda rieccomi a parlare di L system. Infatti dopo aver visto qualche fantastico esempio offerto dalle potenzialità di questo algoritmo, mi sono dato alla sperimentazione (più che altro grafica).
la funzione da cui sono partito scritta da Jim Bumgardner è la seguente:
function drawFern(px,py,a,rad,level)
  {
   var cx = px+Math.cos(a)*rad*trunkRatio;
   var cy = py+Math.sin(a)*rad*trunkRatio;
   lineTo(cx, cy);
   if (level > 0) {
    a += bendAngle;
    level--;
    drawFern(cx,cy,a-branchAngle,rad*branchRatio,level);
    moveTo(cx,cy);
    drawFern(cx,cy,a+branchAngle,rad*branchRatio,level);
    moveTo(cx,cy);
   }
  }

Con una sintassi semplificata il procedimento può anche essere scritto così:
R(i)     :  Livello del Ramo
t        :  trasla la fine del ramo
s        :  Scala 
r1,r2    :  ruota in senso orario e antiorario
R(i) = s(t[T(i-1)] r1[R(i-1)] r2[R(i-1)])

Purtroppo nel nostro caso non abbiamo un metodo dinamico basato sulla sostituzione, la struttura di base dell'albero è scolpita all'interno dell'applicazione.

A proposito dell'arte generativa e di L system

È da qualche giorno che mi sono perso dietro L system. Di che cosa sta parlando questo qua??? in questo sito è spiegato tutto molto meglio: http://www.johngrindall.com/maths/lsystems/index.php http://www.webfract.it/FRATTALI/lsystem.htm L systems è un algoritmo inventato da Lindenmayer per simulare la crescita di alcuni tipi di organismi. Reiterando e sostituendo delle coordinate, seguendo determinate regole è possibile creare figure veramente suggestive.
ecco un estratto estrapolato da uno dei siti citati:
FRATTALI CREATI CON LA TECNICA L - SYSTEM

L-System è l'acronimo di Lindenmayer-Systems, dal nome di Aristide Lindenmayer (1925-1989), un biologo olandese che per primo sviluppò la tecnica usata per generare questi frattali. Lo scopo di Lindenmayer era di riprodurre in modo virtuale la crescita di svariati tipi di organismi.

L-System non è perciò un tipo di frattale, ma è un metodo che permette di ritrovare i frattali, anche i più noti, come Koch, Sierpinski, alberi etc., che si possono costruire per altra via, purché lineare.

Il metodo adottato da Lindenmayer è molto suggestivo. Si parte da un disegno iniziale (che può essere, ad esempio, un segmento o anche una poligonale). Questo disegno viene riprodotto al computer usando delle regole ben precise:
Regola F
Avanzare di un segmento di lunghezza assegnata
Regola f
Avanzare di un segmento di lunghezza assegnata ma senza lasciare traccia
Regola +
Ruotare in senso antiorario di un angolo assegnato
Regola -
Ruotare in senso orario di un angolo assegnato

Ad esempio, per costruire il triangolo equilatero in figura, partendo dal vertice A, potremo dare le seguenti istruzioni: vai avanti di un segmento di lunghezza data (arriviamo in B), ruota in senso orario di 120°, vai avanti di un segmento di lunghezza data (arriviamo in C), ruota in senso orario di 120°, vai avanti di un segmento di lunghezza data (torniamo in A). Tradotte queste istruzioni nel nostro linguaggio, potremo scrivere: F-F-F

Ovviamente, affinché la procedura sia effettivamente eseguita da un computer, dovremo dare le istruzioni necessarie per eseguire una rotazione, e dovremo immettere come dati iniziali un valore per l'angolo (in questo caso 120°) e un valore per la lunghezza del segmento (in questo caso 90 pixel).

Fatte queste premesse, vediamo come si possa costruire un frattale.

La costruzione iniziale prende il nome di axiom (assioma). Sulla costruzione iniziale viene poi effettuata una sostituzione secondo una regola assegnata, si ripete il procedimento più volte... ed ecco il frattale!

Applichiamo il procedimento per costruire il frattale di Koch:

Dati iniziali:
angolo= 60°
lato= numero pixel prescelto (esempio: 900 pixel)
axiom: F
Viene tracciata una linea di lunghezza assegnata
Ripeti:
lato <-- lato/3 Il lato diventa un terzo del precedente
Sostituzione: F <-- F+F--F+F Sostituendo ad ogni F questa stringa,
il segmento viene sostituito
dalla spezzata
(Avanza, ruota di 60° in senso antiorario, avanza, ruota di 60° + 60° = 120° in senso orario, avanza, ruota di 60° in senso antiorario, avanza).
Fino a quando il lato diventa minore di un numero assegnato.

ephemeral swf