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

box2d绳子一则

2013年05月31日 ⁄ 综合 ⁄ 共 6568字 ⁄ 字号 评论关闭

参考资料:http://www.cocos2d-iphone.org/forum/topic/10411

这是我改写的一则绳子,绳子以body小节相连接

不过我还是觉得 verlet rope那种原型方式更加漂亮!

原型的缺点就是绳子一旦被切断,就要即刻清除所有相关内容,

一根绳子被切断后就这么凭空消失了,这总让人觉得有点儿说不过去吧?

于是我便想以body的形式改写一则更有质感的绳子,

这样的话,即使在被切断了之后,两段“绳子尸体”依然还能飘来荡去~

学到了不少新的东西,例如CCSpriteBatchNode的正确使用方法~

以前我也用 CCSpriteBatchNode,但是用的方法不正确

我现在是这么认识的,CCSpriteBatchNode加载一份图片文件,

其他的CCSprite都可以来使用这份图片,直接从内存里面取的,迅速快捷~

如果一份图片反复要在游戏里面用到,但是每次都通过 [CCSprite spriteWithFile:@"123.png"]的方式来取的话

就会存在每次都要从磁盘介质里面拿取这份图片,而读磁盘是很耗时间的,不管怎么说,一定比从内存读取慢!

其实很多时候都要权衡利弊,从内存里面读取资源文件虽快,但是ios设备内存吃紧

将整个游戏几十兆的资源文件一次性全部加载到内存,程序很有可能会被强干掉

上次我查了一番加密资源文件的手法,有一种方式是将资源文件“打碎成”字节数据放在头文件里面

后来我一想,游戏一运行,那么装载头文件里面的资源文件肯定在第一时间就会被全部加载到内存

快是够快了,内存够不够用却又成问题了~

后来我留言给作者,作者的回复也是如同我所想,此种加密方式仅限于一些必须要保密的资源,

如防止别人篡改公司logo,就可能将logo图片置于头文件中~

last,绳子其实还很有待挖掘,今后有时间的话,一定会力争写出更真实,更高效的绳子来~

//

//  BYRope.h

//  GoldMine0.6

//

//  Created by Bruce Yang on 12-1-13.

//  Copyright (c) 2012 __MyCompanyName__. All rights reserved.

//

#import
<Foundation/Foundation.h>

#import
"cocos2d.h"

#import
"Box2D.h"

#import
<vector>

#define PTM_RATIO
32

// 绳子小段图片的高度和宽度~

#define ROPE_ITEM_WIDTH
16.0f

#define ROPE_ITEM_HEIGHT
4.0f

// 绳子 bar
图片的高度和宽度~

#define ROPE_BAR_DIAMETER
8.0f

// 1.是否在绳子的两个连接点之间启用
距离限定关节~

#define B2_ROPE_JOINT_ENABLED NO

// 2.bar body
到底是连接在绳子最外侧小节的 body
上,还是连接在
comp 元素的 body
~

#define CONNECTED_WITH_COMP_BODY
0  // 紧随comp

#define CONNECTED_WITH_ROPE_BODY
1  // 紧随绳子最外侧小节(因为会随着绳子抖动,所以效果感觉不怎么样)~

#define ROPE_BAR_CONNECT_MODE
0

/**

 * added by BruceYang on 2012.01.15.06.22

 *
Box2D b2Math.h 做功能扩充(c语言
运算符重载的用法)~

 * 之所以放在该类里面而不直接去 box2d
源码里面修改,主要还是为了升级 box2d 库的时候不出现方法丢失的问题~

 * 可想而知,如果这些代码是插进 box2d
源码里面的话,升级的时候一个替换,这些我自己新添加的东西肯定就要丢失了~

 */

inline
b2Vec2
operator * (const
b2Vec2& a,
float32 s) {

return
b2Vec2(s * a.x, s * a.y);

}

inline
b2Vec2
operator / (const
b2Vec2& a,
float32 s) {

return
b2Vec2(a.x / s, a.y / s);

}

inline
float32 b2Vec2ToAngle(const
b2Vec2& v) {

return
atan2f(v.y, v.x);

}

