基于Cocos2d-x的2D光线效果雏形
来源:互联网 发布:迅雷极速版特别优化版 编辑:程序博客网 时间:2024/05/21 18:35
这个效果起初是在一篇blog看见的,效果很赞,是网页版的,然后想在Cocos2d上实现下,然后就去做了。
blog地址:http://huangwei.pro/2015-08/game-sight-light/
我的github:https://github.com/pepsigit/Cocos2d/tree/master/2DLighgt
首先,在 .h 里面定义一下需要的结构体:
typedef struct LIGHTLINE{ Point segA; // 光线的起始点 Point segB; // 光线的终止点 float t1;}LightLine;
typedefstruct POINTANDANGLE{ Point point; // 光源打在墙上的点 float angle; // 相对于光源的角度}PointAndAngle;
是的,我们只需要这些。再来 .cpp 里面,现在初始化下多边形的顶点:
boolHelloWorld::InitSegments(){ int subX =60; int subY =0; LightLine tmp; // Border tmp.segA = Vec2( origin.x,origin.y); tmp.segB = Vec2( origin.x,origin.y +visibleSize.height ); m_segments.push_back(tmp); tmp.segA = Point( origin.x,origin.y ); tmp.segB = Point( origin.x +visibleSize.width,origin.y ); m_segments.push_back(tmp); tmp.segA = Point( origin.x,origin.y +visibleSize.height ); tmp.segB = Point( origin.x +visibleSize.width,origin.y + visibleSize.height ); m_segments.push_back(tmp); tmp.segA = Point( origin.x +visibleSize.width,origin.y ); tmp.segB = Point( origin.x +visibleSize.width,origin.y + visibleSize.height ); m_segments.push_back(tmp); // polygon #1 tmp.segA =Point(100-subX,150-subY ); tmp.segB =Point(120-subX, 50-subY ); m_segments.push_back(tmp); tmp.segA =Point(120-subX,50-subY ); tmp.segB =Point(200-subX,80-subY ); m_segments.push_back(tmp); tmp.segA =Point(200-subX, 80-subY ); tmp.segB =Point(140-subX,210-subY ); m_segments.push_back(tmp); tmp.segA =Point(140-subX,210-subY ); tmp.segB =Point(100-subX,150-subY ); m_segments.push_back(tmp); // polygon #2 tmp.segA =Point(100-subX,200-subY ); tmp.segB =Point(120-subX,250-subY ); m_segments.push_back(tmp); tmp.segA =Point(120-subX,250-subY ); tmp.segB =Point( 60-subX,300-subY ); m_segments.push_back(tmp); tmp.segA =Point(60-subX, 300-subY ); tmp.segB =Point(100-subX,200-subY ); m_segments.push_back(tmp); // polygon #3 tmp.segA =Point(200-subX,260-subY ); tmp.segB =Point(220-subX,150-subY ); m_segments.push_back(tmp); tmp.segA =Point(220-subX,150-subY ); tmp.segB =Point(300-subX,200-subY ); m_segments.push_back(tmp); tmp.segA =Point(300-subX,200-subY ); tmp.segB =Point(350-subX,320-subY ); m_segments.push_back(tmp); tmp.segA =Point(350-subX,320-subY ); tmp.segB =Point(200-subX,260-subY ); m_segments.push_back(tmp); // polygon #4 tmp.segA =Point(340-subX,60-subY ); tmp.segB =Point(360-subX,40-subY ); m_segments.push_back(tmp); tmp.segA =Point(360-subX,40-subY ); tmp.segB =Point(370-subX,70-subY ); m_segments.push_back(tmp); tmp.segA =Point(370-subX,70-subY ); tmp.segB =Point(340-subX,60-subY ); m_segments.push_back(tmp); // polygon #5 tmp.segA =Point(450-subX,190-subY ); tmp.segB =Point(560-subX,170-subY ); m_segments.push_back(tmp); tmp.segA =Point(560-subX,170-subY ); tmp.segB =Point(540-subX,270-subY ); m_segments.push_back(tmp); tmp.segA =Point(540-subX,270-subY ); tmp.segB =Point(430-subX,290-subY ); m_segments.push_back(tmp); tmp.segA =Point(430-subX,290-subY ); tmp.segB =Point(450-subX,190-subY ); m_segments.push_back(tmp); // polygon #6 tmp.segA =Point(400-subX,95-subY ); tmp.segB =Point(580-subX,50-subY ); m_segments.push_back(tmp); tmp.segA =Point(580-subX,50-subY ); tmp.segB =Point(480-subX,150-subY ); m_segments.push_back(tmp); tmp.segA =Point(480-subX,150-subY ); tmp.segB =Point(400-subX,95-subY ); m_segments.push_back(tmp); if(0 < m_segments.size() ) { vector<LightLine>::iterator it =m_segments.begin(); for( ; it !=m_segments.end(); it++ ) { drawNode->drawLine(it->segA, it->segB,Color4F(1,1,0,1) ); } } return true;}
接下来添加光源,其实就是添加一个随便的精灵即可,这里我使用了自带的资源,CloseNormal.png,然后添加下触摸事件,你就可以移动这个光源了,这部分省略吧。
刚才初始化多边形的时候,已经将所有的线段保存在类成员m_segments里面了,下面要去除下重复的点,因为一个点连接2条线段:
void HelloWorld::GetEachPointAngle(){ vector<Point> tmpPoint; vector<LightLine>::iterator it =m_segments.begin(); vector<Point>::iterator isFind; // 获得线段唯一点 for( ; it !=m_segments.end(); it++ ) { isFind =find( tmpPoint.begin(), tmpPoint.end(), it->segA); if( isFind == tmpPoint.end() ) { tmpPoint.push_back(it->segA); } isFind =find( tmpPoint.begin(), tmpPoint.end(), it->segB); if( isFind == tmpPoint.end() ) { tmpPoint.push_back(it->segB); } } // ......}
现在获得了唯一点,不需要了很多重复的计算,接下来计算当前光源静止的位置到各个点的角度,并且额外增加两条 0.00001 角度的线,为了能让光源打在后面的墙上。
void HelloWorld::GetEachPointAngle(){ // ....... //获得唯一点的角度,额外增加 2条射线 vector<Point>::iterator it_point = tmpPoint.begin(); for( ; it_point != tmpPoint.end(); it_point++ ) { float angle =atan2(it_point->y -light->getPositionY(), it_point->x -light->getPositionX()); m_angle.push_back(angle -0.00001); m_angle.push_back(angle); m_angle.push_back(angle +0.00001); } // .......}
接下来开始计算打到墙上的点。将光源点分别与线段计算.公式看下原文。
void HelloWorld::GetEachPointAngle(){ // ......... //循环个角度,找出最近的交点 vector<float>::iterator it_angle =m_angle.begin(); for( ; it_angle !=m_angle.end(); it_angle++ ) { float dx =cos(*it_angle); float dy =sin(*it_angle); //CCLOG("%f,%f,%f", *it_angle,dx, dy); LightLine l; l.segA =Point(light->getPositionX(),light->getPositionY() ); l.segB =Point(light->getPositionX() + dx,light->getPositionY() + dy ); float minT1 =0; it =m_segments.begin(); for( ; it !=m_segments.end(); it++ ) { float tmpT1 =GetIntersection( l, *it ); if( -1 == tmpT1 ) { continue; } if(0 == minT1 || minT1 > tmpT1 ) { minT1 = tmpT1; } } PointAndAngle p; p.point =Point(light->getPositionX() + minT1 * dx,light->getPositionY() + minT1 * dy ); p.angle = *it_angle; m_intersects.push_back(p); //CCLOG("%f, %f, %f", p.point.x, p.point.y, *it_angle); } sort(m_intersects.begin(),m_intersects.end(),SortAngle ); }floatHelloWorld::GetIntersection(LightLine ray,LightLine seg ){ //CCLOG("%f,%f,%f,%f",ray.segA.x,ray.segA.y,ray.segB.x,ray.segB.y); int r_px = ray.segA.x; int r_py = ray.segA.y; float r_dx = ray.segB.x - ray.segA.x; float r_dy = ray.segB.y - ray.segA.y; int s_px = seg.segA.x; int s_py = seg.segA.y; float s_dx = seg.segB.x - seg.segA.x; float s_dy = seg.segB.y - seg.segA.y; float r_mag =sqrt( r_dx * r_dx + r_dy * r_dy ); float s_mag =sqrt( s_dx * s_dx + s_dy * s_dy ); if( ( r_dx / r_mag ) == ( s_dx / s_mag ) && ( r_dy / r_mag ) == ( s_dy / s_mag) ) { return -1; } float t2 = ( r_dx * (s_py-r_py) + r_dy * (r_px - s_px)) / (s_dx*r_dy - s_dy*r_dx); float t1 = ( s_px + s_dx * t2 - r_px )/ r_dx; if( t1 <0 || t2 <0 || t2 >1 ) { return -1; } CCLOG("%d,%d,%f,%f,%d,%d,%f,%f, %f", r_px, r_py, r_dx, r_dy, s_px, s_py, s_dx, s_dy, t1); return t1;}
最后循环填充三角形即可。
这里说下的是,光线和多边形不在一个layer上,因为在你每次移动的过程中,需要清楚旧光线,来画新光线,所以进行了分层,并且对旧数据进行清除,每次移动,重新计算再绘制。
这里可能会出现不准确的情况,效果:
个人认为是移动时候,数值之间计算的误差导致。并非整数,所以我在 onTouchMoved 这样处理的:
/*********************************************************** * 移动触摸会有误差值,不是整数,所以会出现三角形连接错误 * 根据小数大小,取整运算 ***********************************************************/subP.x = ( ( subP.x - (int)subP.x ) > 0.5 ) ? ceil(subP.x) : floor(subP.x);subP.y = ( ( subP.y - (int)subP.y ) > 0.5 ) ? ceil(subP.y) : floor(subP.y);
效果有所改善:
大神们勿喷,谢谢,谢谢。
0 0
- 基于Cocos2d-x的2D光线效果雏形
- 源码分析使用Cocos2d-x实现2D光线效果
- 【Cocos2d-x】视线和光线:如何创建 2D 视觉范围效果
- 【Cocos2d-x】视线和光线:如何创建 2D 视觉范围效果
- 【Cocos2d-x】视线和光线:如何创建 2D 视觉范围效果
- Cocos2d-x 跟随光线效果实现
- 【Cocos2d-x】水面效果的2D实现(一)
- 基于cocos2d-x的2D空间中的OBB(Orient Bounding Box)碰撞检测算法
- 基于cocos2d-x的2D空间中的OBB(Orient Bounding Box)碰撞检测算法
- 基于egret的点光源光线效果的实现
- cocos2d-x 的粒子效果
- 3、cocos2d-x学习笔记——2d简易破碎效果
- Cocos2d-x 的水波效果的思考
- Cocos2d-x 实现运动的尾巴效果
- cocos2d-x 的震屏效果
- Cocos2d-x 实现运动的尾巴效果
- Cocos2d-x实现android的Toast效果
- Cocos2d-x能够实现的动画效果
- hdoj 2404 Permutation Recovery【水水】
- 第二周项目2程序的多文件组成
- 《剑指offer》数组中的逆序对
- uva 201
- 使用 VisualVM 进行性能分析及调优
- 基于Cocos2d-x的2D光线效果雏形
- OSCache介绍
- OC中instancetype与id的区别
- UVA 11520 Fill the Square
- 堆栈经典应用:表达式求值、后缀表达式
- OK6410出现selected device is not a touchscreen I understand解决办法
- Permutation Recovery 2404 (逆序列 规律 好题)
- javascript面向对象开发(一)
- SpringMVC4+Hibernate4学习笔记