Ok grazie, il linguaggio è [obj-c] e posto un po' di codice. Questa è la versione originale dell'autore della classe, la mia differisce solo nell'esporre come proprietà le altezze delle onde in modo da farle interagire con il motore fisico (box2d) e nel rendeering di una texture al posto di un poligono trasparente. Anche la mia versione funziona perfettamente, quindi posto l'originale perché è più pulita e comprensibile:
codice:
//
// Waves1DNode.h
// Waves1D
//
// Created by Scott Lembcke on 12/10/11.
// Copyright Howling Moon Software 2011. All rights reserved.
//
#import "cocos2d.h"
@interface Waves1DNode : CCNode {
CGRect _bounds;
float _diffusion;
float _damping;
int _count;
// Heightfields that the simulation vertlet integrates between.
float *_h1, *_h2;
}
// 'bounds' are the rectangle to draw for the water. The top of the bounds is the rest height for the water, it wil wave above and below it.
// 'count' is the number of slices to simulate. One per 10-20 pixels is usually sufficient.
// 'damping' is how fast the water settles back to rest. 1.0 is never (bad), 0.0 is immediately (also bad). 0.99 is a decent damping amount.
// 'diffusion' is how fast the waves spread to neighbors. Values outside of 0.6 - 0.9 can become unstable.
-(id)initWithBounds:(CGRect)bounds count:(int)count damping:(float)damping diffusion:(float)diffusion;
-(void)makeSplashAt:(float)x;
@end
codice:
//
// Waves1DNode.m
// Waves1D
//
// Created by Scott Lembcke on 12/10/11.
// Copyright Howling Moon Software 2011. All rights reserved.
//
#import "Waves1DNode.h"
@implementation Waves1DNode
-(id)initWithBounds:(CGRect)bounds count:(int)count damping:(float)damping diffusion:(float)diffusion;
{
if((self = [super init])){
_bounds = bounds;
_count = count;
_damping = damping;
_diffusion = diffusion;
_h1 = calloc(_count, sizeof(float));
_h2 = calloc(_count, sizeof(float));
}
return self;
}
- (void) dealloc
{
free(_h1);
free(_h2);
[super dealloc];
}
-(void)vertlet {
for(int i=0; i<_count; i++) _h1[i] = 2.0*_h2[i] - _h1[i];
float *temp = _h2;
_h2 = _h1;
_h1 = temp;
}
static inline float
diffuse(float diff, float damp, float prev, float curr, float next){
return (curr*diff + ((prev + next)*0.5f)*(1.0f - diff))*damp;
}
-(void)diffuse {
float prev = _h2[0];
float curr = _h2[0];
float next = _h2[1];
_h2[0] = diffuse(_diffusion, _damping, prev, curr, next);
for(int i=1; i<(_count - 1); ++i){
prev = curr;
curr = next;
next = _h2[i + 1];
_h2[i] = diffuse(_diffusion, _damping, prev, curr, next);
}
prev = curr;
curr = next;
_h2[_count - 1] = diffuse(_diffusion, _damping, prev, curr, next);
}
-(float)dx{return _bounds.size.width/(GLfloat)(_count - 1);}
- (void)draw {
// It would be better to run these on a fixed timestep.
// As an GFX only effect it doesn't really matter though.
[self vertlet];
[self diffuse];
GLfloat dx = [self dx];
GLfloat top = _bounds.size.height;
// Build a vertex array and render it.
struct Vertex{GLfloat x,y;};
struct Vertex verts[_count*2];
for(int i=0; i<_count; i++){
GLfloat x = i*dx;
verts[2*i + 0] = (struct Vertex){x, 0};
verts[2*i + 1] = (struct Vertex){x, top + _h2[i]};
}
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisable(GL_TEXTURE_2D);
GLfloat r = 105.0f/255.0f;
GLfloat g = 193.0f/255.0f;
GLfloat b = 212.0f/255.0f;
GLfloat a = 0.3f;
glColor4f(r*a, g*a, b*a, a);
glVertexPointer(2, GL_FLOAT, 0, verts);
glPushMatrix(); {
glScalef(CC_CONTENT_SCALE_FACTOR(), CC_CONTENT_SCALE_FACTOR(), 1.0);
glTranslatef(_bounds.origin.x, _bounds.origin.y, 0.0);
glDrawArrays(GL_TRIANGLE_STRIP, 0, _count*2);
} glPopMatrix();
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnable(GL_TEXTURE_2D);
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
}
-(void)makeSplashAt:(float)x;
{
// Changing the values of heightfield in h2 will make the waves move.
// Here I only change one column, but you get the idea.
// Change a bunch of the heights using a nice smoothing function for a better effect.
int index = MAX(0, MIN((int)(x/[self dx]), _count - 1));
_h2[index] += CCRANDOM_MINUS1_1()*20.0;
}
@end
/**
-Ideas to make it better:
* Add clamping to avoid giant, crappy looking waves.
* Make it run on a fixed timestep.
* Add texturing to give the surface a nice (and anti-aliased) look.
* Fancier makeSplash method that does more than a single point.
*/
Per realizzare l'acqua che scorre(scrolla in 2d sullo schermo) ho usato il solito trucchetto dei due elementi che si inseguono rimpiazzandosi come nell'immagine qua sotto:
Le mie 2 acque si inseguono sostituendosi l'una all'altra e passandosi le altezze del primo e dell'ultimo vertice al fine di creare una continuità fra le onde la dove le acque si uniscono :Mosè:
Non sono soddisfatto perché si nota sempre una piccola cresta aggiuntiva sulle onde che passano in prossimità del punto di giunzione delle acque e oltretutto trovo dispendioso avere due acque al posto di una che resta fissa sullo schermo e che accetta come parametro la velocità di scorrimento.
Quindi ho provato a modificare la classe in modo che gli elementi dell'array delle altezze scalassero verso l'inizio o la fine dello stesso a seconda della direzione di scorrimento dell'acqua. Funziona nel senso che fa scorrere le onde nella direzione giusta ma è ovvio che non ne posso controllare la velocità perché questa è data solo dallo scalare di posizione degli elementi del vettore e che quindi non è possibile fare interpolazioni perché non ci sono posizioni intermedie(il piano d'acqua è costituito da un numero di punti limitato così come l'array che li contiene)
A me servirebbe di riuscire a interpolare i valori della formula in modo che questi tendano a propagarsi in direzione dell'inizio o della fine dell'array in base a una velocità variabile...
Edit: in realtà non necessito di consigli scritti in objective-c, va benissimo pseudo codice o anche solo una mezza idea! ;)