@interface BYRope :
NSObject {

   
// ~

}

/**

 * p1
为在 body1 fxitures
内部的一个世界坐标点
~

 * p2
为在 body2 fxitures
内部的一个世界坐标点
~

 * itemBatch
装载绳子小节图片

 * barBatch 装载绳子端点圆形小图片(若传入参数nil,则绳子两端不包含圆形小图片)~

 */

-(id) init:(b2Body*)body1 

    point1:(b2Vec2)p1 

     body2:(b2Body*)body2 

    point2:(b2Vec2)p2 

 itemBatch:(CCSpriteBatchNode*)itemBatch 

  barBatch:(CCSpriteBatchNode*)barBatch;

-(void) dealloc;

@end

//

//  BYRope.mm

//  GoldMine0.6

//

//  Created by Bruce Yang on 12-1-13.

//  Copyright (c) 2012 __MyCompanyName__. All rights reserved.

//

#import
"BYRope.h"

@implementation BYRope

-(id) init:(b2Body*)body1 

    point1:(b2Vec2)p1 

     body2:(b2Body*)body2 

    point2:(b2Vec2)p2 

 itemBatch:(CCSpriteBatchNode*)itemBatch 

  barBatch:(CCSpriteBatchNode*)barBatch 

{

if((self = [super
init])) {

        // world
完全没必要用一个参数传进来,直接从 body 里面取出来就是了~

       
b2World
*world = body1->GetWorld();

       
vector
<b2Vec2> vPoints;

        

       
// 计算两点之间的距离~

       
float
distance = b2Distance(p1, p2);

        

        //
定义绳子的每段平均长度:长度越短,段数越多;长度越长,段数越少~

       
float
segmentLength = ROPE_ITEM_WIDTH /
PTM_RATIO;

       
int
pointsCount = distance / segmentLength + 1;

        

       
// 两点间的矢量差~

       
b2Vec2
diffVector = p2 - p1;

       
// 求出单位向量~

        diffVector.Normalize();

        

       
float
multiplier = distance / (pointsCount - 1);

       
for
(int i =
0
; i < pointsCount; ++ i) {

           
b2Vec2
vector = p1 + multiplier * i * diffVector;

            vPoints.push_back(vector);

        }

        

       
b2Body
*prevBody = body1;

       
b2BodyDef
bodyDef;

       
b2Body
* body;

       
b2Fixture
* fixture;

       
b2RevoluteJointDef jd;

        

       
b2Body
*firstBd, *lastBd;

       
for
(int i =
0
; i < pointsCount-1; ++ i) {

           
b2Vec2
p1_ = vPoints.at(i);

           
b2Vec2
p2_ = vPoints.at(i+1);

           
b2Vec2
stickVector = p1_ - p2_;

           
float
stickAngle = b2Vec2ToAngle(stickVector);

            

           
b2Vec2
midPoint = (p1_ + p2_) / 2.0f;

            

            bodyDef.type =
b2_dynamicBody;

            body = world->CreateBody(&bodyDef);

            

            //
如果是绳子的第一个或最后一个关节,则不可以被切割~

           
if
(i == 0) {

                firstBd = body;

                body->m_isCuttable =
false;

            }

            

           
b2PolygonShape
boxShape;

            boxShape.SetAsBox(multiplier/2.0f,
ROPE_ITEM_HEIGHT/PTM_RATIO/2.0f);

            fixture = body->CreateFixture(&boxShape,
1.0f);

            

           
// 设置绳子单元不响应碰撞~

            fixture->SetSensor(true);

            body->SetTransform(b2Vec2(midPoint.x, midPoint.y),
stickAngle);

            

           
/**

             * 如果将下面这块代码放到上面那块代码的前面,会出现很奇葩的现象:

             * 所预期的绳子关节不会建立起来,绳子小段会到处乱飞,sprite图片也会一个个从场景中消失不见~

             *
猜测原因可能是因为 body
创建出来的时候
position 还没有确定下来!!

             */

            jd.collideConnected =
false;

           
b2Vec2
anchor(p1_.x, p1_.y);

            jd.Initialize(prevBody, body, anchor);

            world->CreateJoint(&jd);

            prevBody = body;

            

           
if
(i == pointsCount-2) {

                lastBd = body;

                body->m_isCuttable =
false;

                jd.collideConnected =
false;

               
b2Vec2
lastAnchor(p2_.x, p2_.y);

                jd.Initialize(body, body2, lastAnchor);

                world->CreateJoint(&jd);

            }

            

           
CGRect
spriteRect = CGRectMake(0,
0, multiplier*PTM_RATIO,
ROPE_ITEM_HEIGHT);

CCSprite *itemSprite = [CCSprite
spriteWithBatchNode:itemBatch
rect
:spriteRect];

            

ccTexParams params = {
GL_LINEAR, GL_LINEAR,
GL_REPEAT, GL_REPEAT };

[itemSprite.texture
setTexParameters:&params];

            

[itemSprite
setPosition:ccp(midPoint.x*PTM_RATIO, midPoint.y*PTM_RATIO)];

[itemSprite
setRotation:-1 *
CC_RADIANS_TO_DEGREES(stickAngle)];

[itemBatch
addChild:itemSprite];

            body->SetUserData(itemSprite);

        }

        

        //
创建绳子关节,限定两物体之间的最大距离(解决了绳子与被连接物体碰撞的问题,这个绳子关节便没必要创建了)~

       
if(B2_ROPE_JOINT_ENABLED ==
YES) {

           
b2RopeJointDef
rjd;

            rjd.bodyA = body1;

            rjd.bodyB = body2;

            rjd.localAnchorA = p1-body1->GetPosition();

            rjd.localAnchorB = p2-body2->GetPosition();

            rjd.maxLength = (p2 - p1).Length();

            world->CreateJoint(&rjd);

        }

        

       
// 添加绳子端点的图片~

       
if
(barBatch != nil) {

           
// 1.创建绳子端点上的body(给绳子 bar
依附用)~

           
b2BodyDef
bd;

            bd.type =
b2_dynamicBody;

bd.position.Set(p1.x, p1.y);

           
b2Body
*b1 = world->CreateBody(&bd);
// p1
点的 body~

bd.position.Set(p2.x, p2.y);

           
b2Body
*b2 = world->CreateBody(&bd);
// p2
点的 body~

            

           
// 2.将端点 body
连接到绳子最外侧的两个绳子小节
~

           
b2RevoluteJointDef jd;

            jd.collideConnected =
false;

           
if(ROPE_BAR_CONNECT_MODE ==
CONNECTED_WITH_COMP_BODY) {

                jd.Initialize(b1, body1, p1);

                world->CreateJoint(&jd);

                jd.Initialize(b2, body2, p2);

            }
else
if(ROPE_BAR_CONNECT_MODE ==
CONNECTED_WITH_ROPE_BODY) {

                jd.Initialize(b1, firstBd, p1);

                world->CreateJoint(&jd);

                jd.Initialize(b2, lastBd, p2);

            }

            world->CreateJoint(&jd);

            

           
// 3.创建绳子 bar sprite~

           
CCTexture2D
*tex2d = barBatch.textureAtlas.texture;

           
CGRect barRect =
CGRectMake(0,
0, ROPE_BAR_DIAMETER,
ROPE_BAR_DIAMETER);

           
CCSprite
*spriteA = [CCSprite
spriteWithTexture
:tex2d rect:barRect];

            [spriteA
setPosition:ccp(p1.x*PTM_RATIO, p1.y*PTM_RATIO)];

            [barBatch
addChild:spriteA];

            b1->SetUserData(spriteA);

           
CCSprite
*spriteB = [CCSprite
spriteWithTexture
:tex2d rect:barRect];

            [spriteB
setPosition:ccp(p2.x*PTM_RATIO, p2.y*PTM_RATIO)];

            [barBatch
addChild:spriteB];

            b2->SetUserData(spriteB);

        }

}

return
self;

}

-(void)dealloc{

    [super
dealloc];

}

@end

抱歉!评论已关闭.