-1

半径方向の重力を作成するために、次のコードを微調整しています。

http://www.vellios.com/2010/06/06/box2d-and-radial-gravity-code/

現在は正常に動作していますが、たとえば、現在のスプライトがスプライトから特定の距離内にある場合にのみこのコードがトリガーされるようにしたかったのです。

いくつかのガイドが必要です。世界に無重力を与えたので、今はスプライトが浮いていますが、次のようにしたかったのです。

スプライトが X へのプロジェクト パスを移動しています。重力をオフにしているため、これには重力が適用されません。D と呼ばれるこの物体がこのパスの特定の制限内にある場合、半径方向の重力コードが影響を及ぼします。それ以外の場合は、投影されたパスを続行します。

このコードを変更してそれを行う方法を知っている人はいますか?

      // Import the interfaces  
    #import "HelloWorldLayer.h"

    // Needed to obtain the Navigation Controller
    #import "AppDelegate.h"

    #import "PhysicsSprite.h"

    enum {
kTagParentNode = 1,
    };

    CGPoint location;
    CGPoint nodePosition;

    #pragma mark - HelloWorldLayer

    @interface HelloWorldLayer()
    -(void) initPhysics;
    -(void) addNewSpriteAtPosition:(CGPoint)p;
    -(void) createMenu;
    @end

    @implementation HelloWorldLayer

    +(CCScene *) scene
    {
// 'scene' is an autorelease object.
CCScene *scene = [CCScene node];

// 'layer' is an autorelease object.
HelloWorldLayer *layer = [HelloWorldLayer node];

// add layer as a child to scene
[scene addChild: layer];

// return the scene
return scene;
    }

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

    // enable events

    self.isTouchEnabled = YES;
    self.isAccelerometerEnabled = YES;
    CGSize s = [CCDirector sharedDirector].winSize;

    // init physics
    [self initPhysics];

    // create reset button
    [self createMenu];

    //Set up sprite

    #if 1
    // Use batch node. Faster
    CCSpriteBatchNode *parent = [CCSpriteBatchNode batchNodeWithFile:@"blocks.png"                      capacity:100];
    spriteTexture_ = [parent texture];
    #else
    // doesn't use batch node. Slower
    spriteTexture_ = [[CCTextureCache sharedTextureCache] addImage:@"blocks.png"];
    CCNode *parent = [CCNode node];
    #endif
    [self addChild:parent z:0 tag:kTagParentNode];


    [self addNewSpriteAtPosition:ccp(s.width/2 - 150, s.height/2)];


    [self scheduleUpdate];
}
return self;
            }

    -(void) dealloc
    {
delete world;
world = NULL;

delete m_debugDraw;
m_debugDraw = NULL;

[super dealloc];
    }   

    -(void) createMenu
    {
// Default font size will be 22 points.
[CCMenuItemFont setFontSize:22];

// Reset Button
CCMenuItemLabel *reset = [CCMenuItemFont itemWithString:@"Reset" block:^(id sender){
    [[CCDirector sharedDirector] replaceScene: [HelloWorldLayer scene]];
}];



CCMenu *menu = [CCMenu menuWithItems:reset, nil];

[menu alignItemsVertically];

CGSize size = [[CCDirector sharedDirector] winSize];
[menu setPosition:ccp( size.width/2, size.height/2)];


[self addChild: menu z:-1]; 
    }

    -(void) initPhysics
    {

CGSize s = [[CCDirector sharedDirector] winSize];

b2Vec2 gravity;
gravity.Set(0.0f, 0.0f);
world = new b2World(gravity);


// Do we want to let bodies sleep?
world->SetAllowSleeping(true);

world->SetContinuousPhysics(true);

m_debugDraw = new GLESDebugDraw( PTM_RATIO );
world->SetDebugDraw(m_debugDraw);

uint32 flags = 0;
flags += b2Draw::e_shapeBit;
//      flags += b2Draw::e_jointBit;
//      flags += b2Draw::e_aabbBit;
//      flags += b2Draw::e_pairBit;
//      flags += b2Draw::e_centerOfMassBit;
m_debugDraw->SetFlags(flags);       


// Define the ground body.
b2BodyDef groundBodyDef;
groundBodyDef.position.Set(0, 0); // bottom-left corner

// Call the body factory which allocates memory for the ground body
// from a pool and creates the ground box shape (also from a pool).
// The body is also added to the world.
b2Body* groundBody = world->CreateBody(&groundBodyDef);

// Define the ground box shape.
b2EdgeShape groundBox;      

// bottom

groundBox.Set(b2Vec2(0,0), b2Vec2(s.width/PTM_RATIO,0));
groundBody->CreateFixture(&groundBox,0);

// top
groundBox.Set(b2Vec2(0,s.height/PTM_RATIO),            b2Vec2(s.width/PTM_RATIO,s.height/PTM_RATIO));
groundBody->CreateFixture(&groundBox,0);

// left
groundBox.Set(b2Vec2(0,s.height/PTM_RATIO), b2Vec2(0,0));
groundBody->CreateFixture(&groundBox,0);

// right
groundBox.Set(b2Vec2(s.width/PTM_RATIO,s.height/PTM_RATIO), b2Vec2(s.width/PTM_RATIO,0));
groundBody->CreateFixture(&groundBox,0);

b2CircleShape shape;
shape.m_radius = 0.5f;
shape.m_p.Set(8.0f, 5.0f);
b2FixtureDef fd;
fd.shape = &shape;
planet = groundBody->CreateFixture(&fd);

    }

    -(void) draw
    {
//
// IMPORTANT:
// This is only for debug purposes
// It is recommend to disable it
//
[super draw];

ccGLEnableVertexAttribs( kCCVertexAttribFlag_Position );

kmGLPushMatrix();

world->DrawDebugData(); 

kmGLPopMatrix();
    }

    -(void) addNewSpriteAtPosition:(CGPoint)p
    {
CCLOG(@"Add sprite %0.2f x %02.f",p.x,p.y);
CCNode *parent = [self getChildByTag:kTagParentNode];

//We have a 64x64 sprite sheet with 4 different 32x32 images.  The following code is
//just randomly picking one of the images
int idx = (CCRANDOM_0_1() > .5 ? 0:1);
int idy = (CCRANDOM_0_1() > .5 ? 0:1);
PhysicsSprite *sprite = [PhysicsSprite spriteWithTexture:spriteTexture_ rect:CGRectMake(16 * idx,16 * idy,16,16)];
[parent addChild:sprite];

sprite.position = ccp( p.x, p.y);

// Define the dynamic body.
//Set up a 1m squared box in the physics world
b2BodyDef bodyDef;
bodyDef.type = b2_dynamicBody;
bodyDef.position.Set(p.x/PTM_RATIO, p.y/PTM_RATIO);
b2Body *body = world->CreateBody(&bodyDef);

// Define another box shape for our dynamic body.
b2PolygonShape dynamicBox;
dynamicBox.SetAsBox(.3f, .3f);//These are mid points for our 1m box

// Define the dynamic body fixture.
b2FixtureDef fixtureDef;
fixtureDef.shape = &dynamicBox; 
fixtureDef.density = 2.0f;
fixtureDef.friction = 0.3f;
body->CreateFixture(&fixtureDef);

[sprite setPhysicsBody:body];

        b2Vec2 currentPosition = body->GetPosition();
        b2Vec2 desiredPosition;
        desiredPosition.Set(467.0f/PTM_RATIO, 169.0f/PTM_RATIO);

        b2Vec2 necessaryMovement = desiredPosition - currentPosition;
        float necessaryDistance = necessaryMovement.Length();
        necessaryMovement.Normalize();
        float forceMagnitude = b2Min(150.0f, necessaryDistance *PTM_RATIO /2);
        b2Vec2 force = forceMagnitude * necessaryMovement;
        body->ApplyForce( force, body->GetWorldCenter() );

    }

    -(void) update: (ccTime) dt
    {
//It is recommended that a fixed time step is used with Box2D for stability
//of the simulation, however, we are using a variable time step here.
//You need to make an informed choice, the following URL is useful
//http://gafferongames.com/game-physics/fix-your-timestep/

int32 velocityIterations = 8;
int32 positionIterations = 1;

// Instruct the world to perform a single step of simulation. It is
// generally best to keep the time step and iterations fixed.
world->Step(dt, velocityIterations, positionIterations);

for (b2Body* b = world->GetBodyList(); b; b = b->GetNext())
{
    b2Body* ground = planet->GetBody();
    b2CircleShape* circle = (b2CircleShape*)planet->GetShape();
    // Get position of our "Planet"
    b2Vec2 center = ground->GetWorldPoint(circle->m_p);
    // Get position of our current body in the iteration
    b2Vec2 position = b->GetPosition();
    // Get the distance between the two objects.
    b2Vec2 d = center - position;
    // The further away the objects are, the weaker the gravitational force is
    float force = 0.0f / d.LengthSquared(); // 150 can be changed to adjust the amount of force
    d.Normalize();
    b2Vec2 F = force * d;
    // Finally apply a force on the body in the direction of the "Planet"
    b->ApplyForce(F, position);

    if (b->GetUserData() != NULL) {
        CCSprite *myActor = (CCSprite*)b->GetUserData();
        myActor.position = CGPointMake( b->GetPosition().x * PTM_RATIO, b->GetPosition().y * PTM_RATIO);
        myActor.rotation = -1 * CC_RADIANS_TO_DEGREES(b->GetAngle());
    }   
}

    }

    - (void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
    {
//Add a new body/atlas sprite at the touched location
for( UITouch *touch in touches ) {
    location = [touch locationInView: [touch view]];

    location = [[CCDirector sharedDirector] convertToGL: location];

    nodePosition = [self convertToNodeSpace: location];

    [self addNewSpriteAtPosition: location];
}
    }



    @end
4

1 に答える 1

0

あなたはあなたの体に力を加えていません。

float force = 0.0f / d.LengthSquared();

dの値に関係なく、常にゼロになります。

これが線形重力井戸の簡単な式です。もちろん、これは重力が実際にどのように機能するかではありませんが、あなたが望むものには十分かもしれません。

最大距離maxDistanceでゼロ力を適用し、ゼロ距離で最大力maxForceを適用する場合、力の大きさは単純に次のようになります。

Force = maxForce * (maxDistance - d)/maxDistance;

したがって、d = maxDistanceの場合、力は0であり、d = 0の場合、force=maxForceです。

私が言ったように、これは本当の重力がどのように機能するかではありません。実際には重力は距離の2乗に比例するため、これがうまくいかない場合は実験する必要があります。

于 2013-01-13T03:46:58.633 に答える