现在的位置: 首页 > 综合 > 正文

游戏效果解密—-一维水波效果

2013年12月30日 ⁄ 综合 ⁄ 共 3886字 ⁄ 字号 评论关闭
============================================================
博文原创,转载请声明出处
电子咖啡(原id蓝岩)
============================================================

感谢开源社区的所有贡献者。

一维水波效果地址:http://www.supersuraccoon-cocos2d.com/2011/09/17/sticky-demo-resource-list-keep-updating/

水波主要有Waves1DNode实现。详情见代码注释。截图如下:

Waves1DNode.h

#import "cocos2d.h"

@interface Waves1DNode : CCNode {
	CGRect _bounds;
	
	float _diffusion;
	float _damping;
	
	int _count;
	// Heightfields that the simulation verlet 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;

Waves1DNode.m

#import "Waves1DNode.h"

@implementation Waves1DNode

/**
 bounds 水深度
 count 水平vertex数目,越大,越逼真
 damping 阻尼
 
 */
-(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];
}

/**屋里引擎算法,牵动运动,参考

http://en.wikipedia.org/wiki/Verlet_integration

 */
-(void)verlet {
	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);
}

//dx 相邻两点的距离(count个点)
-(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.
    //进行verlet和diffuse的simulate计算
	[self verlet];
	[self diffuse];
	
	GLfloat dx = [self dx];
	GLfloat top = _bounds.size.height;
	
	// Build a vertex array and render it.
	struct Vertex{GLfloat x,y;};
    //opengl绘制三角形图元,数组绘制可以共用一个顶点,因此只绘制两个顶点,所以*2
	struct Vertex verts[_count*2];
	for(int i=0; i<_count; i++){
		GLfloat x = i*dx;
		//底部顶点
        verts[2*i + 0] = (struct Vertex){x, 0};
        // top + _h2[i] 为水深+对应的波浪起伏
		verts[2*i + 1] = (struct Vertex){x, top + _h2[i]};
	}
    
    //By default, all client-side capabilities are disabled.
    //默认是disable,这里是在cocos2d中enable的
//    printf("%s:%d %i,%i,%i,%i\n",__FUNCTION__,__LINE__,glIsEnabled(GL_COLOR_ARRAY),\
           glIsEnabled(GL_TEXTURE_COORD_ARRAY),glIsEnabled(GL_TEXTURE_2D),glIsEnabled(GL_VERTEX_ARRAY));

    
    
	glDisableClientState(GL_COLOR_ARRAY);
	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
	glDisable(GL_TEXTURE_2D);
    
//    glDisableClientState(GL_VERTEX_ARRAY);
    
  	
	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);
	
    //制定vertex数组
	glVertexPointer(2, GL_FLOAT, 0, verts);
	
    //因为后面要进行translate,所有需要push matrix
	glPushMatrix();
    {
        //针对retina进行优化
		glScalef(CC_CONTENT_SCALE_FACTOR(), CC_CONTENT_SCALE_FACTOR(), 1.0);
        //平移水面到bound位置,否则在(0,0)处
		glTranslatef(_bounds.origin.x, _bounds.origin.y, 0.0);
//		glDrawArrays(GL_TRIANGLE_FAN, 0, _count*2);
        //绘制图元
		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

抱歉!评论已关闭.